Initial import of ViperOS

This commit is contained in:
Viper
2026-07-19 12:38:20 +08:00
commit 6813947181
104 changed files with 26710 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
import t, c
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
@c.Attribute(t.attr.packed)
class memory_map_entry:
type: t.CUnsignedInt
_pad: t.CUnsignedInt
physical_start: t.CUnsignedLong
virtual_start: t.CUnsignedLong
num_pages: t.CUnsignedLong
attribute: t.CUnsignedLong
class bootinfo:
MemmapAddr: t.CUnsignedLong
MemmapSize: t.CUnsignedLong
MemmapDescSize: t.CUnsignedLong
kernel_PhysAddr: t.CUnsignedLong
framebuffer_addr: t.CUnsignedLong
framebuffer_size: t.CUnsignedLong
framebuffer_width: t.CUnsignedLong
framebuffer_height: t.CUnsignedLong
framebuffer_pitch: t.CUnsignedLong
framebuffer_format: t.CUnsignedLong
system_table: t.CUnsignedLong

View File

@@ -0,0 +1,251 @@
import asm
import intr.gdt as gdt
import intr.idt as idt
import drivers.serial.uart.serial as serial
import drivers.core.cpu.cpu as cpu
import mm.mm as mm
import platform.pch.timer as timer
import viperlib
import t, c
IA32_APIC_BASE: t.CDefine = 0x1B
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
LAPIC_ID: t.CDefine = 0x020
LAPIC_VERSION: t.CDefine = 0x030
LAPIC_TPR: t.CDefine = 0x080
LAPIC_EOI: t.CDefine = 0x0B0
LAPIC_LDR: t.CDefine = 0x0D0
LAPIC_SVR: t.CDefine = 0x0F0
LAPIC_ISR0: t.CDefine = 0x100
LAPIC_ICR_LOW: t.CDefine = 0x300
LAPIC_ICR_HIGH: t.CDefine = 0x310
LAPIC_LVT_TIMER: t.CDefine = 0x320
LAPIC_LVT_LINT0: t.CDefine = 0x350
LAPIC_LVT_LINT1: t.CDefine = 0x360
LAPIC_LVT_ERROR: t.CDefine = 0x370
LAPIC_TIMER_INIT: t.CDefine = 0x380
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
LAPIC_SVR_ENABLE: t.CDefine = 0x100
LAPIC_LVT_MASKED: t.CDefine = 0x10000
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
LAPIC_ICR_INIT: t.CDefine = 0x500
LAPIC_ICR_STARTUP: t.CDefine = 0x600
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
MAX_CPUS: t.CDefine = 8
AP_TRAMPOLINE_ADDR: t.CDefine = 0x7000
_lapic_base: t.CStatic | t.CUInt64T = 0
_cpu_count: t.CStatic | t.CUInt32T = 1
_bsp_lapic_id: t.CStatic | t.CUInt32T = 0
_ap_ready: t.CStatic | t.CUInt32T = 0
def read(offset: t.CUInt32T) -> t.CUInt32T:
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
return c.Deref(t.CUInt32T(addr, t.CPtr))
def write(offset: t.CUInt32T, value: t.CUInt32T):
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
c.Set(c.Deref(t.CUInt32T(addr, t.CPtr)), value)
def eoi():
write(LAPIC_EOI, 0)
def get_id() -> t.CUInt32T:
return read(LAPIC_ID) >> 24
@c.Attribute(t.attr.noinline)
def init():
global _lapic_base, _bsp_lapic_id
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
_bsp_lapic_id = read(LAPIC_ID) >> 24
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
write(LAPIC_TPR, 0)
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
write(LAPIC_TIMER_DIVIDE, 0x0B)
write(LAPIC_LDR, 0x01000000)
eoi()
@c.Attribute(t.attr.noinline)
def detect_cpu_count() -> t.CUInt32T:
res: cpu.cpuid_result
cpu.cpuid(0, c.Addr(res))
max_leaf: t.CUInt32T = res.eax
if max_leaf >= 0x0B:
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
num_threads: t.CUInt32T = res.ebx & 0xFFFF
if num_threads > 0 and num_threads <= MAX_CPUS:
return num_threads
cpu.cpuid(1, c.Addr(res))
if res.edx & cpu.CPU_FEATURE_HTT:
count: t.CUInt32T = (res.ebx >> 16) & 0xFF
if count > 0 and count <= MAX_CPUS:
return count
return 1
def _wait_icr():
timeout: t.CUInt32T = 1000000
while timeout > 0:
val: t.CUInt32T = read(LAPIC_ICR_LOW)
if (val & (1 << 12)) == 0:
return
timeout -= 1
def _send_ipi(apic_id: t.CUInt32T, vector: t.CUInt32T, delivery_mode: t.CUInt32T):
_wait_icr()
write(LAPIC_ICR_HIGH, apic_id << 24)
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
_wait_icr()
def ap_entry():
global _ap_ready
my_id: t.CUInt32T = get_id()
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
serial.puts(buf)
_ap_ready = 1
while True:
asm.sti()
asm.hlt()
_trampoline_bin: t.CStatic | t.CArray[t.CUInt8T, 128] = [
0xFA, # cli
0x31, 0xC0, # xor ax, ax
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
0x0F, 0x20, 0xC0, # mov eax, cr0
0x83, 0xC8, 0x01, # or eax, 1
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
# 32-bit 保护模式开始
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x0F, 0x20, 0xE0, # mov eax, cr4
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
0x0F, 0x22, 0xE0, # mov cr4, eax
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
0x0F, 0x22, 0xD8, # mov cr3, eax
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
0x0F, 0x32, # rdmsr
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
0x0F, 0x79, # wrmsr
0x0F, 0x20, 0xC0, # mov eax, cr0
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
0x0F, 0x22, 0xC0, # mov cr0, eax
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
# 64-bit 长模式开始
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
0x8E, 0xD8, # mov ds, ax
0x8E, 0xC0, # mov es, ax
0x8E, 0xE0, # mov fs, ax
0x8E, 0xE8, # mov gs, ax
0x8E, 0xD0, # mov ss, ax
0x48, 0x8B, 0x04, 0x25, 0x28, 0x7F, 0x00, 0x00, # mov rax, [0x7F28]
0xFF, 0xE0 # jmp rax
]
def _setup_trampoline(entry_addr: t.CUInt64T, stack_addr: t.CUInt64T, cr3_val: t.CUInt64T):
dest: t.CUInt8T | t.CPtr = t.CUInt8T(AP_TRAMPOLINE_ADDR, t.CPtr)
src: t.CUInt8T | t.CPtr = c.Addr(_trampoline_bin)
i: t.CInt
for i in range(128):
c.Set(c.Deref(dest + t.CUInt64T(i)), c.Deref(src + t.CUInt64T(i)))
gdt_ptr_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E00
c.Set(c.Deref(t.CUInt16T(gdt_ptr_addr, t.CPtr)), t.CUInt16T(23))
c.Set(c.Deref(t.CUInt64T(gdt_ptr_addr + 2, t.CPtr)), t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0E10))
gdt_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E10
c.Set(c.Deref(t.CUInt64T(gdt_addr, t.CPtr)), t.CUInt64T(0))
c.Set(c.Deref(t.CUInt64T(gdt_addr + 8, t.CPtr)), t.CUInt64T(0x00AF9A000000FFFF))
c.Set(c.Deref(t.CUInt64T(gdt_addr + 16, t.CPtr)), t.CUInt64T(0x00CF92000000FFFF))
c.Set(c.Deref(t.CUInt32T(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), t.CUInt32T(cr3_val))
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
gp_addr: t.CUInt64T = t.CUInt64T(c.Addr(gdt.gp))
gdt_base: t.CUInt64T = c.Deref(t.CUInt64T(gp_addr + 2, t.CPtr))
gdt_limit: t.CUInt16T = c.Deref(t.CUInt16T(gp_addr, t.CPtr))
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
idt_addr: t.CUInt64T = t.CUInt64T(c.Addr(idt.idp))
idt_base: t.CUInt64T = c.Deref(t.CUInt64T(idt_addr + 2, t.CPtr))
idt_limit: t.CUInt16T = c.Deref(t.CUInt16T(idt_addr, t.CPtr))
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F28, t.CPtr)), entry_addr)
def start_aps():
global _cpu_count, _ap_ready
if _cpu_count <= 1: return
cr3_val: t.CUInt64T = 0
c.Asm(f"""mov rax, cr3
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
stack_size: t.CUInt64T = 8192
i: t.CUInt32T
for i in range(1, _cpu_count):
_ap_ready = 0
stack: t.CVoid | t.CPtr = mm.malloc(stack_size)
if stack is None: continue
stack_top: t.CUInt64T = t.CUInt64T(stack) + stack_size
stack_top = stack_top & ~t.CUInt64T(15)
_setup_trampoline(t.CUInt64T(ap_entry), stack_top, cr3_val)
_send_ipi(i, 0, LAPIC_ICR_INIT)
timer.timer_msleep(10)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
timer.timer_msleep(1)
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
wait: t.CUInt32T = 0
while _ap_ready == 0 and wait < 5000:
timer.timer_msleep(1)
wait += 1
def early_init():
global _cpu_count, _bsp_lapic_id
features: t.CUInt32T = cpu.detect_features_static()
if features & cpu.CPU_FEATURE_APIC:
init()
_cpu_count = detect_cpu_count()
else:
_cpu_count = 1
def get_cpu_count() -> t.CUInt32T:
return _cpu_count
def get_lapic_id() -> t.CUInt32T:
return get_id()

View File

@@ -0,0 +1,346 @@
import fpu
import asm
import intr.gdt as gdt
import string
import t, c
IA32_KERNEL_GS_BASE: t.CDefine = 0xC0000102
KERN_STACK_SIZE: t.CDefine = 8192
CPU_FEATURE_FPU: t.CDefine = (1 << 0)
CPU_FEATURE_PSE: t.CDefine = (1 << 1)
CPU_FEATURE_MSR: t.CDefine = (1 << 2)
CPU_FEATURE_PAE: t.CDefine = (1 << 3)
CPU_FEATURE_MCE: t.CDefine = (1 << 4)
CPU_FEATURE_CX8: t.CDefine = (1 << 5)
CPU_FEATURE_APIC: t.CDefine = (1 << 6)
CPU_FEATURE_SEP: t.CDefine = (1 << 7)
CPU_FEATURE_MTRR: t.CDefine = (1 << 8)
CPU_FEATURE_PGE: t.CDefine = (1 << 9)
CPU_FEATURE_MCA: t.CDefine = (1 << 10)
CPU_FEATURE_CMOV: t.CDefine = (1 << 11)
CPU_FEATURE_PAT: t.CDefine = (1 << 12)
CPU_FEATURE_PSE36: t.CDefine = (1 << 13)
CPU_FEATURE_PSN: t.CDefine = (1 << 14)
CPU_FEATURE_CLFSH: t.CDefine = (1 << 15)
CPU_FEATURE_DS: t.CDefine = (1 << 16)
CPU_FEATURE_ACPI: t.CDefine = (1 << 17)
CPU_FEATURE_MMX: t.CDefine = (1 << 18)
CPU_FEATURE_FXSR: t.CDefine = (1 << 19)
CPU_FEATURE_SSE: t.CDefine = (1 << 20)
CPU_FEATURE_SSE2: t.CDefine = (1 << 21)
CPU_FEATURE_SS: t.CDefine = (1 << 22)
CPU_FEATURE_HTT: t.CDefine = (1 << 23)
CPU_FEATURE_TM: t.CDefine = (1 << 24)
CPU_FEATURE_PBE: t.CDefine = (1 << 25)
class cpu_info(t.CStruct):
vendor_id: t.CArray[t.CChar, 13]
brand_string: t.CArray[t.CChar, 48]
features: t.CUInt32T
family: t.CUInt32T
model: t.CUInt32T
stepping: t.CUInt32T
cpu_type: t.CUInt32T
ext_model: t.CUInt32T
ext_family: t.CUInt32T
cpu_freq: t.CUInt64T
@c.Attribute(t.attr.packed)
class _tss:
reserved0: t.CUInt64T
rsp0: t.CUInt64T
rsp1: t.CUInt64T
rsp2: t.CUInt64T
reserved1: t.CUInt64T
ist1: t.CUInt64T
ist2: t.CUInt64T
ist3: t.CUInt64T
ist4: t.CUInt64T
ist5: t.CUInt64T
ist6: t.CUInt64T
ist7: t.CUInt64T
reserved2: t.CUInt64T
reserved3: t.CUInt16T
io_map_base: t.CUInt16T
class cpuid_result(t.CStruct):
eax: t.CUInt32T
ebx: t.CUInt32T
ecx: t.CUInt32T
edx: t.CUInt32T
@c.Attribute(t.attr.naked)
def _rdmsr_naked():
c.Asm(f"""rdmsr
shl rdx, 32
or rax, rdx
ret""",
op=[t.ASM_DESCR.CLOBBER_RDX])
@c.Attribute(t.attr.naked)
def _wrmsr_naked():
# msr_write sets ecx=msr, r8=value. wrmsr needs ECX=msr, EDX:EAX=value.
# Old code did `mov rax,rcx` (rax=msr) which wrote (value>>32):msr to MSR,
# corrupting IA32_KERNEL_GS_BASE -> swapgs -> #GP on gs:[0]. Fixed below.
c.Asm(f"""mov rax, r8
mov rdx, r8
shr rdx, 32
wrmsr
ret""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
def msr_read(msr: t.CUInt32T) -> t.CUInt64T:
result: t.CUInt64T = 0
func: t.CVoid | t.CPtr = _rdmsr_naked
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
return result
def msr_write(msr: t.CUInt32T, value: t.CUInt64T):
func: t.CVoid | t.CPtr = _wrmsr_naked
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
mov r8, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8])
@c.Attribute(t.attr.naked)
def _cpuid_naked():
c.Asm(f"""push rbx
mov eax, ecx
cpuid
mov dword ptr [rdx], eax
mov dword ptr [rdx + 4], ebx
mov dword ptr [rdx + 8], ecx
mov dword ptr [rdx + 12], edx
pop rbx
ret""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDX])
@c.Attribute(t.attr.naked)
def _cpuid_sub_naked():
c.Asm(f"""push rbx
mov eax, ecx
mov ecx, r8d
cpuid
mov dword ptr [rdx], eax
mov dword ptr [rdx + 4], ebx
mov dword ptr [rdx + 8], ecx
mov dword ptr [rdx + 12], edx
pop rbx
ret""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDX])
@c.Attribute(t.attr.noinline)
def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
func: t.CVoid | t.CPtr = _cpuid_naked
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8,
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
t.ASM_DESCR.CLOBBER_R11])
@c.Attribute(t.attr.noinline)
def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
func: t.CVoid | t.CPtr = _cpuid_sub_naked
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
mov r8d, {c.AsmInp(sub, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX,
t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_R8,
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
t.ASM_DESCR.CLOBBER_R11])
@c.Attribute(t.attr.noinline)
def detect_features_static() -> t.CUInt32T:
features: t.CUInt32T = 0
res: cpuid_result
cpuid(1, c.Addr(res))
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
return features
@c.Attribute(t.attr.packed)
class per_cpu_data:
user_rsp: t.CUInt64T
kernel_rsp0: t.CUInt64T
current_pid: t.CInt
_pad0: t.CUInt32T
_pad1: t.CUInt64T
_per_cpu: per_cpu_data
@t.Object
class _CPUObject:
tss: _tss
features: t.CUInt32T
def __init__(self):
self.__init_tss__()
def __init_tss__(self):
global _per_cpu
string.memset(c.Addr(self.tss), 0, self.tss.__sizeof__())
self.tss.io_map_base = self.tss.__sizeof__()
string.memset(c.Addr(_per_cpu), 0, per_cpu_data.__sizeof__())
gdt.setTSS64(5, t.CUInt64T(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
gdt.flush()
# IA32_KERNEL_GS_BASE holds the per_cpu address for swapgs.
# When entering from Ring 3, swapgs swaps IA32_GS_BASE (0) with
# IA32_KERNEL_GS_BASE (_per_cpu), making gs: accessible in kernel.
# When returning to Ring 3, swapgs swaps back, restoring GS base to 0.
msr_write(IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(_per_cpu)))
def getInfo(self, info: cpu_info | t.CPtr):
if not info: return
res: cpuid_result
cpuid(0, c.Addr(res))
(t.CUInt32T(info.vendor_id, t.CPtr))[0] = res.ebx
(t.CUInt32T(info.vendor_id, t.CPtr))[1] = res.edx
(t.CUInt32T(info.vendor_id, t.CPtr))[2] = res.ecx
info.vendor_id[12] = '\0'
info.features = self.detectFeatures()
cpuid(1, c.Addr(res))
info.stepping = (res.eax >> 0) & 0x0F
info.model = (res.eax >> 4) & 0x0F
info.family = (res.eax >> 8) & 0x0F
info.cpu_type = (res.eax >> 12) & 0x03
info.ext_model = (res.eax >> 16) & 0x0F
info.ext_family = (res.eax >> 20) & 0xFF
for i in range(4):
cpuid(0x80000002 + i, c.Addr(res))
base: t.CUInt32T | t.CPtr = t.CUInt32T(info.brand_string, t.CPtr)
base[i * 4 + 0] = res.eax
base[i * 4 + 1] = res.ebx
base[i * 4 + 2] = res.ecx
base[i * 4 + 3] = res.edx
info.brand_string[47] = '\0'
info.cpu_freq = 2000000000
def detectFeatures(self) -> t.CUInt32T:
features: t.CInt32T = 0
res: cpuid_result
cpuid(1, c.Addr(res))
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
return features
def enableInterrupts(self):
c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY])
def disableInterrupts(self):
c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])
def enableNmis(self):
current: t.CUInt8T = asm.inb(0x70)
asm.outb(0x70, current & 0x7F)
def disableNmis(self):
current: t.CUInt8T = asm.inb(0x70)
asm.outb(0x70, current | 0x80)
def readCR0(self) -> t.CUInt64T:
cr0: t.CUInt64T
c.Asm(f"""mov rax, cr0
mov {c.AsmOut(cr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
return cr0
def writeCR0(self, value: t.CUInt64T):
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov cr0, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
def readCR3(self) -> t.CUInt64T:
cr3: t.CUInt64T
c.Asm(f"""mov rax, cr3
mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
return cr3
def writeCR3(self, value: t.CUInt64T):
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov cr3, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
def readCR4(self) -> t.CUInt64T:
cr4: t.CUInt64T
c.Asm(f"""mov rax, cr4
mov {c.AsmOut(cr4, t.ASM_DESCR.OUTPUT_REG)}, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
return cr4
def writeCR4(self, value: t.CUInt64T):
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
mov cr4, rax""",
[t.ASM_DESCR.CLOBBER_RAX])
def readMSR(self, msr: t.CUInt32T) -> t.CUInt64T:
return msr_read(msr)
def writeMSR(self, msr: t.CUInt32T, value: t.CUInt64T):
msr_write(msr, value)
def setTSSRSP0(self, rsp0: t.CUInt64T):
global _per_cpu
self.tss.rsp0 = rsp0
_per_cpu.kernel_rsp0 = rsp0
def set_kernel_rsp0(rsp0: t.CUInt64T):
global _per_cpu
_per_cpu.kernel_rsp0 = rsp0

View File

@@ -0,0 +1,50 @@
import cpu
import t, c
# FPU上下文结构体
@c.Attribute(t.attr.aligned(16))
class fpu_context:
data: t.CUInt8T[512] # FXSAVE区域大小
@t.Object
class _FPUObject:
CPUObject: cpu._CPUObject | t.CPtr
# 初始化FPU
def __init__(self, CPUObject: cpu._CPUObject | t.CPtr):
self.enable()
self.CPUObject = CPUObject
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
# 启用FPU
def enable(self):
cr0: t.CUInt64T = self.CPUObject.readCR0()
# 清除EM位禁用仿真设置MP位监控协处理器
cr0 &= ~(1 << 2); # 清除EM位
cr0 |= (1 << 1); # 设置MP位
# 写入CR0寄存器
self.CPUObject.writeCR0(cr0)
# 读取CR4寄存器
cr4: t.CUInt64T = self.CPUObject.readCR4()
# 设置OSFXSR位和OSXMMEXCPT位启用SSE
cr4 |= (1 << 9) | (1 << 10)
# 写入CR4寄存器
self.CPUObject.writeCR4(cr4)
# 初始化FPU
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
# 禁用FPU
def disable(self):
cr0: t.CUInt64T = self.CPUObject.readCR0()
# 设置EM位启用仿真清除MP位禁用监控协处理器
cr0 |= (1 << 2) # 设置EM位
cr0 &= ~(1 << 1) # 清除MP位
# 写入CR0寄存器
self.CPUObject.writeCR0(cr0)
# 保存FPU上下文
def save_context(self, context: fpu_context | t.CPtr):
# 保存FPU状态到内存
c.Asm(f"fxsave [{c.AsmInp(context, t.ASM_DESCR.REG_ANY)}]", [t.ASM_DESCR.CLOBBER_MEMORY])
# 恢复FPU上下文
def restore_context(self, context: t.CConst | fpu_context | t.CPtr):
# 从内存恢复FPU状态
c.Asm(f"fxrstor [{c.AsmInp(context, t.ASM_DESCR.REG_ANY)}]", [t.ASM_DESCR.CLOBBER_MEMORY])

View File

@@ -0,0 +1,491 @@
import drivers.serial.uart.serial as serial
import viperstring as string
import t, c
MAX_FILE_DESCRIPTORS: t.CDefine = 64
MAX_DEVICE_FILES: t.CDefine = 32
MAX_DIRECTORIES: t.CDefine = 16
PATH_BUFFER_SIZE: t.CDefine = 256
directories: t.CArray[devfs_directory, MAX_DIRECTORIES] = [0]
directory_count: t.CStatic | t.CInt = 0
files: t.CArray[devfs_file, MAX_DEVICE_FILES] = [0]
file_count: t.CStatic | t.CInt = 0
class _fd_table:
file: devfs_file | t.CPtr
flags: t.CInt
fd_table: t.CArray[_fd_table, MAX_FILE_DESCRIPTORS] = [0]
@t.Object
class devfs_directory:
name: t.CArray[t.CChar, 64]
parent: 'devfs_directory' | t.CPtr
@staticmethod
def find(path: t.CConst | str,
root_directory: devfs_directory | t.CPtr) -> devfs_directory | t.CPtr:
if not path or string.strchr(path, '/') != path: return None
if not root_directory: return None
current_dir: devfs_directory | t.CPtr = root_directory
result: t.CArray[str, PATH_BUFFER_SIZE]
token = string.split(path, "/", result)
for i in result:
found: bool = False
for d in range(directory_count):
dirp: devfs_directory = c.Addr(directories[d])
if dirp.parent == current_dir and string.samestr(dirp.name, i):
current_dir = dirp
found = True
break
if not found: return None
return current_dir
@staticmethod
def find_child(name: t.CConst | str,
parent: devfs_directory | t.CPtr) -> devfs_directory | t.CPtr:
for d in range(directory_count):
dirp: devfs_directory = c.Addr(directories[d])
if dirp.parent == parent and string.samestr(dirp.name, name):
return dirp
return None
@staticmethod
def list_subdirs(dir_ptr: devfs_directory | t.CPtr,
buffer: str,
size: t.CUInt32T,
pos: t.CInt) -> t.CInt:
for d in range(directory_count):
dirp: devfs_directory = c.Addr(directories[d])
if dirp.parent == dir_ptr:
name_len: t.CInt = string.strlen(dirp.name)
if pos + name_len + 1 > size:
break
string.strcpy(buffer + pos, dirp.name)
pos += name_len
buffer[pos] = '\n'
pos += 1
return pos
@t.Object
@t.CVTable
class devfs_file:
name: t.CArray[t.CChar, 64]
private_data: t.CVoid | t.CPtr
parent_dir: 'devfs_directory' | t.CPtr
@staticmethod
def find_in_dir(file_name: t.CConst | str,
dir_ptr: devfs_directory | t.CPtr) -> devfs_file | t.CPtr:
for f in range(file_count):
fp: devfs_file | t.CPtr = c.Addr(files[f])
if fp.parent_dir == dir_ptr and string.samestr(fp.name, file_name):
return fp
return None
@staticmethod
def list_in_dir(dir_ptr: devfs_directory | t.CPtr,
buffer: str,
size: t.CUInt32T,
pos: t.CInt) -> t.CInt:
for f in range(file_count):
filep: devfs_file | t.CPtr = c.Addr(files[f])
if filep.parent_dir == dir_ptr:
name_len: t.CInt = string.strlen(filep.name)
if pos + name_len + 1 > size:
break
string.strcpy(buffer + pos, filep.name)
pos += name_len
buffer[pos] = '\n'
pos += 1
return pos
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
return 0
def close(self, fd: t.CInt) -> t.CInt:
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
return 0
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
return 0
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
return 0
@t.Object
class _DevFSObject:
root_directory: devfs_directory | t.CPtr
def __init__(self):
global directory_count, file_count
self.root_directory = None
directory_count = 0
file_count = 0
string.memset(c.Addr(directories), 0, devfs_directory.__sizeof__() * MAX_DIRECTORIES)
string.memset(c.Addr(files), 0, devfs_file.__sizeof__() * MAX_DEVICE_FILES)
string.memset(c.Addr(fd_table), 0, _fd_table.__sizeof__() * MAX_FILE_DESCRIPTORS)
def create_single_dir(self, parent: devfs_directory | t.CPtr,
dir_name: t.CConst | str) -> devfs_directory | t.CPtr:
global directory_count
if not parent or not dir_name: return None
if directory_count >= MAX_DIRECTORIES: return None
if string.strlen(dir_name) >= 64: return None
new_dir: devfs_directory | t.CPtr = c.Addr(directories[directory_count])
directory_count += 1
string.strcpy(new_dir.name, dir_name)
new_dir.parent = parent
return new_dir
def find_or_create_directory(self, path: t.CConst | str) -> devfs_directory | t.CPtr:
global directory_count
if not path or string.samestr(path, "/"): return None
serial.puts("A")
if not self.root_directory:
self.root_directory = c.Addr(directories[directory_count])
directory_count += 1
string.strcpy(self.root_directory.name, "")
self.root_directory.parent = None
serial.puts("B")
current: devfs_directory | t.CPtr = self.root_directory
buf: t.CArray[t.CChar, PATH_BUFFER_SIZE]
string.memset(c.Addr(buf), 0, PATH_BUFFER_SIZE)
buf_idx: t.CInt = 0
p: t.CInt = 0
if path[p] == '/':
p += 1
serial.puts("C")
while path[p] != '\0':
if path[p] == '/':
if buf_idx > 0:
found_child: devfs_directory | t.CPtr = devfs_directory.find_child(buf, current)
if not found_child:
found_child = self.create_single_dir(current, buf)
if not found_child: return None
current = found_child
string.memset(c.Addr(buf), 0, PATH_BUFFER_SIZE)
buf_idx = 0
p += 1
else:
buf[buf_idx] = path[p]
buf_idx += 1
p += 1
serial.puts("D")
if buf_idx > 0:
found_child: devfs_directory | t.CPtr = devfs_directory.find_child(buf, current)
if not found_child:
found_child = self.create_single_dir(current, buf)
if not found_child: return None
current = found_child
serial.puts("E")
return current
def init(self) -> t.CInt:
self.create_directory("/dev")
self.create_directory("/dev/input")
return 0
def create_directory(self, path: t.CConst | str) -> t.CInt:
serial.puts("T1")
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(path)
serial.puts("T2")
return 0 if dir_ptr else -1
def create_file(self, path: t.CConst | str,
file_ptr: devfs_file | t.CPtr,
private_data: t.CVoid | t.CPtr) -> t.CInt:
global file_count
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
string.strcpy(path_copy, path)
last_slash: str | t.CPtr = string.strrchr(path_copy, '/')
if not last_slash: return -1
last_slash[0] = '\0'
dir_path = path_copy
file_name: str | t.CPtr = last_slash + 1
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(dir_path)
if not dir_ptr: return -1
if devfs_file.find_in_dir(file_name, dir_ptr):
return -1
if file_count >= MAX_DEVICE_FILES: return -1
if file_ptr:
string.strcpy(file_ptr.name, file_name)
file_ptr.private_data = private_data
file_ptr.parent_dir = dir_ptr
files[file_count] = file_ptr
else:
new_file: devfs_file | t.CPtr = c.Addr(files[file_count])
string.strcpy(new_file.name, file_name)
new_file.private_data = private_data
new_file.parent_dir = dir_ptr
file_count += 1
return 0
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
string.strcpy(path_copy, path)
last_slash: str | t.CPtr = string.strrchr(path_copy, '/')
if not last_slash: return -1
last_slash[0] = '\0'
dir_path = path_copy
file_name: str | t.CPtr = last_slash + 1
dir_ptr: devfs_directory | t.CPtr = devfs_directory.find(dir_path, self.root_directory)
if not dir_ptr: return -1
file_ptr: devfs_file | t.CPtr = devfs_file.find_in_dir(file_name, dir_ptr)
if not file_ptr: return -1
fd: t.CInt = -1
for i in range(MAX_FILE_DESCRIPTORS):
if not fd_table[i].file:
fd = i
break
if fd == -1: return -1
ret: t.CInt = file_ptr.open(path, flags)
if ret != 0: return ret
fd_table[fd].file = file_ptr
fd_table[fd].flags = flags
return fd
def close(self, fd: t.CInt) -> t.CInt:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
file_ptr.close(fd)
fd_table[fd].file = None
fd_table[fd].flags = 0
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
return file_ptr.read(fd, buffer, size)
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
return file_ptr.write(fd, buffer, size)
def ioctl(self, fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
return -1
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
return file_ptr.ioctl(fd, cmd, arg)
def list_directory(self, path: t.CConst | str,
buffer: str,
size: t.CUInt32T) -> t.CInt:
dir_ptr: devfs_directory | t.CPtr = devfs_directory.find(path, self.root_directory)
if not dir_ptr or not buffer or size == 0: return -1
pos: t.CInt = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
pos = devfs_file.list_in_dir(dir_ptr, buffer, size, pos)
return pos
DevFSObject: _DevFSObject | t.CPtr
_DevFSObject_instance: _DevFSObject
def devfs_init() -> t.CInt:
global DevFSObject, _DevFSObject_instance
DevFSObject = c.Addr(_DevFSObject_instance)
_DevFSObject_instance = _DevFSObject()
# _DevFSObject_instance.__init__()
DevFSObject.init()
return 0
def devfs_create_directory(path: t.CConst | str) -> t.CInt:
return DevFSObject.create_directory(path)
def devfs_create_file(path: t.CConst | str,
file_ptr: devfs_file | t.CPtr,
private_data: t.CVoid | t.CPtr) -> t.CInt:
return DevFSObject.create_file(path, file_ptr, private_data)
def devfs_open(path: t.CConst | str, flags: t.CInt) -> t.CInt:
return DevFSObject.open(path, flags)
def devfs_close(fd: t.CInt) -> t.CInt:
return DevFSObject.close(fd)
def devfs_read(fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
return DevFSObject.read(fd, buffer, size)
def devfs_write(fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
return DevFSObject.write(fd, buffer, size)
def devfs_ioctl(fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
return DevFSObject.ioctl(fd, cmd, arg)
def devfs_list_directory(path: t.CConst | str,
buffer: str,
size: t.CUInt32T) -> t.CInt:
return DevFSObject.list_directory(path, buffer, size)
serial0_file: devfs_file
def serial0_open(self: t.CVoid | t.CPtr, path: t.CConst | str, flags: t.CInt) -> t.CInt:
serial.puts("[serial0] open: ")
serial.puts(path)
serial.puts("\n")
return 0
def serial0_close(self: t.CVoid | t.CPtr, fd: t.CInt) -> t.CInt:
serial.puts("[serial0] close\n")
return 0
def serial0_read(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
serial.puts("[serial0] read\n")
return 0
def serial0_write(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
serial.puts("[serial0] write\n")
serial.puts(str(buffer))
serial.puts("\n")
return size
def devfs_register_serial0() -> t.CInt:
global serial0_file
serial0_file = devfs_file()
serial0_file.open = serial0_open
serial0_file.close = serial0_close
serial0_file.read = serial0_read
serial0_file.write = serial0_write
return devfs_create_file("/dev/serial0", serial0_file, None)
@t.Object
@t.CVTable
class serial1_device(devfs_file):
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
serial.puts("[serial1] open: ")
serial.puts(path)
serial.puts("\n")
return 0
def close(self, fd: t.CInt) -> t.CInt:
serial.puts("[serial1] close\n")
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
serial.puts("[serial1] read\n")
return 0
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
serial.puts("[serial1] write\n")
serial.puts(str(buffer))
serial.puts("\n")
return size
serial1_file: serial1_device
def devfs_register_serial1() -> t.CInt:
global serial1_file
serial1_file = serial1_device()
return devfs_create_file("/dev/serial1", serial1_file, None)
import drivers.input.keyboard.keyboard as keyboard
import drivers.input.mouse.mouse as mouse
@t.Object
@t.CVTable
class keyboard_device(devfs_file):
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
return 0
def close(self, fd: t.CInt) -> t.CInt:
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
count: t.CUInt32T = 0
while count < size and keyboard.has_data():
sc: t.CUInt8T = keyboard.read_scancode()
ch: t.CChar = keyboard.scancode_to_ascii(sc)
if ch != '\0':
c.Set(t.CChar(buffer, t.CPtr)[count], ch)
count += 1
return count
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
return -1
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
return 0
kbd_file: keyboard_device
def devfs_register_keyboard() -> t.CInt:
global kbd_file
kbd_file = keyboard_device()
keyboard.init()
return devfs_create_file("/dev/input/keyboard", kbd_file, None)
@t.Object
@t.CVTable
class mouse_device(devfs_file):
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
return 0
def close(self, fd: t.CInt) -> t.CInt:
return 0
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
if not mouse.has_data(): return 0
pkt: mouse.mouse_packet
mouse.read_packet(c.Addr(pkt))
if size >= 1:
c.Set(t.CUInt8T(buffer, t.CPtr)[0], pkt.buttons)
if size >= 5:
buf: t.CUInt32T | t.CPtr = t.CVoid(t.CUInt64T(buffer) + 1, t.CPtr)
c.Set(t.CInt32T(buf, t.CPtr)[0], mouse.get_x())
c.Set(t.CInt32T(buf, t.CPtr)[1], mouse.get_y())
return 5
return 1
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
return -1
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
return 0
mse_file: mouse_device
def devfs_register_mouse() -> t.CInt:
global mse_file
mse_file = mouse_device()
mouse.init()
return devfs_create_file("/dev/input/mouse", mse_file, None)

View File

@@ -0,0 +1,237 @@
from stdint import *
import fat32 as fs
import fat32_types as types
import fat32_part as part
import fat32_mkfs as mkfs_mod
import t, c
def print_fresult(res: types.FRESULT, msg: t.CConst) -> t.CInt:
if res == types.FRESULT.FR_OK:
print(f"[成功] {msg}")
return 0
else:
print(f"[失败] {msg}: {res}")
return -1
def print_fresult_void(res: types.FRESULT, msg: t.CConst):
print_fresult(res, msg)
def example_main() -> t.CInt:
print("=== FAT32 文件系统完整示例 ===")
print()
# 1. 扫描可用驱动器
print("--- 1. 扫描可用驱动器 ---")
res: types.FRESULT = fs.scan_drives()
print_fresult_void(res, "扫描驱动器")
drive_count: t.CInt = fs.get_drive_count()
print(f"找到 {drive_count} 个驱动器")
i: t.CInt
for i in range(drive_count):
letter: t.CChar = fs.get_drive_letter(i)
part_count: t.CInt = fs.get_partition_count(letter)
print(f" 驱动器 {i}: {letter}")
for j in range(part_count):
is_fat32: t.CInt = fs.is_partition_fat32(letter, j)
print(f" 分区 {j}: FAT32={is_fat32}")
print()
# 2. 挂载文件系统
print("--- 2. 挂载文件系统 ---")
res = fs.mount()
if print_fresult(res, "挂载文件系统") != 0:
print("提示: 可能需要先格式化磁盘")
print()
# 3. 文件系统信息
print("--- 3. 文件系统信息 ---")
mounted: t.CInt = fs.is_mounted()
print(f"已挂载: {mounted}")
if mounted:
total_clusters: t.CUInt32T = fs.get_total()
free_clusters: t.CUInt32T = fs.get_free()
cluster_size: t.CUInt32T = fs.get_cluster_size()
total_bytes: t.CUInt64T = t.CUInt64T(total_clusters) * t.CUInt64T(cluster_size)
free_bytes: t.CUInt64T = t.CUInt64T(free_clusters) * t.CUInt64T(cluster_size)
print(f"总簇数: {total_clusters}")
print(f"空闲簇数: {free_clusters}")
print(f"簇大小: {cluster_size} 字节")
print(f"总大小: {total_bytes} 字节")
print(f"空闲大小: {free_bytes} 字节")
print()
# 4. 元数据操作
print("--- 4. 元数据操作 ---")
fs.set_metadata(0x12345678)
metadata: t.CUInt32T = fs.get_metadata()
print(f"设置的元数据: 0x{metadata:08X}")
print()
# 5. 获取 FAT 时间
print("--- 5. 获取 FAT 时间 ---")
fattime: t.CUInt32T = fs.get_fattime()
print(f"当前 FAT 时间: 0x{fattime:08X}")
print()
# 6. 目录操作
if fs.is_mounted():
print("--- 6. 目录操作 ---")
# 创建目录
res = fs.mkdir("/test_dir_1")
print_fresult_void(res, "创建目录 /test_dir_1")
res = fs.mkdir("/test_dir_1/subdir")
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
res = fs.mkdir("/test_dir_2")
print_fresult_void(res, "创建目录 /test_dir_2")
print()
# 7. 文件操作
print("--- 7. 文件操作 ---")
# 创建并写入文件
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp1 is not None:
test_data1: t.CConst = "Hello, World!"
written: t.CUInt32T = fs.write(fp1, test_data1, 13)
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
fs.close(fp1)
# 打开追加
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
if fp2 is not None:
test_data2: t.CConst = " Append data!"
written2: t.CUInt32T = fs.write(fp2, test_data2, 13)
print(f"追加写入: {written2} 字节")
fs.close(fp2)
# 读取文件
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
if fp3 is not None:
buf: t.CArray[t.CUInt8T, 256]
read_bytes: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"读取字节数: {read_bytes}")
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# seek 和 tell
fs.seek(fp3, 5)
pos: t.CUInt32T = fs.tell(fp3)
print(f"seek 到位置 5, 当前位置: {pos}")
read_bytes2: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
# 获取文件大小
fsize: t.CUInt32T = fs.size(fp3)
print(f"文件大小: {fsize} 字节")
fs.close(fp3)
# 创建另一个文件
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
if fp4 is not None:
large_data: t.CArray[t.CUInt8T, 1024]
k: t.CInt
for k in range(1024):
large_data[k] = t.CUInt8T(ord('A') + (k % 26))
written3: t.CUInt32T = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
print(f"创建大文件, 写入: {written3} 字节")
fs.close(fp4)
print()
# 8. 文件状态和属性
print("--- 8. 文件状态和属性 ---")
info: types.fileinfo
res = fs.stat("/test_dir_1/file1.txt", info)
print_fresult_void(res, "获取文件信息")
if res == types.FRESULT.FR_OK:
print(f" 文件名: {info.fname}")
print(f" 大小: {info.file_size} 字节")
print(f" 属性: 0x{info.attr:02X}")
print(f" 创建时间: 0x{info.ctime:04X}")
print(f" 创建日期: 0x{info.cdate:04X}")
print(f" 修改时间: 0x{info.mtime:04X}")
print(f" 修改日期: 0x{info.mdate:04X}")
print(f" 访问日期: 0x{info.adate:04X}")
# 修改属性
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
print_fresult_void(res, "设置文件为只读")
print()
# 9. 重命名和移动
print("--- 9. 重命名和移动 ---")
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
print_fresult_void(res, "重命名文件")
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
print_fresult_void(res, "移动文件")
res = fs.rename("/test_dir_2", "/test_dir_renamed")
print_fresult_void(res, "重命名目录")
print()
# 10. 列出目录
print("--- 10. 列出目录 ---")
dp: types.dirobj
res = fs.opendir("/", dp)
if res == types.FRESULT.FR_OK:
print("根目录内容:")
dir_info: types.fileinfo
while True:
res = fs.readdir(dp, dir_info)
if res != types.FRESULT.FR_OK:
break
attr_str: t.CConst = ""
if dir_info.attr & types.AM_DIR:
attr_str = attr_str + "D"
else:
attr_str = attr_str + "F"
if dir_info.attr & types.AM_RDO:
attr_str = attr_str + "R"
if dir_info.attr & types.AM_HID:
attr_str = attr_str + "H"
if dir_info.attr & types.AM_SYS:
attr_str = attr_str + "S"
if dir_info.attr & types.AM_ARC:
attr_str = attr_str + "A"
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
fs.closedir(dp)
print()
# 11. 删除文件和目录
print("--- 11. 删除文件和目录 ---")
res = fs.remove("/test_dir_renamed/moved.txt")
print_fresult_void(res, "删除文件")
res = fs.remove("/test_dir_1/large_file.txt")
print_fresult_void(res, "删除大文件")
res = fs.rmdir("/test_dir_1/subdir")
print_fresult_void(res, "删除子目录")
res = fs.rmdir("/test_dir_1")
print_fresult_void(res, "删除目录 /test_dir_1")
res = fs.rmdir("/test_dir_renamed")
print_fresult_void(res, "删除目录 /test_dir_renamed")
print()
# 12. 卸载文件系统
print("--- 12. 卸载文件系统 ---")
res = fs.unmount()
print_fresult_void(res, "卸载文件系统")
print()
print("=== 示例完成 ===")
return 0

View File

@@ -0,0 +1,208 @@
from stdint import *
import string
import fat32_types as types
import fat32_time as ftime
import fat32_mkfs as mkfs_mod
import fat32_part as part
import fat32_diskio as diskio
import sched.sched as sched
import t, c
default_fs: types.volinfo = types.volinfo()
_fs_lock: t.CInt = 0
def lock():
global _fs_lock
while True:
c.Asm("cli")
if _fs_lock == 0:
_fs_lock = 1
c.Asm("sti")
return
c.Asm("sti")
sched.Scheduler._yield()
def unlock():
global _fs_lock
_fs_lock = 0
def mount() -> types.FRESULT:
default_fs.pdrv = 0
default_fs.hidden_sectors = 0
buf: t.CArray[t.CUInt8T, 512]
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
if dres == types.DRESULT.RES_OK:
if buf[0] == 0xEB or buf[0] == 0xE9:
default_fs.hidden_sectors = 0
else:
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
if sig == 0xAA55:
ptype: t.CUInt8T = buf[450]
if ptype != 0:
slba: t.CUInt32T = t.CUInt32T(buf[454]) | (t.CUInt32T(buf[455]) << 8) | (t.CUInt32T(buf[456]) << 16) | (t.CUInt32T(buf[457]) << 24)
default_fs.hidden_sectors = slba
if default_fs.mounted: return types.FRESULT.FR_OK
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK:
dsk_res = diskio.init(default_fs.pdrv)
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
wres: types.FRESULT = default_fs.win_read(0)
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
bps: t.CUInt16T = default_fs.win[11] | (t.CUInt16T(default_fs.win[12]) << 8)
spc: t.CUInt8T = default_fs.win[13]
rsc: t.CUInt16T = default_fs.win[14] | (t.CUInt16T(default_fs.win[15]) << 8)
nf: t.CUInt8T = default_fs.win[16]
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
root_ent: t.CUInt16T = default_fs.win[17] | (t.CUInt16T(default_fs.win[18]) << 8)
fat16sz: t.CUInt16T = default_fs.win[22] | (t.CUInt16T(default_fs.win[23]) << 8)
tot32: t.CUInt32T = t.CUInt32T(default_fs.win[32]) | (t.CUInt32T(default_fs.win[33]) << 8) | (t.CUInt32T(default_fs.win[34]) << 16) | (t.CUInt32T(default_fs.win[35]) << 24)
fat32sz: t.CUInt32T = t.CUInt32T(default_fs.win[36]) | (t.CUInt32T(default_fs.win[37]) << 8) | (t.CUInt32T(default_fs.win[38]) << 16) | (t.CUInt32T(default_fs.win[39]) << 24)
root_clus: t.CUInt32T = t.CUInt32T(default_fs.win[44]) | (t.CUInt32T(default_fs.win[45]) << 8) | (t.CUInt32T(default_fs.win[46]) << 16) | (t.CUInt32T(default_fs.win[47]) << 24)
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
fsinfo_sec: t.CUInt16T = default_fs.win[48] | (t.CUInt16T(default_fs.win[49]) << 8)
bkboot_sec: t.CUInt16T = default_fs.win[50] | (t.CUInt16T(default_fs.win[51]) << 8)
default_fs.sector_size = 512
default_fs.cluster_sectors = spc
default_fs.cluster_size = t.CUInt32T(spc) * 512
default_fs.num_fats = nf
default_fs.reserved_sectors = rsc
default_fs.fat_size = fat32sz
default_fs.fat_start = t.CUInt64T(rsc)
default_fs.total_sectors = t.CUInt64T(tot32)
default_fs.root_cluster = root_clus
default_fs.fsinfo_sector = fsinfo_sec
default_fs.backup_sector = bkboot_sec
default_fs.vol_id = t.CUInt32T(default_fs.win[67]) | (t.CUInt32T(default_fs.win[68]) << 8) | (t.CUInt32T(default_fs.win[69]) << 16) | (t.CUInt32T(default_fs.win[70]) << 24)
data_sectors: t.CUInt64T = default_fs.total_sectors - t.CUInt64T(rsc) - t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
default_fs.total_clusters = t.CUInt32T(data_sectors / t.CUInt64T(spc))
default_fs.data_start = default_fs.fat_start + t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
default_fs.last_alloc = 2
default_fs.free_clusters = 0xFFFFFFFF
if fsinfo_sec != 0:
default_fs.fsinfo_read()
default_fs.mounted = 1
return types.FRESULT.FR_OK
def unmount() -> types.FRESULT:
return default_fs.unmount()
def format(sec_per_clus: t.CUInt8T = 0, vol_id: t.CUInt32T = 0) -> types.FRESULT:
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
def open(path: t.CConst | str, mode: t.CUInt8T) -> types.fileobj | t.CPtr:
return default_fs.file_open(path, mode)
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.close()
def read(fp: types.fileobj | t.CPtr, buff: t.CVoid | t.CPtr, btr: t.CUInt32T) -> t.CUInt32T:
br: t.CUInt32T = 0
fp.read(buff, btr, c.Addr(br))
return br
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CVoid | t.CPtr, btw: t.CUInt32T) -> t.CUInt32T:
bw: t.CUInt32T = 0
fp.write(buff, btw, c.Addr(bw))
return bw
def seek(fp: types.fileobj | t.CPtr, offset: t.CUInt32T) -> types.FRESULT:
return fp.seek(offset)
def tell(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
return fp.tell()
def size(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
return fp.size()
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
return fp.truncate()
def remove(path: t.CConst | str) -> types.FRESULT:
return default_fs.file_delete(path)
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
return default_fs.file_rename(old_path, new_path)
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.file_stat(path, info)
def mkdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_make(path)
def rmdir(path: t.CConst | str) -> types.FRESULT:
return default_fs.dir_remove(path)
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
return default_fs.dir_open_path(path, dp)
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
return default_fs.dir_read(dp, info)
def closedir(dp: types.dirobj | t.CPtr):
dp.is_open = 0
def chmod(path: t.CConst | str, attr: t.CUInt8T, mask: t.CUInt8T) -> types.FRESULT:
return default_fs.chmod(path, attr, mask)
def utime(path: t.CConst | str, mtime: t.CUInt16T, mdate: t.CUInt16T) -> types.FRESULT:
return default_fs.utime(path, mtime, mdate)
def get_free() -> t.CUInt32T:
if not default_fs.mounted: return 0
if default_fs.free_clusters == 0xFFFFFFFF:
return default_fs.count_free_clusters()
return default_fs.free_clusters
def get_total() -> t.CUInt32T:
if not default_fs.mounted: return 0
return default_fs.total_clusters
def get_cluster_size() -> t.CUInt32T:
if not default_fs.mounted: return 0
return default_fs.cluster_size
def is_mounted() -> t.CInt:
return default_fs.mounted
def last_error() -> t.CUInt32T:
return default_fs.last_error
def get_fattime() -> t.CUInt32T:
return ftime.get_fattime()
def get_metadata() -> t.CUInt32T:
return default_fs.metadata
def set_metadata(val: t.CUInt32T):
default_fs.metadata = val
def scan_drives() -> types.FRESULT:
return part.scan_drives()
def get_drive_count() -> t.CInt:
return part.get_drive_count()
def get_drive_letter(idx: t.CInt) -> t.CChar:
return part.get_drive_letter(idx)
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
return part.set_drive_letter(idx, letter)
def get_partition_count(letter: t.CChar) -> t.CInt:
return part.get_partition_count(letter)
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
return part.is_partition_fat32(letter, part_idx)

View File

@@ -0,0 +1,16 @@
from stdint import *
import fat32_types as types
import t, c
_read32 = types._read32
_read16 = types._read16
_write32 = types._write32
_write16 = types._write16
def is_eoc(cluster: t.CUInt32T) -> t.CInt:
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
def is_free(cluster: t.CUInt32T) -> t.CInt:
return 1 if cluster == types.CLUSTER_FREE else 0

View File

@@ -0,0 +1,13 @@
from stdint import *
import fat32_types as types
import t, c
sfn_checksum = types.sfn_checksum
uni2oem_placeholder = types.uni2oem_placeholder
lfn_get_char = types.lfn_get_char
lfn_set_char = types.lfn_set_char
lfn_extract = types.lfn_extract
sfn_from_lfn = types.sfn_from_lfn
sfn_to_str = types.sfn_to_str
_split_path = types._split_path

View File

@@ -0,0 +1,76 @@
import drivers.storage.ide.ide as ide
import fat32_types as types
import spinlock
import string
import t, c
MAX_DRIVES: t.CDefine = 4
drive_initialized: t.CArray[t.CInt, MAX_DRIVES]
drive_lock: spinlock._spinlock = spinlock._spinlock()
def status(pdrv: t.CUInt8T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
return types.DRESULT.RES_OK
def init(pdrv: t.CUInt8T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
drive_lock.lock()
err: t.CInt = ide.init()
if err != 0:
drive_lock.unlock()
return types.DRESULT.RES_NOTRDY
drive_initialized[pdrv] = 1
drive_lock.unlock()
return types.DRESULT.RES_OK
def read(pdrv: t.CUInt8T, buff: t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: t.CUInt32T
for i in range(count):
rd_res: t.CInt = ide.readSector(sector + i, buff + (i * 512))
if rd_res != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def write(pdrv: t.CUInt8T, buff: t.CConst | t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
drive_lock.lock()
i: t.CUInt32T
for i in range(count):
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
drive_lock.unlock()
return types.DRESULT.RES_ERROR
drive_lock.unlock()
return types.DRESULT.RES_OK
def ioctl(pdrv: t.CUInt8T, cmd: t.CUInt8T, buff: t.CVoid | t.CPtr) -> types.DRESULT:
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
match cmd:
case types.GET_SECTOR_COUNT:
disk_size: t.CUInt64T = ide.getDiskSize()
if disk_size == 0:
c.Set(t.CUInt32T(buff, t.CPtr), 131072)
elif disk_size > 0xFFFFFFFF:
c.Set(t.CUInt32T(buff, t.CPtr), 0xFFFFFFFF)
else:
c.Set(t.CUInt32T(buff, t.CPtr), t.CUInt32T(disk_size))
return types.DRESULT.RES_OK
case types.GET_SECTOR_SIZE:
c.Set(t.CUInt16T(buff, t.CPtr), 512)
return types.DRESULT.RES_OK
case types.GET_BLOCK_SIZE:
c.Set(t.CUInt32T(buff, t.CPtr), 1)
return types.DRESULT.RES_OK
case types.CTRL_SYNC:
return types.DRESULT.RES_OK
case _:
return types.DRESULT.RES_PARERR

View File

@@ -0,0 +1,17 @@
from stdint import *
import fat32_types as types
import t, c
handle_table = types.handle_table
lock_table = types.lock_table
handles_initialized = types.handles_initialized
handles_init = types.handles_init
handle_alloc = types.handle_alloc
lock_check = types.lock_check
lock_acquire = types.lock_acquire
lock_release = types.lock_release
def handle_free(fp):
fp.is_open = 0
fp.lock_count = 0

View File

@@ -0,0 +1,143 @@
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import fat32_time as ftime
import string
import t, c
def _div_round_up(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T:
return (a + b - 1) / b
def _calc_fat_size(total_sectors: t.CUInt64T, reserved: t.CUInt32T, sec_per_clus: t.CUInt8T, num_fats: t.CUInt8T) -> t.CUInt32T:
tmp: t.CUInt64T = total_sectors - t.CUInt64T(reserved)
fat_sz: t.CUInt32T = 1
while True:
data_sectors: t.CUInt64T = tmp - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
needed: t.CUInt64T = _div_round_up(t.CUInt64T(total_clusters) * 4, 512)
if needed <= t.CUInt64T(fat_sz): break
fat_sz = t.CUInt32T(needed)
return fat_sz
def _write_boot_sector(pdrv: t.CUInt8T, total_sectors: t.CUInt64T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T, fat_sz: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
types._write16(c.Addr(buf[0]), 11, 512)
buf[13] = sec_per_clus
types._write16(c.Addr(buf[0]), 14, 32)
buf[16] = 2
types._write16(c.Addr(buf[0]), 17, 0)
buf[21] = 0xF8
types._write16(c.Addr(buf[0]), 22, 0)
types._write16(c.Addr(buf[0]), 24, 63)
types._write16(c.Addr(buf[0]), 26, 255)
types._write32(c.Addr(buf[0]), 28, 0)
types._write32(c.Addr(buf[0]), 32, t.CUInt32T(total_sectors))
types._write32(c.Addr(buf[0]), 36, fat_sz)
types._write16(c.Addr(buf[0]), 40, 0)
types._write16(c.Addr(buf[0]), 42, 0)
types._write32(c.Addr(buf[0]), 44, 2)
types._write16(c.Addr(buf[0]), 48, 1)
types._write16(c.Addr(buf[0]), 50, 6)
buf[64] = 0x80
buf[66] = 0x29
types._write32(c.Addr(buf[0]), 67, vol_id)
vol_label: t.CArray[t.CChar, 11]
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
i: t.CInt
for i in range(11): buf[71 + i] = t.CUInt8T(vol_label[i])
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
buf[510] = 0x55; buf[511] = 0xAA
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
def _write_fsinfo(pdrv: t.CUInt8T, free_count: t.CUInt32T, next_free: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x41615252)
types._write32(c.Addr(buf[0]), 484, 0x61417272)
types._write32(c.Addr(buf[0]), 488, free_count)
types._write32(c.Addr(buf[0]), 492, next_free)
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
def _init_fat(pdrv: t.CUInt8T, fat_start: t.CUInt64T, fat_sz: t.CUInt32T, root_cluster: t.CUInt32T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
if root_cluster >= 2:
cluster_off: t.CUInt32T = root_cluster * 4
sector_off: t.CUInt32T = cluster_off / 512
byte_off: t.CUInt32T = cluster_off % 512
if sector_off == 0:
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start), 1)
if res != types.DRESULT.RES_OK: return res
string.memset(c.Addr(buf[0]), 0, 512)
s: t.CUInt32T
for s in range(1, fat_sz):
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start) + s, 1)
if res2 != types.DRESULT.RES_OK: return res2
return types.DRESULT.RES_OK
def _init_root_dir(pdrv: t.CUInt8T, root_sector: t.CUInt64T, sec_per_clus: t.CUInt8T) -> types.DRESULT:
buf: t.CArray[t.CUInt8T, 512]
string.memset(c.Addr(buf[0]), 0, 512)
s: t.CUInt8T
for s in range(sec_per_clus):
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(root_sector + t.CUInt64T(s)), 1)
if res != types.DRESULT.RES_OK: return res
return types.DRESULT.RES_OK
def _calc_sec_per_clus(total_sectors: t.CUInt64T) -> t.CUInt8T:
ts: t.CUInt64T = total_sectors
if ts < 532480: return 1
elif ts < 16777216: return 8
elif ts < 33554432: return 16
elif ts < 67108864: return 32
else: return 64
def mkfs(pdrv: t.CUInt8T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T) -> types.FRESULT:
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
total_sectors_buf: t.CUInt32T = 0
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
total_sectors: t.CUInt64T = t.CUInt64T(total_sectors_buf)
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
return types.FRESULT.FR_INVALID_PARAMETER
if vol_id == 0: vol_id = ftime.get_fattime()
reserved: t.CUInt32T = 32
num_fats: t.CUInt8T = 2
fat_sz: t.CUInt32T = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
data_sectors: t.CUInt64T = total_sectors - t.CUInt64T(reserved) - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
free_count: t.CUInt32T = total_clusters - 1
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
boot_backup: t.CArray[t.CUInt8T, 512]
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
fsinfo_backup: t.CArray[t.CUInt8T, 512]
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
fat_start: t.CUInt64T = t.CUInt64T(reserved)
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
fat2_start: t.CUInt64T = fat_start + t.CUInt64T(fat_sz)
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
root_sector: t.CUInt64T = fat2_start + t.CUInt64T(fat_sz)
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
return types.FRESULT.FR_OK

View File

@@ -0,0 +1,147 @@
from stdint import *
import fat32_types as types
import fat32_diskio as diskio
import string
import t, c
MAX_VOLUMES: t.CDefine = 4
MAX_PARTITIONS: t.CDefine = 4
MBR_SIGNATURE: t.CDefine = 0xAA55
PART_TYPE_FAT32: t.CDefine = 0x0C
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
PART_TYPE_FAT16: t.CDefine = 0x06
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
class partition_entry:
boot_flag: t.CUInt8T
start_chs: t.CArray[t.CUInt8T, 3]
part_type: t.CUInt8T
end_chs: t.CArray[t.CUInt8T, 3]
start_lba: t.CUInt32T
total_sectors: t.CUInt32T
drive_pdrv: t.CArray[t.CUInt8T, MAX_VOLUMES]
drive_num_parts: t.CArray[t.CInt, MAX_VOLUMES]
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
volume_mounted: t.CArray[t.CInt, MAX_VOLUMES]
part_types: t.CArray[t.CUInt8T, MAX_VOLUMES * MAX_PARTITIONS]
part_start_lbas: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
part_totals: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
part_is_fat32: t.CArray[t.CInt, MAX_VOLUMES * MAX_PARTITIONS]
num_drives: t.CInt = 0
def _init():
if num_drives > 0: return
i: t.CInt
for i in range(MAX_VOLUMES):
drive_letter_map[i] = 0
volume_mounted[i] = 0
drive_pdrv[i] = 0
drive_num_parts[i] = 0
j: t.CInt
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
part_types[j] = 0
part_start_lbas[j] = 0
part_totals[j] = 0
part_is_fat32[j] = 0
def _part_idx(drive: t.CInt, part: t.CInt) -> t.CInt:
return drive * MAX_PARTITIONS + part
def parse_mbr(pdrv: t.CUInt8T, drive_idx: t.CInt) -> types.FRESULT:
buf: t.CArray[t.CUInt8T, 512]
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
if buf[0] == 0xEB or buf[0] == 0xE9:
return types.FRESULT.FR_NO_FILESYSTEM
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
drive_pdrv[drive_idx] = pdrv
drive_num_parts[drive_idx] = 0
i: t.CInt
for i in range(4):
base: t.CUInt32T = 446 + t.CUInt32T(i * 16)
ptype: t.CUInt8T = buf[base + 4]
slba: t.CUInt32T = t.CUInt32T(buf[base + 8]) | (t.CUInt32T(buf[base + 9]) << 8) | (t.CUInt32T(buf[base + 10]) << 16) | (t.CUInt32T(buf[base + 11]) << 24)
tsec: t.CUInt32T = t.CUInt32T(buf[base + 12]) | (t.CUInt32T(buf[base + 13]) << 8) | (t.CUInt32T(buf[base + 14]) << 16) | (t.CUInt32T(buf[base + 15]) << 24)
if ptype != 0 and tsec > 0:
pi: t.CInt = drive_num_parts[drive_idx]
if pi < MAX_PARTITIONS:
pidx: t.CInt = _part_idx(drive_idx, pi)
part_types[pidx] = ptype
part_start_lbas[pidx] = t.CUInt64T(slba)
part_totals[pidx] = t.CUInt64T(tsec)
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
drive_num_parts[drive_idx] = pi + 1
return types.FRESULT.FR_OK
def scan_drives() -> types.FRESULT:
_init()
global num_drives
num_drives = 0
pdrv: t.CUInt8T
for pdrv in range(MAX_VOLUMES):
res: types.DRESULT = diskio.init(pdrv)
if res != types.DRESULT.RES_OK: continue
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
else:
drive_pdrv[num_drives] = pdrv
drive_num_parts[num_drives] = 1
pidx: t.CInt = _part_idx(num_drives, 0)
part_types[pidx] = PART_TYPE_FAT32_LBA
part_start_lbas[pidx] = 0
part_totals[pidx] = 0
part_is_fat32[pidx] = 1
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
num_drives = num_drives + 1
if num_drives >= MAX_VOLUMES: break
return types.FRESULT.FR_OK
def get_drive(letter: t.CChar) -> t.CInt:
_init()
i: t.CInt
for i in range(num_drives):
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
return i
return -1
def get_pdrv(letter: t.CChar) -> t.CUInt8T:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
return drive_pdrv[idx]
def get_partition_start(letter: t.CChar, part_idx: t.CInt) -> t.CUInt64T:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: t.CInt = _part_idx(idx, part_idx)
return part_start_lbas[pidx]
def get_partition_count(letter: t.CChar) -> t.CInt:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
return drive_num_parts[idx]
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
idx: t.CInt = get_drive(letter)
if idx < 0: return 0
if part_idx >= drive_num_parts[idx]: return 0
pidx: t.CInt = _part_idx(idx, part_idx)
return part_is_fat32[pidx]
def get_drive_count() -> t.CInt:
return num_drives
def get_drive_letter(idx: t.CInt) -> t.CChar:
if idx < 0 or idx >= num_drives: return 0
return drive_letter_map[idx]
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
drive_letter_map[idx] = letter
return types.FRESULT.FR_OK

View File

@@ -0,0 +1,64 @@
from stdint import *
import t, c
import asm
rtc_cmos_addr: t.CUInt16T = 0x70
rtc_cmos_data: t.CUInt16T = 0x71
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
asm.outb(rtc_cmos_addr, reg)
return asm.inb(rtc_cmos_data)
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def get_rtc_time() -> t.CUInt32T:
while cmos_read(0x0A) & 0x80: pass
sec: t.CUInt8T = cmos_read(0x00)
min_: t.CUInt8T = cmos_read(0x02)
hour: t.CUInt8T = cmos_read(0x04)
day: t.CUInt8T = cmos_read(0x07)
mon: t.CUInt8T = cmos_read(0x08)
year: t.CUInt8T = cmos_read(0x09)
reg_b: t.CUInt8T = cmos_read(0x0B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
fat_year: t.CUInt16T = t.CUInt16T(year) + 2000 - 1980
if fat_year > 127: fat_year = 127
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(mon) << 5) | t.CUInt16T(day)
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(min_) << 5) | (t.CUInt16T(sec) / 2)
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
def get_fattime() -> t.CUInt32T:
return get_rtc_time()
def to_year(ft: t.CUInt32T) -> t.CUInt16T:
return t.CUInt16T((ft >> 25) & 0x7F) + 1980
def to_month(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 21) & 0x0F)
def to_day(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 16) & 0x1F)
def to_hour(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 11) & 0x1F)
def to_minute(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft >> 5) & 0x3F)
def to_second(ft: t.CUInt32T) -> t.CUInt8T:
return t.CUInt8T((ft & 0x1F) * 2)
def make(year: t.CUInt16T, month: t.CUInt8T, day: t.CUInt8T, hour: t.CUInt8T, minute: t.CUInt8T, second: t.CUInt8T) -> t.CUInt32T:
fat_year: t.CUInt16T = year - 1980
if fat_year > 127: fat_year = 127
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(month) << 5) | t.CUInt16T(day)
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(minute) << 5) | (t.CUInt16T(second) / 2)
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
import fat32

View File

@@ -0,0 +1,146 @@
import asm
import intr.idt as idt
import drivers.serial.uart.serial as serial
import viperstring as string
import t, c
KBD_DATA: t.CDefine = 0x60
KBD_STATUS: t.CDefine = 0x64
KBD_COMMAND: t.CDefine = 0x64
KBD_BUF_SIZE: t.CDefine = 1024
KEY_RELEASED: t.CDefine = 0x80
buffer: t.CArray[t.CUInt8T, KBD_BUF_SIZE]
buf_head: t.CStatic | t.CUInt32T = 0
buf_tail: t.CStatic | t.CUInt32T = 0
buf_count: t.CStatic | t.CUInt32T = 0
shift_l: t.CStatic | t.CUInt8T = 0
shift_r: t.CStatic | t.CUInt8T = 0
ctrl_l: t.CStatic | t.CUInt8T = 0
alt_l: t.CStatic | t.CUInt8T = 0
caps_lock: t.CStatic | t.CUInt8T = 0
scancode_set1: t.CArray[t.CChar, 128] = [
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0'
]
scancode_set1_shift: t.CArray[t.CChar, 128] = [
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
'\0'
]
def _wait_read():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(KBD_STATUS) & 0x01) != 0: return
timeout -= 1
def _wait_write():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(KBD_STATUS) & 0x02) == 0: return
timeout -= 1
def irq_handler() -> t.CInt:
global buf_head, buf_tail, buf_count
scancode: t.CUInt8T = asm.inb(KBD_DATA)
if buf_count < KBD_BUF_SIZE:
buffer[buf_tail] = scancode
buf_tail = buf_tail + 1
if buf_tail >= KBD_BUF_SIZE:
buf_tail = 0
buf_count += 1
return 0
def read_scancode() -> t.CUInt8T:
global buf_head, buf_count
asm.cli()
if buf_count == 0:
asm.sti()
return 0
code: t.CUInt8T = buffer[buf_head]
buf_head = buf_head + 1
if buf_head >= KBD_BUF_SIZE:
buf_head = 0
buf_count -= 1
asm.sti()
return code
def scancode_to_ascii(scancode: t.CUInt8T) -> t.CChar:
code: t.CUInt8T = scancode & ~t.CUInt8T(KEY_RELEASED)
if code >= 128: return '\0'
shifted: bool = (shift_l or shift_r) != 0
if caps_lock and code >= 0x10 and code <= 0x32:
shifted = not shifted
if shifted:
return scancode_set1_shift[code]
return scancode_set1[code]
def has_data() -> t.CInt:
return buf_count
def init():
drain: t.CUInt32T
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_COMMAND, 0xAD)
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_COMMAND, 0x20)
_wait_read()
ccb: t.CUInt8T = asm.inb(KBD_DATA)
ccb = ccb | 0x01
ccb = ccb | 0x40
ccb = ccb & 0xEF
_wait_write()
asm.outb(KBD_COMMAND, 0x60)
_wait_write()
asm.outb(KBD_DATA, ccb)
_wait_write()
asm.outb(KBD_COMMAND, 0xAE)
drain = 0
while (asm.inb(KBD_STATUS) & 0x01) != 0:
asm.inb(KBD_DATA)
drain += 1
if drain > 1000: break
_wait_write()
asm.outb(KBD_DATA, 0xF4)
_wait_read()
asm.inb(KBD_DATA)
idt.irqInstallHandler(1, irq_handler, "keyboard")

View File

@@ -0,0 +1,134 @@
import asm
import intr.idt as idt
import platform.pch.pic as pic
import drivers.serial.uart.serial as serial
import t, c
MOUSE_DATA: t.CDefine = 0x60
MOUSE_STATUS: t.CDefine = 0x64
MOUSE_COMMAND: t.CDefine = 0x64
MOUSE_BUF_SIZE: t.CDefine = 1024
MOUSE_LEFT: t.CDefine = 0x01
MOUSE_RIGHT: t.CDefine = 0x02
MOUSE_MIDDLE: t.CDefine = 0x04
class mouse_packet:
flags: t.CUInt8T
dx: t.CInt8T
dy: t.CInt8T
buttons: t.CUInt8T
packets: t.CArray[mouse_packet, MOUSE_BUF_SIZE]
pack_head: t.CStatic | t.CUInt32T = 0
pack_tail: t.CStatic | t.CUInt32T = 0
pack_count: t.CStatic | t.CUInt32T = 0
cycle: t.CStatic | t.CUInt8T = 0
byte1: t.CStatic | t.CUInt8T = 0
byte2: t.CStatic | t.CInt8T = 0
byte3: t.CStatic | t.CInt8T = 0
mouse_x: t.CStatic | t.CInt32T = 0
mouse_y: t.CStatic | t.CInt32T = 0
mouse_buttons: t.CStatic | t.CUInt8T = 0
def _wait_read():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
timeout -= 1
def _wait_write():
timeout: t.CUInt32T = 100000
while timeout > 0:
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
timeout -= 1
def _write_cmd(cmd: t.CUInt8T):
_wait_write()
asm.outb(MOUSE_COMMAND, 0xD4)
_wait_write()
asm.outb(MOUSE_DATA, cmd)
_wait_read()
asm.inb(MOUSE_DATA)
def irq_handler() -> t.CInt:
global cycle, byte1, byte2, byte3, pack_tail, pack_count
status: t.CUInt8T = asm.inb(MOUSE_STATUS)
if (status & 0x20) == 0: return 0
data: t.CUInt8T = asm.inb(MOUSE_DATA)
if cycle == 0:
if (data & 0x08) != 0:
byte1 = data
cycle = 1
return 0
if cycle == 1:
byte2 = data
cycle = 2
return 0
byte3 = data
cycle = 0
if pack_count < MOUSE_BUF_SIZE:
packets[pack_tail].flags = byte1
packets[pack_tail].dx = byte2
packets[pack_tail].dy = byte3
packets[pack_tail].buttons = byte1 & t.CUInt8T(0x07)
pack_tail = pack_tail + 1
if pack_tail >= MOUSE_BUF_SIZE:
pack_tail = 0
pack_count += 1
return 0
def read_packet(out: mouse_packet | t.CPtr) -> t.CInt:
global pack_head, pack_count
asm.cli()
if pack_count == 0:
asm.sti()
out.flags = 0
out.dx = 0
out.dy = 0
out.buttons = 0
return -1
out.flags = packets[pack_head].flags
out.dx = packets[pack_head].dx
out.dy = packets[pack_head].dy
out.buttons = packets[pack_head].buttons
pack_head = pack_head + 1
if pack_head >= MOUSE_BUF_SIZE:
pack_head = 0
pack_count -= 1
asm.sti()
return 0
def has_data() -> t.CInt:
return pack_count
def get_x() -> t.CInt32T:
return mouse_x
def get_y() -> t.CInt32T:
return mouse_y
def get_buttons() -> t.CUInt8T:
return mouse_buttons
def init():
_wait_write()
asm.outb(MOUSE_COMMAND, 0xA8)
_wait_write()
asm.outb(MOUSE_COMMAND, 0x20)
_wait_read()
status: t.CUInt8T = asm.inb(MOUSE_DATA)
status = status | 0x02
status = status & 0xDF
_wait_write()
asm.outb(MOUSE_COMMAND, 0x60)
_wait_write()
asm.outb(MOUSE_DATA, status)
_write_cmd(0xF6)
_write_cmd(0xF4)
pic.clearMask(12)
idt.irqInstallHandler(12, irq_handler, "mouse")

View File

@@ -0,0 +1,46 @@
import platform.pch.pic as pic
import su8250
import t, c
# 串口初始化
def init():
# 初始化COM1端口
su8250.init(su8250.COM1_PORT)
# 启用COM1中断IRQ4
pic.clearMask(4)
# 发送一个字符到COM1
def putc(cr: t.CChar):
su8250.putchar(su8250.COM1_PORT, cr)
def putchar(cr: t.CChar):
su8250.putchar(su8250.COM1_PORT, cr)
# 从COM1读取一个字符
def getchar() -> t.CChar:
return su8250.getchar(su8250.COM1_PORT)
# 发送一个字符串到COM1
def puts(s: str):
# 逐个字符发送直接复用putchar的逻辑
for i in s:
putchar(i)
# 检查COM1是否有数据可读
def isDataAvailable() -> t.CInt:
return su8250.isDataAvailable(su8250.COM1_PORT)
# 检查COM1发送缓冲区是否为空
def isTransmitEmpty() -> t.CInt:
return su8250.isTransmitEmpty(su8250.COM1_PORT)
# 发送32位十六进制值到COM1
def put_hex32(value: t.CUInt32T):
hex_digits: t.CArray[t.CChar, None] = ["0123456789ABCDEF"]
buffer: t.CArray[t.CChar, 9]
for i in range(7, -1, -1):
buffer[i] = hex_digits[value & 0xF]
value >>= 4
buffer[8] = '\0'
puts(buffer)

View File

@@ -0,0 +1,116 @@
import platform.pch as pch
import asm
import t, c
# 串口端口定义
COM1_PORT: t.CDefine = 0x3F8 # COM1端口地址
COM2_PORT: t.CDefine = 0x2F8 # COM2端口地址
# 8250/16550 UART寄存器偏移
UART_RBR: t.CDefine = 0 # 接收缓冲区寄存器(读)
UART_THR: t.CDefine = 0 # 发送保持寄存器(写)
UART_DLL: t.CDefine = 0 # 除数锁存低位DLAB=1
UART_IER: t.CDefine = 1 # 中断使能寄存器
UART_DLM: t.CDefine = 1 # 除数锁存高位DLAB=1
UART_FCR: t.CDefine = 2 # FIFO控制寄存器
UART_IIR: t.CDefine = 2 # 中断识别寄存器(读)
UART_LCR: t.CDefine = 3 # 线路控制寄存器
UART_MCR: t.CDefine = 4 # 调制解调器控制寄存器
UART_LSR: t.CDefine = 5 # 线路状态寄存器
UART_MSR: t.CDefine = 6 # 调制解调器状态寄存器
UART_SCR: t.CDefine = 7 # scratch register
UART_LSR_THRE: t.CDefine = 0x20 # THRE发送保持寄存器空
UART_LSR_TEMT: t.CDefine = 0x40 # TEMT发送移位寄存器空真正的发送完成
# 线路控制寄存器位定义
UART_LCR_DLAB: t.CDefine = 0x80 # 除数锁存访问位
UART_LCR_8BIT: t.CDefine = 0x03 # 8位数据位
# 线路状态寄存器位定义
UART_LSR_DR: t.CDefine = 0x01 # 数据就绪
UART_LSR_THRE: t.CDefine = 0x20 # 发送保持寄存器空
# 波特率除数115200 bps
BAUD_115200: t.CDefine = 1
# 初始化UART 8250/16550
def init(port: t.CUInt16T):
# 1. 禁用中断
asm.outb(port + UART_IER, 0x00)
delay(1000)
# 2. 设置波特率除数115200 bps
asm.outb(port + UART_LCR, UART_LCR_DLAB) # 设置DLAB位
delay(1000)
asm.outb(port + UART_DLL, 0x01) # 除数低位 (115200 bps)
delay(1000)
asm.outb(port + UART_DLM, 0x00) # 除数高位
delay(1000)
# 3. 设置线路控制8位数据位1位停止位无校验
asm.outb(port + UART_LCR, UART_LCR_8BIT)
delay(1000)
# 4. 初始化FIFO
asm.outb(port + UART_FCR, 0x07) # 启用FIFO清除接收和发送FIFO
delay(1000)
# 5. 设置调制解调器控制
asm.outb(port + UART_MCR, 0x03) # 启用DTR、RTS
delay(1000)
# 6. 清除任何待处理的中断
asm.inb(port + UART_IIR)
delay(1000)
asm.inb(port + UART_RBR)
delay(1000)
# 7. 等待一段时间让设备稳定
delay(10000)
# 延迟函数
def delay(count: t.CInt):
for i in range(count): c.Asm("nop")
# 检查发送缓冲区是否为空
def isTransmitEmpty(port: t.CUInt16T) -> t.CInt:
return asm.inb(port + UART_LSR) & UART_LSR_THRE
def putchar(port: t.CUInt16T, cr: t.CChar):
# 1. 处理换行符:串口终端需要\r\n才会正确换行只发\n会错位
if cr == '\n':
# 直接发送\r避免递归调用
timeout: t.CUInt32T = 1000000
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
c.Asm("nop")
timeout -= 1
if timeout == 0: return
asm.outb(port + UART_THR, '\r')
timeout = 1000000
while ((asm.inb(port + UART_LSR) & UART_LSR_TEMT) == 0) and timeout:
c.Asm("nop")
timeout -= 1
# 2. 等待发送缓冲区为空
timeout: t.CUInt32T = 1000000
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
c.Asm("nop")
timeout -= 1
if timeout == 0: return
# 3. 发送字符
asm.outb(port + UART_THR, cr)
# 4. 等待发送完成
timeout = 1000000
while ((asm.inb(port + UART_LSR) & UART_LSR_TEMT) == 0) and timeout:
c.Asm("nop")
timeout -= 1
# 检查是否有数据可读
def isDataAvailable(port: t.CUInt16T) -> t.CInt:
return asm.inb(port + UART_LSR) & UART_LSR_DR
# 读取一个字符
def getchar(port: t.CUInt16T) -> t.CChar:
# 等待数据可用
while not isDataAvailable(port): pass
# 读取字符
return asm.inb(port + UART_RBR)

View File

@@ -0,0 +1,161 @@
import asm
import t, c
import serial
import viperlib
import pci
class IDError(t.CEnum):
IDE_ERR_NONE: t.State = 0
IDE_ERR_TIMEOUT: t.State
IDE_ERR_DEVICE_ERROR: t.State
IDE_ERR_DEVICE_BUSY: t.State
IDE_ERR_INVALID_PARAM: t.State
IDE_ERR_BUFFER_NULL: t.State
IDE_ERR_SECTOR_COUNT: t.State
IDE_ERR_DEVICE_NOT_READY: t.State
IDE_ERR_DEVICE_FAILURE: t.State
IDE_ERR_COMMAND_FAILED: t.State
IDE_ERR_INVALID_LBA: t.State
IDE_baseport_PRIMARY: t.CDefine = 0x1F0
IDE_baseport_SECONDARY: t.CDefine = 0x170
IDE_STATUS_BSY: t.CDefine = 0x80
IDE_STATUS_DRDY: t.CDefine = 0x40
IDE_STATUS_DF: t.CDefine = 0x20
IDE_STATUS_DRQ: t.CDefine = 0x08
IDE_STATUS_ERR: t.CDefine = 0x01
SECTOR_SIZE: t.CDefine = 512
_ide_initialized: t.CInt = 0
def waitReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
timeout: t.CInt = 100000
while timeout > 0:
status: t.CUInt8T = asm.inb(baseport + 7)
if status & IDE_STATUS_DF:
return IDError.IDE_ERR_DEVICE_FAILURE
if not status & IDE_STATUS_BSY and status & IDE_STATUS_DRDY:
return IDError.IDE_ERR_NONE
timeout -= 1
return IDError.IDE_ERR_TIMEOUT
def waitDataReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
timeout: t.CInt = 100000
while timeout > 0:
status: t.CUInt8T = asm.inb(baseport + 7)
if status & IDE_STATUS_ERR: return IDError.IDE_ERR_DEVICE_ERROR
if status & IDE_STATUS_DF: return IDError.IDE_ERR_DEVICE_FAILURE
if not status & IDE_STATUS_BSY and (status & IDE_STATUS_DRQ or status & IDE_STATUS_DRDY):
return IDError.IDE_ERR_NONE
timeout -= 1
return IDError.IDE_ERR_TIMEOUT
def init() -> t.CInt:
if _ide_initialized: return IDError.IDE_ERR_NONE
dbg: t.CArray[t.CChar, 120]
bus: t.CUInt8T
dev_n: t.CUInt8T
func: t.CUInt8T
for bus in range(2):
for dev_n in range(32):
for func in range(8):
vendor: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x00)
if vendor == 0xFFFF: continue
cls: t.CUInt32T = pci.pci_get_class(bus, dev_n, func)
if cls == 0x010180 or cls == 0x0101:
cmd: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x04)
pci.pci_write32(bus, dev_n, func, 0x04, t.CUInt32T(cmd | 0x0007))
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", t.CInt(bus), t.CInt(dev_n), t.CInt(func), t.CUInt32T(pci.pci_read16(bus, dev_n, func, 0x04)))
serial.puts(dbg)
asm.outb(0x3F6, 0x04)
i: t.CInt
for i in range(10000):
asm.nop()
asm.outb(0x3F6, 0x00)
for i in range(10000):
asm.nop()
status: t.CUInt8T = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", t.CUInt32T(status))
serial.puts(dbg)
_ide_initialized = 1
return IDError.IDE_ERR_NONE
def readSector(lba: t.CUInt32T, buffer: t.CVoid | t.CPtr) -> t.CInt:
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
dbg: t.CArray[t.CChar, 120]
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE:
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", t.CInt(err))
serial.puts(dbg)
return err
asm.outb(0x3F6, 0x02)
asm.outb(0x1F2, 1)
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
asm.outb(0x1F7, 0x20)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE:
st: t.CUInt8T = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", t.CInt(err), t.CUInt32T(st))
serial.puts(dbg)
return err
st2: t.CUInt8T = asm.inb(0x1F7)
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
for j in range(256):
c.Set(c.Deref(buf), asm.inw(0x1F0))
buf += 1
first_byte: t.CUInt8T = c.Deref(t.CUInt8T(buffer, t.CPtr))
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, t.CUInt32T(st2), t.CUInt32T(first_byte))
# serial.puts(dbg)
return IDError.IDE_ERR_NONE
def writeSector(lba: t.CUInt32T, buffer: t.CConst | t.CVoid | t.CPtr) -> t.CInt:
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return err
asm.outb(0x3F6, 0x02)
asm.outb(0x1F2, 1)
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
asm.outb(0x1F7, 0x30)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return err
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
for j in range(256):
val: t.CUInt16T = c.Deref(buf)
asm.outw(0x1F0, val)
buf += 1
asm.outb(0x1F7, 0xE7)
waitReady(IDE_baseport_PRIMARY)
return IDError.IDE_ERR_NONE
def getDiskSize() -> t.CUInt64T:
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return 0
asm.outb(0x1F6, 0xE0)
asm.outb(0x1F7, 0xEC)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return 0
status: t.CUInt8T = asm.inb(0x1F7)
if not status & IDE_STATUS_DRDY: return 0
if status & IDE_STATUS_ERR: return 0
identify_data: t.CArray[t.CUInt16T, 256]
for i in range(256):
identify_data[i] = asm.inw(0x1F0)
totalSectors: t.CUInt64T = identify_data[60] | t.CUInt64T(identify_data[61]) << 16
if identify_data[83] & (1 << 10):
lba48_sectors: t.CUInt64T = (
t.CUInt64T(identify_data[100]) |
t.CUInt64T(identify_data[101]) << 16 |
t.CUInt64T(identify_data[102]) << 32 |
t.CUInt64T(identify_data[103]) << 48)
if lba48_sectors > totalSectors:
totalSectors = lba48_sectors
return totalSectors

View File

@@ -0,0 +1,37 @@
import t, c
import drivers.usb.usb as usb
HID_BOOT_PROTOCOL: t.CDefine = 0
HID_REPORT_PROTOCOL: t.CDefine = 1
HID_KBD_REPORT_SIZE: t.CDefine = 8
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
class hid_kbd_report(t.CStruct):
modifier: t.CUInt8T
reserved: t.CUInt8T
keycode: t.CArray[t.CUInt8T, 6]
class hid_mouse_report(t.CStruct):
buttons: t.CUInt8T
dx: t.CInt8T
dy: t.CInt8T
wheel: t.CInt8T
def init_keyboard(dev: usb.usb_device | t.CPtr) -> t.CInt:
if dev.iface_class != 0x03: return -1
if dev.iface_protocol != 0x01: return -2
if dev.ep_in == 0: return -3
return 0
def init_mouse(dev: usb.usb_device | t.CPtr) -> t.CInt:
if dev.iface_class != 0x03: return -1
if dev.iface_protocol != 0x02: return -2
if dev.ep_in == 0: return -3
return 0
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> t.CInt:
return usb.read_interrupt(dev, c.Addr(report))
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> t.CInt:
return usb.read_interrupt(dev, c.Addr(report))

View File

@@ -0,0 +1,111 @@
import t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
KBD_BUF_SIZE: t.CDefine = 1024
KBD_EVT_PRESS: t.CDefine = 0
KBD_EVT_RELEASE: t.CDefine = 1
class usb_kbd_event(t.CStruct):
modifier: t.CUInt8T
keycode: t.CUInt8T
event_type: t.CUInt8T
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
kbd_buf_head: t.CInt = 0
kbd_buf_tail: t.CInt = 0
kbd_buf_count: t.CInt = 0
kbd_dev: usb.usb_device | t.CPtr = None
kbd_report: hid.hid_kbd_report
kbd_prev_keycodes: t.CArray[t.CUInt8T, 6]
kbd_initialized: t.CInt = 0
kbd_slot_id: t.CInt = -1
def init() -> t.CInt:
global kbd_dev, kbd_initialized, kbd_slot_id
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
if dev is None:
serial.puts("[usb_kbd] no USB keyboard found\n")
return -1
kbd_dev = dev
if hid.init_keyboard(dev) != 0:
serial.puts("[usb_kbd] init failed\n")
return -2
kbd_initialized = 1
serial.puts("[usb_kbd] initialized\n")
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
if kbd_slot_id < 0:
serial.puts("[usb_kbd] register callback failed\n")
kbd_initialized = 0
return -3
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(kbd_report))
return 0
def _on_int_complete() -> t.CInt:
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
if kbd_initialized == 0: return 0
i: t.CInt
j: t.CInt
for i in range(6):
code: t.CUInt8T = kbd_report.keycode[i]
if code == 0: continue
found: t.CInt = 0
for j in range(6):
if code == kbd_prev_keycodes[j]:
found = 1
break
if found == 0:
if kbd_buf_count < KBD_BUF_SIZE:
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
kbd_buf[kbd_buf_tail].keycode = code
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
kbd_buf_tail = kbd_buf_tail + 1
if kbd_buf_tail >= KBD_BUF_SIZE:
kbd_buf_tail = 0
kbd_buf_count += 1
for i in range(6):
prev: t.CUInt8T = kbd_prev_keycodes[i]
if prev == 0: continue
found2: t.CInt = 0
for j in range(6):
if prev == kbd_report.keycode[j]:
found2 = 1
break
if found2 == 0:
if kbd_buf_count < KBD_BUF_SIZE:
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
kbd_buf[kbd_buf_tail].keycode = prev
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
kbd_buf_tail = kbd_buf_tail + 1
if kbd_buf_tail >= KBD_BUF_SIZE:
kbd_buf_tail = 0
kbd_buf_count += 1
for i in range(6):
kbd_prev_keycodes[i] = kbd_report.keycode[i]
dev: usb.usb_device | t.CPtr = kbd_dev
if dev is not None and kbd_slot_id >= 0:
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(kbd_report))
return 0
def has_data() -> t.CInt:
if kbd_buf_count > 0: return 1
return 0
def poll() -> t.CInt:
if kbd_initialized == 0: return 0
if kbd_buf_count > 0: return 1
return 0
def read_event(out: usb_kbd_event | t.CPtr) -> t.CInt:
global kbd_buf_head, kbd_buf_count
if kbd_buf_count == 0: return -1
out.modifier = kbd_buf[kbd_buf_head].modifier
out.keycode = kbd_buf[kbd_buf_head].keycode
out.event_type = kbd_buf[kbd_buf_head].event_type
kbd_buf_head = kbd_buf_head + 1
if kbd_buf_head >= KBD_BUF_SIZE:
kbd_buf_head = 0
kbd_buf_count -= 1
return 0

View File

@@ -0,0 +1,77 @@
import t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
MOUSE_BUF_SIZE: t.CDefine = 1024
class usb_mouse_packet(t.CStruct):
buttons: t.CUInt8T
dx: t.CInt16T
dy: t.CInt16T
wheel: t.CInt8T
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
mse_buf_head: t.CInt = 0
mse_buf_tail: t.CInt = 0
mse_buf_count: t.CInt = 0
mse_dev: usb.usb_device | t.CPtr = None
mse_report: hid.hid_mouse_report
mse_initialized: t.CInt = 0
mse_slot_id: t.CInt = -1
def init() -> t.CInt:
global mse_dev, mse_initialized, mse_slot_id
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x02)
if dev is None:
serial.puts("[usb_mse] no USB mouse found\n")
return -1
mse_dev = dev
if hid.init_mouse(dev) != 0:
serial.puts("[usb_mse] init failed\n")
return -2
mse_initialized = 1
serial.puts("[usb_mse] initialized\n")
mse_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
if mse_slot_id < 0:
serial.puts("[usb_mse] register callback failed\n")
mse_initialized = 0
return -3
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(mse_report))
return 0
def _on_int_complete() -> t.CInt:
global mse_buf_head, mse_buf_tail, mse_buf_count
if mse_initialized == 0: return 0
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
if mse_buf_count < MOUSE_BUF_SIZE:
mse_buf[mse_buf_tail].buttons = mse_report.buttons
mse_buf[mse_buf_tail].dx = t.CInt16T(mse_report.dx)
mse_buf[mse_buf_tail].dy = t.CInt16T(mse_report.dy)
mse_buf[mse_buf_tail].wheel = mse_report.wheel
mse_buf_tail = mse_buf_tail + 1
if mse_buf_tail >= MOUSE_BUF_SIZE:
mse_buf_tail = 0
mse_buf_count += 1
dev: usb.usb_device | t.CPtr = mse_dev
if dev is not None and mse_slot_id >= 0:
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(mse_report))
return 0
def has_data() -> t.CInt:
if mse_buf_count > 0: return 1
return 0
def read_packet(out: usb_mouse_packet | t.CPtr) -> t.CInt:
global mse_buf_head, mse_buf_count
if mse_buf_count == 0: return -1
out.buttons = mse_buf[mse_buf_head].buttons
out.dx = mse_buf[mse_buf_head].dx
out.dy = mse_buf[mse_buf_head].dy
out.wheel = mse_buf[mse_buf_head].wheel
mse_buf_head = mse_buf_head + 1
if mse_buf_head >= MOUSE_BUF_SIZE:
mse_buf_head = 0
mse_buf_count -= 1
return 0

View File

@@ -0,0 +1,93 @@
import t, c
import asm
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
PCI_CONFIG_DATA: t.CDefine = 0xCFC
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
class pci_device(t.CStruct):
bus: t.CUInt8T
dev: t.CUInt8T
func: t.CUInt8T
vendor_id: t.CUInt16T
device_id: t.CUInt16T
class_code: t.CUInt32T
irq: t.CUInt8T
bar: t.CArray[t.CUInt32T, 6]
def pci_read32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt32T:
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
asm.outl(PCI_CONFIG_ADDR, addr)
return asm.inl(PCI_CONFIG_DATA)
def pci_write32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T, value: t.CUInt32T):
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
asm.outl(PCI_CONFIG_ADDR, addr)
asm.outl(PCI_CONFIG_DATA, value)
def pci_read16(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt16T:
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x02) * 8
return t.CUInt16T((val >> shift) & 0xFFFF)
def pci_read8(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt8T:
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x03) * 8
return t.CUInt8T((val >> shift) & 0xFF)
def pci_get_class(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T) -> t.CUInt32T:
cls: t.CUInt8T = pci_read8(bus, dev, func, 0x0B)
sub: t.CUInt8T = pci_read8(bus, dev, func, 0x0A)
proto: t.CUInt8T = pci_read8(bus, dev, func, 0x09)
return (t.CUInt32T(cls) << 16) | (t.CUInt32T(sub) << 8) | t.CUInt32T(proto)
def pci_get_bar(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, bar_idx: t.CUInt8T) -> t.CUInt32T:
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
def pci_enable_device(dev: pci_device | t.CPtr):
cmd: t.CUInt16T = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
pci_write32(dev.bus, dev.dev, dev.func, 0x04, t.CUInt32T(cmd))
def pci_fill_device(bus: t.CUInt8T, dev_n: t.CUInt8T, func: t.CUInt8T, out: pci_device | t.CPtr):
out.bus = bus
out.dev = dev_n
out.func = func
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
out.device_id = pci_read16(bus, dev_n, func, 0x02)
out.class_code = pci_get_class(bus, dev_n, func)
out.irq = pci_read8(bus, dev_n, func, 0x3C)
i: t.CInt
for i in range(6):
out.bar[i] = pci_get_bar(bus, dev_n, func, t.CUInt8T(i))
_uhci_dev: pci_device
_uhci_found: t.CInt = 0
def find_uhci() -> t.CUInt16T:
global _uhci_dev, _uhci_found
bus: t.CUInt8T
dev_n: t.CUInt8T
func: t.CUInt8T
for bus in range(1):
for dev_n in range(32):
for func in range(8):
vendor: t.CUInt16T = pci_read16(bus, dev_n, func, 0x00)
if vendor == 0xFFFF: continue
cls: t.CUInt32T = pci_get_class(bus, dev_n, func)
if cls == PCI_CLASS_SERIAL_UHCI:
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
pci_enable_device(c.Addr(_uhci_dev))
_uhci_found = 1
bar: t.CUInt32T = _uhci_dev.bar[4]
io_base: t.CUInt16T = t.CUInt16T(bar & 0xFFFE)
return io_base
return 0

View File

@@ -0,0 +1,415 @@
import t, c
import asm
import mm.mm as mm
import viperstring as string
import drivers.serial.uart.serial as serial
import platform.pch.timer as timer
import intr.idt as idt
import platform.pch.pic as pic
import drivers.usb.pci as pci
UHCI_USBCMD: t.CDefine = 0x00
UHCI_USBSTS: t.CDefine = 0x02
UHCI_USBINTR: t.CDefine = 0x04
UHCI_FRNUM: t.CDefine = 0x06
UHCI_FLBASEADD: t.CDefine = 0x08
UHCI_SOFMOD: t.CDefine = 0x0C
UHCI_PORTSC1: t.CDefine = 0x10
UHCI_PORTSC2: t.CDefine = 0x12
UHCI_CMD_RUN: t.CDefine = 0x0001
UHCI_CMD_HCRESET: t.CDefine = 0x0002
UHCI_CMD_GRESET: t.CDefine = 0x0004
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
UHCI_CMD_CF: t.CDefine = 0x0040
UHCI_STS_HCHALTED: t.CDefine = 0x0020
UHCI_STS_USBINT: t.CDefine = 0x0001
UHCI_STS_USBERRINT: t.CDefine = 0x0002
UHCI_STS_RESUME: t.CDefine = 0x0004
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
UHCI_INTR_RESUME: t.CDefine = 0x0002
UHCI_INTR_IOC: t.CDefine = 0x0004
UHCI_INTR_SHORT: t.CDefine = 0x0008
UHCI_PORT_CONNECT: t.CDefine = 0x0001
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
UHCI_PORT_ENABLE: t.CDefine = 0x0004
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
UHCI_PORT_RESET: t.CDefine = 0x0200
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
TD_CTRL_IOC: t.CDefine = 0x01000000
TD_CTRL_LS: t.CDefine = 0x04000000
TD_CTRL_SPD: t.CDefine = 0x20000000
TD_CTRL_CERR_SHIFT: t.CDefine = 27
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
TD_TOKEN_SETUP: t.CDefine = 0x2D
TD_TOKEN_IN: t.CDefine = 0x69
TD_TOKEN_OUT: t.CDefine = 0xE1
TD_TOKEN_DATA0: t.CDefine = 0
TD_TOKEN_DATA1: t.CDefine = 1
TD_LINK_TERMINATE: t.CDefine = 0x00000001
TD_LINK_QH: t.CDefine = 0x00000002
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
UHCI_NUM_FRAMES: t.CDefine = 1024
UHCI_INT_SLOTS: t.CDefine = 4
class uhci_td(t.CStruct):
link: t.CUInt32T
ctrl_status: t.CUInt32T
token: t.CUInt32T
buffer: t.CUInt32T
class uhci_qh(t.CStruct):
link: t.CUInt32T
element: t.CUInt32T
class int_slot(t.CStruct):
td: uhci_td | t.CPtr
callback: t.CInt | t.CPtr
active: t.CInt
qh: uhci_qh | t.CPtr
_io_base: t.CUInt16T = 0
_frame_list: t.CUInt32T | t.CPtr = None
_ctrl_qh: uhci_qh | t.CPtr = None
_bulk_qh: uhci_qh | t.CPtr = None
_irq: t.CInt = -1
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
_int_slot_count: t.CInt = 0
def _reg_read16(offset: t.CUInt16T) -> t.CUInt16T:
return asm.inw(_io_base + offset)
def _reg_write16(offset: t.CUInt16T, value: t.CUInt16T):
asm.outw(_io_base + offset, value)
def _reg_read32(offset: t.CUInt16T) -> t.CUInt32T:
return asm.inl(_io_base + offset)
def _reg_write32(offset: t.CUInt16T, value: t.CUInt32T):
asm.outl(_io_base + offset, value)
def _uhci_irq_handler() -> t.CInt:
sts: t.CUInt16T = _reg_read16(UHCI_USBSTS)
_reg_write16(UHCI_USBSTS, sts)
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
return 0
for si in range(_int_slot_count):
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
if slot.active and slot.td is not None and slot.callback is not None:
status: t.CUInt32T = slot.td.ctrl_status
if (status & TD_CTRL_ACTIVE) == 0:
slot.active = 0
c.Asm(f"""mov rbp, rsp
and rsp, -16
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
mov rsp, rbp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RBX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
t.ASM_DESCR.CLOBBER_RBP])
return 0
def register_int_callback(cb: t.CInt | t.CPtr) -> t.CInt:
global _int_slot_count
if _int_slot_count >= UHCI_INT_SLOTS:
return -1
si: t.CInt = _int_slot_count
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
if qh is None:
return -2
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
_qh_set_link(qh, 0, 0, 1)
_qh_set_element(qh, 0, 1)
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
if td is None:
return -3
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
slot.td = td
slot.callback = cb
slot.active = 0
slot.qh = qh
_int_slot_count = si + 1
_rebuild_int_chain()
return si
def schedule_int_transfer(slot_id: t.CInt, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, toggle_ptr: t.CUInt8T | t.CPtr, buf: t.CVoid | t.CPtr):
if slot_id < 0 or slot_id >= _int_slot_count:
return
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
td: uhci_td | t.CPtr = slot.td
qh: uhci_qh | t.CPtr = slot.qh
if td is None or qh is None:
return
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
_td_set_link(td, 0, 0, 1)
_td_set_ctrl(td, ls, max_pkt)
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
td.buffer = t.CUInt32T(t.CUInt64T(buf))
_qh_set_element(qh, t.CUInt32T(t.CUInt64T(td)), 0)
slot.active = 1
def _rebuild_int_chain():
if _int_slot_count == 0:
return
first_qh: uhci_qh | t.CPtr = None
prev_qh: uhci_qh | t.CPtr = None
for si in range(_int_slot_count):
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
if cur_qh is not None:
if first_qh is None:
first_qh = cur_qh
if prev_qh is not None:
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(cur_qh)) | TD_LINK_QH, 1, 0)
prev_qh = cur_qh
if prev_qh is not None:
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(_ctrl_qh)) | TD_LINK_QH, 1, 0)
if first_qh is not None:
qh_addr: t.CUInt32T = t.CUInt32T(t.CUInt64T(first_qh)) | TD_LINK_QH
i: t.CInt
for i in range(UHCI_NUM_FRAMES):
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
c.Set(c.Deref(entry_ptr), qh_addr)
def _td_set_link(td: uhci_td | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
val: t.CUInt32T = (addr & 0xFFFFFFF0)
if is_qh: val = val | TD_LINK_QH
if terminate: val = val | TD_LINK_TERMINATE
td.link = val
def _td_set_token(td: uhci_td | t.CPtr, pid: t.CUInt8T, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, toggle: t.CUInt8T, max_len: t.CUInt16T):
len_bits: t.CUInt32T
if max_len == 0:
len_bits = 0x7FF
else:
len_bits = t.CUInt32T(max_len) - 1
td.token = (t.CUInt32T(pid) << 0) | (t.CUInt32T(dev_addr) << 8) | (t.CUInt32T(endpoint & 0x0F) << 15) | (t.CUInt32T(toggle & 1) << 19) | (len_bits << 21)
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: t.CInt, maxlen: t.CUInt16T):
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
val: t.CUInt32T = (addr & 0xFFFFFFF0)
if is_qh: val = val | TD_LINK_QH
if terminate: val = val | TD_LINK_TERMINATE
qh.link = val
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, terminate: t.CInt):
val: t.CUInt32T = (addr & 0xFFFFFFF0)
if terminate: val = val | TD_LINK_TERMINATE
qh.element = val
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: t.CInt) -> t.CInt:
start: t.CUInt64T = timer.timer_get_ticks()
deadline: t.CUInt64T = start + t.CUInt64T(timeout_ms)
poll_cnt: t.CInt = 0
while timer.timer_get_ticks() < deadline:
status: t.CUInt32T = td.ctrl_status
if (status & TD_CTRL_ACTIVE) == 0:
if (status & 0x00600000) != 0:
return -1
return 0
poll_cnt += 1
if poll_cnt >= 100:
poll_cnt = 0
asm.sti()
asm.hlt()
return -2
def reset(io_base: t.CUInt16T) -> t.CInt:
global _io_base
_io_base = io_base
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
i: t.CInt
for i in range(1000):
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
break
_reg_write16(UHCI_USBSTS, 0xFFFF)
_reg_write16(UHCI_USBINTR, 0x0000)
return 0
def init(io_base: t.CUInt16T) -> t.CInt:
global _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
_io_base = io_base
_int_slot_count = 0
serial.puts("[uhci] resetting...\n")
if reset(io_base) != 0:
serial.puts("[uhci] reset failed\n")
return -1
serial.puts("[uhci] allocating frame list...\n")
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
if _frame_list is None:
serial.puts("[uhci] frame list alloc failed\n")
return -2
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
if _ctrl_qh is None:
serial.puts("[uhci] ctrl_qh alloc failed\n")
return -3
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
_qh_set_link(_ctrl_qh, 0, 0, 1)
_qh_set_element(_ctrl_qh, 0, 1)
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
if _bulk_qh is None:
serial.puts("[uhci] bulk_qh alloc failed\n")
return -4
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
_qh_set_link(_bulk_qh, 0, 0, 1)
_qh_set_element(_bulk_qh, 0, 1)
serial.puts("[uhci] setting up frame list...\n")
qh_addr: t.CUInt32T = t.CUInt32T(c.Addr(_ctrl_qh)) | TD_LINK_QH
i: t.CInt
for i in range(UHCI_NUM_FRAMES):
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
c.Set(c.Deref(entry_ptr), qh_addr)
_reg_write32(UHCI_FLBASEADD, t.CUInt32T(t.CUInt64T(_frame_list)))
_reg_write16(UHCI_FRNUM, 0)
_reg_write16(UHCI_SOFMOD, 64)
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
timer.timer_msleep(10)
_reg_write16(UHCI_USBSTS, 0xFFFF)
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
_irq = t.CInt(pci._uhci_dev.irq)
if _irq > 0 and _irq < 16:
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
pic.clearMask(t.CUInt8T(_irq))
serial.puts("[uhci] started\n")
return 0
def port_reset(port: t.CInt) -> t.CInt:
sc: t.CUInt16T
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if (sc & UHCI_PORT_CONNECT) == 0:
return -1
if port == 0:
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
else:
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
if port == 0:
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
else:
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
timer.timer_msleep(50)
if port == 0:
_reg_write16(UHCI_PORTSC1, 0x0000)
else:
_reg_write16(UHCI_PORTSC2, 0x0000)
timer.timer_msleep(10)
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
else:
sc = _reg_read16(UHCI_PORTSC2)
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
timer.timer_msleep(10)
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if (sc & UHCI_PORT_ENABLE) == 0:
return -2
return 0
def port_is_connected(port: t.CInt) -> t.CInt:
sc: t.CUInt16T
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if sc & UHCI_PORT_CONNECT: return 1
return 0
def port_is_low_speed(port: t.CInt) -> t.CInt:
sc: t.CUInt16T
if port == 0:
sc = _reg_read16(UHCI_PORTSC1)
else:
sc = _reg_read16(UHCI_PORTSC2)
if sc & UHCI_PORT_LOW_SPEED: return 1
return 0
def control_transfer(dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup_buf: t.CVoid | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
td_count: t.CInt = 2
if data_len > 0:
td_count = td_count + 1
total: t.CUInt64T = t.CUInt64T(td_count) * uhci_td.__sizeof__()
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
if tds is None: return -1
string.memset(c.Addr(tds), 0, total)
setup_td: uhci_td | t.CPtr = tds
_td_set_link(setup_td, t.CUInt32T(t.CUInt64T(tds) + uhci_td.__sizeof__()), 0, 0)
_td_set_ctrl(setup_td, ls, 8)
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
setup_td.buffer = t.CUInt32T(t.CUInt64T(setup_buf))
if data_len > 0:
data_td: uhci_td | t.CPtr = t.CUInt64T(tds) + uhci_td.__sizeof__()
_td_set_link(data_td, t.CUInt32T(t.CUInt64T(data_td) + uhci_td.__sizeof__()), 0, 0)
_td_set_ctrl(data_td, ls, max_pkt)
if data_in:
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
else:
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
data_td.buffer = t.CUInt32T(t.CUInt64T(data_buf))
status_td: uhci_td | t.CPtr = t.CUInt64T(data_td) + uhci_td.__sizeof__()
_td_set_link(status_td, 0, 0, 1)
_td_set_ctrl(status_td, ls, max_pkt)
if data_in:
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
else:
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
status_td.buffer = 0
else:
status_td: uhci_td | t.CPtr = t.CUInt64T(tds) + uhci_td.__sizeof__()
_td_set_link(status_td, 0, 0, 1)
_td_set_ctrl(status_td, ls, max_pkt)
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
status_td.buffer = 0
_qh_set_element(_ctrl_qh, t.CUInt32T(t.CUInt64T(setup_td)), 0)
result: t.CInt = _wait_for_complete(status_td, 500)
_qh_set_element(_ctrl_qh, 0, 1)
mm.free(tds)
return result

View File

@@ -0,0 +1,330 @@
import t, c
import mm.mm as mm
import viperstring as string
import drivers.serial.uart.serial as serial
import drivers.usb.uhci as uhci
import drivers.usb.pci as pci
import platform.pch.timer as timer
import viperlib
USB_DESC_DEVICE: t.CDefine = 1
USB_DESC_CONFIG: t.CDefine = 2
USB_DESC_STRING: t.CDefine = 3
USB_DESC_INTERFACE: t.CDefine = 4
USB_DESC_ENDPOINT: t.CDefine = 5
USB_REQ_GET_STATUS: t.CDefine = 0
USB_REQ_CLEAR_FEATURE: t.CDefine = 1
USB_REQ_SET_FEATURE: t.CDefine = 3
USB_REQ_SET_ADDRESS: t.CDefine = 5
USB_REQ_GET_DESCRIPTOR: t.CDefine = 6
USB_REQ_SET_DESCRIPTOR: t.CDefine = 7
USB_REQ_GET_CONFIGURATION: t.CDefine = 8
USB_REQ_SET_CONFIGURATION: t.CDefine = 9
USB_REQ_SET_INTERFACE: t.CDefine = 11
HID_CLASS: t.CDefine = 0x03
HID_SUBCLASS_BOOT: t.CDefine = 0x01
HID_PROTO_KEYBOARD: t.CDefine = 0x01
HID_PROTO_MOUSE: t.CDefine = 0x02
HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B
HID_REQ_SET_IDLE: t.CDefine = 0x0A
HID_REQ_GET_REPORT: t.CDefine = 0x01
USB_MAX_DEVICES: t.CDefine = 8
class usb_dev_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
bcdUSB: t.CUInt16T
bDeviceClass: t.CUInt8T
bDeviceSubClass: t.CUInt8T
bDeviceProtocol: t.CUInt8T
bMaxPacketSize0: t.CUInt8T
idVendor: t.CUInt16T
idProduct: t.CUInt16T
bcdDevice: t.CUInt16T
iManufacturer: t.CUInt8T
iProduct: t.CUInt8T
iSerialNumber: t.CUInt8T
bNumConfigurations: t.CUInt8T
class usb_config_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
wTotalLength: t.CUInt16T
bNumInterfaces: t.CUInt8T
bConfigurationValue: t.CUInt8T
iConfiguration: t.CUInt8T
bmAttributes: t.CUInt8T
bMaxPower: t.CUInt8T
class usb_iface_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
bInterfaceNumber: t.CUInt8T
bAlternateSetting: t.CUInt8T
bNumEndpoints: t.CUInt8T
bInterfaceClass: t.CUInt8T
bInterfaceSubClass: t.CUInt8T
bInterfaceProtocol: t.CUInt8T
iInterface: t.CUInt8T
class usb_ep_desc(t.CStruct):
bLength: t.CUInt8T
bDescriptorType: t.CUInt8T
bEndpointAddress: t.CUInt8T
bmAttributes: t.CUInt8T
wMaxPacketSize: t.CUInt16T
bInterval: t.CUInt8T
class usb_setup_pkt(t.CStruct):
bmRequestType: t.CUInt8T
bRequest: t.CUInt8T
wValue: t.CUInt16T
wIndex: t.CUInt16T
wLength: t.CUInt16T
class usb_device(t.CStruct):
addr: t.CUInt8T
ls: t.CInt
max_pkt0: t.CUInt8T
iface_class: t.CUInt8T
iface_subclass: t.CUInt8T
iface_protocol: t.CUInt8T
iface_num: t.CUInt8T
ep_in: t.CUInt8T
ep_in_max: t.CUInt16T
ep_in_interval: t.CUInt8T
ep_in_toggle: t.CUInt8T
configured: t.CInt
_devices: t.CArray[usb_device, USB_MAX_DEVICES]
_device_count: t.CInt = 0
def _setup_packet(bmRequestType: t.CUInt8T, bRequest: t.CUInt8T, wValue: t.CUInt16T, wIndex: t.CUInt16T, wLength: t.CUInt16T, buf: usb_setup_pkt | t.CPtr):
buf.bmRequestType = bmRequestType
buf.bRequest = bRequest
buf.wValue = wValue
buf.wIndex = wIndex
buf.wLength = wLength
def _send_control(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup: usb_setup_pkt | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in)
def get_descriptor(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, desc_type: t.CUInt8T, desc_idx: t.CUInt8T, buf: t.CVoid | t.CPtr, length: t.CUInt16T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (t.CUInt16T(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1)
def set_address(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, new_addr: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def set_configuration(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, config_val: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def hid_set_protocol(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, protocol: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, t.CUInt16T(iface), 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def hid_set_idle(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, duration: t.CUInt8T) -> t.CInt:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_IDLE, t.CUInt16T(duration) << 8, t.CUInt16T(iface), 0, c.Addr(setup))
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CVoid | t.CPtr, total_len: t.CUInt16T):
offset: t.CInt = 0
found_hid: t.CInt = 0
while offset < t.CInt(total_len):
p: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset)
desc_len: t.CUInt8T = c.Deref(p)
p2: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset) + 1
desc_type: t.CUInt8T = c.Deref(p2)
if desc_len == 0: break
if desc_type == USB_DESC_INTERFACE:
iface: usb_iface_desc | t.CPtr = config_buf + t.CUInt64T(offset)
if iface.bInterfaceClass == HID_CLASS:
found_hid = 1
dev.iface_class = HID_CLASS
dev.iface_subclass = iface.bInterfaceSubClass
dev.iface_protocol = iface.bInterfaceProtocol
dev.iface_num = iface.bInterfaceNumber
if desc_type == USB_DESC_ENDPOINT and found_hid:
ep: usb_ep_desc | t.CPtr = config_buf + t.CUInt64T(offset)
if (ep.bEndpointAddress & 0x80) != 0:
dev.ep_in = ep.bEndpointAddress & 0x0F
dev.ep_in_max = ep.wMaxPacketSize
dev.ep_in_interval = ep.bInterval
found_hid = 0
offset = offset + t.CInt(desc_len)
def enumerate_port(port: t.CInt) -> t.CInt:
global _device_count
if _device_count >= USB_MAX_DEVICES: return -1
ls: t.CInt = uhci.port_is_low_speed(port)
reset_ok: t.CInt = -1
reset_retry: t.CInt
for reset_retry in range(3):
if uhci.port_reset(port) == 0:
reset_ok = 0
break
timer.timer_msleep(50)
if reset_ok != 0:
return -2
timer.timer_msleep(10)
dev_buf: t.CVoid | t.CPtr = mm.malloc(usb_dev_desc.__sizeof__())
if dev_buf is None: return -3
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
result: t.CInt = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
retry: t.CInt
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
uhci.port_reset(port)
timer.timer_msleep(10)
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
if result != 0:
mm.free(dev_buf)
return -4
desc: usb_dev_desc | t.CPtr = dev_buf
max_pkt: t.CUInt8T = desc.bMaxPacketSize0
if max_pkt < 8: max_pkt = 8
new_addr: t.CUInt8T = t.CUInt8T(_device_count + 1)
result = set_address(0, ls, max_pkt, new_addr)
for retry in range(3):
if result == 0: break
timer.timer_msleep(20)
result = set_address(0, ls, max_pkt, new_addr)
if result != 0:
mm.free(dev_buf)
return -5
timer.timer_msleep(10)
dev: usb_device | t.CPtr = c.Addr(_devices[_device_count])
dev.addr = new_addr
dev.ls = ls
dev.max_pkt0 = max_pkt
dev.configured = 0
dev.iface_class = 0
dev.iface_subclass = 0
dev.iface_protocol = 0
dev.ep_in = 0
dev.ep_in_max = 0
dev.ep_in_interval = 0
dev.ep_in_toggle = 0
config_buf: t.CVoid | t.CPtr = mm.malloc(256)
if config_buf is None:
mm.free(dev_buf)
return -6
string.memset(config_buf, 0, 256)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -7
cfg: usb_config_desc | t.CPtr = config_buf
total_len: t.CUInt16T = cfg.wTotalLength
if total_len > 256: total_len = 256
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -8
_parse_config(dev, config_buf, total_len)
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -9
dev.configured = 1
if dev.iface_class == HID_CLASS:
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
_device_count = _device_count + 1
mm.free(config_buf)
mm.free(dev_buf)
return t.CInt(new_addr)
def init() -> t.CInt:
global _device_count
_device_count = 0
io_base: t.CUInt16T = pci.find_uhci()
if io_base == 0:
serial.puts("[usb] UHCI controller not found\n")
return -1
buf: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", t.CUInt32T(io_base))
serial.puts(buf)
if uhci.init(io_base) != 0:
serial.puts("[usb] UHCI init failed\n")
return -2
serial.puts("[usb] UHCI initialized\n")
timer.timer_msleep(50)
port: t.CInt
for port in range(2):
if uhci.port_is_connected(port):
viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", t.CUInt32T(port))
serial.puts(buf)
dev_id: t.CInt = enumerate_port(port)
if dev_id > 0:
dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1])
viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
t.CUInt32T(dev.addr), t.CUInt32T(dev.iface_class),
t.CUInt32T(dev.iface_protocol), t.CUInt32T(dev.ep_in))
serial.puts(buf)
else:
viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", t.CUInt32T(port), t.CInt32T(dev_id))
serial.puts(buf)
return _device_count
def find_hid_device(protocol: t.CUInt8T) -> usb_device | t.CPtr:
i: t.CInt
for i in range(_device_count):
dev: usb_device | t.CPtr = c.Addr(_devices[i])
if dev.iface_class == HID_CLASS:
if dev.iface_protocol == protocol:
if dev.configured != 0:
return dev
return None
def read_interrupt(dev: usb_device | t.CPtr, buf: t.CVoid | t.CPtr) -> t.CInt:
return 0

View File

@@ -0,0 +1,85 @@
from stdint import *
import drivers.video.vesafb.gfx as gfx
import t, c
MAX_SHEETS: t.CDefine = 64
MAX_UI_COMPONENTS: t.CDefine = 256
_next_sheet_id: t.CInt = 0
_next_component_id: t.CInt = 0
@t.Object
class Sheet:
id: t.CInt
x: t.CInt
y: t.CInt
w: t.CInt
h: t.CInt
visible: t.CInt
_surf_obj: gfx.Surface
_renderer_obj: gfx.Renderer
surf: gfx.Surface | t.CPtr
renderer: gfx.Renderer | t.CPtr
parent: 'Sheet | t.CPtr'
bg_color: t.CUInt32T
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, parent: 'Sheet | t.CPtr' = None):
global _next_sheet_id
self.id = _next_sheet_id
_next_sheet_id += 1
self.x = x
self.y = y
self.w = w
self.h = h
self.visible = 1
self._surf_obj = gfx.Surface(fb, zb, w, h)
self.surf = c.Addr(self._surf_obj)
self._renderer_obj = gfx.Renderer(self.surf)
self.renderer = c.Addr(self._renderer_obj)
self.parent = parent
self.bg_color = gfx.COLOR_RGB(20, 20, 30)
def MoveTo(self, nx: t.CInt, ny: t.CInt):
self.x = nx
self.y = ny
def Resize(self, nw: t.CInt, nh: t.CInt):
self.w = nw
self.h = nh
def Show(self):
self.visible = 1
def Hide(self):
self.visible = 0
def Clear(self):
r: gfx.Renderer = c.Deref(self.renderer)
r.Clear(self.bg_color)
def Fill(self, color: t.CUInt32T):
r: gfx.Renderer = c.Deref(self.renderer)
r.Clear(color)
def DrawRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
r: gfx.Renderer = c.Deref(self.renderer)
r.DrawLine2D(rx, ry, rx + rw - 1, ry, color)
r.DrawLine2D(rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
r.DrawLine2D(rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
r.DrawLine2D(rx, ry + rh - 1, rx, ry, color)
def DrawFilledRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
surf: gfx.Surface = c.Deref(self.surf)
fb: UINT32PTR = surf.fb
w: t.CInt = surf.w
h: t.CInt = surf.h
for py in range(ry, ry + rh):
if py < 0 or py >= h: continue
for px in range(rx, rx + rw):
if px < 0 or px >= w: continue
fb[py * w + px] = color
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
return 1
return 0

View File

@@ -0,0 +1,152 @@
from stdint import *
import drivers.video.vesafb.gfx as gfx
import drivers.video.ui.sheet as sheet
import string
import t, c
UI_LABEL: t.CDefine = 0
UI_BUTTON: t.CDefine = 1
UI_PANEL: t.CDefine = 2
UI_PROGRESS: t.CDefine = 3
@t.Object
class UIComponent:
id: t.CInt
ctype: t.CInt
x: t.CInt
y: t.CInt
w: t.CInt
h: t.CInt
visible: t.CInt
sheet: sheet.Sheet | t.CPtr
fg_color: t.CUInt32T
bg_color: t.CUInt32T
text: t.CArray[t.CChar, 128]
text_len: t.CInt
value: t.CInt
def __init__(self, ctype: t.CInt, sh: sheet.Sheet | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt):
global _next_component_id
self.id = _next_component_id
_next_component_id += 1
self.ctype = ctype
self.x = x
self.y = y
self.w = w
self.h = h
self.visible = 1
self.sheet = sh
self.fg_color = gfx.COLOR_RGB(255, 255, 255)
self.bg_color = gfx.COLOR_RGB(40, 40, 60)
string.memset(c.Addr(self.text), 0, 128)
self.text_len = 0
self.value = 0
def SetText(self, s: str):
i: t.CInt = 0
for ch in s:
if i >= 127: break
self.text[i] = ch
i += 1
self.text[i] = 0
self.text_len = i
def SetValue(self, v: t.CInt):
self.value = v
def Render(self):
if self.visible == 0: return
sh: sheet.Sheet = c.Deref(self.sheet)
match self.ctype:
case 0:
self._RenderLabel(sh)
case 1:
self._RenderButton(sh)
case 2:
self._RenderPanel(sh)
case 3:
self._RenderProgress(sh)
def _RenderLabel(self, sh: sheet.Sheet):
sh.DrawFilledRect(self.x, self.y, self.w, self.h, 0)
def _RenderButton(self, sh: sheet.Sheet):
sh.DrawFilledRect(self.x, self.y, self.w, self.h, self.bg_color)
sh.DrawRect(self.x, self.y, self.w, self.h, self.fg_color)
def _RenderPanel(self, sh: sheet.Sheet):
sh.DrawFilledRect(self.x, self.y, self.w, self.h, self.bg_color)
sh.DrawRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(80, 80, 120))
def _RenderProgress(self, sh: sheet.Sheet):
sh.DrawFilledRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(30, 30, 40))
fill_w: t.CInt = self.w * self.value / 100
if fill_w > 0:
sh.DrawFilledRect(self.x, self.y, fill_w, self.h, gfx.COLOR_RGB(0, 180, 255))
sh.DrawRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(80, 80, 100))
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
return 1
return 0
@t.Object
class UIManager:
sheets: t.CArray[sheet.Sheet | t.CPtr, 64]
sheet_count: t.CInt
components: t.CArray[UIComponent | t.CPtr, 256]
component_count: t.CInt
screen_w: t.CInt
screen_h: t.CInt
def __init__(self, w: t.CInt, h: t.CInt):
self.sheet_count = 0
self.component_count = 0
self.screen_w = w
self.screen_h = h
i: t.CInt
for i in range(64):
self.sheets[i] = None
for i in range(256):
self.components[i] = None
def AddSheet(self, sh: sheet.Sheet | t.CPtr) -> t.CInt:
if self.sheet_count >= 64: return -1
self.sheets[self.sheet_count] = sh
self.sheet_count += 1
return 0
def AddComponent(self, comp: UIComponent | t.CPtr) -> t.CInt:
if self.component_count >= 256: return -1
self.components[self.component_count] = comp
self.component_count += 1
return 0
def FindComponent(self, cid: t.CInt) -> UIComponent | t.CPtr:
i: t.CInt
for i in range(self.component_count):
p: UIComponent | t.CPtr = self.components[i]
if p is not None:
comp: UIComponent = c.Deref(p)
if comp.id == cid: return p
return None
def RenderAll(self):
i: t.CInt
for i in range(self.component_count):
p: UIComponent | t.CPtr = self.components[i]
if p is not None:
comp: UIComponent = c.Deref(p)
comp.Render()
def HitTest(self, px: t.CInt, py: t.CInt) -> UIComponent | t.CPtr:
i: t.CInt = self.component_count - 1
while i >= 0:
p: UIComponent | t.CPtr = self.components[i]
if p is not None:
comp: UIComponent = c.Deref(p)
if comp.visible == 1 and comp.Contains(px, py) == 1:
return p
i -= 1
return None

View File

@@ -0,0 +1,305 @@
from stdint import *
import vipermath
import string
import t, c
PI: t.CDefine = float(3.14159265358979323846)
SPHERE_SLICES: t.CDefine = (24 * 1)
SPHERE_STACKS: t.CDefine = (16 * 1)
SIN_WAVE_GRID: t.CDefine = (40 * 1)
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | t.CInt:
return (255 << 24) | (r << 16) | (g << 8) | (b)
@t.Object
class Vec3:
x: float
y: float
z: float
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
def Sub(self, b: 'Vec3') -> 'Vec3':
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
def Cross(self, b: 'Vec3') -> 'Vec3':
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
def Dot(self, b: 'Vec3') -> float:
return self.x * b.x + self.y * b.y + self.z * b.z
def Norm(self) -> 'Vec3':
l = vipermath.sqrtf(self.Dot(self))
return Vec3(self.x / l, self.y / l, self.z / l)
class Mat4:
m: t.CArray[t.CArray[float, 4], 4]
def Mat4_Identity() -> Mat4:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
return m
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
res: Mat4 = Mat4()
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
for i in range(4):
for j in range(4):
for k in range(4):
res.m[i][j] += a.m[i][k] * b.m[k][j]
return res
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
w: float = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3]
if w != 0:
x /= w; y /= w; z /= w
return Vec3(x, y, z)
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
m: Mat4 = Mat4()
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
m.m[0][0] = f / aspect; m.m[1][1] = f
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
return m
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
zaxis: Vec3 = eye.Sub(target).Norm()
xaxis: Vec3 = up.Cross(zaxis).Norm()
yaxis: Vec3 = zaxis.Cross(xaxis)
m: Mat4 = Mat4_Identity()
m.m[0][0]=xaxis.x; m.m[0][1]=xaxis.y; m.m[0][2]=xaxis.z; m.m[0][3]= -xaxis.Dot(eye)
m.m[1][0]=yaxis.x; m.m[1][1]=yaxis.y; m.m[1][2]=yaxis.z; m.m[1][3]= -yaxis.Dot(eye)
m.m[2][0]=zaxis.x; m.m[2][1]=zaxis.y; m.m[2][2]=zaxis.z; m.m[2][3]= -zaxis.Dot(eye)
m.m[3][3] = 1
return m
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
m: Mat4 = Mat4_Identity()
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
return m
def Mat4_RotateY(a: float) -> Mat4:
m: Mat4 = Mat4_Identity();
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
return m
@t.Object
class Surface:
fb: UINT32PTR
zb: float | t.CPtr
w: int
h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self.fb = fb
self.zb = zb
self.w = w
self.h = h
@t.Object
class Renderer:
_fb: UINT32PTR
_zb: float | t.CPtr
_w: int
_h: int
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self._fb = fb
self._zb = zb
self._w = w
self._h = h
def Clear(self, color: t.CUInt32T):
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
size: int = self._w * self._h
for i in range(size):
fb[i] = color
zb[i] = float(1.0)
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: t.CUInt32T):
fb: UINT32PTR = self._fb
w: int = self._w; h: int = self._h
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
sx: int = 1 if x0 < x1 else -1; sy: int = 1 if y0 < y1 else -1
err: int = dx - dy
while True:
if x0 >= 0 and x0 < w and y0 >= 0 and y0 < h: fb[y0 * w + x0] = col
if x0 == x1 and y0 == y1: break
e2: int = 2 * err
if e2 > -dy: err -= dy; x0 += sx
if e2 < dx: err += dx; y0 += sy
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: t.CUInt32T):
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
fb: UINT32PTR = self._fb
zb: float | t.CPtr = self._zb
w: int = self._w
h: int = self._h
sx0: float = (v0.x + float(1.0)) * float(0.5) * w; sy0: float = (float(1.0) - v0.y) * float(0.5) * h
sx1: float = (v1.x + float(1.0)) * float(0.5) * w; sy1: float = (float(1.0) - v1.y) * float(0.5) * h
sx2: float = (v2.x + float(1.0)) * float(0.5) * w; sy2: float = (float(1.0) - v2.y) * float(0.5) * h
minX: int = max(0, int(vipermath.floorf(min(min(sx0, sx1), sx2))))
maxX: int = min(w - 1, int(vipermath.ceilf(max(max(sx0, sx1), sx2))))
minY: int = max(0, int(vipermath.floorf(min(min(sy0, sy1), sy2))))
maxY: int = min(h - 1, int(vipermath.ceilf(max(max(sy0, sy1), sy2))))
dx12: float = sx1 - sx2; dy12: float = sy1 - sy2
dx02: float = sx0 - sx2; dy02: float = sy0 - sy2
denom: float = dx12 * dy02 - dy12 * dx02
if denom < float(0.001) and denom > float(-0.001): return
invDenom: float = float(1.0) / denom
row_dxP_start: float = float(minX) - sx2
for y in range(minY, maxY + 1):
dyP: float = float(y) - sy2
dxP: float = row_dxP_start
row_base: int = y * w
for x in range(minX, maxX + 1):
w0: float = (dx12 * dyP - dy12 * dxP) * invDenom
w1: float = (dxP * dy02 - dyP * dx02) * invDenom
w2: float = float(1.0) - w0 - w1
if w0 >= 0 and w1 >= 0 and w2 >= 0:
z: float = w0 * v0.z + w1 * v1.z + w2 * v2.z
idx: int = row_base + x
if z < zb[idx]:
zb[idx] = z
fb[idx] = col
dxP += float(1.0)
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: t.CUInt32T, intensity: float):
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
r: int = int(radius) + 4
ix: int = int(x); iy: int = int(y)
for dy in range(-r, r + 1):
py: int = iy + dy
if py < 0 or py >= h: continue
for dx in range(-r, r + 1):
px: int = ix + dx
if px < 0 or px >= w: continue
dist: float = vipermath.sqrtf(float(dx*dx + dy*dy))
if dist < radius:
self.BlendPixel(px, py, core_col, intensity)
elif dist < float(r):
fade: float = 1.0 - (dist - radius) / 4.0
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
def BlendPixel(self, x: int, y: int, col: t.CUInt32T, alpha: float):
if alpha <= 0.0: return
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
if x < 0 or x >= w or y < 0 or y >= h: return
idx: int = y * w + x
bg: t.CUInt32T = fb[idx]
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
a: int = int(alpha * 255.0)
inv_a: int = 255 - a
nr: int = (f_r * a + bg_r * inv_a) >> 8
ng: int = (f_g * a + bg_g * inv_a) >> 8
nb: int = (f_b * a + bg_b * inv_a) >> 8
fb[idx] = COLOR_RGB(255 if (nr > 255) else nr,
255 if (ng > 255) else ng,
255 if (nb > 255) else nb)
@t.Object
class Scene3D:
renderer: Renderer
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
self.renderer = Renderer(fb, zb, w, h)
def Render(self, time: float):
rw: int = self.renderer._w
rh: int = self.renderer._h
self.renderer.Clear(COLOR_RGB(15, 15, 25))
yaw: float = float(45.0) * PI / float(180.0); pitch: float = float(45.0) * PI / float(180.0); radius: float = float(10.0)
eye: Vec3 = Vec3(radius*vipermath.cosf(pitch)*vipermath.cosf(yaw), radius*vipermath.sinf(pitch), radius*vipermath.cosf(pitch)*vipermath.sinf(yaw))
target: Vec3 = Vec3(0, 0, 0); up: Vec3 = Vec3(0, 1, 0)
view: Mat4 = Mat4_LookAt(eye, target, up)
proj: Mat4 = Mat4_Perspective(PI / float(3.0), float(rw)/float(rh), float(0.1), float(100.0))
vp: Mat4 = Mat4_Mul(proj, view)
cubeX: float = float(-3.5)
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
colors: t.CArray[t.CUInt32T, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
for i in range(4):
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
sphereMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(pos.x, pos.y, pos.z))
self._DrawSphere(sphereMVP, Vec3(0,0,0), float(0.5), colors[i])
self._Draw3DSinWave(vp, Vec3(float(3.5), 0, 0), time)
self.renderer.DrawLine2D(50, rh - 150, rw - 50, rh - 150, COLOR_RGB(80, 80, 80))
self.renderer.DrawLine2D(50, rh - 50, 50, rh - 250, COLOR_RGB(80, 80, 80))
wave_shift: float = time * float(2.0)
prev_x: int = 50; prev_y: int = rh - 150 - int(vipermath.sinf(0 - wave_shift) * float(100.0))
for i in range(1, rw - 100):
tr: float = float(i) / float(rw-100) * float(4.0) * PI
cx: int = 50 + i; cy: int = rh - 150 - int(vipermath.sinf(tr - wave_shift) * float(100.0))
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
prev_x = cx; prev_y = cy
def _DrawCube(self, mvp: Mat4, col: t.CUInt32T):
v: t.CArray[Vec3, 8] = [
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
]
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
faces: t.CArray[t.CArray[int, 3], 12] = [
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
]
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: t.CUInt32T):
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
for i in range(SPHERE_STACKS):
for j in range(SPHERE_SLICES):
theta1: float = i * step_pi; theta2: float = (i + 1) * step_pi
phi1: float = j * step_2pi; phi2: float = (j + 1) * step_2pi
v: t.CArray[Vec3, 4]
v[0] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi1))
v[1] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi2))
v[2] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi1))
v[3] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi2))
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
mvp: Mat4 = Mat4_Mul(vp, Mat4_Mul(Mat4_Translate(pos.x, pos.y, pos.z), Mat4_RotateY(time * float(1.0))))
for i in range(SIN_WAVE_GRID):
for j in range(SIN_WAVE_GRID):
x0: float = -PI + i * step; z0 = -PI + j * step; x1: float = x0 + step; z1 = z0 + step
y00: float = vipermath.sinf(x0) * vipermath.cosf(z0) * scale; y10: float = vipermath.sinf(x1) * vipermath.cosf(z0) * scale
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
col1: t.CUInt32T = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
col2: t.CUInt32T = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
self.renderer.DrawTriangle(v00, v10, v11, col1); self.renderer.DrawTriangle(v00, v11, v01, col2)

View File

@@ -0,0 +1,504 @@
import string # std: standard
#import math # std: standard
import t, c
# 颜色格式枚举
class __ColorFormat(t.CEnum):
ColorFormat_BGRA: t.State # BGRA格式蓝色、绿色、红色、Alpha
ColorFormat_RGBA: t.State # RGBA格式红色、绿色、蓝色、Alpha
ColorFormat_BGR: t.State # BGR格式蓝色、绿色、红色
ColorFormat_RGB: t.State # RGB格式红色、绿色、蓝色
# 常量定义 - 提升代码可读性和可维护性
VGA_WIDTH: t.CDefine = 80
VGA_HEIGHT: t.CDefine = 25
FONT_WIDTH: t.CDefine = 8
FONT_HEIGHT: t.CDefine = 16
DEFAULT_CHAR: t.CDefine = 0 # 非ASCII字符的默认替换字符
SERIAL_PORT: t.CDefine = 0x3F8 # 串口调试端口地址
# 8x16字符点阵字库 (每个字符16字节共256个字符)
font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
# 字符编号 0x00 - 0x0F
{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x00
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x01
{0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x56, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x02
{0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x56, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x03
{0x00, 0x00, 0x70, 0x55, 0x55, 0x57, 0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x04
{0x00, 0x00, 0x70, 0x57, 0x54, 0x57, 0x71, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x05
{0x00, 0x00, 0x70, 0x57, 0x54, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x06
{0x00, 0x00, 0x70, 0x57, 0x51, 0x52, 0x72, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x07
{0x00, 0x00, 0x70, 0x57, 0x55, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x08
{0x00, 0x00, 0x70, 0x57, 0x55, 0x57, 0x71, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x09
{0x00, 0x00, 0x70, 0x56, 0x51, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0A
{0x00, 0x00, 0x70, 0x54, 0x54, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0B
{0x00, 0x00, 0x70, 0x50, 0x50, 0x57, 0x74, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0C
{0x00, 0x00, 0x70, 0x51, 0x51, 0x57, 0x75, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0D
{0x00, 0x00, 0x70, 0x57, 0x55, 0x57, 0x74, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0E
{0x00, 0x00, 0x70, 0x53, 0x54, 0x56, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x0F
# 字符编号 0x10 - 0x1F
{0x00, 0x00, 0x10, 0x37, 0x15, 0x15, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x10
{0x00, 0x00, 0x10, 0x32, 0x16, 0x12, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x11
{0x00, 0x00, 0x20, 0x6E, 0x22, 0x2E, 0x28, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x12
{0x00, 0x00, 0x10, 0x37, 0x11, 0x13, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x13
{0x00, 0x00, 0x10, 0x35, 0x15, 0x17, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x14
{0x00, 0x00, 0x10, 0x37, 0x14, 0x17, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x15
{0x00, 0x00, 0x10, 0x37, 0x14, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x16
{0x00, 0x00, 0x10, 0x37, 0x11, 0x12, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x17
{0x00, 0x00, 0x10, 0x37, 0x15, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x18
{0x00, 0x00, 0x10, 0x37, 0x15, 0x17, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x19
{0x00, 0x00, 0x10, 0x36, 0x11, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1A
{0x00, 0x00, 0x10, 0x34, 0x14, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1B
{0x00, 0x00, 0x10, 0x30, 0x10, 0x17, 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1C
{0x00, 0x00, 0x10, 0x31, 0x11, 0x17, 0x15, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1D
{0x00, 0x00, 0x10, 0x37, 0x15, 0x17, 0x14, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1E
{0x00, 0x00, 0x10, 0x33, 0x14, 0x16, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x1F
# 字符编号 0x20 - 0x2F
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x20
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x21
{0x6C, 0x6C, 0x6C, 0x6C, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x22
{0x36, 0x36, 0x36, 0x7F, 0x7F, 0x36, 0x36, 0x36, 0x7F, 0x7F, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00}, # 0x23
{0x0C, 0x0C, 0x3E, 0x7F, 0x68, 0x68, 0x3E, 0x0B, 0x0B, 0x7F, 0x3E, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x24
{0x60, 0x60, 0x66, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x60, 0x66, 0x06, 0x06, 0x00, 0x00, 0x00}, # 0x25
{0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x38, 0x6C, 0x6D, 0x66, 0x66, 0x6F, 0x3B, 0x00, 0x00, 0x00}, # 0x26
{0x18, 0x18, 0x18, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x27
{0x1C, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x1C, 0x00, 0x00}, # 0x28
{0x38, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x38, 0x00, 0x00}, # 0x29
{0x00, 0x00, 0x18, 0x18, 0x7E, 0x3C, 0x3C, 0x3C, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2A
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2B
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00}, # 0x2C
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2D
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x2E
{0x00, 0x00, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x2F
# 字符编号 0x30 - 0x3F
{0x3C, 0x7E, 0x66, 0x66, 0x6E, 0x6E, 0x7E, 0x76, 0x76, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x30
{0x18, 0x38, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x31
{0x3C, 0x7E, 0x66, 0x06, 0x06, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x32
{0x3C, 0x7E, 0x66, 0x06, 0x06, 0x1C, 0x1C, 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x33
{0x0C, 0x0C, 0x1C, 0x1C, 0x3C, 0x2C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00}, # 0x34
{0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7E, 0x06, 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x35
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x36
{0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00}, # 0x37
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x38
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x39
{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x3A
{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x00}, # 0x3B
{0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x00, 0x00}, # 0x3C
{0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x3D
{0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00}, # 0x3E
{0x3C, 0x7E, 0x66, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x3F
# 字符编号 0x40 - 0x4F
{0x3C, 0x7E, 0x66, 0x66, 0x6E, 0x6A, 0x6A, 0x6A, 0x6E, 0x60, 0x60, 0x7C, 0x3C, 0x00, 0x00, 0x00}, # 0x40
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x41
{0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7C, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00, 0x00}, # 0x42
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x43
{0x78, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0x7C, 0x78, 0x00, 0x00, 0x00}, # 0x44
{0x7E, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x45
{0x7E, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0x46
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x47
{0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x48
{0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x49
{0x3E, 0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x7C, 0x38, 0x00, 0x00, 0x00}, # 0x4A
{0x66, 0x66, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x4B
{0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x4C
{0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00}, # 0x4D
{0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x4E
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x4F
# 字符编号 0x50 - 0x5F
{0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0x50
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6A, 0x6A, 0x6C, 0x7E, 0x36, 0x00, 0x00, 0x00}, # 0x51
{0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x52
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x78, 0x3C, 0x0E, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x53
{0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x54
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x55
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x56
{0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x77, 0x22, 0x00, 0x00, 0x00}, # 0x57
{0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x58
{0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x59
{0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x5A
{0x78, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x78, 0x00, 0x00}, # 0x5B
{0xC0, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x03, 0x03, 0x00, 0x00, 0x00}, # 0x5C
{0x1E, 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x1E, 0x00, 0x00}, # 0x5D
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x5E
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00}, # 0x5F
# 字符编号 0x60 - 0x6F
{0x30, 0x38, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x60
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0x61
{0x60, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00, 0x00}, # 0x62
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x63
{0x06, 0x06, 0x06, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0x64
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x65
{0x1C, 0x3E, 0x30, 0x30, 0x30, 0x7C, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00}, # 0x66
{0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x3E, 0x3C, 0x00}, # 0x67
{0x60, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x68
{0x18, 0x18, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x69
{0x0C, 0x0C, 0x00, 0x00, 0x3C, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, 0x78, 0x00}, # 0x6A
{0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x6B
{0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x6C
{0x00, 0x00, 0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00}, # 0x6D
{0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x6E
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x6F
# 字符编号 0x70 - 0x7F
{0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00}, # 0x70
{0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x07, 0x07, 0x00}, # 0x71
{0x00, 0x00, 0x00, 0x00, 0x6C, 0x7E, 0x76, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0x72
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x62, 0x70, 0x3C, 0x0E, 0x46, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0x73
{0x30, 0x30, 0x30, 0x30, 0x7C, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x1C, 0x00, 0x00, 0x00}, # 0x74
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0x75
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x76
{0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x7F, 0x36, 0x00, 0x00, 0x00}, # 0x77
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x78
{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0x79
{0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0x7A
{0x0E, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x0E, 0x00, 0x00}, # 0x7B
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}, # 0x7C
{0x70, 0x78, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x78, 0x70, 0x00, 0x00}, # 0x7D
{0x31, 0x79, 0x6B, 0x4F, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x7E
{0x00, 0x00, 0x70, 0x13, 0x24, 0x26, 0x24, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x7F
# 字符编号 0x80 - 0x8F
{0x03, 0x03, 0x03, 0x03, 0x06, 0x06, 0x06, 0x06, 0x66, 0x7C, 0x3C, 0x1C, 0x0C, 0x00, 0x00, 0x00}, # 0x80
{0x1C, 0x36, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x7F, 0x77, 0x22, 0x00, 0x00, 0x00}, # 0x81
{0x1C, 0x36, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00, 0x00, 0x00}, # 0x82
{0xFE, 0x92, 0x92, 0x92, 0x92, 0x92, 0xF2, 0x82, 0x82, 0x82, 0x82, 0x82, 0xFE, 0x00, 0x00, 0x00}, # 0x83
{0x66, 0x66, 0x99, 0x99, 0x81, 0x42, 0x42, 0x42, 0x81, 0x99, 0x99, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x84
{0x18, 0x3C, 0x66, 0x00, 0x42, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0x85
{0x18, 0x3C, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0x86
{0x07, 0x01, 0x01, 0x01, 0x02, 0x02, 0x64, 0x94, 0x94, 0x90, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}, # 0x87
{0x18, 0x28, 0x28, 0x48, 0x4F, 0x81, 0x81, 0x81, 0x4F, 0x48, 0x28, 0x28, 0x18, 0x00, 0x00, 0x00}, # 0x88
{0x18, 0x14, 0x14, 0x12, 0xF2, 0x81, 0x81, 0x81, 0xF2, 0x12, 0x14, 0x14, 0x18, 0x00, 0x00, 0x00}, # 0x89
{0x3C, 0x24, 0x24, 0x24, 0x24, 0x24, 0xE7, 0x81, 0x42, 0x42, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00}, # 0x8A
{0x18, 0x24, 0x24, 0x42, 0x42, 0x81, 0xE7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x3C, 0x00, 0x00, 0x00}, # 0x8B
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00}, # 0x8C
{0x45, 0x4B, 0x51, 0x61, 0x61, 0x61, 0x51, 0x49, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x8D
{0xC0, 0xC0, 0xCC, 0x0C, 0x18, 0x18, 0x30, 0x60, 0x60, 0xC0, 0xDB, 0x1B, 0x1B, 0x00, 0x00, 0x00}, # 0x8E
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x8F
# 字符编号 0x90 - 0x9F
{0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x90
{0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x91
{0x00, 0x00, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x00, 0x00, 0x00}, # 0x92
{0x00, 0x00, 0x30, 0x30, 0x18, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x00, 0x00, 0x00}, # 0x93
{0x1B, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x94
{0x36, 0x36, 0x36, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x95
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x6C, 0x6C}, # 0x96
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x97
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x98
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x99
{0x77, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xFF, 0x77, 0x00, 0x00, 0x00}, # 0x9A
{0x00, 0x00, 0x00, 0x00, 0x6E, 0xFF, 0xDB, 0xDB, 0xDF, 0xD8, 0xD8, 0xFF, 0x6E, 0x00, 0x00, 0x00}, # 0x9B
{0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, # 0x9C
{0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, # 0x9D
{0x3C, 0x7C, 0x60, 0x66, 0x66, 0xF0, 0xF6, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x9E
{0x3E, 0x7E, 0x66, 0x66, 0x66, 0xF6, 0xF6, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0x9F
# 字符编号 0xA0 - 0xAF
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xA0
{0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xA1
{0x08, 0x08, 0x3E, 0x7F, 0x6B, 0x68, 0x68, 0x68, 0x6B, 0x7F, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00}, # 0xA2
{0x1C, 0x3E, 0x36, 0x30, 0x30, 0x7C, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xA3
{0x00, 0x00, 0x42, 0x66, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x66, 0x42, 0x00, 0x00, 0x00}, # 0xA4
{0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xA5
{0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xA6
{0x3C, 0x7E, 0x60, 0x78, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x1E, 0x06, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xA7
{0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xA8
{0x3C, 0x42, 0x42, 0x81, 0x99, 0xA5, 0xA1, 0xA1, 0xA1, 0xA5, 0x99, 0x81, 0x42, 0x42, 0x3C, 0x00}, # 0xA9
{0x1C, 0x1E, 0x06, 0x06, 0x1E, 0x36, 0x36, 0x3E, 0x1E, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00}, # 0xAA
{0x00, 0x00, 0x33, 0x33, 0x66, 0x66, 0xCC, 0xCC, 0xCC, 0x66, 0x66, 0x33, 0x33, 0x00, 0x00, 0x00}, # 0xAB
{0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xAC
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xAD
{0x3C, 0x42, 0x42, 0x81, 0xB9, 0xA5, 0xA5, 0xA5, 0xB9, 0xA5, 0xA5, 0x81, 0x42, 0x42, 0x3C, 0x00}, # 0xAE
{0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xAF
# 字符编号 0xB0 - 0xBF
{0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB0
{0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00}, # 0xB1
{0x38, 0x04, 0x04, 0x04, 0x18, 0x20, 0x20, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB2
{0x38, 0x04, 0x04, 0x04, 0x18, 0x04, 0x04, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB3
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB4
{0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x3E, 0x30, 0x60, 0x60}, # 0xB5
{0x03, 0x03, 0x3E, 0x7E, 0x76, 0x76, 0x76, 0x36, 0x36, 0x36, 0x36, 0x3E, 0x3E, 0x00, 0x00, 0x00}, # 0xB6
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB7
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x18, 0x30, 0x00}, # 0xB8
{0x10, 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0xB9
{0x1C, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00}, # 0xBA
{0x00, 0x00, 0x88, 0xCC, 0x66, 0x66, 0x33, 0x33, 0x33, 0x66, 0x66, 0xCC, 0x88, 0x00, 0x00, 0x00}, # 0xBB
{0x40, 0x40, 0xC0, 0x40, 0x40, 0x40, 0x48, 0x48, 0x48, 0x08, 0x0A, 0x0A, 0x0F, 0x02, 0x02, 0x00}, # 0xBC
{0x40, 0x40, 0xC0, 0x40, 0x40, 0x40, 0x4F, 0x41, 0x41, 0x01, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x00}, # 0xBD
{0xE0, 0x20, 0x20, 0x20, 0xE0, 0x20, 0x28, 0x28, 0xE8, 0x08, 0x0A, 0x0A, 0x0F, 0x02, 0x02, 0x00}, # 0xBE
{0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x30, 0x60, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xBF
# 字符编号 0xC0 - 0xCF
{0x30, 0x38, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC0
{0x0C, 0x1C, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC1
{0x18, 0x3C, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC2
{0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC3
{0x66, 0x66, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC4
{0x3C, 0x66, 0x66, 0x3C, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x7E, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xC5
{0x3F, 0x7F, 0x6C, 0x6C, 0x6C, 0x7F, 0x7F, 0x6C, 0x6C, 0x6C, 0x6C, 0x6F, 0x6F, 0x00, 0x00, 0x00}, # 0xC6
{0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x18, 0x30, 0x30, 0x60, 0x00}, # 0xC7
{0x30, 0x38, 0x18, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xC8
{0x0C, 0x1C, 0x18, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xC9
{0x3C, 0x7E, 0x66, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCA
{0x66, 0x66, 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCB
{0x30, 0x38, 0x18, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCC
{0x0C, 0x1C, 0x18, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCD
{0x3C, 0x7E, 0x66, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCE
{0x66, 0x66, 0x66, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xCF
# 字符编号 0xD0 - 0xDF
{0x78, 0x7C, 0x6C, 0x66, 0x66, 0xF6, 0xF6, 0x66, 0x66, 0x66, 0x6C, 0x7C, 0x78, 0x00, 0x00, 0x00}, # 0xD0
{0x36, 0x7E, 0x6C, 0x00, 0x66, 0x66, 0x76, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xD1
{0x30, 0x38, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD2
{0x0C, 0x1C, 0x18, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD3
{0x3C, 0x7E, 0x66, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD4
{0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD5
{0x66, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD6
{0x00, 0x00, 0x63, 0x63, 0x36, 0x36, 0x1C, 0x08, 0x1C, 0x36, 0x36, 0x63, 0x63, 0x00, 0x00, 0x00}, # 0xD7
{0x3D, 0x7F, 0x66, 0x66, 0x6E, 0x6E, 0x7E, 0x76, 0x76, 0x66, 0x66, 0x7E, 0xBC, 0x80, 0x00, 0x00}, # 0xD8
{0x30, 0x38, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xD9
{0x0C, 0x1C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xDA
{0x3C, 0x7E, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xDB
{0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xDC
{0x0C, 0x1C, 0x18, 0x00, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00}, # 0xDD
{0xF0, 0xF0, 0x60, 0x78, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x78, 0x60, 0xF0, 0xF0, 0x00, 0x00, 0x00}, # 0xDE
{0x3C, 0x7E, 0x66, 0x66, 0x66, 0x6C, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x6E, 0x6C, 0x60, 0xC0, 0x00}, # 0xDF
# 字符编号 0xE0 - 0xEF
{0x30, 0x38, 0x18, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE0
{0x0C, 0x1C, 0x18, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE1
{0x18, 0x3C, 0x66, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE2
{0x36, 0x7E, 0x6C, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE3
{0x66, 0x66, 0x00, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE4
{0x3C, 0x66, 0x66, 0x3C, 0x00, 0x3C, 0x3E, 0x06, 0x3E, 0x7E, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE5
{0x00, 0x00, 0x00, 0x00, 0x3E, 0x3F, 0x0B, 0x3B, 0x7F, 0x6F, 0x68, 0x7F, 0x3F, 0x00, 0x00, 0x00}, # 0xE6
{0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x60, 0x60, 0x60, 0x66, 0x7E, 0x3C, 0x10, 0x60, 0x00}, # 0xE7
{0x30, 0x38, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE8
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xE9
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xEA
{0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x7E, 0x7E, 0x60, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xEB
{0x30, 0x38, 0x18, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xEC
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xED
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xEE
{0x66, 0x66, 0x00, 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00, 0x00}, # 0xEF
# 字符编号 0xF0 - 0xFF
{0x18, 0x18, 0x7E, 0x7E, 0x0C, 0x06, 0x06, 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF0
{0x36, 0x7E, 0x6C, 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00}, # 0xF1
{0x30, 0x38, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF2
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF3
{0x3C, 0x7E, 0x66, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF4
{0x36, 0x7E, 0x6C, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF5
{0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00, 0x00}, # 0xF6
{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0xFF, 0xFF, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00}, # 0xF7
{0x00, 0x00, 0x00, 0x02, 0x02, 0x3C, 0x7E, 0x6E, 0x76, 0x76, 0x66, 0x7E, 0xBC, 0x80, 0x00, 0x00}, # 0xF8
{0x30, 0x38, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xF9
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xFA
{0x18, 0x3C, 0x66, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xFB
{0x66, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00, 0x00}, # 0xFC
{0x0C, 0x1C, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0xFD
{0x60, 0x60, 0x60, 0x78, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x78, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00}, # 0xFE
{0x66, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06, 0x7E, 0x7C, 0x00}, # 0xFF
]
@t.Object
class _VGAScreenDriver:
# 帧缓冲区信息
fbv: t.CVoid | t.CPtr # = None
fb: t.CUnsignedChar | t.CPtr # = None
fw: int # = 800
fh: int # = 600
fp: int # = 800 * 4 # 3200 800*4
ColorFormat: __ColorFormat # = __ColorFormat.ColorFormat_BGRA # 默认使用BGRA格式
BgColor: t.CUnsignedInt = 0xFF000080 # RGBA: 不透明深蓝色
# 初始化VGA驱动
def __init__(self, fb: t.CVoid | t.CPtr, width: int, height: int, pitch: int, format: int):
# 先做参数合法性检查
if fb is None or width <= 0 or height <= 0 or pitch <= 0: return
# 更新帧缓冲区参数
self.fbv = fb
self.fb = t.CUnsignedChar(fb, t.CPtr)
self.fw = width
self.fh = height
self.fp = pitch
# 设置颜色格式
match format:
case 0: self.ColorFormat = __ColorFormat.ColorFormat_RGBA
case 1: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
case 2: pass
case 3: pass
case _: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
# 检测硬件实际颜色格式覆盖传入的format
self.DetectColorFormat()
# 初始化背景颜色
self.ClearScreen(self.BgColor)
# 检测硬件颜色格式 - 优化测试逻辑,避免误判
def DetectColorFormat(self) -> t.CStatic | t.CVoid:
if self.fb is None: return
fb: t.CUnsignedChar | t.CPtr = t.CUnsignedChar(self.fb, t.CPtr)
testX: int = 0
testY: int = 0
offset: int = testY * self.fp + testX * 4
# 保存测试位置原始像素值,避免污染屏幕
OriginalPixel: t.CUInt32T = c.Deref(t.CUInt32T(fb + offset, t.CPtr))
# 写入测试颜色:青色 (RGBA逻辑值: 0xFF00FFFF)
fb[offset + 0] = 0xFF # B
fb[offset + 1] = 0xFF # G
fb[offset + 2] = 0x00 # R
fb[offset + 3] = 0xFF # A
# 读取回测试像素
b: t.CUnsignedChar = fb[offset + 0]
g: t.CUnsignedChar = fb[offset + 1]
r: t.CUnsignedChar = fb[offset + 2]
# t.CVoid(fb[offset + 3]) # 忽略Alpha
# 恢复原始像素
c.Set(c.Deref(t.CUInt32T(fb + offset, t.CPtr)), OriginalPixel)
# 判定颜色格式
if r == 0x00 and g == 0xFF and b == 0xFF: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
elif r == 0xFF and g == 0xFF and b == 0x00: self.ColorFormat = __ColorFormat.ColorFormat_RGBA
else: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
# 设置像素颜色 - 统一接口输入为RGBA逻辑颜色
# color格式: 0xAARRGGBB (Alpha, Red, Green, Blue)
def SetPixel(self, x: int, y: int, color: t.CUInt32T):
fb: t.CUnsignedChar | t.CPtr = self.fb
if fb is None: return
if x < 0 or x >= self.fw or y < 0 or y >= self.fh: return
offset: int = y * self.fp + x * 4
# 解析RGBA分量
r: t.CUnsignedChar = (color >> 16) & 0xFF
g: t.CUnsignedChar = (color >> 8) & 0xFF
b: t.CUnsignedChar = color & 0xFF
a: t.CUnsignedChar = (color >> 24) & 0xFF
# 根据硬件格式写入像素
match self.ColorFormat:
case __ColorFormat.ColorFormat_BGRA:
self.fb[offset + 0] = b
fb[offset + 1] = g
fb[offset + 2] = r
fb[offset + 3] = a
case __ColorFormat.ColorFormat_RGBA:
fb[offset + 0] = r
fb[offset + 1] = g
fb[offset + 2] = b
fb[offset + 3] = a
case __ColorFormat.ColorFormat_BGR:
fb[offset + 0] = b
fb[offset + 1] = g
fb[offset + 2] = r
case __ColorFormat.ColorFormat_RGB:
fb[offset + 0] = r
fb[offset + 1] = g
fb[offset + 2] = b
case _:
# 降级到BGRA
fb[offset + 0] = b
fb[offset + 1] = g
fb[offset + 2] = r
fb[offset + 3] = a
# 清除屏幕 - 优化循环效率,减少函数调用开销
def ClearScreen(self, color: t.CUInt32T):
fb: t.CUnsignedChar | t.CPtr = self.fb
fp: int = self.fp
if fb is None: return
PixelSize: int = 3 if self.ColorFormat == __ColorFormat.ColorFormat_BGR or self.ColorFormat == __ColorFormat.ColorFormat_RGB else 4
RowSize: int = self.fw * PixelSize
# 解析清除颜色的RGBA分量
r: t.CUnsignedChar = (color >> 16) & 0xFF
g: t.CUnsignedChar = (color >> 8 ) & 0xFF
b: t.CUnsignedChar = (color) & 0xFF
a: t.CUnsignedChar = (color >> 24) & 0xFF
# 逐行填充比逐像素调用SetPixel快得多
for y in range(self.fh):
row_ptr: t.CUnsignedChar | t.CPtr = fb + y * fp
for x in range(self.fw):
offset: int = x * PixelSize
match self.ColorFormat:
case __ColorFormat.ColorFormat_BGRA:
row_ptr[offset + 0] = b
row_ptr[offset + 1] = g
row_ptr[offset + 2] = r
row_ptr[offset + 3] = a
case __ColorFormat.ColorFormat_RGBA:
row_ptr[offset + 0] = r
row_ptr[offset + 1] = g
row_ptr[offset + 2] = b
row_ptr[offset + 3] = a
case __ColorFormat.ColorFormat_BGR:
row_ptr[offset + 0] = b
row_ptr[offset + 1] = g
row_ptr[offset + 2] = r
case __ColorFormat.ColorFormat_RGB:
row_ptr[offset + 0] = r
row_ptr[offset + 1] = g
row_ptr[offset + 2] = b
def Print(self, x: int, y: int, s: str, fontcolor: t.CUnsignedInt = 0xFFFFFFFF, size: int = 16):
self.PrintColor(x, y, s, fontcolor, 0x00000000, size)
def PutcharColor(self, x: int, y: int, cr: t.CChar, fontcolor: t.CUnsignedInt = 0xFFFFFFFF, bgcolor: t.CUnsignedInt = 0x00000000, size: int = 16):
fw: int = self.fw
fh: int = self.fh
fb: t.CUnsignedChar | t.CPtr = self.fb
if fb is None: return
# 提前判断字符整体是否越界8x16避免内层循环冗余检查
if x < 0 or y < 0 or (x + FONT_WIDTH) > fw or (y + FONT_HEIGHT) > fh: return
# 处理字符范围非ASCII字符替换为默认字符
ch: t.CUnsignedChar = t.CUnsignedChar(cr)
if ch >= 128: ch = DEFAULT_CHAR
# 预解析背景色Alpha避免内层循环重复计算
bg_alpha: t.CUInt8T = (bgcolor >> 24) & 0xFF
draw_bg: int = (bg_alpha != 0) # 背景是否需要绘制
# 渲染8x16点阵字符
for fy in range(FONT_HEIGHT):
row: t.CUnsignedChar = font[ch][fy]
for fx in range(FONT_WIDTH):
px: int = x + fx
py: int = y + fy
# 检测当前点阵位是否点亮
if row & (0x80 >> fx):
# 绘制前景色
self.SetPixel(px, py, fontcolor)
elif draw_bg:
# 仅当背景不透明时绘制背景色
self.SetPixel(px, py, bgcolor)
# 在指定位置显示带颜色和字号的字符串
def PrintColor(self, x: int, y: int, s: str, fontcolor: t.CUnsignedInt = 0xFFFFFFFF, bgcolor: t.CUnsignedInt = 0x00000000, size: int = 16):
fw: int = self.fw
fh: int = self.fh
# fb: t.CUnsignedChar | t.CPtr = self.fb
currentX: int = x
currentY: int = y
if s is None: return
# 逐字符处理
for _s in s:
if _s == '\n':
# 换行重置XY增加字符高度
currentX = x
currentY += size + 2 # 字体大小 + 2像素行间距
# 检查换行后是否越界
if currentY + size > fh: break
else:
# 显示普通字符
self.PutcharColor(currentX, currentY, _s, fontcolor, bgcolor, size)
# 计算字符宽度
CharWidth: int = size / 2 + 1 # 简单估算字符宽度
currentX += CharWidth
# 检查横向是否越界
if currentX + CharWidth > fw:
# 自动换行
currentX = x
currentY += size + 2
if currentY + size > fh: break

View File

@@ -0,0 +1,757 @@
import drivers.serial.uart.serial as serial
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import drivers.core.cpu.cpu as cpu
import mm.mm as mm
import paging.paging as paging
import sched.process as proc
import sched.sched as sched
import intr.gdt as gdt
# Do NOT import KERN_STACK_SIZE/USER_STACK_SIZE from process - CDefine cross-module import is broken
# Redefine them here to ensure correct values
KERN_STACK_SIZE: t.CDefine = 8192
USER_STACK_SIZE: t.CDefine = 65536
import viperlib
import string
import asm
import t, c
ELFMAG0: t.CDefine = 0x7F
ELFMAG1: t.CDefine = 0x45
ELFMAG2: t.CDefine = 0x4C
ELFMAG3: t.CDefine = 0x46
ELFCLASS64: t.CDefine = 2
ELFDATA2LSB: t.CDefine = 1
ET_EXEC: t.CDefine = 2
ET_DYN: t.CDefine = 3
EM_X86_64: t.CDefine = 62
PT_LOAD: t.CDefine = 1
PT_DYNAMIC: t.CDefine = 2
PF_X: t.CDefine = 1
PF_W: t.CDefine = 2
PF_R: t.CDefine = 4
DT_NULL: t.CDefine = 0
DT_HASH: t.CDefine = 4
DT_STRTAB: t.CDefine = 5
DT_SYMTAB: t.CDefine = 6
DT_STRSZ: t.CDefine = 10
DT_SYMENT: t.CDefine = 11
DT_RELA: t.CDefine = 7
DT_RELASZ: t.CDefine = 8
DT_RELAENT: t.CDefine = 9
DT_PLTRELSZ: t.CDefine = 2
DT_JMPREL: t.CDefine = 23
R_X86_64_64: t.CDefine = 1
R_X86_64_GLOB_DAT: t.CDefine = 6
R_X86_64_JUMP_SLOT: t.CDefine = 7
R_X86_64_RELATIVE: t.CDefine = 8
STB_GLOBAL: t.CDefine = 1
STB_WEAK: t.CDefine = 2
@c.Attribute(t.attr.packed)
class Elf64_Ehdr:
e_ident: t.CArray[t.CUInt8T, 16]
e_type: t.CUInt16T
e_machine: t.CUInt16T
e_version: t.CUInt32T
e_entry: t.CUInt64T
e_phoff: t.CUInt64T
e_shoff: t.CUInt64T
e_flags: t.CUInt32T
e_ehsize: t.CUInt16T
e_phentsize: t.CUInt16T
e_phnum: t.CUInt16T
e_shentsize: t.CUInt16T
e_shnum: t.CUInt16T
e_shstrndx: t.CUInt16T
@c.Attribute(t.attr.packed)
class Elf64_Phdr:
p_type: t.CUInt32T
p_flags: t.CUInt32T
p_offset: t.CUInt64T
p_vaddr: t.CUInt64T
p_paddr: t.CUInt64T
p_filesz: t.CUInt64T
p_memsz: t.CUInt64T
p_align: t.CUInt64T
MAX_PHDRS: t.CDefine = 16
@c.Attribute(t.attr.packed)
class Elf64_Shdr:
sh_name: t.CUInt32T
sh_type: t.CUInt32T
sh_flags: t.CUInt64T
sh_addr: t.CUInt64T
sh_offset: t.CUInt64T
sh_size: t.CUInt64T
sh_link: t.CUInt32T
sh_info: t.CUInt32T
sh_addralign: t.CUInt64T
sh_entsize: t.CUInt64T
@c.Attribute(t.attr.packed)
class Elf64_Sym:
st_name: t.CUInt32T
st_info: t.CUInt8T
st_other: t.CUInt8T
st_shndx: t.CUInt16T
st_value: t.CUInt64T
st_size: t.CUInt64T
@c.Attribute(t.attr.packed)
class Elf64_Rela:
r_offset: t.CUInt64T
r_info: t.CUInt64T
r_addend: t.CInt64T
@c.Attribute(t.attr.packed)
class Elf64_Dyn:
d_tag: t.CInt64T
d_val: t.CUInt64T
MAX_SHDRS: t.CDefine = 64
MAX_DYNS: t.CDefine = 64
MAX_RELAS: t.CDefine = 256
def load_elf(path: t.CConst | str, do_map: t.CInt = 1) -> t.CVoid | t.CPtr:
fp: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
if fp is None:
err: t.CUInt32T = fat32.last_error()
eb: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(eb), 64, "[elf] failed to open file err=%d\n", err)
serial.puts(eb)
return None
ehdr_buf: t.CArray[t.CUInt8T, 64]
string.memset(c.Addr(ehdr_buf), 0, 64)
read_len: t.CUInt32T = fat32.read(fp, c.Addr(ehdr_buf), 64)
if read_len < 64:
serial.puts("[elf] failed to read ehdr\n")
fat32.close(fp)
return None
ehdr: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf)
if ehdr.e_ident[0] != ELFMAG0 or ehdr.e_ident[1] != ELFMAG1 or ehdr.e_ident[2] != ELFMAG2 or ehdr.e_ident[3] != ELFMAG3:
serial.puts("[elf] bad magic\n")
fat32.close(fp)
return None
if ehdr.e_ident[4] != ELFCLASS64:
serial.puts("[elf] not ELF64\n")
fat32.close(fp)
return None
if ehdr.e_ident[5] != ELFDATA2LSB:
serial.puts("[elf] not little-endian\n")
fat32.close(fp)
return None
if ehdr.e_type != ET_EXEC and ehdr.e_type != ET_DYN:
serial.puts("[elf] not ET_EXEC or ET_DYN\n")
fat32.close(fp)
return None
if ehdr.e_machine != EM_X86_64:
serial.puts("[elf] not x86_64\n")
fat32.close(fp)
return None
entry_point: t.CUInt64T = ehdr.e_entry
phoff: t.CUInt64T = ehdr.e_phoff
phentsize: t.CUInt16T = ehdr.e_phentsize
phnum: t.CUInt16T = ehdr.e_phnum
if phentsize == 0 or phnum == 0 or phnum > MAX_PHDRS:
serial.puts("[elf] invalid phdr count\n")
fat32.close(fp)
return None
cr: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr), 80, "[elf] entry=0x%lx phoff=%lu phentsize=%u phnum=%u\n", entry_point, phoff, phentsize, phnum)
serial.puts(cr)
phdr_bufs: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs), 0, MAX_PHDRS * 56)
for pi in range(phnum):
phdr_off: t.CUInt64T = phoff + t.CUInt64T(pi) * t.CUInt64T(phentsize)
fat32.seek(fp, t.CUInt32T(phdr_off))
fat32.read(fp, c.Addr(phdr_bufs[pi]), 56)
found_load: t.CInt = 0
lowest_vaddr: t.CUInt64T = 0
highest_vaddr_end: t.CUInt64T = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
seg_end: t.CUInt64T = phdr_bufs[pi].p_vaddr + phdr_bufs[pi].p_memsz
if found_load == 0:
lowest_vaddr = phdr_bufs[pi].p_vaddr
highest_vaddr_end = seg_end
found_load = 1
else:
if phdr_bufs[pi].p_vaddr < lowest_vaddr:
lowest_vaddr = phdr_bufs[pi].p_vaddr
if seg_end > highest_vaddr_end:
highest_vaddr_end = seg_end
if found_load == 0:
serial.puts("[elf] no LOAD segments\n")
fat32.close(fp)
return None
total_memsz: t.CUInt64T = highest_vaddr_end - lowest_vaddr
total_pages: t.CUInt64T = (total_memsz + 0xFFF) // 0x1000
cr2: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr2), 80, "[elf] vaddr 0x%lx-0x%lx pages=%lu\n", lowest_vaddr, highest_vaddr_end, total_pages)
serial.puts(cr2)
raw_alloc: t.CVoid | t.CPtr = mm.malloc(total_pages * 0x1000 + 0x1000)
_db_ra: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_db_ra), 80, "[elf] malloc ret raw_alloc=0x%lx\n", t.CUInt64T(raw_alloc))
serial.puts(_db_ra)
if not raw_alloc:
serial.puts("[elf] malloc failed\n")
fat32.close(fp)
return None
phys_base_aligned: t.CUInt64T = (t.CUInt64T(raw_alloc) + t.CUInt64T(0xFFF)) & ~t.CUInt64T(0xFFF)
phys_base: t.CVoid | t.CPtr = t.CVoid(phys_base_aligned, t.CPtr)
string.memset(phys_base, 0, total_pages * 0x1000)
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
vaddr: t.CUInt64T = phdr_bufs[pi].p_vaddr
file_off: t.CUInt64T = phdr_bufs[pi].p_offset
filesz: t.CUInt64T = phdr_bufs[pi].p_filesz
memsz: t.CUInt64T = phdr_bufs[pi].p_memsz
dest_off: t.CUInt64T = vaddr - lowest_vaddr
dest: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(phys_base) + dest_off, t.CPtr)
if filesz > 0:
fat32.seek(fp, t.CUInt32T(file_off))
fat32.read(fp, dest, t.CUInt32T(filesz))
if memsz > filesz:
bss_start: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(dest) + filesz, t.CPtr)
bss_len: t.CUInt64T = memsz - filesz
string.memset(bss_start, 0, bss_len)
fat32.close(fp)
virt_page_start: t.CUInt64T = lowest_vaddr & ~t.CUInt64T(0xFFF)
phys_page_start: t.CUInt64T = t.CUInt64T(phys_base) & ~t.CUInt64T(0xFFF)
map_end: t.CUInt64T = (highest_vaddr_end + 0xFFF) & ~t.CUInt64T(0xFFF)
num_map_pages: t.CUInt64T = (map_end - virt_page_start) // 0x1000
# Store mapping info for spawn_elf (used when do_map=0)
global _last_elf_phys_page_start, _last_elf_virt_page_start, _last_elf_num_map_pages
_last_elf_phys_page_start = phys_page_start
_last_elf_virt_page_start = virt_page_start
_last_elf_num_map_pages = num_map_pages
if do_map != 0:
for mi in range(num_map_pages):
virt_addr: t.CUInt64T = virt_page_start + mi * 0x1000
phys_addr: t.CUInt64T = phys_page_start + mi * 0x1000
page_flags: t.CUInt64T = paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER
paging.MapPage(virt_addr, phys_addr, page_flags)
entry_addr: t.CVoid | t.CPtr = t.CVoid(entry_point, t.CPtr)
return entry_addr
def run_elf(path: t.CConst | str) -> t.CInt:
entry: t.CVoid | t.CPtr = load_elf(path)
if entry is None:
serial.puts("[elf] load failed\n")
return -1
serial.puts("[elf] jumping to entry...\n")
c.Asm(f"""call {c.AsmInp(entry, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
serial.puts("[elf] returned from entry\n")
return 0
MAX_SPAWNED: t.CDefine = 8
_elf_entries: t.CArray[t.CVoid | t.CPtr, MAX_SPAWNED]
# User stack virtual address: top of 48-bit user space, 64KB below
USER_STACK_VTOP: t.CDefine = 0x7FFFFFE00000
# Globals for ELF mapping info (set by load_elf when do_map=0, used by spawn_elf
# to map ELF pages in the cloned PML4 instead of kernel PML4).
# ROOT CAUSE: previously load_elf mapped ELF vaddr (e.g. 0x400000) into the
# kernel PML4, overwriting the identity mapping of buddy system memory_block
# headers at 0x400000. This corrupted buddy metadata -> malloc failures,
# pid=0, and #GP in split_block. Fix: load_elf does NOT map; spawn_elf maps
# in the cloned PML4 after clone_for_process.
_last_elf_phys_page_start: t.CUInt64T = 0
_last_elf_virt_page_start: t.CUInt64T = 0
_last_elf_num_map_pages: t.CUInt64T = 0
def _elf_entry_wrapper(arg: t.CVoid | t.CPtr) -> t.CInt:
pid: t.CInt = t.CInt(t.CUInt64T(arg))
_db1: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(_db1), 64, "[elf] wrapper pid=%d\n", pid)
serial.puts(_db1)
# Disable interrupts around switch_pid + MapPage + TSS setup: @pml4 is a global
# that switch_pid modifies. A timer interrupt mid-section would make the scheduler
# call switch_pid for another thread, corrupting @pml4 for our MapPage calls.
asm.cli()
proc.switch_pid(pid)
cur_p: proc.Process | t.CPtr = proc.ProcessManager.current()
entry_fn: t.CVoid | t.CPtr = cur_p.entry
if entry_fn is not None:
user_stack_vtop: t.CUInt64T = USER_STACK_VTOP
us_sz: t.CUInt64T = USER_STACK_SIZE
user_stack_vbottom: t.CUInt64T = USER_STACK_VTOP - us_sz
# Physical pages of the user stack (allocated by mm.malloc, identity-mapped)
us_size: t.CUInt64T = USER_STACK_SIZE
phys_bottom: t.CUInt64T = (cur_p.user_stack - us_size) & ~t.CUInt64T(0xFFF)
# Map each page of the user stack at the virtual address with PTE_USER
num_stack_pages: t.CUInt64T = 16 # USER_STACK_SIZE(65536) / PAGE_SIZE(4096) = 16
si: t.CUInt64T
for si in range(num_stack_pages):
vaddr: t.CUInt64T = (user_stack_vbottom & ~t.CUInt64T(0xFFF)) + si * t.CUInt64T(0x1000)
paddr: t.CUInt64T = phys_bottom + si * t.CUInt64T(0x1000)
paging.MapPage(vaddr, paddr, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
# Set TSS RSP0 so interrupts from Ring 3 use kernel stack
gdt.set_tss_rsp0(cur_p.kern_stack)
# Set GS kernel_rsp0 for syscall entry from Ring 3
cpu.set_kernel_rsp0(cur_p.kern_stack)
# Keep interrupts disabled until iretq: drop_to_user_mode's iretq
# will set RFLAGS.IF from the saved frame (0x202) for user mode.
# This prevents timer interrupt preemption between TSS setup and iretq.
# Drop to Ring 3 user mode via iretq
proc.drop_to_user_mode(entry_fn, user_stack_vtop, cur_p.kern_stack)
cur: proc.Process | t.CPtr = proc.ProcessManager.current()
cur.exit()
return 0
def spawn_elf(path: t.CConst | str) -> t.CInt:
fat32.lock()
name_start: t.CInt = 0
si: t.CInt = 0
while True:
ch: t.CChar = path[si]
if ch == 0: break
if ch == 47:
name_start = si + 1
si += 1
lowest_vaddr: t.CUInt64T = 0
highest_vaddr_end: t.CUInt64T = 0
fp_scan: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
if fp_scan is None:
serr: t.CUInt32T = fat32.last_error()
seb: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(seb), 64, "[elf] spawn scan open failed err=%d\n", serr)
serial.puts(seb)
fat32.unlock()
return -1
if fp_scan is not None:
ehdr_buf_s: t.CArray[t.CUInt8T, 64]
string.memset(c.Addr(ehdr_buf_s), 0, 64)
fat32.read(fp_scan, c.Addr(ehdr_buf_s), 64)
ehdr_s: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf_s)
if ehdr_s.e_type == ET_EXEC or ehdr_s.e_type == ET_DYN:
phoff_s: t.CUInt64T = ehdr_s.e_phoff
phentsize_s: t.CUInt16T = ehdr_s.e_phentsize
phnum_s: t.CUInt16T = ehdr_s.e_phnum
if phentsize_s > 0 and phnum_s > 0 and phnum_s <= MAX_PHDRS:
phdr_bufs_s: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs_s), 0, MAX_PHDRS * 56)
found_load_s: t.CInt = 0
for pi_s in range(phnum_s):
fat32.seek(fp_scan, t.CUInt32T(phoff_s + t.CUInt64T(pi_s) * t.CUInt64T(phentsize_s)))
fat32.read(fp_scan, c.Addr(phdr_bufs_s[pi_s]), 56)
if phdr_bufs_s[pi_s].p_type == PT_LOAD:
seg_end_s: t.CUInt64T = phdr_bufs_s[pi_s].p_vaddr + phdr_bufs_s[pi_s].p_memsz
if found_load_s == 0:
lowest_vaddr = phdr_bufs_s[pi_s].p_vaddr
highest_vaddr_end = seg_end_s
found_load_s = 1
else:
if phdr_bufs_s[pi_s].p_vaddr < lowest_vaddr:
lowest_vaddr = phdr_bufs_s[pi_s].p_vaddr
if seg_end_s > highest_vaddr_end:
highest_vaddr_end = seg_end_s
fat32.close(fp_scan)
isolate_va: t.CUInt64T = lowest_vaddr
if isolate_va == 0:
isolate_va = 0x400000
# Load ELF to physical memory WITHOUT mapping in kernel PML4.
# do_map=0: load_elf stores mapping info in globals for spawn_elf to use.
# ROOT CAUSE FIX: previously load_elf mapped ELF vaddr (e.g. 0x400000) into
# kernel PML4, overwriting identity mapping of buddy memory_block headers.
entry: t.CVoid | t.CPtr = load_elf(path, 0)
if entry is None:
serial.puts("[elf] spawn: load failed\n")
fat32.unlock()
return -1
# Clone kernel PML4 (identity mapping intact, no ELF mapping yet)
proc_pml4: t.CUInt64T = paging.clone_for_process(isolate_va)
slog1: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(slog1), 80, "[elf] spawn: clone pml4=0x%lx va=0x%lx\n", proc_pml4, isolate_va)
serial.puts(slog1)
if proc_pml4 == 0:
serial.puts("[elf] spawn: clone_for_process failed\n")
fat32.unlock()
return -1
# Map ELF pages in the CLONED PML4 (not kernel's).
# This prevents overwriting kernel identity mapping at 0x400000 which
# would corrupt buddy system memory_block headers.
# Must disable interrupts: @pml4 global is used by MapPage and a timer
# interrupt mid-section would call switch_pid, corrupting @pml4.
asm.cli()
_kernel_cr3: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(_kernel_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3""", op=[t.ASM_DESCR.CLOBBER_MEMORY])
c.Asm(f"mov cr3, {c.AsmInp(proc_pml4, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(proc_pml4)
mi: t.CUInt64T
for mi in range(_last_elf_num_map_pages):
_va: t.CUInt64T = _last_elf_virt_page_start + mi * 0x1000
_pa: t.CUInt64T = _last_elf_phys_page_start + mi * 0x1000
paging.MapPage(_va, _pa, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
c.Asm(f"mov cr3, {c.AsmInp(_kernel_cr3, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(_kernel_cr3)
asm.sti()
p: proc.Process | t.CPtr = proc.ProcessManager.create_process(path[name_start:], entry)
if p is None:
serial.puts("[elf] spawn: create_process failed\n")
fat32.unlock()
return -2
p.elf_base = t.CUInt64T(entry)
p.pml4_root = proc_pml4
if p.pid >= 0 and p.pid < MAX_SPAWNED:
_elf_entries[p.pid] = entry
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(_elf_entry_wrapper, t.CVoid(t.CUInt64T(p.pid), t.CPtr), p.pid)
if th is None:
serial.puts("[elf] spawn: create_thread failed\n")
p.exit()
fat32.unlock()
return -3
tid: t.CInt = th.tid
p.addThread(tid)
slog: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(slog), 80, "[elf] spawn: pid=%d tid=%d entry=0x%lx pml4=0x%lx\n", p.pid, tid, t.CUInt64T(entry), p.pml4_root)
serial.puts(slog)
fat32.unlock()
return p.pid
def _resolve_symbol(name: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CPtr:
nm: t.CInt = 0
while c.Deref(name + nm) != 0:
nm += 1
cmp_name: t.CConst | t.CChar | t.CPtr = name
cmp_len: t.CInt = nm
if nm > 9:
sha1_len2: t.CInt = 0
for si2 in range(nm):
ch2: t.CChar = c.Deref(name + si2)
if ch2 == 46:
if sha1_len2 >= 8:
cmp_name = t.CConst(t.CUInt64T(name) + si2 + 1, t.CPtr)
cmp_len = nm - si2 - 1
break
if ch2 == 0:
break
if (ch2 >= 48 and ch2 <= 57) or (ch2 >= 97 and ch2 <= 102):
sha1_len2 += 1
else:
break
if cmp_len == 11:
match: t.CInt = 1
for i in range(cmp_len):
if c.Deref(cmp_name + i) != c.Deref("serial_puts" + i):
match = 0
if match:
return t.CVoid(c.Addr(serial.puts), t.CPtr)
return None
_so_strtab: t.CVoid | t.CPtr
_so_symtab: t.CVoid | t.CPtr
_so_syment: t.CUInt64T
_so_sym_count: t.CInt
def load_so(path: t.CConst | str) -> t.CVoid | t.CPtr:
fat32.lock()
fp: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
if fp is None:
serial.puts("[so] failed to open file\n")
fat32.unlock()
return None
ehdr_buf: t.CArray[t.CUInt8T, 64]
string.memset(c.Addr(ehdr_buf), 0, 64)
read_len: t.CUInt32T = fat32.read(fp, c.Addr(ehdr_buf), 64)
if read_len < 64:
serial.puts("[so] failed to read ehdr\n")
fat32.close(fp)
fat32.unlock()
return None
ehdr: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf)
if ehdr.e_ident[0] != ELFMAG0 or ehdr.e_ident[1] != ELFMAG1 or ehdr.e_ident[2] != ELFMAG2 or ehdr.e_ident[3] != ELFMAG3:
serial.puts("[so] bad magic\n")
fat32.close(fp)
fat32.unlock()
return None
if ehdr.e_ident[4] != ELFCLASS64:
serial.puts("[so] not ELF64\n")
fat32.close(fp)
fat32.unlock()
return None
if ehdr.e_type == ET_DYN:
pass
elif ehdr.e_type == ET_EXEC:
pass
else:
serial.puts("[so] not ET_DYN or ET_EXEC\n")
fat32.close(fp)
fat32.unlock()
return None
phoff: t.CUInt64T = ehdr.e_phoff
phentsize: t.CUInt16T = ehdr.e_phentsize
phnum: t.CUInt16T = ehdr.e_phnum
phdr_bufs: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs), 0, MAX_PHDRS * 56)
for pi in range(phnum):
phdr_off: t.CUInt64T = phoff + t.CUInt64T(pi) * t.CUInt64T(phentsize)
fat32.seek(fp, t.CUInt32T(phdr_off))
fat32.read(fp, c.Addr(phdr_bufs[pi]), 56)
found_load: t.CInt = 0
lowest_vaddr: t.CUInt64T = 0
highest_vaddr_end: t.CUInt64T = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
seg_end: t.CUInt64T = phdr_bufs[pi].p_vaddr + phdr_bufs[pi].p_memsz
if found_load == 0:
lowest_vaddr = phdr_bufs[pi].p_vaddr
highest_vaddr_end = seg_end
found_load = 1
else:
if phdr_bufs[pi].p_vaddr < lowest_vaddr:
lowest_vaddr = phdr_bufs[pi].p_vaddr
if seg_end > highest_vaddr_end:
highest_vaddr_end = seg_end
if found_load == 0:
serial.puts("[so] no LOAD segments\n")
fat32.close(fp)
fat32.unlock()
return None
total_memsz: t.CUInt64T = highest_vaddr_end - lowest_vaddr
total_pages: t.CUInt64T = (total_memsz + 0xFFF) // 0x1000
so_load_addr: t.CUInt64T = 0x600000
raw_alloc: t.CVoid | t.CPtr = mm.malloc(total_pages * 0x1000 + 0x1000)
if not raw_alloc:
serial.puts("[so] malloc failed\n")
fat32.close(fp)
fat32.unlock()
return None
phys_base_aligned: t.CUInt64T = (t.CUInt64T(raw_alloc) + 0xFFF) & ~t.CUInt64T(0xFFF)
phys_base: t.CVoid | t.CPtr = t.CVoid(phys_base_aligned, t.CPtr)
string.memset(phys_base, 0, total_pages * 0x1000)
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_LOAD:
vaddr: t.CUInt64T = phdr_bufs[pi].p_vaddr
file_off: t.CUInt64T = phdr_bufs[pi].p_offset
filesz: t.CUInt64T = phdr_bufs[pi].p_filesz
memsz: t.CUInt64T = phdr_bufs[pi].p_memsz
dest_off: t.CUInt64T = vaddr - lowest_vaddr
dest: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(phys_base) + dest_off, t.CPtr)
if filesz > 0:
fat32.seek(fp, t.CUInt32T(file_off))
fat32.read(fp, dest, t.CUInt32T(filesz))
if memsz > filesz:
bss_start: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(dest) + filesz, t.CPtr)
bss_len: t.CUInt64T = memsz - filesz
string.memset(bss_start, 0, bss_len)
virt_page_start: t.CUInt64T = (so_load_addr + lowest_vaddr) & ~t.CUInt64T(0xFFF)
phys_page_start: t.CUInt64T = t.CUInt64T(phys_base) & ~t.CUInt64T(0xFFF)
map_end: t.CUInt64T = (so_load_addr + highest_vaddr_end + 0xFFF) & ~t.CUInt64T(0xFFF)
num_map_pages: t.CUInt64T = (map_end - virt_page_start) // 0x1000
for mi in range(num_map_pages):
virt_addr: t.CUInt64T = virt_page_start + mi * 0x1000
phys_addr: t.CUInt64T = phys_page_start + mi * 0x1000
paging.MapPage(virt_addr, phys_addr, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
base_vaddr: t.CUInt64T = so_load_addr + lowest_vaddr
dyn_buf: t.CArray[Elf64_Dyn, MAX_DYNS]
string.memset(c.Addr(dyn_buf), 0, MAX_DYNS * 16)
dyn_count: t.CInt = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_DYNAMIC:
fat32.seek(fp, t.CUInt32T(phdr_bufs[pi].p_offset))
dyn_read: t.CUInt32T = fat32.read(fp, c.Addr(dyn_buf), t.CUInt32T(phdr_bufs[pi].p_filesz))
dyn_count = t.CInt(dyn_read) // 16
strtab_vaddr: t.CUInt64T = 0
symtab_vaddr: t.CUInt64T = 0
hash_vaddr: t.CUInt64T = 0
syment: t.CUInt64T = 0
rela_vaddr: t.CUInt64T = 0
relasz: t.CUInt64T = 0
jmprel_vaddr: t.CUInt64T = 0
pltrelsz: t.CUInt64T = 0
for di in range(dyn_count):
if dyn_buf[di].d_tag == DT_NULL: break
if dyn_buf[di].d_tag == DT_STRTAB: strtab_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_SYMTAB: symtab_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_HASH: hash_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_SYMENT: syment = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_RELA: rela_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_RELASZ: relasz = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_JMPREL: jmprel_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_PLTRELSZ: pltrelsz = dyn_buf[di].d_val
strtab_ptr: t.CVoid | t.CPtr = t.CVoid(strtab_vaddr + so_load_addr, t.CPtr)
symtab_ptr: t.CVoid | t.CPtr = t.CVoid(symtab_vaddr + so_load_addr, t.CPtr)
if rela_vaddr != 0 and relasz > 0:
rela_count: t.CUInt64T = relasz // 24
for ri in range(rela_count):
rela: Elf64_Rela | t.CPtr = t.CVoid(t.CUInt64T(rela_vaddr) + so_load_addr + ri * 24, t.CPtr)
r_type: t.CUInt32T = t.CUInt32T(rela.r_info & 0xFFFFFFFF)
r_sym: t.CUInt32T = t.CUInt32T(rela.r_info >> 32)
target_addr: t.CVoid | t.CPtr = t.CVoid(rela.r_offset + so_load_addr, t.CPtr)
if r_type == R_X86_64_RELATIVE:
val: t.CUInt64T = t.CUInt64T(rela.r_addend) + so_load_addr
string.memcpy(target_addr, c.Addr(val), 8)
elif r_type == R_X86_64_64 or r_type == R_X86_64_GLOB_DAT or r_type == R_X86_64_JUMP_SLOT:
sym: Elf64_Sym | t.CPtr = t.CVoid(t.CUInt64T(symtab_ptr) + t.CUInt64T(r_sym) * syment, t.CPtr)
sym_name: t.CConst | t.CChar | t.CPtr = t.CConst(t.CUInt64T(strtab_ptr) + sym.st_name, t.CPtr)
resolved: t.CVoid | t.CPtr = _resolve_symbol(sym_name)
if resolved is not None:
val2: t.CUInt64T = t.CUInt64T(resolved) + t.CUInt64T(rela.r_addend)
string.memcpy(target_addr, c.Addr(val2), 8)
elif sym.st_value != 0:
val3: t.CUInt64T = sym.st_value + so_load_addr + t.CUInt64T(rela.r_addend)
string.memcpy(target_addr, c.Addr(val3), 8)
if jmprel_vaddr != 0 and pltrelsz > 0:
jmprel_count: t.CUInt64T = pltrelsz // 24
for ji in range(jmprel_count):
rela2: Elf64_Rela | t.CPtr = t.CVoid(jmprel_vaddr + so_load_addr + ji * 24, t.CPtr)
r_type2: t.CUInt32T = t.CUInt32T(rela2.r_info & 0xFFFFFFFF)
r_sym2: t.CUInt32T = t.CUInt32T(rela2.r_info >> 32)
target2: t.CVoid | t.CPtr = t.CVoid(rela2.r_offset + so_load_addr, t.CPtr)
if r_type2 == R_X86_64_JUMP_SLOT or r_type2 == R_X86_64_GLOB_DAT:
sym2: Elf64_Sym | t.CPtr = t.CVoid(t.CUInt64T(symtab_ptr) + t.CUInt64T(r_sym2) * syment, t.CPtr)
sym_name2: t.CConst | t.CChar | t.CPtr = t.CConst(t.CUInt64T(strtab_ptr) + sym2.st_name, t.CPtr)
resolved2: t.CVoid | t.CPtr = _resolve_symbol(sym_name2)
if resolved2 is not None:
val4: t.CUInt64T = t.CUInt64T(resolved2) + t.CUInt64T(rela2.r_addend)
string.memcpy(target2, c.Addr(val4), 8)
elif sym2.st_value != 0:
val5: t.CUInt64T = sym2.st_value + so_load_addr + t.CUInt64T(rela2.r_addend)
string.memcpy(target2, c.Addr(val5), 8)
else:
cr3: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr3), 80, "[so] WARN: unresolved PLT sym offset=%lu\n", sym2.st_name)
serial.puts(cr3)
fat32.close(fp)
_so_strtab = strtab_ptr
_so_symtab = symtab_ptr
_so_syment = syment
_so_sym_count = 0
if hash_vaddr != 0:
hash_ptr: t.CVoid | t.CPtr = t.CVoid(hash_vaddr + so_load_addr, t.CPtr)
nchain: t.CUInt32T = c.Deref(t.CVoid(t.CUInt64T(hash_ptr) + 4, t.CPtr))
_so_sym_count = t.CInt(nchain)
elif syment > 0 and strtab_vaddr > symtab_vaddr and symtab_vaddr != 0:
sym_tab_size: t.CUInt64T = strtab_vaddr - symtab_vaddr
_so_sym_count = t.CInt(sym_tab_size // syment)
cr: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr), 80, "[so] loaded at 0x%lx\n", base_vaddr)
serial.puts(cr)
fat32.unlock()
return t.CVoid(base_vaddr, t.CPtr)
def get_so_symbol(so_base: t.CVoid | t.CPtr, name: t.CConst | t.CChar | t.CPtr, so_path: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CPtr:
if _so_symtab is None or _so_strtab is None or _so_syment == 0:
return None
if name is None:
return None
for symi in range(_so_sym_count):
sb2: Elf64_Sym | t.CPtr = t.CVoid(t.CUInt64T(_so_symtab) + t.CUInt64T(symi) * _so_syment, t.CPtr)
if sb2.st_value != 0 and sb2.st_shndx != 0:
sym_name_off2: t.CUInt32T = sb2.st_name
cmp_off2: t.CUInt32T = sym_name_off2
match2: t.CInt = 0
ni2: t.CInt = 0
while True:
sc3: t.CChar = c.Deref(t.CVoid(t.CUInt64T(_so_strtab) + cmp_off2 + ni2, t.CPtr))
nc3: t.CChar = c.Deref(name + ni2)
if sc3 != nc3:
break
if sc3 == 0:
match2 = 1
break
ni2 += 1
if match2 == 0:
dot_pos3: t.CUInt32T = sym_name_off2
is_sha1_2: t.CInt = 0
sha1_len_2: t.CUInt32T = 0
while True:
dc4: t.CChar = c.Deref(t.CVoid(t.CUInt64T(_so_strtab) + dot_pos3, t.CPtr))
if dc4 == 46:
if sha1_len_2 >= 8:
is_sha1_2 = 1
break
if dc4 == 0:
break
if (dc4 >= 48 and dc4 <= 57) or (dc4 >= 97 and dc4 <= 102):
sha1_len_2 += 1
else:
break
dot_pos3 += 1
if is_sha1_2:
cmp_off2 = dot_pos3 + 1
match2 = 1
ni2 = 0
while True:
sc4: t.CChar = c.Deref(t.CVoid(t.CUInt64T(_so_strtab) + cmp_off2 + ni2, t.CPtr))
nc4: t.CChar = c.Deref(name + ni2)
if sc4 != nc4:
match2 = 0
break
if sc4 == 0:
break
ni2 += 1
if match2:
result_addr: t.CUInt64T = t.CUInt64T(so_base) + sb2.st_value
dbg2: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(dbg2), 80, "[so] found '%s' at 0x%lx\n", t.CVoid(t.CUInt64T(_so_strtab) + sym_name_off2, t.CPtr), result_addr)
serial.puts(dbg2)
return t.CVoid(result_addr, t.CPtr)
serial.puts("[so] symbol not found\n")
return None

View File

@@ -0,0 +1,2 @@
from . import gdt
from . import idt

142
VKernel/Kernel/intr/gdt.py Normal file
View File

@@ -0,0 +1,142 @@
import t, c
@c.Attribute(t.attr.packed)
class gdt_entry:
limit_low: t.CUInt16T
base_low: t.CUInt16T
base_middle: t.CUInt8T
access: t.CUInt8T
granularity: t.CUInt8T
base_high: t.CUInt8T
@c.Attribute(t.attr.packed)
class gdt_entry64:
limit_low: t.CUInt16T
base_low: t.CUInt16T
base_middle: t.CUInt8T
access: t.CUInt8T
granularity: t.CUInt8T
base_high: t.CUInt8T
base_upper: t.CUInt32T
reserved: t.CUInt32T
@c.Attribute(t.attr.packed)
class gdt_ptr:
limit: t.CUInt16T
base: t.CUInt64T
gdt: t.CArray[gdt_entry, 7] = []
gp: t.CArray[t.CUInt8T, 10]
# TSS buffer: 104 bytes, raw byte array to avoid packed struct issues
# x86_64 TSS layout: reserved0(4) rsp0(8) rsp1(8) rsp2(8) reserved1(8) ist1-ist7(56) reserved2(8) reserved3(2) iomap_base(2)
tss_buf: t.CArray[t.CUInt8T, 104]
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
DATA_SEG: t.CDefine | t.CUInt16T = 0x10
USER_CODE_SEG: t.CDefine | t.CUInt16T = 0x18
USER_DATA_SEG: t.CDefine | t.CUInt16T = 0x20
TSS_SEG: t.CDefine | t.CUInt16T = 0x28
def init():
global gp, gdt, tss_buf
gdt[0].limit_low = 0
gdt[0].base_low = 0
gdt[0].base_middle = 0
gdt[0].access = 0
gdt[0].granularity = 0
gdt[0].base_high = 0
gdt[1].limit_low = 0
gdt[1].base_low = 0
gdt[1].base_middle = 0
gdt[1].access = 0x9A
gdt[1].granularity = 0x20
gdt[1].base_high = 0
gdt[2].limit_low = 0
gdt[2].base_low = 0
gdt[2].base_middle = 0
gdt[2].access = 0x92
gdt[2].granularity = 0xCF
gdt[2].base_high = 0
gdt[3].limit_low = 0
gdt[3].base_low = 0
gdt[3].base_middle = 0
gdt[3].access = 0xFA
gdt[3].granularity = 0x20
gdt[3].base_high = 0
gdt[4].limit_low = 0
gdt[4].base_low = 0
gdt[4].base_middle = 0
gdt[4].access = 0xF2
gdt[4].granularity = 0xCF
gdt[4].base_high = 0
# Set up TSS descriptor in GDT entries 5-6 (selector 0x28)
setTSS64(5, t.CUInt64T(c.Addr(tss_buf)), 103)
c.Asm("""lea rax, [rip + gdt]
lea rcx, [rip + gp]
mov word ptr [rcx], 0x37
mov qword ptr [rcx+2], rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX])
c.Asm("sfence; mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
flush()
# Initialize TSS: set iomap_base = 104 (0x68) at offset 102
tss_buf[102] = 0x68
tss_buf[103] = 0x00
# Load Task Register with TSS selector 0x28
c.Asm("""mov ax, 0x28
ltr ax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
@c.Attribute(t.attr.naked)
def flush():
c.Asm("""lea rax, [rip + gp]
lgdt [rax]
push 0x08
lea rax, [rip+2f]
push rax
.byte 0x48, 0xcb
2:
mov eax, 0x10
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
ret""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
def set_tss_rsp0(rsp0: t.CUInt64T):
global tss_buf
# TSS RSP0 is at offset 4 (8 bytes) in x86_64 TSS layout
tss_buf[4] = t.CUInt8T(rsp0 & 0xFF)
tss_buf[5] = t.CUInt8T((rsp0 >> 8) & 0xFF)
tss_buf[6] = t.CUInt8T((rsp0 >> 16) & 0xFF)
tss_buf[7] = t.CUInt8T((rsp0 >> 24) & 0xFF)
tss_buf[8] = t.CUInt8T((rsp0 >> 32) & 0xFF)
tss_buf[9] = t.CUInt8T((rsp0 >> 40) & 0xFF)
tss_buf[10] = t.CUInt8T((rsp0 >> 48) & 0xFF)
tss_buf[11] = t.CUInt8T((rsp0 >> 56) & 0xFF)
def setGate(num: int, base: t.CUInt64T, limit: t.CUInt32T, access: t.CUInt8T, gran: t.CUInt8T):
global gdt
gdt[num].limit_low = (limit & 0xFFFF)
gdt[num].base_low = (base & 0xFFFF)
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num].granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0)
gdt[num].access = access
def setTSS64(num: int, base: t.CUInt64T, limit: t.CUInt32T):
global gdt
gdt[num].limit_low = limit & 0xFFFF
gdt[num].base_low = base & 0xFFFF
gdt[num].base_middle = (base >> 16) & 0xFF
gdt[num].access = 0x89
gdt[num].granularity = 0x00
gdt[num].base_high = (base >> 24) & 0xFF
gdt[num + 1].limit_low = (base >> 32) & 0xFFFF
gdt[num + 1].base_low = (base >> 48) & 0xFFFF
gdt[num + 1].base_middle = 0
gdt[num + 1].access = 0
gdt[num + 1].granularity = 0
gdt[num + 1].base_high = 0

415
VKernel/Kernel/intr/idt.py Normal file
View File

@@ -0,0 +1,415 @@
import platform.pch.pic as pic
import platform.pch.timer as timer
import sched.sched as sched
import drivers.serial.uart.serial as serial
import viperlib
import asm
import t, c
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
@c.Attribute(t.attr.packed)
class idt_entry:
base_low: t.CUInt16T
selector: t.CUInt16T
ist_attr: t.CUInt8T
type_attr: t.CUInt8T
base_middle: t.CUInt16T
base_high: t.CUInt32T
reserved1: t.CUInt32T
idt: t.CArray[idt_entry, 256] = []
irq_handler_t: t.CTypedef | t.Callable[[], t.CInt]
def isr0() -> t.CExtern | t.CVoid | t.State: pass
def isr1() -> t.CExtern | t.CVoid | t.State: pass
def isr2() -> t.CExtern | t.CVoid | t.State: pass
def isr3() -> t.CExtern | t.CVoid | t.State: pass
def isr4() -> t.CExtern | t.CVoid | t.State: pass
def isr5() -> t.CExtern | t.CVoid | t.State: pass
def isr6() -> t.CExtern | t.CVoid | t.State: pass
def isr7() -> t.CExtern | t.CVoid | t.State: pass
def isr8() -> t.CExtern | t.CVoid | t.State: pass
def isr9() -> t.CExtern | t.CVoid | t.State: pass
def isr10() -> t.CExtern | t.CVoid | t.State: pass
def isr11() -> t.CExtern | t.CVoid | t.State: pass
def isr12() -> t.CExtern | t.CVoid | t.State: pass
def isr13() -> t.CExtern | t.CVoid | t.State: pass
def isr14() -> t.CExtern | t.CVoid | t.State: pass
def isr15() -> t.CExtern | t.CVoid | t.State: pass
def isr16() -> t.CExtern | t.CVoid | t.State: pass
def isr17() -> t.CExtern | t.CVoid | t.State: pass
def isr18() -> t.CExtern | t.CVoid | t.State: pass
def isr19() -> t.CExtern | t.CVoid | t.State: pass
def isr20() -> t.CExtern | t.CVoid | t.State: pass
def isr21() -> t.CExtern | t.CVoid | t.State: pass
def isr22() -> t.CExtern | t.CVoid | t.State: pass
def isr23() -> t.CExtern | t.CVoid | t.State: pass
def isr24() -> t.CExtern | t.CVoid | t.State: pass
def isr25() -> t.CExtern | t.CVoid | t.State: pass
def isr26() -> t.CExtern | t.CVoid | t.State: pass
def isr27() -> t.CExtern | t.CVoid | t.State: pass
def isr28() -> t.CExtern | t.CVoid | t.State: pass
def isr29() -> t.CExtern | t.CVoid | t.State: pass
def isr30() -> t.CExtern | t.CVoid | t.State: pass
def isr31() -> t.CExtern | t.CVoid | t.State: pass
def isr32() -> t.CExtern | t.CVoid | t.State: pass
def isr33() -> t.CExtern | t.CVoid | t.State: pass
def isr34() -> t.CExtern | t.CVoid | t.State: pass
def isr35() -> t.CExtern | t.CVoid | t.State: pass
def isr36() -> t.CExtern | t.CVoid | t.State: pass
def isr37() -> t.CExtern | t.CVoid | t.State: pass
def isr38() -> t.CExtern | t.CVoid | t.State: pass
def isr39() -> t.CExtern | t.CVoid | t.State: pass
def isr40() -> t.CExtern | t.CVoid | t.State: pass
def isr41() -> t.CExtern | t.CVoid | t.State: pass
def isr42() -> t.CExtern | t.CVoid | t.State: pass
def isr43() -> t.CExtern | t.CVoid | t.State: pass
def isr44() -> t.CExtern | t.CVoid | t.State: pass
def isr45() -> t.CExtern | t.CVoid | t.State: pass
def isr46() -> t.CExtern | t.CVoid | t.State: pass
def isr47() -> t.CExtern | t.CVoid | t.State: pass
def isr80() -> t.CExtern | t.CVoid | t.State: pass
def isr_default() -> t.CExtern | t.CVoid | t.State: pass
def setGate(num: int, base: t.CUInt64T, sel: t.CUInt16T, flags: t.CUInt8T):
global idt
idt[num].base_low = (base & 0xFFFF)
idt[num].base_middle = (base >> 16) & 0xFFFF
idt[num].base_high = (base >> 32) & 0xFFFFFFFF
idt[num].selector = sel
idt[num].ist_attr = 0
idt[num].type_attr = flags
idt[num].reserved1 = 0
def isrCommonhandler(interrupt: t.CInt):
c.Asm(f"""mov dx, 0x3F8
mov al, 91
out dx, al
mov ecx, {c.AsmInp(interrupt, t.ASM_DESCR.REG_ANY)}
mov rax, rcx
shr rax, 4
and al, 15
add al, 48
cmp al, 57
jle 1f
add al, 7
1:
out dx, al
mov rax, rcx
and al, 15
add al, 48
cmp al, 57
jle 2f
add al, 7
2:
out dx, al
mov al, 93
out dx, al""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
# Print CR2 for page faults (ISR 14)
if interrupt == 14:
cr2: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(cr2, t.ASM_DESCR.OUTPUT_REG)}, cr2""",
op=[t.ASM_DESCR.CLOBBER_RAX])
fault_rip: t.CUInt64T = 0
fault_err: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(fault_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(fault_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
buf: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(buf), 80, "[PF] cr2=0x%lx rip=0x%lx err=0x%lx\n", cr2, fault_rip, fault_err)
serial.puts(buf)
elif interrupt == 13:
gp_rip: t.CUInt64T = 0
gp_err: t.CUInt64T = 0
c.Asm(f"""mov {c.AsmOut(gp_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
mov {c.AsmOut(gp_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]""",
op=[t.ASM_DESCR.CLOBBER_RAX])
gp_buf: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(gp_buf), 80, "[GP] rip=0x%lx err=0x%lx\n", gp_rip, gp_err)
serial.puts(gp_buf)
s: sched.Scheduler | t.CPtr = sched._sched_ptr
# 如果调度器未初始化,直接进入安全停机状态
if s == 0:
serial.puts(" KERNEL PANIC (sched not init)\n")
while True:
asm.sti()
asm.hlt()
tid: t.CInt = s.current_tid
if tid == 0:
serial.puts(" KERNEL PANIC\n")
while True:
asm.sti()
asm.hlt()
buf2: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(buf2), 64, " exc in tid=%d, terminating\n", tid)
serial.puts(buf2)
s.threads[tid].state = 3
# Restore GS to kernel-normal state before _yield().
# ISR entry does swapgs for user-mode exceptions (GS_BASE=&_per_cpu).
# Since _yield() switches to another thread and never returns via ISR exit,
# the swapgs at ISR exit is never executed. We must swap back here.
# Check IA32_GS_BASE (MSR 0xC0000101): if non-zero, swapgs was done at entry.
c.Asm(f"""mov ecx, 0xC0000101
rdmsr
shl rdx, 32
or rax, rdx
test rax, rax
jz 1f
swapgs
1:""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
sched.Scheduler._yield()
while True:
asm.sti()
asm.hlt()
def isr0_handler() -> t.CExport | t.CVoid: isrCommonhandler(0)
def isr1_handler() -> t.CExport | t.CVoid: isrCommonhandler(1)
def isr2_handler() -> t.CExport | t.CVoid: isrCommonhandler(2)
def isr3_handler() -> t.CExport | t.CVoid: isrCommonhandler(3)
def isr4_handler() -> t.CExport | t.CVoid: isrCommonhandler(4)
def isr5_handler() -> t.CExport | t.CVoid: isrCommonhandler(5)
def isr6_handler() -> t.CExport | t.CVoid: isrCommonhandler(6)
def isr7_handler() -> t.CExport | t.CVoid: isrCommonhandler(7)
def isr8_handler() -> t.CExport | t.CVoid: isrCommonhandler(8)
def isr9_handler() -> t.CExport | t.CVoid: isrCommonhandler(9)
def isr10_handler() -> t.CExport | t.CVoid: isrCommonhandler(10)
def isr11_handler() -> t.CExport | t.CVoid: isrCommonhandler(11)
def isr12_handler() -> t.CExport | t.CVoid: isrCommonhandler(12)
def isr13_handler() -> t.CExport | t.CVoid:
isrCommonhandler(13)
def isr14_handler() -> t.CExport | t.CVoid: isrCommonhandler(14)
def isr15_handler() -> t.CExport | t.CVoid: isrCommonhandler(15)
def isr16_handler() -> t.CExport | t.CVoid: isrCommonhandler(16)
def isr17_handler() -> t.CExport | t.CVoid: isrCommonhandler(17)
def isr18_handler() -> t.CExport | t.CVoid: isrCommonhandler(18)
def isr19_handler() -> t.CExport | t.CVoid: isrCommonhandler(19)
def isr20_handler() -> t.CExport | t.CVoid: isrCommonhandler(20)
def isr21_handler() -> t.CExport | t.CVoid: isrCommonhandler(21)
def isr22_handler() -> t.CExport | t.CVoid: isrCommonhandler(22)
def isr23_handler() -> t.CExport | t.CVoid: isrCommonhandler(23)
def isr24_handler() -> t.CExport | t.CVoid: isrCommonhandler(24)
def isr25_handler() -> t.CExport | t.CVoid: isrCommonhandler(25)
def isr26_handler() -> t.CExport | t.CVoid: isrCommonhandler(26)
def isr27_handler() -> t.CExport | t.CVoid: isrCommonhandler(27)
def isr28_handler() -> t.CExport | t.CVoid: isrCommonhandler(28)
def isr29_handler() -> t.CExport | t.CVoid: isrCommonhandler(29)
def isr30_handler() -> t.CExport | t.CVoid: isrCommonhandler(30)
def isr31_handler() -> t.CExport | t.CVoid: isrCommonhandler(31)
def isr32_handler() -> t.CExport | t.CVoid:
timer.timer_handler()
def isr33_handler() -> t.CExport | t.CVoid:
handler: irq_handler_t = irqGetHandler(1)
if handler:
c.Asm(f"""call {c.AsmInp(handler, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(1)
def isr34_handler() -> t.CExport | t.CVoid:
handler2: irq_handler_t = irqGetHandler(2)
if handler2:
c.Asm(f"""call {c.AsmInp(handler2, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(2)
def isr35_handler() -> t.CExport | t.CVoid:
handler3: irq_handler_t = irqGetHandler(3)
if handler3:
c.Asm(f"""call {c.AsmInp(handler3, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(3)
def isr36_handler() -> t.CExport | t.CVoid:
handler4: irq_handler_t = irqGetHandler(4)
if handler4:
c.Asm(f"""call {c.AsmInp(handler4, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(4)
def isr37_handler() -> t.CExport | t.CVoid:
handler5: irq_handler_t = irqGetHandler(5)
if handler5:
c.Asm(f"""call {c.AsmInp(handler5, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(5)
def isr38_handler() -> t.CExport | t.CVoid:
handler6: irq_handler_t = irqGetHandler(6)
if handler6:
c.Asm(f"""call {c.AsmInp(handler6, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(6)
def isr39_handler() -> t.CExport | t.CVoid:
if pic.isSpurious(7):
return
handler7: irq_handler_t = irqGetHandler(7)
if handler7:
c.Asm(f"""call {c.AsmInp(handler7, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(7)
def isr40_handler() -> t.CExport | t.CVoid:
handler8: irq_handler_t = irqGetHandler(8)
if handler8:
c.Asm(f"""call {c.AsmInp(handler8, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(8)
def isr41_handler() -> t.CExport | t.CVoid:
handler9: irq_handler_t = irqGetHandler(9)
if handler9:
c.Asm(f"""call {c.AsmInp(handler9, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(9)
def isr42_handler() -> t.CExport | t.CVoid:
handler10: irq_handler_t = irqGetHandler(10)
if handler10:
c.Asm(f"""call {c.AsmInp(handler10, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(10)
def isr43_handler() -> t.CExport | t.CVoid:
handler11: irq_handler_t = irqGetHandler(11)
if handler11:
c.Asm(f"""call {c.AsmInp(handler11, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(11)
def isr44_handler() -> t.CExport | t.CVoid:
handler: irq_handler_t = irqGetHandler(12)
if handler:
c.Asm(f"""call {c.AsmInp(handler, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
pic.eoi(12)
def isr45_handler() -> t.CExport | t.CVoid: pic.eoi(13)
def isr46_handler() -> t.CExport | t.CVoid: pic.eoi(14)
def isr47_handler() -> t.CExport | t.CVoid:
if pic.isSpurious(15):
return
pic.eoi(15)
def init_exceptions():
setGate(0, t.CUInt64T(isr0), CODE_SEG, 0x8E)
setGate(1, t.CUInt64T(isr1), CODE_SEG, 0x8E)
setGate(2, t.CUInt64T(isr2), CODE_SEG, 0x8E)
setGate(3, t.CUInt64T(isr3), CODE_SEG, 0x8E)
setGate(4, t.CUInt64T(isr4), CODE_SEG, 0x8E)
setGate(5, t.CUInt64T(isr5), CODE_SEG, 0x8E)
setGate(6, t.CUInt64T(isr6), CODE_SEG, 0x8E)
setGate(7, t.CUInt64T(isr7), CODE_SEG, 0x8E)
setGate(8, t.CUInt64T(isr8), CODE_SEG, 0x8E)
setGate(9, t.CUInt64T(isr9), CODE_SEG, 0x8E)
setGate(10, t.CUInt64T(isr10), CODE_SEG, 0x8E)
setGate(11, t.CUInt64T(isr11), CODE_SEG, 0x8E)
setGate(12, t.CUInt64T(isr12), CODE_SEG, 0x8E)
setGate(13, t.CUInt64T(isr13), CODE_SEG, 0x8E)
setGate(14, t.CUInt64T(isr14), CODE_SEG, 0x8E)
setGate(15, t.CUInt64T(isr15), CODE_SEG, 0x8E)
setGate(16, t.CUInt64T(isr16), CODE_SEG, 0x8E)
setGate(17, t.CUInt64T(isr17), CODE_SEG, 0x8E)
setGate(18, t.CUInt64T(isr18), CODE_SEG, 0x8E)
setGate(19, t.CUInt64T(isr19), CODE_SEG, 0x8E)
setGate(20, t.CUInt64T(isr20), CODE_SEG, 0x8E)
setGate(21, t.CUInt64T(isr21), CODE_SEG, 0x8E)
setGate(22, t.CUInt64T(isr22), CODE_SEG, 0x8E)
setGate(23, t.CUInt64T(isr23), CODE_SEG, 0x8E)
setGate(24, t.CUInt64T(isr24), CODE_SEG, 0x8E)
setGate(25, t.CUInt64T(isr25), CODE_SEG, 0x8E)
setGate(26, t.CUInt64T(isr26), CODE_SEG, 0x8E)
setGate(27, t.CUInt64T(isr27), CODE_SEG, 0x8E)
setGate(28, t.CUInt64T(isr28), CODE_SEG, 0x8E)
setGate(29, t.CUInt64T(isr29), CODE_SEG, 0x8E)
setGate(30, t.CUInt64T(isr30), CODE_SEG, 0x8E)
setGate(31, t.CUInt64T(isr31), CODE_SEG, 0x8E)
def init_irqs():
setGate(32, t.CUInt64T(isr32), CODE_SEG, 0x8E)
setGate(33, t.CUInt64T(isr33), CODE_SEG, 0x8E)
setGate(34, t.CUInt64T(isr34), CODE_SEG, 0x8E)
setGate(35, t.CUInt64T(isr35), CODE_SEG, 0x8E)
setGate(36, t.CUInt64T(isr36), CODE_SEG, 0x8E)
setGate(37, t.CUInt64T(isr37), CODE_SEG, 0x8E)
setGate(38, t.CUInt64T(isr38), CODE_SEG, 0x8E)
setGate(39, t.CUInt64T(isr39), CODE_SEG, 0x8E)
setGate(40, t.CUInt64T(isr40), CODE_SEG, 0x8E)
setGate(41, t.CUInt64T(isr41), CODE_SEG, 0x8E)
setGate(42, t.CUInt64T(isr42), CODE_SEG, 0x8E)
setGate(43, t.CUInt64T(isr43), CODE_SEG, 0x8E)
setGate(44, t.CUInt64T(isr44), CODE_SEG, 0x8E)
setGate(45, t.CUInt64T(isr45), CODE_SEG, 0x8E)
setGate(46, t.CUInt64T(isr46), CODE_SEG, 0x8E)
setGate(47, t.CUInt64T(isr47), CODE_SEG, 0x8E)
irq_handlers: t.CStatic | t.CArray[irq_handler_t, 16] = [None]
def irqInstallHandler(irq: t.CInt, handler: irq_handler_t, name: str) -> t.CInt:
global irq_handlers
if irq < 0 or irq > 15: return -1
irq_handlers[irq] = handler
return 0
def irqGetHandler(irq: t.CInt) -> irq_handler_t:
if irq < 0 or irq > 15: return None
return irq_handlers[irq]
def init():
global idt
for i in range(256):
setGate(i, t.CUInt64T(isr_default), CODE_SEG, 0x8E)
pic.init()
init_exceptions()
init_irqs()
# Register ISR 0x80 for int 0x80 syscall interface (user-mode ELF apps)
setGate(0x80, t.CUInt64T(isr80), CODE_SEG, 0xEE) # DPL=3 allows Ring 3 to call int 0x80
# Build idt_ptr on stack and load directly in one asm block
c.Asm("""lea rax, [rip + idt]
sub rsp, 16
mov word ptr [rsp], 0x0fff
mov qword ptr [rsp+2], rax
lidt [rsp]
add rsp, 16""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])

595
VKernel/Kernel/intr/isr.s Normal file
View File

@@ -0,0 +1,595 @@
.section .bss
.comm _per_cpu, 32, 8
.comm _proc_mgr, 8192, 16
.comm _proc_mgr_ptr, 8, 8
.comm _saved_cr3, 8, 8
.comm _yield_cnt, 4, 4
.comm _yield_lock, 4, 4
.comm _fs_lock, 4, 4
.comm _fault_rip, 8, 8
.comm _fault_err, 8, 8
.section .text
.intel_syntax noprefix
.globl isr_default
isr_default:
push rax
push rdx
mov al, 0x20
out 0xA0, al
out 0x20, al
pop rdx
pop rax
iretq
# =============================================================================
# ISR macros with Ring 3 support
#
# When CPU takes interrupt/exception:
# From Ring 0: pushes RFLAGS, CS, RIP (3 qwords)
# From Ring 3: pushes SS, RSP, RFLAGS, CS, RIP (5 qwords)
# CPU also switches to TSS RSP0 stack when coming from Ring 3.
#
# Strategy:
# 1. Check CS RPL to determine if from Ring 3
# 2. If from Ring 3: swapgs (make gs: point to per_cpu), save user RSP
# 3. Save full interrupt frame into registers
# 4. Re-push in uniform format with is_user flag
# 5. Call handler
# 6. On return, rebuild correct iretq frame based on is_user
# 7. If returning to Ring 3: swapgs back
# =============================================================================
.macro ISR_NOERR num
.globl isr\num
isr\num:
# Check CS RPL to determine if from Ring 3
mov rax, [rsp + 8] # CS from interrupt frame
test al, 3 # RPL bits: 0 = Ring 0, 3 = Ring 3
jnz isr\num\()_from_user
isr\num\()_from_kernel:
# From Ring 0: no swapgs needed, already on kernel stack
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
xor r11, r11 # SS = 0
xor rax, rax # RSP = 0
add rsp, 24 # remove the 3 CPU-pushed qwords
jmp isr\num\()_frame_ready
isr\num\()_from_user:
# From Ring 3: swapgs to make gs: accessible, CPU already switched to TSS RSP0
swapgs
# Save user RSP to per_cpu.user_rsp (gs:[0x0])
# Note: CPU has already switched RSP to TSS RSP0, so the user RSP is on this stack
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
mov rax, [rsp + 24] # RSP (user)
mov r11, [rsp + 32] # SS (user)
# Save user RSP to per_cpu for potential later use
mov gs:[0x0], rax
add rsp, 40 # remove the 5 CPU-pushed qwords
isr\num\()_frame_ready:
# r8=RIP, r9=CS, r10=RFLAGS, rax=RSP(0 if kernel), r11=SS(0 if kernel)
# Build uniform frame on stack for iretq later
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
# Push is_user flag (1 if from Ring 3, 0 if from Ring 0)
xor ecx, ecx
test r9b, 3 # test CS RPL
setnz cl # cl = 1 if from Ring 3
push rcx # is_user
# Push all general-purpose registers
push rax
push rbx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
# Save faulting RIP and error code for debug
mov [_fault_rip], r8
mov [_fault_err], rdx
call isr\num\()_handler
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rbx
pop rax
# Pop is_user flag
pop rcx # is_user
# Pop the uniform frame into registers
pop r8 # RIP
pop r9 # CS
pop r10 # RFLAGS
pop rax # RSP (user)
pop r11 # SS (user)
test rcx, rcx
jnz isr\num\()_ret_user
isr\num\()_ret_kernel:
# Return to Ring 0: push RFLAGS, CS, RIP only
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
isr\num\()_ret_user:
# Return to Ring 3: swapgs back, then push SS, RSP, RFLAGS, CS, RIP
swapgs
# DIAG+FIX: if RFLAGS.NT (bit 14) is set, iretq performs hardware task-return
# which loads TSS selector 0x28 -> #GP(err=0x28). Detect and clear it.
test r10, 0x4000
jz 1f
btr r10, 14
mov dx, 0x3F8
mov al, 0x4E # 'N' marker = NT was set (now cleared)
out dx, al
1:
cmp r9, 0x1B
jne 8f
cmp r11, 0x23
jne 8f
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
8:
mov dx, 0x3F8
mov al, 0x42 # 'B' = bad CS/SS
out dx, al
mov al, 0x20 # space
out dx, al
# Output CS (r9) low byte as 2 hex digits
mov rcx, r9
mov rax, rcx
shr rax, 4
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 2f
add al, 7
2:
out dx, al
mov rax, rcx
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 3f
add al, 7
3:
out dx, al
mov al, 0x20 # space
out dx, al
# Output SS (r11) low byte as 2 hex digits
mov rcx, r11
mov rax, rcx
shr rax, 4
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 4f
add al, 7
4:
out dx, al
mov rax, rcx
and rax, 0xF
add al, 0x30
cmp al, 0x39
jle 5f
add al, 7
5:
out dx, al
mov al, 0x0A # newline
out dx, al
cli
7:
hlt
jmp 7b
.endm
.macro ISR_ERR num
.globl isr\num
isr\num:
# Stack at entry (with error code):
# From Ring 0: [rsp]=error_code, [rsp+8]=RIP, [rsp+16]=CS, [rsp+24]=RFLAGS
# From Ring 3: [rsp]=error_code, [rsp+8]=RIP, [rsp+16]=CS, [rsp+24]=RFLAGS, [rsp+32]=RSP, [rsp+40]=SS
# Check CS RPL
mov rax, [rsp + 16] # CS from interrupt frame
test al, 3
jnz isr\num\()_from_user
isr\num\()_from_kernel:
# From Ring 0: no swapgs needed
mov rdx, [rsp] # error_code
mov r8, [rsp + 8] # RIP
mov r9, [rsp + 16] # CS
mov r10, [rsp + 24] # RFLAGS
xor r11, r11 # SS = 0
xor rax, rax # RSP = 0
add rsp, 32 # remove 4 CPU-pushed qwords (error + 3 frame)
jmp isr\num\()_frame_ready
isr\num\()_from_user:
# From Ring 3: swapgs, CPU already on TSS RSP0
swapgs
mov rdx, [rsp] # error_code
mov r8, [rsp + 8] # RIP
mov r9, [rsp + 16] # CS
mov r10, [rsp + 24] # RFLAGS
mov rax, [rsp + 32] # RSP (user)
mov r11, [rsp + 40] # SS (user)
mov gs:[0x0], rax # save user RSP
add rsp, 48 # remove 6 CPU-pushed qwords (error + 5 frame)
isr\num\()_frame_ready:
# rdx=error_code, r8=RIP, r9=CS, r10=RFLAGS, rax=RSP, r11=SS
# Build uniform frame on stack
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
push rdx # error_code
# Push is_user flag
xor ecx, ecx
test r9b, 3
setnz cl
push rcx # is_user
# Push all general-purpose registers
push rax
push rbx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
# Save faulting RIP and error code for debug
mov [_fault_rip], r8
mov [_fault_err], rdx
call isr\num\()_handler
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rbx
pop rax
# Pop is_user flag
pop rcx # is_user
add rsp, 8 # skip error_code (handler already consumed it)
pop r8 # RIP
pop r9 # CS
pop r10 # RFLAGS
pop rax # RSP (user)
pop r11 # SS (user)
test rcx, rcx
jnz isr\num\()_ret_user
isr\num\()_ret_kernel:
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
isr\num\()_ret_user:
swapgs
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
.endm
ISR_NOERR 0
ISR_NOERR 1
ISR_NOERR 2
ISR_NOERR 3
ISR_NOERR 4
ISR_NOERR 5
ISR_NOERR 6
ISR_NOERR 7
ISR_ERR 8
ISR_NOERR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR_NOERR 15
ISR_NOERR 16
ISR_ERR 17
ISR_NOERR 18
ISR_NOERR 19
ISR_NOERR 20
ISR_NOERR 21
ISR_NOERR 22
ISR_NOERR 23
ISR_NOERR 24
ISR_NOERR 25
ISR_NOERR 26
ISR_NOERR 27
ISR_NOERR 28
ISR_NOERR 29
ISR_NOERR 30
ISR_NOERR 31
ISR_NOERR 32
ISR_NOERR 33
ISR_NOERR 34
ISR_NOERR 35
ISR_NOERR 36
ISR_NOERR 37
ISR_NOERR 38
ISR_NOERR 39
ISR_NOERR 40
ISR_NOERR 41
ISR_NOERR 42
ISR_NOERR 43
ISR_NOERR 44
ISR_NOERR 45
ISR_NOERR 46
ISR_NOERR 47
.globl syscall_entry
syscall_entry:
mov rax, rsp
shr rax, 47
test rax, rax
jnz syscall_from_kernel
syscall_from_user:
swapgs
mov gs:[0x0], rsp
mov rsp, gs:[0x8]
jmp syscall_common
syscall_from_kernel:
syscall_common:
push rcx
push r11
push rbx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r12
push r13
push r14
push r15
mov rbp, rsp
and rsp, ~15
push r9
mov r9, r8
mov r8, r10
mov rcx, rdx
mov rdx, rsi
mov rsi, rdi
mov rdi, rax
call syscall_handler
add rsp, 8
mov rsp, rbp
pop r15
pop r14
pop r13
pop r12
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rbx
pop r11
pop rcx
mov rax, rcx
shr rax, 47
test rax, rax
jnz syscall_ret_kernel
syscall_ret_user:
mov rsp, gs:[0x0]
swapgs
push r11
popfq
sysretq
syscall_ret_kernel:
push r11
popfq
jmp rcx
# =============================================================================
# ISR 0x80 - int 0x80 syscall handler for user-mode ELF apps
#
# int 0x80 calling convention (ViperOS):
# rax = syscall number
# rbx = arg1
# rcx = arg2
# rdx = arg3
# r10 = arg4
#
# Translated to syscall_handler calling convention:
# rdi = n (syscall number)
# rsi = arg1
# rdx = arg2
# rcx = arg3
# r8 = arg4
# r9 = arg5 (0)
# stack = arg6 (0)
#
# Return value in rax.
# =============================================================================
.globl isr80
isr80:
# Check CS RPL to determine if from Ring 3
mov rax, [rsp + 8] # CS from interrupt frame
test al, 3
jnz isr80_from_user
isr80_from_kernel:
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
xor r11, r11 # SS = 0
xor rax, rax # RSP = 0
add rsp, 24
jmp isr80_frame_ready
isr80_from_user:
swapgs
mov r8, [rsp] # RIP
mov r9, [rsp + 8] # CS
mov r10, [rsp + 16] # RFLAGS
mov rax, [rsp + 24] # RSP (user)
mov r11, [rsp + 32] # SS (user)
mov gs:[0x0], rax
add rsp, 40
isr80_frame_ready:
# Build uniform frame on stack
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
# Save ALL registers FIRST (including original rcx = arg2)
# Order: rax, rbx, rcx, rdx, rsi, rdi, rbp, r8, r9, r10, r11, r12, r13, r14, r15
push rax # [rsp+112] rax (syscall number)
push rbx # [rsp+104] rbx (arg1)
push rcx # [rsp+96] rcx (arg2)
push rdx # [rsp+88] rdx (arg3)
push rsi # [rsp+80]
push rdi # [rsp+72]
push rbp # [rsp+64]
push r8 # [rsp+56]
push r9 # [rsp+48]
push r10 # [rsp+40] r10 (arg4)
push r11 # [rsp+32]
push r12 # [rsp+24]
push r13 # [rsp+16]
push r14 # [rsp+8]
push r15 # [rsp+0]
# Calculate is_user from saved CS on stack
# CS is at [rsp + 15*8 + 16] = [rsp + 136]
mov rax, [rsp + 136] # CS from frame
xor ecx, ecx
test al, 3
setnz cl
push rcx # is_user (pushed AFTER all registers)
# Stack layout now:
# [rsp+0] = is_user
# [rsp+8] = r15 [rsp+16] = r14 [rsp+24] = r13 [rsp+32] = r12
# [rsp+40] = r11 [rsp+48] = r10 [rsp+56] = r9 [rsp+64] = r8
# [rsp+72] = rbp [rsp+80] = rdi [rsp+88] = rsi [rsp+96] = rdx
# [rsp+104] = rcx [rsp+112] = rbx [rsp+120] = rax
# Translate int 0x80 calling convention to syscall_handler convention
mov rdi, [rsp + 120] # original rax = syscall number -> rdi
mov rsi, [rsp + 112] # original rbx = arg1 -> rsi
mov rdx, [rsp + 104] # original rcx = arg2 -> rdx
mov rcx, [rsp + 96] # original rdx = arg3 -> rcx
mov r8, [rsp + 48] # original r10 = arg4 -> r8
xor r9, r9 # arg5 = 0
push 0 # arg6 = 0 (on stack)
call syscall_handler
add rsp, 8 # remove arg6
# Save return value by overwriting saved rax on stack
mov [rsp + 120], rax
# Pop is_user flag
pop rcx # is_user
# Restore registers
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx # restore original rcx (arg2)
pop rbx
pop rax # now has the return value
# Pop frame
pop r8 # RIP
pop r9 # CS
pop r10 # RFLAGS
pop rax # RSP (user)
pop r11 # SS (user)
test rcx, rcx
jnz isr80_ret_user
isr80_ret_kernel:
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq
isr80_ret_user:
swapgs
push r11 # SS
push rax # RSP
push r10 # RFLAGS
push r9 # CS
push r8 # RIP
iretq

View File

@@ -0,0 +1,470 @@
import drivers.serial.uart.serial as serial
import services.desktop as desktop
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import sched.sched as sched
import sched.process as process
import viperlib
import string
import mm.mm as mm
import paging.paging as paging
import execrunner.elf as elf
import t, c
CREATE_WINDOW: t.CDefine = 1
DRAW_TEXT: t.CDefine = 2
EXIT: t.CDefine = 3
OPEN: t.CDefine = 4
CLOSE: t.CDefine = 5
READ: t.CDefine = 6
WRITE: t.CDefine = 7
SEEK: t.CDefine = 8
TELL: t.CDefine = 9
SIZE: t.CDefine = 10
MKDIR: t.CDefine = 11
REMOVE: t.CDefine = 12
OPENDIR: t.CDefine = 13
READDIR: t.CDefine = 14
CLOSEDIR: t.CDefine = 15
STAT: t.CDefine = 16
WAIT_WINDOW: t.CDefine = 17
SERIAL_PUTS: t.CDefine = 18
LOAD_SO: t.CDefine = 19
SO_CALL1: t.CDefine = 20
GET_WINBUF: t.CDefine = 21
WIN_FLUSH: t.CDefine = 22
POLL_EVENT: t.CDefine = 23
SET_CURSOR: t.CDefine = 24
YIELD: t.CDefine = 25
SET_TITLE: t.CDefine = 26
SET_GEOMETRY: t.CDefine = 27
SPAWN: t.CDefine = 28
MMAP: t.CDefine = 29
MUNMAP: t.CDefine = 30
SET_RESIZABLE: t.CDefine = 31
GET_WIN_SIZE: t.CDefine = 32
THREAD_CREATE: t.CDefine = 33
IA32_EFER: t.CDefine = 0xC0000080
IA32_STAR: t.CDefine = 0xC0000081
IA32_LSTAR: t.CDefine = 0xC0000082
IA32_FMASK: t.CDefine = 0xC0000084
def wrmsr(msr: t.CUInt32T, val: t.CUInt64T):
lo: t.CUInt32T = t.CUInt32T(val & 0xFFFFFFFF)
hi: t.CUInt32T = t.CUInt32T(val >> 32)
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
mov eax, {c.AsmInp(lo, t.ASM_DESCR.REG_ANY)}
mov edx, {c.AsmInp(hi, t.ASM_DESCR.REG_ANY)}
wrmsr""",
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
def rdmsr(msr: t.CUInt32T) -> t.CUInt64T:
lo: t.CUInt32T
hi: t.CUInt32T
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
rdmsr""",
out=[c.AsmOut(lo, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(hi, t.ASM_DESCR.OUTPUT_REG)],
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
return t.CUInt64T(lo) | (t.CUInt64T(hi) << 32)
def _current_proc() -> process.Process | t.CPtr:
return process.ProcessManager.current()
def _fd_alloc(p: process.Process | t.CPtr) -> t.CInt:
for i in range(process.PROC_MAX_FDS):
if not p.fd_used[i]:
p.fd_used[i] = 1
return i
return -1
def _fd_free(p: process.Process | t.CPtr, fd: t.CInt):
if fd >= 0 and fd < process.PROC_MAX_FDS:
p.fd_used[fd] = 0
p.fd_table[fd] = t.CVoid(0, t.CPtr)
def _dir_alloc(p: process.Process | t.CPtr) -> t.CInt:
for i in range(process.PROC_MAX_DIRS):
if not p.dir_used[i]:
p.dir_used[i] = 1
return i
return -1
def _dir_free(p: process.Process | t.CPtr, dd: t.CInt):
if dd >= 0 and dd < process.PROC_MAX_DIRS:
p.dir_used[dd] = 0
p.dir_table[dd] = t.CVoid(0, t.CPtr)
def CREATE_WINDOW(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
desktop.set_app_pid(process.current())
return desktop.create(x, y, w, h, title, style)
def DRAW_TEXT(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
return desktop.draw_text(win_id, x, y, text, color)
def EXIT(code: t.CInt) -> t.CInt:
serial.puts("[syscall] exit called\n")
desktop.destroy_by_pid(process.current())
return 0
def WAIT_WINDOW(win_id: t.CInt) -> t.CInt:
while desktop.is_active(win_id):
sched.Scheduler.try_reschedule()
return 0
def SERIAL_PUTS(str_ptr: t.CVoid | t.CPtr) -> t.CInt:
s: t.CConst | t.CChar | t.CPtr = t.CVoid(str_ptr, t.CPtr)
serial.puts(s)
return 0
_loaded_so_base: t.CVoid | t.CPtr = None
_loaded_so_path: t.CArray[t.CChar, 64]
def LOAD_SO(path_ptr: t.CVoid | t.CPtr) -> t.CUInt64T:
global _loaded_so_base
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
serial.puts("[so] loading: ")
serial.puts(path)
serial.puts("\n")
base: t.CVoid | t.CPtr = elf.load_so(path)
if base is not None:
_loaded_so_base = base
for i in range(63):
ch: t.CChar = c.Deref(path + i)
_loaded_so_path[i] = ch
if ch == 0: break
_loaded_so_path[63] = 0
return t.CUInt64T(base)
return 0
def SO_CALL1(sym_name_ptr: t.CVoid | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
if _loaded_so_base is None: return -1
sym_name: t.CConst | t.CChar | t.CPtr = t.CVoid(sym_name_ptr, t.CPtr)
fn: t.CVoid | t.CPtr = elf.get_so_symbol(_loaded_so_base, sym_name, c.Addr(_loaded_so_path[0]))
if fn is None:
serial.puts("[so] symbol not found\n")
return -2
c.Asm(f"""mov rdi, {c.AsmInp(arg1, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(fn, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
serial.puts("[so] call returned\n")
return 0
def GET_WINBUF(win_id: t.CInt) -> t.CUInt64T:
buf: t.CVoid | t.CPtr = desktop.get_fb(win_id)
if buf is None:
return 0
return t.CUInt64T(buf)
def WIN_FLUSH(win_id: t.CInt) -> t.CInt:
desktop.flush(win_id)
return 0
def SET_CURSOR(win_id: t.CInt, cursor_t: t.CInt) -> t.CInt:
desktop.set_cursor_type(win_id, cursor_t)
return 0
def OPEN(path_ptr: t.CVoid | t.CPtr, mode: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
fp: t.CVoid | t.CPtr = fat32.open(path, t.CUInt8T(mode))
if not fp:
fat32.unlock()
return -1
fd: t.CInt = _fd_alloc(p)
if fd < 0:
fat32.close(fp)
fat32.unlock()
return -1
p.fd_table[fd] = fp
fat32.unlock()
return fd
def CLOSE(fd: t.CInt) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
res: t.CInt = t.CInt(fat32.close(fp))
fat32.unlock()
_fd_free(p, fd)
return res
def READ(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
br: t.CUInt32T = fat32.read(fp, buf_ptr, count)
fat32.unlock()
return t.CInt(br)
def WRITE(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
bw: t.CUInt32T = fat32.write(fp, buf_ptr, count)
fat32.unlock()
return t.CInt(bw)
def SEEK(fd: t.CInt, offset: t.CUInt32T) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
r: t.CInt = t.CInt(fat32.seek(fp, offset))
fat32.unlock()
return r
def TELL(fd: t.CInt) -> t.CUInt32T:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
pos: t.CUInt32T = fat32.tell(fp)
fat32.unlock()
return pos
def fsize(fd: t.CInt) -> t.CUInt32T:
p: process.Process | t.CPtr = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: t.CVoid | t.CPtr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
sz: t.CUInt32T = fat32.size(fp)
fat32.unlock()
return sz
def MKDIR(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
r: t.CInt = t.CInt(fat32.mkdir(path))
fat32.unlock()
return r
def REMOVE(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
fat32.lock()
r: t.CInt = t.CInt(fat32.remove(path))
fat32.unlock()
return r
def OPENdir(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
dd: t.CInt = _dir_alloc(p)
if dd < 0:
return -1
dp: fat32_types.dirobj | t.CPtr = c.Addr(p.dir_pool[dd])
fat32.lock()
res: t.CInt = t.CInt(fat32.opendir(path, dp))
fat32.unlock()
if res != 0:
_dir_free(p, dd)
return -1
p.dir_table[dd] = t.CVoid(t.CUInt64T(dp), t.CPtr)
return dd
def READdir(dd: t.CInt, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CVoid | t.CPtr = p.dir_table[dd]
if not dp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
info: fat32_types.fileinfo | t.CPtr = info_ptr
fat32.lock()
r: t.CInt = t.CInt(fat32.readdir(dp, info))
fat32.unlock()
return r
def CLOSEdir(dd: t.CInt) -> t.CInt:
p: process.Process | t.CPtr = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: t.CVoid | t.CPtr = p.dir_table[dd]
if not dp:
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
fat32.closedir(dp)
fat32.unlock()
_dir_free(p, dd)
return 0
def STAT(path_ptr: t.CVoid | t.CPtr, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
info: fat32_types.fileinfo | t.CPtr = info_ptr
fat32.lock()
r: t.CInt = t.CInt(fat32.stat(path, info))
fat32.unlock()
return r
def SPAWN(path_ptr: t.CVoid | t.CPtr, blocking: t.CInt) -> t.CInt:
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
pid: t.CInt = elf.spawn_elf(path)
if pid < 0:
return pid
if blocking:
p: process.Process | t.CPtr = process.ProcessManager.get_process(pid)
if p:
while p.state != process.PROC_DONE:
sched.Scheduler.try_reschedule()
return pid
USER_HEAP_BASE: t.CDefine = 0x20000000
def MMAP(size: t.CUInt64T) -> t.CUInt64T:
p: process.Process | t.CPtr = _current_proc()
if size == 0: return 0
aligned_size: t.CUInt64T = (size + 4095) & ~t.CUInt64T(4095)
if p.heap_start == 0:
p.heap_start = USER_HEAP_BASE
heap_end: t.CUInt64T = p.heap_start + p.heap_size
new_end: t.CUInt64T = heap_end + aligned_size
for va in range(heap_end, new_end, 4096):
phys_page: t.CVoid | t.CPtr = mm.malloc(4096)
if phys_page is None: return 0
paging.MapPage(va, t.CUInt64T(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
p.heap_size = p.heap_size + aligned_size
return heap_end
def MUNMAP(ptr: t.CUInt64T, size: t.CUInt64T) -> t.CInt:
return 0
def syscall_entry() -> t.CExtern | t.CVoid | t.State: pass
def syscall_handler(num: t.CUInt64T, arg1: t.CUInt64T, arg2: t.CUInt64T, arg3: t.CUInt64T, arg4: t.CUInt64T, arg5: t.CUInt64T, arg6: t.CUInt64T) -> t.CExport | t.CUInt64T:
n: t.CInt = t.CInt(num)
if n == CREATE_WINDOW:
title_ptr: t.CVoid | t.CPtr = t.CVoid(arg5, t.CPtr)
return t.CUInt64T(CREATE_WINDOW(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), title_ptr, t.CInt(arg6)))
elif n == DRAW_TEXT:
text_ptr: t.CVoid | t.CPtr = t.CVoid(arg4, t.CPtr)
return t.CUInt64T(DRAW_TEXT(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), text_ptr, t.CUInt32T(arg5)))
elif n == EXIT:
return t.CUInt64T(EXIT(t.CInt(arg1)))
elif n == OPEN:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(OPEN(path_ptr, t.CUInt32T(arg2)))
elif n == CLOSE:
return t.CUInt64T(CLOSE(t.CInt(arg1)))
elif n == READ:
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(READ(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
elif n == WRITE:
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(WRITE(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
elif n == SEEK:
return t.CUInt64T(SEEK(t.CInt(arg1), t.CUInt32T(arg2)))
elif n == TELL:
return t.CUInt64T(TELL(t.CInt(arg1)))
elif n == SIZE:
return t.CUInt64T(fsize(t.CInt(arg1)))
elif n == MKDIR:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(MKDIR(path_ptr))
elif n == REMOVE:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(REMOVE(path_ptr))
elif n == OPENDIR:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(OPENdir(path_ptr))
elif n == READDIR:
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(READdir(t.CInt(arg1), info_ptr))
elif n == CLOSEDIR:
return t.CUInt64T(CLOSEdir(t.CInt(arg1)))
elif n == STAT:
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(STAT(path_ptr, info_ptr))
elif n == WAIT_WINDOW:
if t.CInt(arg2) == 1:
return t.CUInt64T(desktop.is_active(t.CInt(arg1)))
elif t.CInt(arg2) == 2:
sched.Scheduler.try_reschedule()
return 0
return t.CUInt64T(WAIT_WINDOW(t.CInt(arg1)))
elif n == SERIAL_PUTS:
str_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SERIAL_PUTS(str_ptr_sp))
elif n == LOAD_SO:
path_ptr_so: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return LOAD_SO(path_ptr_so)
elif n == SO_CALL1:
sym_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SO_CALL1(sym_ptr, arg2))
elif n == GET_WINBUF:
return GET_WINBUF(t.CInt(arg1))
elif n == WIN_FLUSH:
return t.CUInt64T(WIN_FLUSH(t.CInt(arg1)))
elif n == POLL_EVENT:
buf_ptr_ev: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
caller_pid_ev: t.CInt = process.current()
return t.CUInt64T(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
elif n == SET_CURSOR:
desktop.set_cursor_type(t.CInt(arg1), t.CInt(arg2))
return 0
elif n == YIELD:
sched.Scheduler.try_reschedule()
return 0
elif n == SET_TITLE:
title_ptr_st: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
return t.CUInt64T(desktop.set_title(t.CInt(arg1), title_ptr_st))
elif n == SET_GEOMETRY:
return t.CUInt64T(desktop.set_geometry(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), t.CInt(arg5)))
elif n == SET_RESIZABLE:
return t.CUInt64T(desktop.set_resizable(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3)))
elif n == GET_WIN_SIZE:
return t.CUInt64T(desktop.get_size(t.CInt(arg1)))
elif n == SPAWN:
path_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
return t.CUInt64T(SPAWN(path_ptr_sp, t.CInt(arg2)))
elif n == MMAP:
return MMAP(arg1)
elif n == MUNMAP:
return t.CUInt64T(MUNMAP(arg1, arg2))
elif n == THREAD_CREATE:
func_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
arg_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
cur_pid: t.CInt = process.current()
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(func_ptr, arg_ptr, cur_pid)
if th is None: return t.CUInt64T(0xFFFFFFFFFFFFFFFF)
p: process.Process | t.CPtr = process.ProcessManager.get_process(cur_pid)
if p:
p.addThread(th.tid)
return t.CUInt64T(th.tid)
return 0
def init():
efer: t.CUInt64T = rdmsr(IA32_EFER)
efer = efer | 1
wrmsr(IA32_EFER, efer)
star_val: t.CUInt64T = (t.CUInt64T(0x08) << 32) | (t.CUInt64T(0x1B) << 48)
wrmsr(IA32_STAR, star_val)
wrmsr(IA32_LSTAR, t.CUInt64T(syscall_entry))
wrmsr(IA32_FMASK, 0x200)
serial.puts("[syscall] MSR init done\n")

347
VKernel/Kernel/main.py Normal file
View File

@@ -0,0 +1,347 @@
from stdint import *
import bootinfo
import intr
import platform.pch as pch
import platform.pch.timer as timer
import platform.pch.rtc as rtc
import drivers.serial.uart.su8250 as su8250
import drivers.serial.uart.serial as serial
import drivers.devfs.devfs as devfs
import paging.paging as paging
import drivers.video.vesafb.vga as vga
import drivers.video.vesafb.gfx as gfx
import drivers.storage.ide.ide as ide
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import mm.mm as mm
import string
import sched.sched as sched
import sched.process as proc
import drivers.input.keyboard.keyboard as keyboard
import drivers.input.mouse.mouse as mouse
import drivers.usb.usb as usb
import drivers.core.cpu.cpu as cpu
import drivers.core.cpu.apic as apic
import viperlib
import services.keyboard as kbd_svc
import services.mouse as mse_svc
import services.desktop as desktop
import intr.syscall as syscall
import execrunner.elf as elf
import t, c
import asm
kbd_tid: t.CInt = -1
mse_tid: t.CInt = -1
BootInfo: bootinfo.bootinfo | t.CPtr
@t.Object
# @t.CVTable
class ViperKernel:
BootInfo: bootinfo.bootinfo | t.CPtr
VGA: vga._VGAScreenDriver | t.CPtr
VGA_drv: vga._VGAScreenDriver
def __init__(self):
global BootInfo
self.BootInfo = BootInfo
BootInfo: bootinfo.bootinfo | t.CPtr = self.BootInfo
serial.init()
serial.puts("===== ViperOS VKernel Test\n =====")
serial.puts("V2.3.8\n")
intr.gdt.init()
# Set IA32_KERNEL_GS_BASE = &_per_cpu so swapgs in ISR/syscall works.
# _CPUObject is never instantiated, so __init_tss__ never runs;
# without this, GS base stays 0 and gs:[0] writes hit null -> triple fault.
cpu.msr_write(cpu.IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(cpu._per_cpu)))
serial.puts("[main] gdt init done\n")
intr.idt.init()
syscall.init()
serial.puts("[main] syscall init done\n")
# 必须在 sti() 之前初始化调度器,否则中断触发时 _sched_ptr 为 NULL 会导致三重故障
sched.Scheduler()
serial.puts("[main] sched init done\n")
timer.timer_init()
serial.puts("[main] timer init done\n")
#mouse.init()
#serial.puts("[main] mouse init done\n")
#apic.early_init()
#serial.puts("[main] apic init done\n")
asm.sti()
serial.puts("[main] sti done\n")
timer.timer_msleep(100)
serial.puts("[main] msleep done\n")
rtc.rtc_init()
serial.puts("[main] rtc init done\n")
ncpu: t.CUInt32T = apic.get_cpu_count()
ncpu_cr: t.CArray[t.CChar, 32]
viperlib.snprintf(c.Addr(ncpu_cr), 32, "[main] cpu_count=%u\n", ncpu)
serial.puts(ncpu_cr)
if ncpu > 1:
apic.start_aps()
serial.puts("[main] kernel init done\n")
fb: t.CVoid | t.CPtr = BootInfo.framebuffer_addr
width: t.CUInt64T = BootInfo.framebuffer_width
height: t.CUInt64T = BootInfo.framebuffer_height
pitch: t.CUInt64T = BootInfo.framebuffer_pitch
fb_format: t.CUInt64T = BootInfo.framebuffer_format
fb_size: t.CUInt64T = BootInfo.framebuffer_size
if BootInfo is not None:
paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
fb_pages: t.CUInt64T = (fb_size + t.CUInt64T(0xFFF)) >> t.CUInt64T(12)
fpi: t.CUInt64T = 0
while fpi < fb_pages:
fva: t.CUInt64T = t.CUInt64T(fb) + fpi * t.CUInt64T(0x1000)
paging.MapPage(fva, fva, paging.PTE_WRITABLE | paging.PTE_PCD)
fpi += 1
mm.init(BootInfo.MemmapAddr, BootInfo.MemmapSize, BootInfo.MemmapDescSize, BootInfo.framebuffer_addr, fb_size)
pt_pool_buf: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
paging.init_pool(pt_pool_buf, t.CUInt64T(513) * t.CUInt64T(4096))
else:
paging.init(0, 0)
mm.init(0, 0, 0, 0, 0)
pt_pool_buf2: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
paging.init_pool(pt_pool_buf2, t.CUInt64T(513) * t.CUInt64T(4096))
serial.puts("[main] paging and mm init done\n")
proc.ProcessManager()
serial.puts("[main] process manager init done\n")
ide.init()
serial.puts("[main] ide init done\n")
serial.puts("[main] initializing FAT32 filesystem\n")
scan_res: t.CInt = fat32.scan_drives()
ndrives: t.CInt = fat32.get_drive_count()
ndrives_cr: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(ndrives_cr), 64, "[fat32] scan_res=%d found %d drives\n", scan_res, ndrives)
serial.puts(ndrives_cr)
if ndrives > 0:
mount_res: t.CInt = fat32.mount()
if mount_res == 0:
dp: fat32_types.dirobj
res: t.CInt = fat32.opendir("/", c.Addr(dp))
if res == 0:
serial.puts("[fat32] listing 0:/\n")
count: t.CInt = 0
while count < 20:
info: fat32_types.fileinfo
res2: t.CInt = fat32.readdir(c.Addr(dp), c.Addr(info))
if res2 != 0: break
if info.fname[0] == 0: break
is_dir: t.CInt = 1 if (info.attr & fat32_types.AM_DIR) else 0
entry_cr: t.CArray[t.CChar, 300]
viperlib.snprintf(c.Addr(entry_cr), 300, " %s size=%lu dir=%d\n", c.Addr(info.fname[0]), info.file_size, is_dir)
serial.puts(entry_cr)
count = count + 1
fat32.closedir(c.Addr(dp))
serial.puts("[fat32] directory listing done\n")
else:
serial.puts("[fat32] failed to open root directory\n")
# Load ELF apps BEFORE running destructive FAT32 tests
serial.puts("[main] loading ELF apps...\n")
dp_apps: fat32_types.dirobj
apps_res: t.CInt = fat32.opendir("/APPS", c.Addr(dp_apps))
if apps_res == 0:
serial.puts("[main] APPS dir listing:\n")
ac: t.CInt = 0
while ac < 20:
ai: fat32_types.fileinfo
ar: t.CInt = fat32.readdir(c.Addr(dp_apps), c.Addr(ai))
if ar != 0: break
if ai.fname[0] == 0: break
ae: t.CArray[t.CChar, 300]
viperlib.snprintf(c.Addr(ae), 300, " %s size=%lu\n", c.Addr(ai.fname[0]), ai.file_size)
serial.puts(ae)
ac = ac + 1
fat32.closedir(c.Addr(dp_apps))
else:
serial.puts("[main] APPS dir not found\n")
sched.Scheduler.disable()
hello_pid: t.CInt = elf.spawn_elf("/APPS/hello.elf")
if hello_pid < 0:
serial.puts("[main] Hello spawn failed\n")
else:
slog: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(slog), 64, "[main] Hello spawned as pid=%d\n", hello_pid)
serial.puts(slog)
term_pid: t.CInt = elf.spawn_elf("/APPS/terminal.elf")
if term_pid < 0:
serial.puts("[main] Terminal spawn failed\n")
else:
tlog: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(tlog), 64, "[main] Terminal spawned as pid=%d\n", term_pid)
serial.puts(tlog)
garg_pid: t.CInt = elf.spawn_elf("/APPS/gargantua.elf")
if garg_pid < 0:
serial.puts("[main] Gargantua spawn failed\n")
else:
glog: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(glog), 64, "[main] Gargantua spawned as pid=%d\n", garg_pid)
serial.puts(glog)
s3d_pid: t.CInt = elf.spawn_elf("/APPS/scene3d.elf")
if s3d_pid < 0:
serial.puts("[main] Scene3D spawn failed\n")
else:
s3d_log: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(s3d_log), 64, "[main] Scene3D spawned as pid=%d\n", s3d_pid)
serial.puts(s3d_log)
so_base: t.CVoid | t.CPtr = elf.load_so("/LIBS/SLOG.SO")
if so_base is not None:
serial.puts("[main] slog.so loaded, calling log_info...\n")
log_info_fn: t.CVoid | t.CPtr = elf.get_so_symbol(so_base, "log_info", "/LIBS/SLOG.SO")
if log_info_fn is not None:
msg: t.CConst | t.CChar | t.CPtr = "Hello from shared library!"
c.Asm(f"""mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}
call {c.AsmInp(log_info_fn, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
else:
serial.puts("[main] log_info symbol not found\n")
else:
serial.puts("[main] failed to load slog.so\n")
sched.Scheduler.enable()
# FAT32 destructive tests removed to prevent disk.img corruption
# (write/rename/delete/mkdir/rmdir permanently modify the disk image)
fat32.unmount()
serial.puts("[fat32] unmounted\n")
else:
serial.puts("[fat32] mount failed\n")
else:
serial.puts("[fat32] no drives found\n")
devfs.devfs_init()
devfs.devfs_register_serial0()
devfs.devfs_register_serial1()
devfs.devfs_register_keyboard()
devfs.devfs_register_mouse()
serial.puts("[main] sched started\n")
fd: t.CInt = devfs.devfs_open("/dev/serial0", 0)
buf: t.CArray[t.CChar, 64]
string.memset(c.Addr(buf), 0, 64)
devfs.devfs_write(fd, "hello from devfs!", 17)
devfs.devfs_read(fd, c.Addr(buf), 64)
devfs.devfs_close(fd)
cr: t.CArray[t.CChar, 30]
string.memset(c.Addr(cr), 0, 30)
viperlib.snprintf(c.Addr(cr), 30, "hello %d %.2f", 42, float(0.24))
serial.puts(cr)
serial.puts("\n")
bootinfo_cr: t.CArray[t.CChar, 256]
string.memset(c.Addr(bootinfo_cr), 0, 256)
viperlib.snprintf(c.Addr(bootinfo_cr), 256, "Bootinfo 0x%016lx %lu %lu %lu %lu %lu map 0x%lx+%lu descsize=%lu",
BootInfo.framebuffer_addr,
BootInfo.framebuffer_format,
BootInfo.framebuffer_width,
BootInfo.framebuffer_height,
BootInfo.framebuffer_pitch,
BootInfo.framebuffer_size,
BootInfo.MemmapAddr,
BootInfo.MemmapSize,
BootInfo.MemmapDescSize)
serial.puts(bootinfo_cr)
serial.puts("\n")
a: t.CConst | str = "Hello"
serial.puts(c.Addr(a[4])) # o
serial.puts("\n")
d: t.CConst | int = 42
b: t.CConst | int | t.CPtr = c.Addr(d)
string.memset(c.Addr(cr), 0, 4)
viperlib.snprintf(c.Addr(cr), 30, "%d", b[0]) # 42
serial.puts(cr)
serial.puts("\n")
# paging and mm already initialized before FAT32
usb.init()
serial.puts("[main] starting keyboard service\n")
kbd_svc.start()
serial.puts("[main] starting mouse service\n")
mse_svc.start()
serial.puts("[main] services started\n")
self.VGA_drv = vga._VGAScreenDriver(fb, width, height, pitch, fb_format)
self.VGA = c.Addr(self.VGA_drv)
self.VGA.Print(100, 100, "ViperOS VKernel Test")
serial.puts("你好\n")
serial.puts("[main] starting desktop\n")
desktop.start(fb, width, height, pitch)
serial.puts("[main] desktop started\n")
# ELF apps already loaded before FAT32 tests
serial.puts("[main] entering main loop\n")
# sched.sched_dump()
last_sec: t.CUInt32T = 0
loop_cnt: t.CUInt32T = 0
while True:
cur_sec: t.CUInt32T = timer.timer_get_seconds()
if cur_sec != last_sec:
last_sec = cur_sec
#if cur_sec % 5 == 0:
# sched.sched_dump()
loop_cnt += 1
sched.Scheduler._yield()
#while True:
# cube.RenderScene(back_fb, cube.SCREEN_W, cube.SCREEN_H, time)
# string.memcpy(fb, back_fb, width * height * 4)
# serial.puts("time")
# time += float(0.1)
# circle(width / 2, height / 2, 180, fb)
# circle(640, 400, 180, 0xFFFFFFFF)
# X 字符串遍历
# c.Cast 更换
# 时钟
# PCI
# SHA1 它者文件更新
# assets
# X attributes语法和谐
# 合成式类型转换
VKP: ViperKernel | t.CPtr
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
def _start() -> t.CInt:
global VKP, BootInfo
saved_rdi: t.CUnsignedLong
c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi",
op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI])
asm.BSSClean()
BootInfo = saved_rdi # 隐式转为 bootinfo*
VKP = c.Addr(ViperKernel())
while True:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
return 0

762
VKernel/Kernel/mm/mm.py Normal file
View File

@@ -0,0 +1,762 @@
import bootinfo
import paging.paging as paging
import viperstring as string
import viperlib
import t, c
# 伙伴系统常量定义
MIN_BLOCK_SIZE: t.CDefine = 4096 # 最小块大小4KB
MAX_BLOCK_SIZE: t.CDefine = 268435456 # 最大块大小256MB
MAX_ORDER: t.CDefine = 18 # 最大阶数2^18 = 262144
# 内存块状态
BLOCK_FREE: t.CDefine = 0 # 空闲
BLOCK_USED: t.CDefine = 1 # 已使用
# 内存类型定义
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
# 内存区域结构
class memory_region(t.CStruct):
start: t.CUInt64T
end: t.CUInt64T
size: t.CUInt64T
type: t.CUInt32T
next: 'memory_region' | t.CPtr
# 全局内存区域链表
memory_regions: t.CStatic | memory_region | t.CPtr = None
# 内存块结构
class memory_block(t.CStruct):
size: t.CUInt64T # 块大小
state: t.CUInt8T # 块状态
order: t.CUInt8T # 块阶数
next: 'memory_block' | t.CPtr # 下一个块
prev: 'memory_block' | t.CPtr # 上一个块
# 伙伴系统结构
class __buddy_system(t.CStruct):
free_lists: t.CArray[memory_block | t.CPtr, MAX_ORDER + 1]
total_memory: t.CUInt64T # 总内存大小
used_memory: t.CUInt64T # 已使用内存大小
free_memory: t.CUInt64T # 空闲内存大小
start_addr: t.CVoid | t.CPtr # 内存起始地址
end_addr: t.CVoid | t.CPtr # 内存结束地址
SLAB_MAGIC: t.CDefine = 0x534C4142
SLAB_NUM_SIZES: t.CDefine = 6
SLAB_THRESHOLD: t.CDefine = 1024
class slab_page(t.CStruct):
magic: t.CUInt32T
obj_size: t.CUInt16T
free_count: t.CUInt16T
data_offset: t.CUInt16T
total_objs: t.CUInt16T
free_head: t.CVoid | t.CPtr
block_ptr: memory_block | t.CPtr
next: 'slab_page' | t.CPtr
prev: 'slab_page' | t.CPtr
# 4K对齐函数
def align_4k(addr: t.CUInt64T) -> t.CUInt64T:
return (addr + 0xFFF) & ~0xFFF
# 计算阶数
def get_order(size: t.CUInt64T) -> t.CStatic | t.CInt:
order: t.CInt = 0
while size > MIN_BLOCK_SIZE:
size >>= 1
order += 1
return order
# 计算块大小
def get_block_size(order: t.CInt) -> t.CStatic | t.CUInt64T:
return MIN_BLOCK_SIZE << order
@t.Object
class _BuddySystemObject:
# 全局伙伴系统实例
buddy: __buddy_system
# 初始化伙伴系统
def __init__(self, start_addr: t.CVoid | t.CPtr, size: t.CUInt64T):
for i in range(MAX_ORDER + 1):
self.buddy.free_lists[i] = None
self.buddy.total_memory = size
self.buddy.used_memory = 0
self.buddy.free_memory = size
self.buddy.start_addr = start_addr
self.buddy.end_addr = t.CVoid(t.CUInt64T(start_addr) + size, t.CPtr)
remaining: t.CUInt64T = size
cur_addr: t.CUInt64T = t.CUInt64T(start_addr)
while remaining >= MIN_BLOCK_SIZE:
order: t.CInt = 0
tmp: t.CUInt64T = remaining
while tmp > MIN_BLOCK_SIZE:
tmp >>= 1
order += 1
block_size: t.CUInt64T = get_block_size(order)
while block_size > remaining and order > 0:
order -= 1
block_size = get_block_size(order)
if block_size > remaining: break
block: memory_block | t.CPtr = cur_addr
block.size = block_size
block.state = BLOCK_FREE
block.order = order
block.next = None
block.prev = None
if order <= MAX_ORDER:
if self.buddy.free_lists[order]:
block.next = self.buddy.free_lists[order]
self.buddy.free_lists[order].prev = block
self.buddy.free_lists[order] = block
cur_addr += block_size
remaining -= block_size
# DEBUG: print free_lists status after init
import drivers.serial.uart.serial as serial
_dmsg: t.CArray[t.CChar, 40]
serial.puts("[mm] buddy init:")
_di: t.CInt = 0
while _di <= MAX_ORDER:
if self.buddy.free_lists[_di]:
viperlib.snprintf(c.Addr(_dmsg), 40, " [%d]=0x%lx", _di, t.CUInt64T(self.buddy.free_lists[_di]))
serial.puts(_dmsg)
_di += 1
serial.puts("\n")
# 分割内存块
def split_block(self, block: memory_block | t.CPtr, target_order: t.CInt) -> memory_block | t.CPtr:
current_order: t.CInt = block.order
# 从当前阶数向下分割,直到达到目标阶数
while current_order > target_order:
current_order -= 1
new_block_size: t.CUInt64T = get_block_size(current_order)
# 创建新块
new_block: memory_block | t.CPtr = t.CUInt64T(block) + new_block_size
new_block.size = new_block_size
new_block.state = BLOCK_FREE
new_block.order = current_order
new_block.next = None
new_block.prev = None
# 更新原块大小和阶数
block.size = new_block_size
block.order = current_order
# 将新块添加到对应阶数的空闲链表
if current_order <= MAX_ORDER:
new_block.next = self.buddy.free_lists[current_order]
if self.buddy.free_lists[current_order]:
self.buddy.free_lists[current_order].prev = new_block
self.buddy.free_lists[current_order] = new_block
return block
# 合并内存块
def merge_blocks(self, block: memory_block | t.CPtr) -> t.CStatic | memory_block | t.CPtr:
order: t.CInt = block.order
while order < MAX_ORDER:
block_size: t.CUInt64T = get_block_size(order)
block_addr: t.CUInt64T = t.CUInt64T(block) - t.CUInt64T(self.buddy.start_addr)
buddy_addr: t.CUInt64T = block_addr ^ block_size
# 计算伙伴块地址
buddy: memory_block | t.CPtr = t.CUInt64T(self.buddy.start_addr) + buddy_addr
# 检查伙伴块是否存在且空闲
if buddy >= t.CType(self.buddy.end_addr, memory_block, t.CPtr):
break # 伙伴块超出内存范围
if buddy.state != BLOCK_FREE or buddy.order != order:
break # 伙伴块不空闲或阶数不匹配
# 从空闲链表中移除伙伴块
if buddy.prev: buddy.prev.next = buddy.next
else: self.buddy.free_lists[order] = buddy.next
if buddy.next:
buddy.next.prev = buddy.prev
# 合并块
merged_block: memory_block | t.CPtr = block if block < buddy else buddy
merged_block.size = get_block_size(order + 1)
merged_block.order = order + 1
block = merged_block
order += 1
return block
# 分配内存块
def allocate_block(self, size: t.CUInt64T) -> t.CStatic | memory_block | t.CPtr:
# 计算所需阶数
order: t.CInt = get_order(size)
if order > MAX_ORDER: return None # 所需块大小超过最大限制
# 查找合适的空闲块
found_order: t.CInt = -1
for i in range(order, MAX_ORDER + 1):
if self.buddy.free_lists[i]:
found_order = i
break
# DEBUG: trace allocate_block
import drivers.serial.uart.serial as serial
_dba: t.CArray[t.CChar, 120]
if found_order == -1:
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc FAIL size=%lu order=%d\n", size, order)
serial.puts(_dba)
_dbf: t.CArray[t.CChar, 200]
_fi: t.CInt = 0
_fo: t.CInt = 0
while _fi <= MAX_ORDER:
if self.buddy.free_lists[_fi]:
_fs: t.CInt = viperlib.snprintf(c.Addr(_dbf) + _fo, 200 - _fo, "[%d]=0x%lx ", _fi, t.CUInt64T(self.buddy.free_lists[_fi]))
_fo = _fo + _fs
_fi += 1
if _fo == 0:
serial.puts("[mm] all free_lists EMPTY\n")
else:
serial.puts(_dbf)
serial.puts("\n")
return None
if found_order == -1: return None # 没有合适的空闲块
# 取出空闲块
block: memory_block | t.CPtr = self.buddy.free_lists[found_order]
# 从空闲链表中移除块
if block.next: block.next.prev = None
self.buddy.free_lists[found_order] = block.next
# 如果块大小大于所需大小,分割块
if found_order > order:
block = self.split_block(block, order)
# 标记块为已使用
block.state = BLOCK_USED
# 更新内存统计
self.buddy.used_memory += block.size
self.buddy.free_memory -= block.size
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc OK size=%lu order=%d found=%d block=0x%lx\n", size, order, found_order, t.CUInt64T(block))
serial.puts(_dba)
return block
# 释放内存块
def free_block(self, block: memory_block | t.CPtr) -> t.CStatic | t.CVoid:
# 标记块为空闲
block.state = BLOCK_FREE
# 更新内存统计
self.buddy.used_memory -= block.size
self.buddy.free_memory += block.size
# 尝试合并块
block = self.merge_blocks(block)
# 将块添加到对应阶数的空闲链表
order: t.CInt = block.order
if order <= MAX_ORDER:
block.next = self.buddy.free_lists[order]
block.prev = None
if self.buddy.free_lists[order]:
self.buddy.free_lists[order].prev = block
self.buddy.free_lists[order] = block
BuddySystemObject: _BuddySystemObject
def _slab_obj_size(size_class: t.CInt) -> t.CUInt16T:
if size_class == 0: return 32
if size_class == 1: return 64
if size_class == 2: return 128
if size_class == 3: return 256
if size_class == 4: return 512
return 1024
def _slab_size_class(size: t.CUInt64T) -> t.CInt:
if size <= 32: return 0
if size <= 64: return 1
if size <= 128: return 2
if size <= 256: return 3
if size <= 512: return 4
if size <= 1024: return 5
return -1
def _slab_read_ptr(addr: t.CVoid | t.CPtr) -> t.CVoid | t.CPtr:
result: t.CVoid | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return result
def _slab_write_ptr(addr: t.CVoid | t.CPtr, val: t.CVoid | t.CPtr):
c.Asm(f"""mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}
mov [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}], rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
def _slab_find_page(ptr: t.CVoid | t.CPtr) -> slab_page | t.CPtr:
if ptr is None: return None
hdr_off: t.CUInt64T = memory_block.__sizeof__()
page_addr: t.CUInt64T = t.CUInt64T(ptr) & ~t.CUInt64T(0xFFF)
page: slab_page | t.CPtr = page_addr + hdr_off
if page.magic == SLAB_MAGIC:
os: t.CUInt16T = page.obj_size
if os == 32 or os == 64 or os == 128 or os == 256 or os == 512 or os == 1024:
return page
page_addr2: t.CUInt64T = page_addr - 4096
page2: slab_page | t.CPtr = page_addr2 + hdr_off
if page2.magic == SLAB_MAGIC:
os2: t.CUInt16T = page2.obj_size
if os2 == 32 or os2 == 64 or os2 == 128 or os2 == 256 or os2 == 512 or os2 == 1024:
return page2
return None
@t.Object
class _SlabAllocator:
caches: t.CArray[slab_page | t.CPtr, SLAB_NUM_SIZES]
def __init__(self):
for i in range(SLAB_NUM_SIZES):
self.caches[i] = None
def _create_page(self, size_class: t.CInt) -> slab_page | t.CPtr:
obj_size: t.CUInt16T = _slab_obj_size(size_class)
aligned_size: t.CUInt16T = t.CUInt16T((obj_size + 15) & ~15)
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(4096 + memory_block.__sizeof__())
if not block: return None
hdr_off: t.CUInt64T = memory_block.__sizeof__()
page: slab_page | t.CPtr = t.CUInt64T(block) + hdr_off
page.magic = SLAB_MAGIC
page.obj_size = aligned_size
d_off: t.CUInt16T = t.CUInt16T((hdr_off + slab_page.__sizeof__() + 15) & ~15)
page.data_offset = d_off
total: t.CUInt16T = t.CUInt16T((block.size - d_off) / aligned_size)
page.total_objs = total
page.free_count = total
page.block_ptr = block
page.next = None
page.prev = None
data_start: t.CUInt64T = t.CUInt64T(block) + d_off
page.free_head = t.CVoid(data_start, t.CPtr)
for i in range(1, total):
cur: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i - 1) * aligned_size, t.CPtr)
nxt: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i) * aligned_size, t.CPtr)
_slab_write_ptr(cur, nxt)
last: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(total - 1) * aligned_size, t.CPtr)
_slab_write_ptr(last, t.CVoid(0, t.CPtr))
return page
def alloc(self, size_class: t.CInt) -> t.CVoid | t.CPtr:
page: slab_page | t.CPtr = self.caches[size_class]
while page:
if page.free_count > 0: break
page = page.next
if not page:
page = self._create_page(size_class)
if not page: return None
page.next = self.caches[size_class]
if self.caches[size_class]:
self.caches[size_class].prev = page
self.caches[size_class] = page
obj: t.CVoid | t.CPtr = page.free_head
page.free_head = _slab_read_ptr(obj)
page.free_count -= 1
return obj
def free_obj(self, ptr: t.CVoid | t.CPtr, page: slab_page | t.CPtr):
_slab_write_ptr(ptr, page.free_head)
page.free_head = ptr
page.free_count += 1
if page.free_count == page.total_objs:
if page.prev:
page.prev.next = page.next
else:
sc: t.CInt = _slab_size_class(page.obj_size)
if sc >= 0:
self.caches[sc] = page.next
if page.next:
page.next.prev = page.prev
page.magic = 0
BuddySystemObject.free_block(page.block_ptr)
SlabAllocator: _SlabAllocator
# 内存分配函数
def malloc(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
if size == 0: return None
if size <= SLAB_THRESHOLD:
sc: t.CInt = _slab_size_class(size)
if sc >= 0:
result: t.CVoid | t.CPtr = SlabAllocator.alloc(sc)
return result
hdr: t.CUInt64T = memory_block.__sizeof__()
if size >= 4096:
total: t.CUInt64T = size + 4096
total = align_4k(total)
order: t.CInt = get_order(total)
if order > MAX_ORDER: return None
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
import drivers.serial.uart.serial as serial
_dbm: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc buddy size=%lu block=0x%lx\n", size, t.CUInt64T(block))
serial.puts(_dbm)
if not block: return None
user_ptr: t.CUInt64T = (t.CUInt64T(block) + hdr + 4095) & ~t.CUInt64T(4095)
real_hdr: t.CUInt64T = user_ptr - 8
c.Asm(f"""mov rax, {c.AsmInp(block, t.ASM_DESCR.REG_ANY)}
mov [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}], rax""",
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc ret user_ptr=0x%lx\n", user_ptr)
serial.puts(_dbm)
return t.CVoid(user_ptr, t.CPtr)
total2: t.CUInt64T = size + hdr
total2 = align_4k(total2)
order2: t.CInt = get_order(total2)
if order2 > MAX_ORDER: return None
block2: memory_block | t.CPtr = BuddySystemObject.allocate_block(total2)
if not block2: return None
return t.CVoid(t.CUInt64T(block2) + hdr, t.CPtr)
def malloc_direct(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
if size == 0: return None
hdr: t.CUInt64T = memory_block.__sizeof__()
total: t.CUInt64T = size + hdr
total = align_4k(total)
order: t.CInt = get_order(total)
if order > MAX_ORDER: return None
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
if not block: return None
return t.CVoid(t.CUInt64T(block) + hdr, t.CPtr)
def free(ptr: t.CVoid | t.CPtr) -> t.CExport:
if ptr is None: return
sp: slab_page | t.CPtr = _slab_find_page(ptr)
if sp:
SlabAllocator.free_obj(ptr, sp)
return
if (t.CUInt64T(ptr) & 0xFFF) == 0:
real_hdr: t.CUInt64T = t.CUInt64T(ptr) - 8
block: memory_block | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(block, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
BuddySystemObject.free_block(block)
return
block2: memory_block | t.CPtr = t.CUInt64T(ptr) - memory_block.__sizeof__()
BuddySystemObject.free_block(block2)
def calloc(nmemb: t.CUInt64T, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
total_size: t.CUInt64T = nmemb * size
ptr: t.CVoid | t.CPtr = malloc(total_size)
if ptr:
string.memset(ptr, 0, total_size)
return ptr
def realloc(ptr: t.CVoid | t.CPtr, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
if ptr is None: return malloc(size)
if size == 0:
free(ptr)
return None
new_ptr: t.CVoid | t.CPtr = malloc(size)
if not new_ptr: return None
sp: slab_page | t.CPtr = _slab_find_page(ptr)
if sp:
old_size: t.CUInt64T = sp.obj_size
elif (t.CUInt64T(ptr) & 0xFFF) == 0:
real_hdr_r: t.CUInt64T = t.CUInt64T(ptr) - 8
block_r: memory_block | t.CPtr
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr_r, t.CPtr), t.ASM_DESCR.REG_ANY)}]
mov {c.AsmOut(block_r, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
old_size = block_r.size - 4096
else:
block2: memory_block | t.CPtr = t.CUInt64T(ptr) - memory_block.__sizeof__()
old_size = block2.size - memory_block.__sizeof__()
copy_size: t.CUInt64T = old_size if old_size < size else size
string.memcpy(new_ptr, ptr, copy_size)
free(ptr)
return new_ptr
# 回收内存区域链表
def free_memory_regions() -> t.CStatic | t.CVoid:
global memory_regions
current: memory_region | t.CPtr = memory_regions
while current:
next_region: memory_region | t.CPtr = current.next
free(current)
current = next_region
memory_regions = None
# 初始化内存管理系统
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt64T, FbAddr: t.CUInt64T = 0, FbSize: t.CUInt64T = 0):
global BuddySystemObject
import drivers.serial.uart.serial as serial
start_addr: t.CVoid | t.CPtr = None
size: t.CUInt64T = 0
if MemmapAddr != 0:
if MemmapSize > 0:
if MemmapDescSize > 0:
num_entries: t.CUInt64T = MemmapSize / MemmapDescSize
max_memory: t.CUInt64T = 0
best_start: t.CUInt64T = 0
best_avail_size: t.CUInt64T = 0
best_avail_start: t.CUInt64T = 0
best_bs_size: t.CUInt64T = 0
best_bs_start: t.CUInt64T = 0
best_ld_size: t.CUInt64T = 0
best_ld_start: t.CUInt64T = 0
i: t.CUInt64T
for i in range(num_entries):
entry: bootinfo.memory_map_entry | t.CPtr = t.CVoid(MemmapAddr + i * MemmapDescSize, t.CPtr)
etype: t.CUInt64T = entry.type
start: t.CUInt64T = align_4k(entry.physical_start)
np: t.CUInt64T = entry.num_pages
end: t.CUInt64T = entry.physical_start + np * 4096
end = align_4k(end - 1)
region_size: t.CUInt64T = end - start
if FbAddr != 0 and FbSize != 0:
fb_end: t.CUInt64T = FbAddr + FbSize
if start < fb_end and end > FbAddr:
continue
if etype == MEMORY_TYPE_AVAILABLE:
if region_size > best_avail_size:
best_avail_size = region_size
best_avail_start = start
if etype == MEMORY_TYPE_BOOT_SERVICES_DATA:
if region_size > best_bs_size:
best_bs_size = region_size
best_bs_start = start
if etype == MEMORY_TYPE_LOADER_DATA:
if region_size > best_ld_size:
best_ld_size = region_size
best_ld_start = start
min_blk: t.CUInt64T = MIN_BLOCK_SIZE
if best_avail_size >= min_blk:
best_start = best_avail_start
max_memory = best_avail_size
elif best_bs_size >= min_blk:
best_start = best_bs_start
max_memory = best_bs_size
elif best_ld_size >= min_blk:
best_start = best_ld_start
max_memory = best_ld_size
cr4: t.CArray[t.CChar, 128]
string.memset(c.Addr(cr4), 0, 128)
viperlib.snprintf(c.Addr(cr4), 128, "mm: best=0x%lx max=%lu entries=%lu avail=%lu bs=%lu ld=%lu\n",
best_start, max_memory, num_entries, best_avail_size, best_bs_size, best_ld_size)
serial.puts(cr4)
if best_start != 0:
if max_memory >= min_blk:
start_addr = t.CVoid(best_start, t.CPtr)
size = max_memory
if start_addr is None:
size = detect_memory_size()
size = align_4k(size)
# 起始地址 4MB内核之后避免超出物理 RAM
# 旧值 0x10000000 在 256MB QEMU 中超出物理 RAM 边界
start_addr = t.CVoid(align_4k(0x400000), t.CPtr)
if size > 0x400000:
size = size - 0x400000
size = align_4k(size)
min_blk2: t.CUInt64T = MIN_BLOCK_SIZE
if size < min_blk2:
size = 33554432
cr2: t.CArray[t.CChar, 128]
string.memset(c.Addr(cr2), 0, 128)
viperlib.snprintf(c.Addr(cr2), 128, "mm.init: start=0x%lx size=%lu bytes\n",
t.CUInt64T(start_addr), size)
serial.puts(cr2)
BuddySystemObject.__init__(start_addr, size)
SlabAllocator.__init__()
# 虚拟内存映射结构
class vm_area(t.CStruct):
VirtAddr: t.CUInt64T
PhysAddr: t.CUInt64T
size: t.CUInt64T
flags: t.CUInt32T
next: 'vm_area' | t.CPtr
# 全局虚拟内存区域链表
vm_areas: vm_area | t.CPtr = None
# 博弈机制参数
ALLOCATION_RETRIES: t.CDefine = 5 # 分配重试次数
FRAGMENTATION_THRESHOLD: t.CDefine = 0.7 # 碎片率阈值
# 获取内存使用统计
@c.CReturn(t.CUInt64T, t.CUInt64T, t.CUInt64T)
def GetMemoryStats():
return (BuddySystemObject.buddy.total_memory, BuddySystemObject.buddy.used_memory, BuddySystemObject.buddy.free_memory)
# 计算内存碎片率
def calculate_fragmentation() -> t.CDouble:
# 计算空闲块的数量和总大小
free_blocks: t.CInt = 0
free_size: t.CUInt64T = 0
for i in range(MAX_ORDER + 1):
block: memory_block | t.CPtr = BuddySystemObject.buddy.free_lists[i]
while block:
free_blocks += 1
free_size += block.size
block = block.next
# 如果没有空闲内存返回0
if free_size == 0:
return 0.0
# 计算碎片率
# 碎片率 = 1 - (最大空闲块大小 / 总空闲内存大小)
max_free_block: t.CUInt64T = 0
for i in range(MAX_ORDER, -1, -1):
if BuddySystemObject.buddy.free_lists[i]:
max_free_block = get_block_size(i)
break
if max_free_block == 0:
return 1.0
return 1.0 - (t.CDouble(max_free_block) / t.CDouble(free_size))
# 内存整理函数
def compact_memory() -> t.CStatic | t.CInt:
freed_pages: t.CInt = 0
for sc in range(SLAB_NUM_SIZES):
page: slab_page | t.CPtr = SlabAllocator.caches[sc]
while page:
next_page: slab_page | t.CPtr = page.next
if page.free_count == page.total_objs:
if page.prev:
page.prev.next = page.next
else:
SlabAllocator.caches[sc] = page.next
if page.next:
page.next.prev = page.prev
page.magic = 0
BuddySystemObject.free_block(page.block_ptr)
freed_pages += 1
page = next_page
return freed_pages
# 虚拟内存分配函数
def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
# 4K对齐
size = align_4k(size)
# 尝试分配物理内存,使用博弈机制
PhysAddr: t.CVoid | t.CPtr = None
retries: t.CInt = 0
while retries < ALLOCATION_RETRIES:
PhysAddr = malloc(size)
if PhysAddr:
break
# 内存不足,尝试进行内存整理
if calculate_fragmentation() > FRAGMENTATION_THRESHOLD:
compact_memory()
retries += 1
if not PhysAddr:
return 0
# 分配虚拟地址
# 简单的虚拟地址分配策略从0x100000000开始
VirtAddr: t.CUInt64T = 0x100000000
current: vm_area | t.CPtr = vm_areas
# 寻找合适的虚拟地址空间
while current:
if VirtAddr + size <= current.VirtAddr:
break
VirtAddr = current.VirtAddr + current.size
current = current.next
# 创建虚拟内存区域
area: vm_area | t.CPtr = malloc(vm_area.__sizeof__())
if area:
area.VirtAddr = VirtAddr
area.PhysAddr = t.CUInt64T(PhysAddr)
area.size = size
area.flags = flags
area.next = vm_areas
vm_areas = area
# 映射虚拟地址到物理地址
# 计算需要映射的页数
pages: t.CUInt64T = size / 4096
i: t.CUInt64T
for i in range(pages):
page_virt: t.CUInt64T = VirtAddr + (i * 4096)
page_phys: t.CUInt64T = t.CUInt64T(PhysAddr) + (i * 4096)
# 调用paging模块的映射函数
paging.MapPage(page_virt, page_phys, flags)
return VirtAddr
# 虚拟内存释放函数
def vm_free(VirtAddr: t.CUInt64T):
# 查找虚拟内存区域
current: vm_area | t.CPtr = vm_areas
prev: vm_area | t.CPtr = None
while current:
if current.VirtAddr == VirtAddr:
# 取消虚拟地址映射
pages: t.CUInt64T = current.size / 4096
i: t.CUInt64T
for i in range(pages):
page_virt: t.CUInt64T = current.VirtAddr + (i * 4096)
paging.UnMapPage(page_virt)
# 释放物理内存
free(t.CVoid(current.PhysAddr, t.CPtr))
if prev:
prev.next = current.next
else:
vm_areas = current.next
free(current)
return
prev = current
current = current.next
# CMOS读取函数
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
c.Asm(f"mov al, {c.AsmInp(reg)}\nout 0x70, al")
val: t.CUInt8T
c.Asm(f"in al, 0x71\nmov {c.AsmOut(val)}, al")
return val
# 内存大小测试函数
def detect_memory_size() -> t.CUInt64T:
# 读取 1MB-16MB 扩展内存KB 单位)
low: t.CUInt8T = cmos_read(0x15)
high: t.CUInt8T = cmos_read(0x16)
mem_kb: t.CUInt32T = (t.CUInt32T(high) << 8) | low
# 读取 16MB 以上扩展内存64KB 块为单位)
low2: t.CUInt8T = cmos_read(0x17)
high2: t.CUInt8T = cmos_read(0x18)
mem_above_16mb: t.CUInt32T = (t.CUInt32T(high2) << 8) | low2
# 两个寄存器都为 0 时使用默认值
if mem_kb == 0 and mem_above_16mb == 0:
return 0x10000000 # 256MB
# 计算总内存1MB 基础 + 1MB-16MB + 16MB 以上
total_size: t.CUInt64T = 1048576 # 前 1MB
if mem_kb > 0:
total_size = total_size + t.CUInt64T(mem_kb) * 1024
if mem_above_16mb > 0:
total_size = total_size + t.CUInt64T(mem_above_16mb) * 65536
total_size = align_4k(total_size)
# 确保内存大小至少为32MB
if total_size < 33554432: # 32MB
total_size = 33554432
return total_size

View File

@@ -0,0 +1,296 @@
import drivers.serial.uart.serial as serial
import viperlib
import t, c
PTE_PRESENT: t.CDefine = (1 << 0)
PTE_WRITABLE: t.CDefine = (1 << 1)
PTE_USER: t.CDefine = (1 << 2)
PTE_PWT: t.CDefine = (1 << 3)
PTE_PCD: t.CDefine = (1 << 4)
PTE_ACCESSED: t.CDefine = (1 << 5)
PTE_DIRTY: t.CDefine = (1 << 6)
PTE_PS: t.CDefine = (1 << 7)
PTE_GLOBAL: t.CDefine = (1 << 8)
class _p:
entries: t.CArray[t.CUInt64T, 512]
PT_POOL_PAGES: t.CDefine = 512
pt_pool_raw: t.CVoid | t.CPtr = None
pt_pool_start: t.CUInt64T = 0
pt_pool_used: t.CUInt64T = 0
AllocatedPages: t.CUInt64T = 0
pml4: _p | t.CPtr = None
pdp: _p | t.CPtr
pd: _p | t.CPtr
pt: _p | t.CPtr
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T):
global pml4
pml4 = GetCurrentPml4()
c.Asm(f"""
mov rax, cr0
and rax, ~0x10000
mov cr0, rax
""")
def init_pool(buf: t.CVoid | t.CPtr, buf_size: t.CUInt64T):
global pt_pool_raw, pt_pool_start, pt_pool_used
pt_pool_raw = buf
if buf is None: return
raw_addr: t.CUInt64T = t.CUInt64T(buf)
aligned_addr: t.CUInt64T = (raw_addr + t.CUInt64T(0xFFF)) & ~t.CUInt64T(0xFFF)
pt_pool_start = aligned_addr
pt_pool_used = 0
def AllocPage() -> t.CVoid | t.CPtr:
global pt_pool_used, pml4, pdp, pd, pt
if pt_pool_raw is None: return None
if pt_pool_used >= t.CUInt64T(PT_POOL_PAGES): return None
page: t.CVoid | t.CPtr = t.CVoid(pt_pool_start + pt_pool_used * t.CUInt64T(4096), t.CPtr)
pt_pool_used = pt_pool_used + t.CUInt64T(1)
c.Asm(f"""mov al, 0
mov ecx, 4096
mov rdi, {c.AsmInp(page, t.ASM_DESCR.REG_ANY)}
rep stosb""",
op = [t.ASM_DESCR.CLOBBER_AL, t.ASM_DESCR.CLOBBER_ECX, t.ASM_DESCR.CLOBBER_RDI])
AllocatedPages = AllocatedPages + t.CUInt64T(1)
return page
def FreePage(page: t.CVoid | t.CPtr):
global pml4, pdp, pd, pt
if page is None: return
if AllocatedPages > t.CUInt64T(0): AllocatedPages = AllocatedPages - t.CUInt64T(1)
def MapPage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T):
global pml4, pdp, pd, pt
if VirtAddr == 0 or PhysAddr == 0: return
VirtAddr = VirtAddr & ~t.CUInt64T(0xFFF)
PhysAddr = PhysAddr & ~t.CUInt64T(0xFFF)
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not (pml4.entries[Pml4Index] & PTE_PRESENT):
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pml4.entries[Pml4Index] & PTE_USER):
pml4.entries[Pml4Index] = pml4.entries[Pml4Index] | PTE_USER
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
if (flags & PTE_USER) and not (pdp.entries[PdpIndex] & PTE_USER):
pdp.entries[PdpIndex] = pdp.entries[PdpIndex] | PTE_USER
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if pd.entries[PdIndex] & 1:
if pd.entries[PdIndex] & 0x80:
big_phys: t.CUInt64T = pd.entries[PdIndex] & ~t.CUInt64T(0x1FFFFF)
inherit_flags: t.CUInt64T = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
pt: _p | t.CPtr = AllocPage()
if not pt: return
split_i: t.CInt = 0
while split_i < 512:
pt.entries[split_i] = (big_phys + t.CUInt64T(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
split_i += 1
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
else:
# PD entry exists as a regular PT (e.g. cloned identity mapping).
# Must propagate PTE_USER to the PD entry so user-mode access is
# allowed at all paging levels, otherwise #PF err=0x5.
if (flags & PTE_USER) and not (pd.entries[PdIndex] & PTE_USER):
pd.entries[PdIndex] = pd.entries[PdIndex] | PTE_USER
else:
pt: _p | t.CPtr = AllocPage()
if not pt: return
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = PhysAddr | flags | PTE_PRESENT
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def MapLargePage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T) -> t.CVoid:
global pml4, pdp, pd, pt
VirtAddr = VirtAddr & ~t.CUInt64T(0x1FFFFF)
PhysAddr = PhysAddr & ~t.CUInt64T(0x1FFFFF)
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
if not pml4:
pml4 = AllocPage()
if not pml4: return
if not pml4.entries[Pml4Index] & PTE_PRESENT:
pdp: _p | t.CPtr = AllocPage()
if not pdp: return
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
pd: _p | t.CPtr = AllocPage()
if not pd: return
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd.entries[PdIndex] = PhysAddr | flags | PTE_PRESENT | PTE_PS
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def UnMapPage(VirtAddr: t.CUInt64T):
global pml4, pdp, pd, pt
if VirtAddr == 0: return
if not pml4: return
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
if not pml4.entries[Pml4Index] & PTE_PRESENT: return
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not pdp.entries[PdpIndex] & PTE_PRESENT: return
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
if not pd.entries[PdIndex] & PTE_PRESENT: return
if pd.entries[PdIndex] & PTE_PS:
pd.entries[PdIndex] = 0
else:
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt.entries[PtIndex] = 0
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
def EnablePaging():
global pml4, pdp, pd, pt
c.Asm(f"mov cr3, {c.AsmInp(t.CUInt64T(pml4), t.ASM_DESCR.REG_ANY)}")
def GetCurrentPml4() -> _p | t.CPtr:
global pml4, pdp, pd, pt
cr3: t.CUInt64T
c.Asm(f"mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3")
return t.CType(cr3 & ~t.CUInt64T(0xFFF), _p, t.CPtr)
def create_process_page_table() -> t.CUInt64T:
global pml4
if not pml4: return 0
new_pml4: _p | t.CPtr = AllocPage()
if not new_pml4: return 0
i: t.CUInt64T
for i in range(512):
entry: t.CUInt64T = pml4.entries[i]
if entry & PTE_PRESENT:
new_pml4.entries[i] = entry
return t.CUInt64T(new_pml4)
def clone_for_process(isolate_vaddr: t.CUInt64T) -> t.CUInt64T:
global pml4
_dbg: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg), 120, "[clone] pml4=0x%lx pool_used=%lu iso_va=0x%lx\n", t.CUInt64T(pml4), pt_pool_used, isolate_vaddr)
serial.puts(_dbg)
if not pml4: return 0
new_pml4_page: _p | t.CPtr = AllocPage()
if not new_pml4_page:
serial.puts("[clone] AllocPage pml4 failed\n")
return 0
_dbg2: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg2), 120, "[clone] new_pml4=0x%lx\n", t.CUInt64T(new_pml4_page))
serial.puts(_dbg2)
i: t.CUInt64T
for i in range(512):
new_pml4_page.entries[i] = pml4.entries[i]
pml4_idx: t.CUInt64T = (isolate_vaddr >> 39) & 0x1FF
_dbg3: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg3), 120, "[clone] pml4_idx=%lu entry0=0x%lx\n", pml4_idx, pml4.entries[pml4_idx])
serial.puts(_dbg3)
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
kernel_pdp: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pdp_page: _p | t.CPtr = AllocPage()
if not new_pdp_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pdp_page.entries[i] = kernel_pdp.entries[i]
new_pml4_page.entries[pml4_idx] = (t.CUInt64T(new_pdp_page) & ~t.CUInt64T(0xFFF)) | (pml4.entries[pml4_idx] & t.CUInt64T(0xFFF))
pdp_idx: t.CUInt64T = (isolate_vaddr >> 30) & 0x1FF
if not (kernel_pdp.entries[pdp_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
kernel_pd: _p | t.CPtr = t.CType(kernel_pdp.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pd_page: _p | t.CPtr = AllocPage()
if not new_pd_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pd_page.entries[i] = kernel_pd.entries[i]
new_pdp_page.entries[pdp_idx] = (t.CUInt64T(new_pd_page) & ~t.CUInt64T(0xFFF)) | (kernel_pdp.entries[pdp_idx] & t.CUInt64T(0xFFF))
pd_idx: t.CUInt64T = (isolate_vaddr >> 21) & 0x1FF
if not (kernel_pd.entries[pd_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
if kernel_pd.entries[pd_idx] & PTE_PS: return t.CUInt64T(new_pml4_page)
kernel_pt: _p | t.CPtr = t.CType(kernel_pd.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
new_pt_page: _p | t.CPtr = AllocPage()
if not new_pt_page: return t.CUInt64T(new_pml4_page)
for i in range(512):
new_pt_page.entries[i] = kernel_pt.entries[i]
new_pd_page.entries[pd_idx] = (t.CUInt64T(new_pt_page) & ~t.CUInt64T(0xFFF)) | (kernel_pd.entries[pd_idx] & t.CUInt64T(0xFFF))
return t.CUInt64T(new_pml4_page)
def save_pt_range(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T, save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T | t.CPtr) -> t.CInt:
global pml4
if not pml4: return -1
c.Set(save_count, t.CUInt32T(0))
va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF)
while va < vaddr_end:
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
if pd_.entries[pd_idx] & PTE_PS: va += 0x200000; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
saved: t.CUInt32T = c.DerefAs(save_count)
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(saved) * 16
c.DerefAs(entry_ptr, va)
c.DerefAs(entry_ptr + 8, pt_.entries[pt_idx])
c.Set(save_count, t.CUInt32T(saved + 1))
va += 0x1000
return 0
def restore_pt_range(save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T):
global pml4
if not pml4: return
i: t.CUInt32T = 0
while i < save_count:
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(i) * 16
va: t.CUInt64T = c.DerefAs(entry_ptr)
orig_pte: t.CUInt64T = c.DerefAs(entry_ptr + 8)
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
if not (pml4.entries[pml4_idx] & PTE_PRESENT): i += 1; continue
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): i += 1; continue
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
if not (pd_.entries[pd_idx] & PTE_PRESENT): i += 1; continue
if pd_.entries[pd_idx] & PTE_PS: i += 1; continue
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
pt_.entries[pt_idx] = orig_pte
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]", op=[t.ASM_DESCR.CLOBBER_MEMORY])
i += 1
def set_active_pml4(cr3_val: t.CUInt64T):
global pml4
pml4 = t.CType(cr3_val & ~t.CUInt64T(0xFFF), _p, t.CPtr)

View File

@@ -0,0 +1,4 @@
from . import pic
from . import pit
from . import timer
from . import rtc

View File

@@ -0,0 +1,120 @@
import asm
import t, c
# PIC端口定义
PIC1_COMMAND: t.CDefine = 0x20
PIC1_DATA: t.CDefine = 0x21
PIC2_COMMAND: t.CDefine = 0xA0
PIC2_DATA: t.CDefine = 0xA1
# ICW1 - 初始化命令字1
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
ICW1_INIT: t.CDefine = 0x10 # 初始化
# ICW4 - 初始化命令字4
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
# OCW2 - 操作命令字2
OCW2_EOI: t.CDefine = 0x20 # 结束中断
# OCW3 - 操作命令字3
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
# 初始化PIC
def init():
# 发送ICW1开始初始化需要ICW4
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
asm.io_wait()
# 发送ICW2中断向量偏移
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
asm.io_wait()
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
asm.io_wait()
# 发送ICW3级联信息
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
asm.io_wait()
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
asm.io_wait()
# 发送ICW48086模式
asm.outb(PIC1_DATA, ICW4_8086)
asm.io_wait()
asm.outb(PIC2_DATA, ICW4_8086)
asm.io_wait()
# 设置初始屏蔽字只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
asm.io_wait()
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
asm.io_wait()
# 发送EOI信号
def eoi(irq: t.CUInt8T):
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
asm.outb(PIC1_COMMAND, OCW2_EOI)
# 检查是否是虚假中断spurious interrupt
# 返回 1 表示是虚假中断0 表示是真实中断
def isSpurious(irq: t.CInt) -> t.CInt:
# 边界检查
if irq < 0 or irq > 15: return 0
isr: t.CUInt8T
if irq < 8:
# 发送OCW3读取ISRInterrupt Service Register
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC1_COMMAND)
# 如果ISR中对应位为0说明是虚假中断
return not (isr & (1 << irq))
else:
# 发送OCW3读取从PIC的ISR
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
asm.io_wait()
isr = asm.inb(PIC2_COMMAND)
# 如果ISR中对应位为0说明是虚假中断
return not (isr & (1 << (irq - 8)))
# 设置IRQ屏蔽
def setMask(irq: t.CUInt8T):
# 边界检查
if irq > 15: return
port: t.CUInt16T
value: t.CUInt8T
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) | (1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效
# 清除IRQ屏蔽
def clearMask(irq: t.CUInt8T):
# 边界检查
if irq > 15: return
port: t.CUInt16T
value: t.CUInt8T
if irq < 8:
port = PIC1_DATA
else:
port = PIC2_DATA
irq -= 8
value = asm.inb(port) & ~(1 << irq)
asm.outb(port, value)
asm.io_wait() # 确保命令生效

View File

@@ -0,0 +1,26 @@
import asm
import t, c
PIT_CHANNEL0: t.CDefine = 0x40
PIT_CHANNEL1: t.CDefine = 0x41
PIT_CHANNEL2: t.CDefine = 0x42
PIT_COMMAND: t.CDefine = 0x43
def pit_init(frequency: t.CInt):
# 参数验证:确保频率为正数
if frequency <= 0: return
# 计算除数使用16位无符号整数
divisor: t.CUInt32T = 1193180 / frequency
# 发送命令字通道0先低后高模式3方波二进制计数
asm.outb(PIT_COMMAND, 0x36)
asm.io_wait()
# 写入低字节
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
asm.io_wait()
# 写入高字节
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
asm.io_wait()

View File

@@ -0,0 +1,97 @@
from stdint import *
import t, c
import asm
RTC_CMOS_ADDR: t.CUInt16T = 0x70
RTC_CMOS_DATA: t.CUInt16T = 0x71
RTC_REG_SECONDS: t.CDefine = 0x00
RTC_REG_MINUTES: t.CDefine = 0x02
RTC_REG_HOURS: t.CDefine = 0x04
RTC_REG_DAY: t.CDefine = 0x07
RTC_REG_MONTH: t.CDefine = 0x08
RTC_REG_YEAR: t.CDefine = 0x09
RTC_REG_STATUS_A: t.CDefine = 0x0A
RTC_REG_STATUS_B: t.CDefine = 0x0B
RTC_TZ_OFFSET: t.CDefine = 8
rtc_seconds: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_minutes: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_hours: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_day: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_month: t.CStatic | t.CVolatile | t.CUInt8T = 0
rtc_year: t.CStatic | t.CVolatile | t.CUInt16T = 0
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
asm.outb(RTC_CMOS_ADDR, reg)
return asm.inb(RTC_CMOS_DATA)
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
return (bcd >> 4) * 10 + (bcd & 0x0F)
def rtc_read_time():
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
sec: t.CUInt8T = cmos_read(RTC_REG_SECONDS)
min_: t.CUInt8T = cmos_read(RTC_REG_MINUTES)
hour: t.CUInt8T = cmos_read(RTC_REG_HOURS)
day: t.CUInt8T = cmos_read(RTC_REG_DAY)
mon: t.CUInt8T = cmos_read(RTC_REG_MONTH)
year: t.CUInt8T = cmos_read(RTC_REG_YEAR)
reg_b: t.CUInt8T = cmos_read(RTC_REG_STATUS_B)
if not (reg_b & 0x04):
sec = bcd_to_bin(sec)
min_ = bcd_to_bin(min_)
hour = bcd_to_bin(hour)
day = bcd_to_bin(day)
mon = bcd_to_bin(mon)
year = bcd_to_bin(year)
if not (reg_b & 0x02) and (hour & 0x80):
hour = ((hour & 0x7F) + 12) % 24
hour = hour + RTC_TZ_OFFSET
if hour >= 24:
hour = hour - 24
day = day + 1
max_day: t.CUInt8T = 31
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
max_day = 30
elif mon == 2:
max_day = 28
y4: t.CUInt16T = t.CUInt16T(year) + 2000
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
max_day = 29
if day > max_day:
day = 1
mon = mon + 1
if mon > 12:
mon = 1
year = year + 1
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
rtc_seconds = sec
rtc_minutes = min_
rtc_hours = hour
rtc_day = day
rtc_month = mon
rtc_year = t.CUInt16T(year) + 2000
def rtc_init():
rtc_read_time()
def rtc_get_hours() -> t.CUInt8T:
return rtc_hours
def rtc_get_minutes() -> t.CUInt8T:
return rtc_minutes
def rtc_get_seconds() -> t.CUInt8T:
return rtc_seconds
def rtc_get_day() -> t.CUInt8T:
return rtc_day
def rtc_get_month() -> t.CUInt8T:
return rtc_month
def rtc_get_year() -> t.CUInt16T:
return rtc_year

View File

@@ -0,0 +1,102 @@
import platform.pch.pic as pic
import platform.pch.pit as pit
import sched.sched as sched
import asm
import t, c
TIMER_FREQUENCY: t.CDefine = 1000
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
ticks: t.CStatic | t.CVolatile | t.CUInt64T = 0
seconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
milliseconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
timer_running: t.CStatic | t.CVolatile | bool = False
def timer_init():
global ticks, seconds, milliseconds, timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
pit.pit_init(TIMER_FREQUENCY)
def timer_handler():
global ticks, seconds, milliseconds, timer_running
if not timer_running:
pic.eoi(0)
return
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = ticks + 1
milliseconds = milliseconds + MILLISECONDS_PER_TICK
if milliseconds >= 1000:
seconds = seconds + 1
milliseconds = milliseconds - 1000
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
sched.Scheduler.sched_tick()
pic.eoi(0)
def timer_start():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = True
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_stop():
global timer_running
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
timer_running = False
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_reset():
global ticks, seconds, milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
ticks = 0
seconds = 0
milliseconds = 0
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_get_ticks() -> t.CUInt64T:
current_ticks: t.CUInt64T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_ticks = ticks
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_ticks
def timer_get_seconds() -> t.CUInt32T:
current_seconds: t.CUInt32T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_seconds = seconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_seconds
def timer_get_milliseconds() -> t.CUInt32T:
current_milliseconds: t.CUInt32T
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
current_milliseconds = milliseconds
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
return current_milliseconds
def timer_get_time(out_seconds: t.CUInt32T | t.CPtr, out_milliseconds: t.CUInt32T | t.CPtr):
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
if out_seconds:
c.Set(c.Deref(out_seconds), seconds)
if out_milliseconds:
c.Set(c.Deref(out_milliseconds), milliseconds)
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
def timer_msleep(ms: t.CUInt32T):
target: t.CUInt64T = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()
def timer_sleep(sec: t.CUInt32T):
target: t.CUInt64T = ticks + sec * TICKS_PER_SECOND
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()

View File

@@ -0,0 +1,202 @@
import mm
import drivers.serial.uart.serial as serial
import asm
import t, c
CORO_READY: t.CDefine = 0
CORO_RUNNING: t.CDefine = 1
CORO_YIELDED: t.CDefine = 2
CORO_DONE: t.CDefine = 3
MAX_COROUTINES: t.CDefine = 32
CORO_STACK_SIZE: t.CDefine = 8192
@t.Object
class Coroutine:
rsp: t.CUInt64T
stack: t.CVoid | t.CPtr
stack_size: t.CUInt64T
func: t.CVoid | t.CPtr
arg: t.CVoid | t.CPtr
state: t.CInt
cid: t.CInt
caller_rsp: t.CUInt64T
ret_val: t.CInt
def resume(self) -> t.CInt:
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if self.state == CORO_DONE: return self.ret_val
if self.state != CORO_READY and self.state != CORO_YIELDED: return -1
prev_cid: t.CInt = m.current_cid
m.current_cid = self.cid
self.state = CORO_RUNNING
_coro_old_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_new_rsp = c.Addr(self.rsp)
self.caller_rsp = t.CUInt64T(_coro_old_rsp)
_coro_switch()
if self.state == CORO_DONE:
return self.ret_val
return 0
@staticmethod
def _yield():
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
cid: t.CInt = m.current_cid
if cid < 0: return
m.coroutines[cid].state = CORO_YIELDED
prev_cid: t.CInt = -1
i: t.CInt
for i in range(m.count):
if m.coroutines[i].state == CORO_RUNNING and m.coroutines[i].caller_rsp != 0:
prev_cid = i
break
if prev_cid < 0: return
m.current_cid = prev_cid
_coro_old_rsp = c.Addr(m.coroutines[cid].rsp)
_coro_new_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_switch()
@property
def is_done(self) -> t.CInt:
if self.state == CORO_DONE:
return 1
return 0
@property
def is_yielded(self) -> t.CInt:
if self.state == CORO_YIELDED:
return 1
return 0
@property
def retval(self) -> t.CInt:
return self.ret_val
@t.Object
class CoroutineManager:
coroutines: t.CArray[Coroutine, MAX_COROUTINES]
current_cid: t.CInt
count: t.CInt
def __init__():
global _coro_mgr_ptr
_coro_mgr_ptr = c.Addr(_coro_mgr)
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
m.current_cid = 0
m.count = 1
m.coroutines[0].state = CORO_RUNNING
m.coroutines[0].cid = 0
m.coroutines[0].caller_rsp = 0
m.coroutines[0].ret_val = 0
m.coroutines[0].rsp = 0
m.coroutines[0].stack = None
m.coroutines[0].stack_size = 0
m.coroutines[0].func = None
m.coroutines[0].arg = None
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(m.coroutines[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def current() -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
return c.Addr(m.coroutines[m.current_cid])
@staticmethod
def get_coroutine(cid: t.CInt) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if cid < 0 or cid >= m.count: return None
return c.Addr(m.coroutines[cid])
@staticmethod
def create(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if m.count >= MAX_COROUTINES: return None
cid: t.CInt = m.count
m.count += 1
co: Coroutine | t.CPtr = c.Addr(m.coroutines[cid])
co.state = CORO_READY
co.cid = cid
co.func = func
co.arg = arg
co.caller_rsp = 0
co.ret_val = 0
stack_ptr: t.CVoid | t.CPtr = mm.malloc(CORO_STACK_SIZE)
if not stack_ptr: return None
co.stack = stack_ptr
co.stack_size = CORO_STACK_SIZE
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + CORO_STACK_SIZE - 16
stack_top = stack_top & ~t.CUInt64T(0xF)
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_coro_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 56], 0
mov qword ptr [rax - 48], 0
mov qword ptr [rax - 40], 0
mov qword ptr [rax - 32], 0
mov qword ptr [rax - 24], 0
mov qword ptr [rax - 16], 0
mov qword ptr [rax - 8], 0
mov qword ptr [rax], {c.AsmInp(entry_addr, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
stack_top = stack_top - 56
co.rsp = stack_top
return co
_coro_mgr: CoroutineManager = CoroutineManager()
_coro_mgr_ptr: CoroutineManager | t.CPtr = c.Addr(_coro_mgr)
_coro_old_rsp: t.CVoid | t.CPtr
_coro_new_rsp: t.CVoid | t.CPtr
@c.Attribute(t.attr.naked)
def _coro_switch():
c.Asm(f"""push rax
push rbx
push rbp
push r12
push r13
push r14
push r15
mov rax, qword ptr [rip + _coro_old_rsp]
mov qword ptr [rax], rsp
mov rax, qword ptr [rip + _coro_new_rsp]
mov rsp, qword ptr [rax]
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rax
ret""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@c.Attribute(t.attr.naked)
def _coro_entry():
c.Asm(f"""sub rsp, 8
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 1056]
movsxd rcx, ecx
shl rcx, 5
mov rdi, qword ptr [rax + rcx + 24]
mov rax, qword ptr [rax + rcx + 16]
call rax
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 1056]
movsxd rcx, ecx
shl rcx, 5
mov dword ptr [rax + rcx + 32], 3
mov dword ptr [rax + rcx + 48], eax
add rsp, 8""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
Coroutine._yield()
while True:
asm.sti()
asm.hlt()

View File

@@ -0,0 +1,277 @@
import mm
import mm.mm as mm_mm
import paging.paging as paging
import drivers.serial.uart.serial as serial
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import drivers.core.cpu.cpu as cpu
import intr.gdt as gdt
import viperlib
import string
import t, c
PROC_READY: t.CDefine = 0
PROC_RUNNING: t.CDefine = 1
PROC_BLOCKED: t.CDefine = 2
PROC_DONE: t.CDefine = 3
MAX_PROCESSES: t.CDefine = 8
MAX_PROC_THREADS: t.CDefine = 8
PROC_MAX_FDS: t.CDefine = 16
PROC_MAX_DIRS: t.CDefine = 8
KERN_STACK_SIZE: t.CDefine = 8192
USER_STACK_SIZE: t.CDefine = 65536
@t.Object
class Process:
pid: t.CInt
pml4_root: t.CUInt64T
threads: t.CArray[t.CInt, 8]
thread_count: t.CInt
state: t.CInt
entry: t.CVoid | t.CPtr
elf_base: t.CUInt64T
heap_start: t.CUInt64T
heap_size: t.CUInt64T
name: t.CArray[t.CChar, 32]
fd_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_FDS]
fd_used: t.CArray[t.CUInt8T, PROC_MAX_FDS]
dir_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_DIRS]
dir_used: t.CArray[t.CUInt8T, PROC_MAX_DIRS]
dir_pool: t.CArray[fat32_types.dirobj, PROC_MAX_DIRS]
kern_stack: t.CUInt64T
user_stack: t.CUInt64T
def addThread(self, tid: t.CInt) -> t.CInt:
if self.thread_count >= MAX_PROC_THREADS: return -1
self.threads[self.thread_count] = tid
self.thread_count += 1
return 0
def exit(self):
self.state = PROC_DONE
for i in range(PROC_MAX_FDS):
if self.fd_used[i]:
fp: t.CVoid | t.CPtr = self.fd_table[i]
if fp:
fat32.close(fp)
self.fd_used[i] = 0
self.fd_table[i] = t.CVoid(0, t.CPtr)
for i in range(PROC_MAX_DIRS):
if self.dir_used[i]:
dp: t.CVoid | t.CPtr = self.dir_table[i]
if dp:
fat32.closedir(dp)
self.dir_used[i] = 0
self.dir_table[i] = t.CVoid(0, t.CPtr)
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if m.current_pid == self.pid:
m.current_pid = 0
m.processes[0].state = PROC_RUNNING
if self.pml4_root != 0:
kernel_cr3: t.CUInt64T = m.processes[0].pml4_root
if kernel_cr3 != 0:
c.Asm(f"mov cr3, {c.AsmInp(kernel_cr3, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(kernel_cr3)
@property
def is_running(self) -> t.CInt:
if self.state == PROC_RUNNING:
return 1
return 0
@property
def is_done(self) -> t.CInt:
if self.state == PROC_DONE:
return 1
return 0
@t.Object
class ProcessManager:
processes: t.CArray[Process, MAX_PROCESSES]
current_pid: t.CInt
count: t.CInt
def __init__():
global _proc_mgr_ptr
_proc_mgr_ptr = c.Addr(_proc_mgr)
m: ProcessManager | t.CPtr = _proc_mgr_ptr
m.current_pid = 0
m.count = 1
p: Process | t.CPtr = c.Addr(m.processes[0])
p.pid = 0
p.state = PROC_RUNNING
p.thread_count = 0
p.pml4_root = 0
p.entry = None
p.elf_base = 0
p.heap_start = 0
p.heap_size = 0
name_str: str = "kernel"
i: t.CInt = 0
for ch in name_str:
if i >= 31: break
p.name[i] = ch
i += 1
p.name[i] = 0
j: t.CInt
for j in range(MAX_PROC_THREADS):
p.threads[j] = -1
for j in range(PROC_MAX_FDS):
p.fd_used[j] = 0
p.fd_table[j] = t.CVoid(0, t.CPtr)
for j in range(PROC_MAX_DIRS):
p.dir_used[j] = 0
p.dir_table[j] = t.CVoid(0, t.CPtr)
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _switch(pid: t.CInt) -> t.CInt:
global _saved_cr3
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if pid < 0 or pid >= m.count: return -1
p: Process | t.CPtr = c.Addr(m.processes[pid])
if p.state == PROC_DONE: return -1
old_pid: t.CInt = m.current_pid
if old_pid == pid: return 0
if old_pid >= 0 and old_pid < m.count:
m.processes[old_pid].state = PROC_READY
p.state = PROC_RUNNING
m.current_pid = pid
c.Asm(f"""mov {c.AsmOut(_saved_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3
mov rax, {c.AsmInp(p.pml4_root, t.ASM_DESCR.REG_ANY)}
mov cr3, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return 0
@staticmethod
def current() -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
return c.Addr(m.processes[m.current_pid])
@staticmethod
def get_process(pid: t.CInt) -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if pid < 0 or pid >= m.count: return None
return c.Addr(m.processes[pid])
@staticmethod
def create_process(name: str, entry: t.CVoid | t.CPtr) -> Process | t.CPtr:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
_dbp: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_dbp), 80, "[process] create_process count=%d MAX=%d\n", m.count, MAX_PROCESSES)
serial.puts(_dbp)
if m.count >= MAX_PROCESSES: return None
pid: t.CInt = m.count
m.count += 1
p: Process | t.CPtr = c.Addr(m.processes[pid])
p.pid = pid
p.state = PROC_READY
p.entry = entry
p.elf_base = 0
p.thread_count = 0
p.heap_start = 0
p.heap_size = 0
string.memset(c.Addr(p.name), 0, 32)
i: t.CInt = 0
for ch in name:
if i >= 31: break
p.name[i] = ch
i += 1
p.name[i] = 0
j: t.CInt
for j in range(MAX_PROC_THREADS):
p.threads[j] = -1
for j in range(PROC_MAX_FDS):
p.fd_used[j] = 0
p.fd_table[j] = t.CVoid(0, t.CPtr)
for j in range(PROC_MAX_DIRS):
p.dir_used[j] = 0
p.dir_table[j] = t.CVoid(0, t.CPtr)
ks: t.CVoid | t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
if ks is None:
serial.puts("[process] kernel stack alloc failed\n")
m.count = m.count - 1
return None
ks_size: t.CUInt64T = KERN_STACK_SIZE
p.kern_stack = t.CUInt64T(ks) + ks_size
us: t.CVoid | t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
if us is None:
serial.puts("[process] user stack alloc failed\n")
mm_mm.free(ks)
m.count = m.count - 1
return None
us_size: t.CUInt64T = USER_STACK_SIZE
p.user_stack = t.CUInt64T(us) + us_size
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
return p
_proc_mgr: ProcessManager = ProcessManager()
_proc_mgr_ptr: ProcessManager | t.CPtr = c.Addr(_proc_mgr)
_saved_cr3: t.CUInt64T
def current() -> t.CInt:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
return m.current_pid
def switch_pid(new_pid: t.CInt):
m: ProcessManager | t.CPtr = _proc_mgr_ptr
if m.current_pid == new_pid: return
if m.current_pid >= 0 and m.current_pid < m.count:
old_p: Process | t.CPtr = c.Addr(m.processes[m.current_pid])
if old_p.state != PROC_DONE:
old_p.state = PROC_READY
if new_pid >= 0 and new_pid < m.count:
new_p: Process | t.CPtr = c.Addr(m.processes[new_pid])
new_p.state = PROC_RUNNING
new_cr3: t.CUInt64T = new_p.pml4_root
if new_cr3 != 0:
c.Asm(f"mov cr3, {c.AsmInp(new_cr3, t.ASM_DESCR.REG_ANY)}",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(new_cr3)
# Update TSS RSP0 and GS kernel_rsp0 for the new process
# This is needed so interrupts from Ring 3 use the correct kernel stack
if new_p.kern_stack != 0:
gdt.set_tss_rsp0(new_p.kern_stack)
cpu.set_kernel_rsp0(new_p.kern_stack)
m.current_pid = new_pid
def get_pid(tid: t.CInt) -> t.CInt:
m: ProcessManager | t.CPtr = _proc_mgr_ptr
i: t.CInt
for i in range(m.count):
p: Process | t.CPtr = c.Addr(m.processes[i])
j: t.CInt
for j in range(p.thread_count):
if p.threads[j] == tid:
return p.pid
return -1
def drop_to_user_mode(entry: t.CVoid | t.CPtr, user_rsp: t.CUInt64T, kern_rsp: t.CUInt64T):
# NOTE: Do NOT swapgs here. This OS uses reverse GS convention:
# GS_BASE = 0 (kernel & user), KERNEL_GS_BASE = &_per_cpu
# syscall/ISR entry does swapgs to get GS_BASE = &_per_cpu
# syscall/ISR return does swapgs to restore GS_BASE = 0
# GS state is restored in isrCommonhandler before _yield() if needed.
c.Asm(f"""cli
mov rsp, {c.AsmInp(kern_rsp, t.ASM_DESCR.REG_ANY)}
mov rdx, {c.AsmInp(user_rsp, t.ASM_DESCR.REG_ANY)}
mov rcx, {c.AsmInp(entry, t.ASM_DESCR.REG_ANY)}
mov r11, 0x202
push 0x23
push rdx
push r11
push 0x1B
push rcx
iretq""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RSI,
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_R8,
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
t.ASM_DESCR.CLOBBER_RBP])

View File

@@ -0,0 +1,299 @@
import mm
import asm
import sched.process as proc
import drivers.serial.uart.serial as serial
import viperlib
import t, c
THREAD_READY: t.CDefine = 0
THREAD_RUNNING: t.CDefine = 1
THREAD_BLOCKED: t.CDefine = 2
THREAD_DONE: t.CDefine = 3
MAX_THREADS: t.CDefine = 16
THREAD_STACK_SIZE: t.CDefine = 65536
SCHED_QUANTUM: t.CDefine = 10
_yield_cnt: t.CUInt32T = 0
_yield_lock: t.CInt = 0
@t.Object
class Thread:
rsp: t.CUInt64T
stack: t.CVoid | t.CPtr
stack_size: t.CUInt64T
func: t.CVoid | t.CPtr
arg: t.CVoid | t.CPtr
state: t.CInt
tid: int
pid: t.CInt
def block(self):
self.state = THREAD_BLOCKED
Scheduler._yield()
def unblock(self):
if self.state == THREAD_BLOCKED:
self.state = THREAD_READY
@property
def is_running(self) -> t.CInt:
if self.state == THREAD_RUNNING:
return 1
return 0
@property
def is_blocked(self) -> t.CInt:
if self.state == THREAD_BLOCKED:
return 1
return 0
@property
def is_done(self) -> t.CInt:
if self.state == THREAD_DONE:
return 1
return 0
@t.Object
class Scheduler:
threads: t.CArray[Thread, MAX_THREADS]
current_tid: t.CInt
thread_count: t.CInt
enabled: t.CInt
needs_reschedule: t.CInt
tick_count: t.CInt
def __init__():
global _sched_ptr
_sched_ptr = c.Addr(_sched_storage)
s: Scheduler | t.CPtr = _sched_ptr
s.current_tid = 0
s.thread_count = 1
s.enabled = 0
s.needs_reschedule = 0
s.tick_count = 0
i: int
for i in range(MAX_THREADS):
s.threads[i].rsp = 0
s.threads[i].stack = None
s.threads[i].stack_size = 0
s.threads[i].func = None
s.threads[i].arg = None
s.threads[i].state = THREAD_DONE
s.threads[i].tid = i
s.threads[i].pid = 0
s.enabled = 1
s.threads[0].state = THREAD_RUNNING
s.threads[0].tid = 0
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(s.threads[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _yield():
global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock
_if_saved: t.CInt = 0
c.Asm(f"""pushfq
pop rax
shr rax, 9
and eax, 1
mov {c.AsmOut(_if_saved, t.ASM_DESCR.OUTPUT_REG)}, eax""",
op=[t.ASM_DESCR.CLOBBER_RAX])
asm.cli()
if _yield_lock:
if _if_saved:
asm.sti()
return
_yield_lock = 1
s: Scheduler | t.CPtr = _sched_ptr
s.needs_reschedule = 0
s.tick_count = 0
old_tid: t.CInt = s.current_tid
next_tid: t.CInt = old_tid + 1
if next_tid >= s.thread_count:
next_tid = 0
found: t.CInt = 0
count: t.CInt = 0
while count < s.thread_count:
st: t.CInt = s.threads[next_tid].state
if st == THREAD_READY or st == THREAD_RUNNING:
found = 1
break
next_tid += 1
if next_tid >= s.thread_count:
next_tid = 0
count += 1
if found == 0:
_yield_lock = 0
if _if_saved:
asm.sti()
return
if next_tid == old_tid:
_yield_lock = 0
if _if_saved:
asm.sti()
return
if s.threads[old_tid].state == THREAD_RUNNING:
s.threads[old_tid].state = THREAD_READY
s.threads[next_tid].state = THREAD_RUNNING
_switch_old_rsp = c.Addr(s.threads[old_tid].rsp)
_switch_new_rsp = c.Addr(s.threads[next_tid].rsp)
s.current_tid = next_tid
next_pid: t.CInt = s.threads[next_tid].pid
_yield_cnt += 1
proc.switch_pid(next_pid)
_yield_lock = 0
_do_switch()
if _if_saved:
asm.sti()
@staticmethod
def sched_tick():
s: Scheduler | t.CPtr = _sched_ptr
if not s.enabled: return
if s.thread_count <= 1: return
s.tick_count += 1
if s.tick_count >= SCHED_QUANTUM:
s.tick_count = 0
s.needs_reschedule = 1
@staticmethod
def try_reschedule():
s: Scheduler | t.CPtr = _sched_ptr
if s.needs_reschedule:
s.needs_reschedule = 0
Scheduler._yield()
@staticmethod
def disable():
s: Scheduler | t.CPtr = _sched_ptr
s.enabled = 0
@staticmethod
def enable():
s: Scheduler | t.CPtr = _sched_ptr
s.enabled = 1
@staticmethod
def current() -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
return c.Addr(s.threads[s.current_tid])
@staticmethod
def get_thread(tid: t.CInt) -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
if tid < 0 or tid >= s.thread_count: return None
return c.Addr(s.threads[tid])
@staticmethod
def create_thread(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr, thread_pid: t.CInt = 0) -> Thread | t.CPtr:
s: Scheduler | t.CPtr = _sched_ptr
if s.thread_count >= MAX_THREADS: return None
tid: int = s.thread_count
s.thread_count += 1
th: Thread | t.CPtr = c.Addr(s.threads[tid])
th.state = THREAD_READY
th.tid = tid
th.pid = thread_pid
th.func = func
th.arg = arg
stack_size: t.CUInt64T = THREAD_STACK_SIZE
stack_ptr: t.CVoid | t.CPtr = mm.malloc(stack_size)
if not stack_ptr: return None
th.stack = stack_ptr
th.stack_size = stack_size
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + stack_size - 16
stack_top = stack_top & ~t.CUInt64T(0xF)
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_thread_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 64], 0x202
mov qword ptr [rax - 56], 0
mov qword ptr [rax - 48], 0
mov qword ptr [rax - 40], 0
mov qword ptr [rax - 32], 0
mov qword ptr [rax - 24], 0
mov qword ptr [rax - 16], 0
mov qword ptr [rax - 8], 0
mov qword ptr [rax], {c.AsmInp(entry_addr, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
stack_top = stack_top - 64
th.rsp = stack_top
return th
_sched_storage: Scheduler = Scheduler()
_sched_ptr: Scheduler | t.CPtr = c.Addr(_sched_storage)
_switch_old_rsp: t.CVoid | t.CPtr
_switch_new_rsp: t.CVoid | t.CPtr
@c.Attribute(t.attr.naked)
def _do_switch():
c.Asm(f"""push rax
push rbx
push rbp
push r12
push r13
push r14
push r15
pushfq
mov rax, qword ptr [rip + _switch_old_rsp]
mov qword ptr [rax], rsp
mov rax, qword ptr [rip + _switch_new_rsp]
mov rsp, qword ptr [rax]
popfq
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rax
ret""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@c.Attribute(t.attr.naked)
def _thread_entry():
c.Asm(f"""sub rsp, 8
mov rax, qword ptr [rip + _sched_ptr]
mov ecx, dword ptr [rax + 896]
movsxd rcx, ecx
imul rcx, rcx, 56
mov rdi, qword ptr [rax + rcx + 32]
mov rax, qword ptr [rax + rcx + 24]
call rax
mov rax, qword ptr [rip + _sched_ptr]
mov ecx, dword ptr [rax + 896]
movsxd rcx, ecx
imul rcx, rcx, 56
mov dword ptr [rax + rcx + 40], 3
add rsp, 8""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
Scheduler._yield()
while True:
asm.sti()
asm.hlt()
Scheduler._yield()
def thread_current() -> t.CInt:
s: Scheduler | t.CPtr = _sched_ptr
return s.current_tid
def needs_reschedule() -> t.CInt:
s: Scheduler | t.CPtr = _sched_ptr
return s.needs_reschedule
def sched_dump():
s: Scheduler | t.CPtr = _sched_ptr
dl: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(dl), 80, "[sched] dump: cur=%d cnt=%d yields=%u\n", s.current_tid, s.thread_count, _yield_cnt)
serial.puts(dl)
for i in range(s.thread_count):
sl: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(sl), 80, " t%d: st=%d pid=%d rsp=0x%lx\n", i, s.threads[i].state, s.threads[i].pid, s.threads[i].rsp)
serial.puts(sl)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
import t, c
import drivers.input.keyboard.keyboard as keyboard
import drivers.usb.hid.usb_kbd as usb_kbd
import drivers.serial.uart.serial as serial
import sched.sched as sched
import viperlib
SERVICE_KEYBOARD: t.CDefine = 1
@t.Object
class KeyboardService:
th: sched.Thread | t.CPtr
running: t.CInt
usb_kbd_th: sched.Thread | t.CPtr
def __init__(self):
self.th = None
self.running = 0
self.usb_kbd_th = None
kbd_svc: KeyboardService
def kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
serial.puts("[kbd_svc] started\n")
while True:
if keyboard.has_data():
sc: t.CUInt8T = keyboard.read_scancode()
else:
sched.Scheduler._yield()
return 0
def usb_kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
serial.puts("[usb_kbd_svc] started\n")
evt: usb_kbd.usb_kbd_event
while True:
if usb_kbd.has_data():
usb_kbd.read_event(c.Addr(evt))
else:
sched.Scheduler._yield()
return 0
def start() -> t.CInt:
global kbd_svc
kbd_svc = KeyboardService()
keyboard.init()
serial.puts("[kbd_svc] PS/2 keyboard initialized, IRQ1 installed\n")
usb_kbd.init()
kbd_svc.running = 1
return 0

View File

@@ -0,0 +1,13 @@
import t, c
import drivers.input.mouse.mouse as mouse
import drivers.usb.hid.usb_mouse as usb_mouse
import drivers.serial.uart.serial as serial
import sched.sched as sched
SERVICE_MOUSE: t.CDefine = 2
def start() -> t.CInt:
serial.puts("[mse_svc] mouse initialized\n")
if usb_mouse.init() == 0:
serial.puts("[mse_svc] usb mouse initialized\n")
return 0

39
VKernel/linker.ld Normal file
View File

@@ -0,0 +1,39 @@
ENTRY(_start)
SECTIONS {
. = 0x100000;
.text : {
*(.text.startup)
*(.text)
*(.text.*)
}
.rodata : {
*(.rodata)
*(.rodata.*)
}
.data : {
*(.data)
*(.data.*)
}
.bss : {
__bss_start = .;
*(.bss)
*(.bss.*)
*(COMMON)
__bss_end = .;
}
/DISCARD/ : {
*(.comment)
*(.note)
*(.eh_frame)
*(.eh_frame_hdr)
*(.reloc)
*(.rela)
*(.debug*)
}
}

31
VKernel/project.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "Kernel",
"version": "1.0.0",
"source_dir": "./Kernel",
"temp_dir": "./temp",
"output_dir": "./output",
"compiler": {
"cmd": "llc",
"flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"]
},
"linker": {
"cmd": "ld.lld.exe",
"flags": [
"-m", "elf_x86_64",
"-T", "linker.ld",
"--oformat", "binary",
"--strip-all"
],
"output": "kernel.bin"
},
"includes": ["../../includes"],
"target": {
"triple": "x86_64-none-elf",
"datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
},
"options": {
"slice_level": 3,
"target": "llvm",
"strict_mode": true
}
}