diff --git a/.vscodeignore b/.vscodeignore
new file mode 100644
index 00000000..3c726a37
--- /dev/null
+++ b/.vscodeignore
@@ -0,0 +1,149 @@
+.git
+.github
+.vscode
+node_modules
+src
+tsconfig.json
+*.md
+*.log
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+*.vsix
+junit.xml
+
+.webpack_cache/
+
+# OS files
+.DS_Store
+Thumbs.db
+
+# Potential venv
+.venv
+
+# Agent files
+serena/
+.beads/
+AGENTS.md
+
+# Generated benchmark output
+packages/pyright-internal/src/tests/benchmarks/.generated/
+
+# perfCompare.py cached commit bundles
+/build/perfCompare/
+
diff --git a/Test/Kernel/drivers/core/cpu/apic.vp b/Test/Kernel/drivers/core/cpu/apic.vp
deleted file mode 100644
index 6bbd49aa..00000000
--- a/Test/Kernel/drivers/core/cpu/apic.vp
+++ /dev/null
@@ -1,251 +0,0 @@
-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()
diff --git a/Test/Kernel/drivers/core/cpu/cpu.vp b/Test/Kernel/drivers/core/cpu/cpu.vp
deleted file mode 100644
index 650bfc31..00000000
--- a/Test/Kernel/drivers/core/cpu/cpu.vp
+++ /dev/null
@@ -1,346 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/core/cpu/fpu.vp b/Test/Kernel/drivers/core/cpu/fpu.vp
deleted file mode 100644
index f326fcff..00000000
--- a/Test/Kernel/drivers/core/cpu/fpu.vp
+++ /dev/null
@@ -1,50 +0,0 @@
-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])
diff --git a/Test/Kernel/drivers/devfs/devfs copy.vp b/Test/Kernel/drivers/devfs/devfs copy.vp
deleted file mode 100644
index 053c9bc0..00000000
--- a/Test/Kernel/drivers/devfs/devfs copy.vp
+++ /dev/null
@@ -1,385 +0,0 @@
-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: list[devfs_directory, MAX_DIRECTORIES] = [0]
-directory_count: t.CStatic | t.CInt = 0
-
-files: list[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: list[_fd_table, MAX_FILE_DESCRIPTORS] = [0]
-
-@t.Object
-class devfs_directory:
- name: list[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: list[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: list[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
-
- 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
-
- current: devfs_directory | t.CPtr = self.root_directory
- buf: list[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
- 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
- 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
-
- 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:
- dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(path)
- return 0 if dir_ptr else -1
-
- def create_file(self, path: t.CConst | str,
- private_data: t.CVoid | t.CPtr) -> t.CInt:
- global file_count
- path_copy: list[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
-
- new_file: devfs_file | t.CPtr = c.Addr(files[file_count])
- file_count += 1
-
- string.strcpy(new_file.name, file_name)
- new_file.private_data = private_data
- new_file.parent_dir = dir_ptr
-
- return 0
-
- def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
- path_copy: list[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
-
- if not file_ptr.open:
- 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
- if file_ptr and file_ptr.close:
- 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
- if file_ptr and file_ptr.read:
- return file_ptr.read(fd, buffer, size)
- return 0
-
- 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
- if file_ptr and file_ptr.write:
- return file_ptr.write(fd, buffer, size)
- return 0
-
- 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
- if file_ptr and file_ptr.ioctl:
- return file_ptr.ioctl(fd, cmd, arg)
- return 0
-
- 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.__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,
- private_data: t.CVoid | t.CPtr) -> t.CInt:
- return DevFSObject.create_file(path, 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
- serial0_file.ioctl = None
- return devfs_create_file("/dev/serial0", serial0_file)
diff --git a/Test/Kernel/drivers/devfs/devfs.vp b/Test/Kernel/drivers/devfs/devfs.vp
deleted file mode 100644
index 1fd9fb65..00000000
--- a/Test/Kernel/drivers/devfs/devfs.vp
+++ /dev/null
@@ -1,491 +0,0 @@
-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)
diff --git a/Test/Kernel/drivers/fs/fat32/example_fs.vp b/Test/Kernel/drivers/fs/fat32/example_fs.vp
deleted file mode 100644
index dac35e67..00000000
--- a/Test/Kernel/drivers/fs/fat32/example_fs.vp
+++ /dev/null
@@ -1,237 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32.vp b/Test/Kernel/drivers/fs/fat32/fat32.vp
deleted file mode 100644
index 27870339..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32.vp
+++ /dev/null
@@ -1,208 +0,0 @@
-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)
-
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_core.vp b/Test/Kernel/drivers/fs/fat32/fat32_core.vp
deleted file mode 100644
index eb59ae25..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_core.vp
+++ /dev/null
@@ -1,16 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_dir.vp b/Test/Kernel/drivers/fs/fat32/fat32_dir.vp
deleted file mode 100644
index 5f85280d..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_dir.vp
+++ /dev/null
@@ -1,13 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_diskio.vp b/Test/Kernel/drivers/fs/fat32/fat32_diskio.vp
deleted file mode 100644
index fe9d00d7..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_diskio.vp
+++ /dev/null
@@ -1,76 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_file.vp b/Test/Kernel/drivers/fs/fat32/fat32_file.vp
deleted file mode 100644
index 49f8bd92..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_file.vp
+++ /dev/null
@@ -1,17 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_mkfs.vp b/Test/Kernel/drivers/fs/fat32/fat32_mkfs.vp
deleted file mode 100644
index e34b950e..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_mkfs.vp
+++ /dev/null
@@ -1,143 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_part.vp b/Test/Kernel/drivers/fs/fat32/fat32_part.vp
deleted file mode 100644
index 611270cc..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_part.vp
+++ /dev/null
@@ -1,147 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_time.vp b/Test/Kernel/drivers/fs/fat32/fat32_time.vp
deleted file mode 100644
index 30e1e7a5..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_time.vp
+++ /dev/null
@@ -1,64 +0,0 @@
-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)
diff --git a/Test/Kernel/drivers/fs/fat32/fat32_types.vp b/Test/Kernel/drivers/fs/fat32/fat32_types.vp
deleted file mode 100644
index b2a87880..00000000
--- a/Test/Kernel/drivers/fs/fat32/fat32_types.vp
+++ /dev/null
@@ -1,1698 +0,0 @@
-from stdint import *
-import t, c
-import spinlock
-import string
-import fat32_diskio as diskio
-import fat32_time as ftime
-
-
-def _read32(buf: t.CUInt8T | t.CPtr, off: t.CUInt32T) -> t.CUInt32T:
- return t.CUInt32T(buf[off]) | (t.CUInt32T(buf[off + 1]) << 8) | (t.CUInt32T(buf[off + 2]) << 16) | (t.CUInt32T(buf[off + 3]) << 24)
-
-def _read16(buf: t.CUInt8T | t.CPtr, off: t.CUInt32T) -> t.CUInt16T:
- return t.CUInt16T(buf[off]) | (t.CUInt16T(buf[off + 1]) << 8)
-
-def _write32(buf: t.CUInt8T | t.CPtr, off: t.CUInt32T, val: t.CUInt32T):
- buf[off + 0] = t.CUInt8T(val & 0xFF)
- buf[off + 1] = t.CUInt8T((val >> 8) & 0xFF)
- buf[off + 2] = t.CUInt8T((val >> 16) & 0xFF)
- buf[off + 3] = t.CUInt8T((val >> 24) & 0xFF)
-
-def _write16(buf: t.CUInt8T | t.CPtr, off: t.CUInt32T, val: t.CUInt16T):
- buf[off + 0] = t.CUInt8T(val & 0xFF)
- buf[off + 1] = t.CUInt8T((val >> 8) & 0xFF)
-
-
-SECTOR_SIZE: t.CDefine = 512
-ENTRY_SIZE: t.CDefine = 32
-CLUSTER_FREE: t.CDefine = 0x00000000
-CLUSTER_EOC_MIN: t.CDefine = 0x0FFFFFF8
-CLUSTER_EOC_MAX: t.CDefine = 0x0FFFFFFF
-CLUSTER_BAD: t.CDefine = 0x0FFFFFF7
-CLUSTER_ROOT: t.CDefine = 0x00000002
-FAT_MASK: t.CDefine = 0x0FFFFFFF
-FAT_RESERVED: t.CDefine = 0xF0000000
-
-MAX_LFN: t.CDefine = 255
-LFN_ENTRY_CHARS: t.CDefine = 13
-LFN_ATTR: t.CDefine = 0x0F
-LFN_FLAG_LAST: t.CDefine = 0x40
-SFN_NAME_LEN: t.CDefine = 8
-SFN_EXT_LEN: t.CDefine = 3
-SFN_DELETED: t.CDefine = 0xE5
-SFN_DOT: t.CDefine = 0x05
-SFN_FREE: t.CDefine = 0x00
-
-MAX_HANDLES: t.CDefine = 32
-MAX_LOCKS: t.CDefine = 32
-PATH_MAX: t.CDefine = 260
-NAME_MAX: t.CDefine = 255
-DEPTH_MAX: t.CDefine = 32
-
-FA_READ: t.CDefine = 0x01
-FA_WRITE: t.CDefine = 0x02
-FA_OPEN_EXISTING: t.CDefine = 0x00
-FA_CREATE_NEW: t.CDefine = 0x04
-FA_CREATE_ALWAYS: t.CDefine = 0x08
-FA_OPEN_ALWAYS: t.CDefine = 0x10
-FA_OPEN_APPEND: t.CDefine = 0x30
-FA_READ_MASK: t.CDefine = 0x0F
-
-AM_RDO: t.CDefine = 0x01
-AM_HID: t.CDefine = 0x02
-AM_SYS: t.CDefine = 0x04
-AM_VOL: t.CDefine = 0x08
-AM_DIR: t.CDefine = 0x10
-AM_ARC: t.CDefine = 0x20
-AM_LFN: t.CDefine = 0x0F
-AM_ANY: t.CDefine = 0x3F
-
-FS_FAT32: t.CDefine = 3
-
-CTRL_SYNC: t.CDefine = 0
-GET_SECTOR_COUNT: t.CDefine = 1
-GET_SECTOR_SIZE: t.CDefine = 2
-GET_BLOCK_SIZE: t.CDefine = 3
-CTRL_TRIM: t.CDefine = 4
-
-STA_NOINIT: t.CDefine = 0x01
-STA_NODISK: t.CDefine = 0x02
-STA_PROTECT: t.CDefine = 0x04
-
-DEV_DISK: t.CDefine = 0
-
-ENTRIES_PER_SECTOR: t.CDefine = 512 / 32
-
-
-class FRESULT(t.CEnum):
- FR_OK: t.State = 0
- FR_DISK_ERR: t.State
- FR_INT_ERR: t.State
- FR_NOT_READY: t.State
- FR_NO_FILE: t.State
- FR_NO_PATH: t.State
- FR_INVALID_NAME: t.State
- FR_DENIED: t.State
- FR_EXIST: t.State
- FR_INVALID_OBJECT: t.State
- FR_WRITE_PROTECTED: t.State
- FR_INVALID_DRIVE: t.State
- FR_NOT_ENABLED: t.State
- FR_NO_FILESYSTEM: t.State
- FR_MKFS_ABORTED: t.State
- FR_TIMEOUT: t.State
- FR_LOCKED: t.State
- FR_NOT_ENOUGH_CORE: t.State
- FR_TOO_MANY_OPEN_FILES: t.State
- FR_INVALID_PARAMETER: t.State
-
-class DRESULT(t.CEnum):
- RES_OK: t.State = 0
- RES_ERROR: t.State
- RES_WRPRT: t.State
- RES_NOTRDY: t.State
- RES_PARERR: t.State
-
-
-@c.Attribute(t.attr.packed)
-class bpb:
- BS_jmpBoot: t.CArray[t.CUInt8T, 3]
- BS_OEMName: t.CArray[t.CChar, 8]
- BPB_BytsPerSec: t.CUInt16T
- BPB_SecPerClus: t.CUInt8T
- BPB_RsvdSecCnt: t.CUInt16T
- BPB_NumFATs: t.CUInt8T
- BPB_RootEntCnt: t.CUInt16T
- BPB_TotSec16: t.CUInt16T
- BPB_Media: t.CUInt8T
- BPB_FATSz16: t.CUInt16T
- BPB_SecPerTrk: t.CUInt16T
- BPB_NumHeads: t.CUInt16T
- BPB_HiddSec: t.CUInt32T
- BPB_TotSec32: t.CUInt32T
- BPB_FATSz32: t.CUInt32T
- BPB_ExtFlags: t.CUInt16T
- BPB_FSVer: t.CUInt16T
- BPB_RootClus: t.CUInt32T
- BPB_FSInfo: t.CUInt16T
- BPB_BkBootSec: t.CUInt16T
- BPB_Reserved: t.CArray[t.CUInt8T, 12]
- BS_DrvNum: t.CUInt8T
- BS_Reserved1: t.CUInt8T
- BS_BootSig: t.CUInt8T
- BS_VolID: t.CUInt32T
- BS_VolLab: t.CArray[t.CChar, 11]
- BS_FilSysType: t.CArray[t.CChar, 8]
-
-@c.Attribute(t.attr.packed)
-class fsinfo:
- FSI_LeadSig: t.CUInt32T
- FSI_Reserved1: t.CArray[t.CUInt8T, 480]
- FSI_StrucSig: t.CUInt32T
- FSI_Free_Count: t.CUInt32T
- FSI_Nxt_Free: t.CUInt32T
- FSI_Reserved2: t.CArray[t.CUInt8T, 12]
- FSI_TrailSig: t.CUInt32T
-
-@c.Attribute(t.attr.packed)
-class dirent:
- DIR_Name: t.CArray[t.CChar, 11]
- DIR_Attr: t.CUInt8T
- DIR_NTRes: t.CUInt8T
- DIR_CrtTimeTenth: t.CUInt8T
- DIR_CrtTime: t.CUInt16T
- DIR_CrtDate: t.CUInt16T
- DIR_LstAccDate: t.CUInt16T
- DIR_FstClusHI: t.CUInt16T
- DIR_WrtTime: t.CUInt16T
- DIR_WrtDate: t.CUInt16T
- DIR_FstClusLO: t.CUInt16T
- DIR_FileSize: t.CUInt32T
-
-@c.Attribute(t.attr.packed)
-class lfn_entry:
- LDIR_Ord: t.CUInt8T
- LDIR_Name1: t.CArray[t.CUInt16T, 5]
- LDIR_Attr: t.CUInt8T
- LDIR_Type: t.CUInt8T
- LDIR_Chksum: t.CUInt8T
- LDIR_Name2: t.CArray[t.CUInt16T, 6]
- LDIR_FstClusLO: t.CUInt16T
- LDIR_Name3: t.CArray[t.CUInt16T, 2]
-
-
-def sfn_checksum(name: t.CConst | t.CChar | t.CPtr) -> t.CUInt8T:
- sum: t.CUInt8T = 0
- i: t.CInt
- for i in range(11):
- sum = ((sum & 1) << 7) + (sum >> 1) + name[i]
- return sum
-
-def uni2oem_placeholder(uni: t.CUInt16T, cp: t.CUInt16T) -> t.CUInt16T:
- if uni < 0x80: return uni
- return t.CUInt16T(0x003F)
-
-def lfn_get_char(entry_bytes: t.CUInt8T | t.CPtr, idx: t.CInt) -> t.CUInt16T:
- if idx < 5:
- off: t.CInt = 1 + idx * 2
- elif idx < 11:
- off = 14 + (idx - 5) * 2
- else:
- off = 28 + (idx - 11) * 2
- lo: t.CUInt8T = c.Deref(t.CUInt8T(t.CUInt64T(entry_bytes) + off, t.CPtr))
- hi: t.CUInt8T = c.Deref(t.CUInt8T(t.CUInt64T(entry_bytes) + off + 1, t.CPtr))
- return t.CUInt16T(lo) | t.CUInt16T(t.CUInt16T(hi) << 8)
-
-def lfn_set_char(entry_bytes: t.CUInt8T | t.CPtr, idx: t.CInt, ch: t.CUInt16T):
- if idx < 5:
- off: t.CInt = 1 + idx * 2
- elif idx < 11:
- off = 14 + (idx - 5) * 2
- else:
- off = 28 + (idx - 11) * 2
- c.Set(t.CUInt8T(t.CUInt64T(entry_bytes) + off, t.CPtr), t.CUInt8T(ch & 0xFF))
- c.Set(t.CUInt8T(t.CUInt64T(entry_bytes) + off + 1, t.CPtr), t.CUInt8T(ch >> 8))
-
-def lfn_extract(entry_bytes: t.CUInt8T | t.CPtr, lfn: t.CUInt16T | t.CPtr, ord_val: t.CUInt8T) -> t.CInt:
- seq: t.CInt = (ord_val & 0x3F) - 1
- base: t.CInt = seq * LFN_ENTRY_CHARS
- i: t.CInt
- for i in range(LFN_ENTRY_CHARS):
- ch: t.CUInt16T = lfn_get_char(entry_bytes, i)
- if ch == 0x0000 or ch == 0xFFFF:
- c.Set(t.CUInt16T(t.CUInt64T(lfn) + (base + i) * 2, t.CPtr), 0)
- return base + i
- c.Set(t.CUInt16T(t.CUInt64T(lfn) + (base + i) * 2, t.CPtr), ch)
- if ord_val & LFN_FLAG_LAST:
- c.Set(t.CUInt16T(t.CUInt64T(lfn) + (base + LFN_ENTRY_CHARS) * 2, t.CPtr), 0)
- return base + LFN_ENTRY_CHARS
-
-def sfn_from_lfn(lfn: t.CConst | t.CChar | t.CPtr, sfn: t.CChar | t.CPtr):
- string.memset(sfn, 0x20, 11)
- if c.Deref(lfn) == '.' and c.Deref(lfn + 1) == 0:
- sfn[0] = '.'; sfn[11] = 0; return
- if c.Deref(lfn) == '.' and c.Deref(lfn + 1) == '.' and c.Deref(lfn + 2) == 0:
- sfn[0] = '.'; sfn[1] = '.'; sfn[11] = 0; return
- si: t.CInt = 0
- dot_pos: t.CInt = -1
- i: t.CInt = 0
- ext_i: t.CInt = 0
- for ch in lfn:
- if ch == '.':
- dot_pos = si; si += 1; ext_i = 0; continue
- uc: t.CChar
- if ch >= 'a' and ch <= 'z': uc = ch - 32
- elif ch == ' ': uc = '_'
- elif ch == '+' or ch == ',' or ch == ';' or ch == '=' or ch == '[' or ch == ']': uc = '_'
- else: uc = ch
- if dot_pos < 0:
- if i < 8: sfn[i] = uc; i += 1
- else:
- if ext_i < 3: sfn[8 + ext_i] = uc; ext_i += 1
- si += 1
- sfn[11] = 0
-
-def sfn_to_str(sfn: t.CConst | t.CChar | t.CPtr, out: t.CChar | t.CPtr):
- i: t.CInt = 0
- j: t.CInt = 0
- for i in range(8):
- if sfn[i] == 0x20: break
- if sfn[i] == 0x05: out[j] = 0xE5
- else: out[j] = sfn[i]
- j += 1
- if sfn[8] != 0x20:
- out[j] = '.'; j += 1
- for i in range(8, 11):
- if sfn[i] == 0x20: break
- out[j] = sfn[i]; j += 1
- out[j] = 0
-
-def _split_path(path: t.CConst | t.CChar | t.CPtr, parent_out: t.CChar | t.CPtr, name_out: t.CChar | t.CPtr):
- pi: t.CInt = 0; last_sep: t.CInt = -1
- for ch in path:
- parent_out[pi] = ch
- if ch == '/' or ch == '\\': last_sep = pi
- pi += 1
- parent_out[pi] = 0
- if last_sep >= 0:
- fi: t.CInt
- for fi in range(last_sep + 1, pi): name_out[fi - last_sep - 1] = path[fi]
- name_out[pi - last_sep - 1] = 0
- parent_out[last_sep] = 0
- else:
- fi2: t.CInt
- for fi2 in range(pi): name_out[fi2] = path[fi2]
- name_out[pi] = 0
- parent_out[0] = '/'; parent_out[1] = 0
-
-
-class fileinfo:
- file_size: t.CUInt32T = 0
- attr: t.CUInt8T = 0
- ctime: t.CUInt16T = 0
- cdate: t.CUInt16T = 0
- mtime: t.CUInt16T = 0
- mdate: t.CUInt16T = 0
- adate: t.CUInt16T = 0
- fname: t.CArray[t.CChar, 256]
- altname: t.CArray[t.CChar, 13]
-
-class filelock:
- cluster: t.CUInt32T = 0
- dir_sector: t.CUInt64T = 0
- dir_offset: t.CUInt32T = 0
- in_use: t.CInt = 0
- shared_count: t.CInt = 0
- exclusive: t.CInt = 0
-
-
-@t.Object
-class volinfo:
- lock: spinlock._spinlock
- mounted: t.CInt = 0
- pdrv: t.CUInt8T = 0
- sector_size: t.CUInt16T = 512
- cluster_size: t.CUInt32T = 0
- cluster_sectors: t.CUInt8T = 0
- fat_start: t.CUInt64T = 0
- fat_size: t.CUInt32T = 0
- data_start: t.CUInt64T = 0
- root_cluster: t.CUInt32T = 2
- total_sectors: t.CUInt64T = 0
- total_clusters: t.CUInt32T = 0
- free_clusters: t.CUInt32T = 4294967295
- last_alloc: t.CUInt32T = 2
- fsinfo_sector: t.CUInt16T = 0
- backup_sector: t.CUInt16T = 6
- vol_id: t.CUInt32T = 0
- vol_label: t.CArray[t.CChar, 12]
- num_fats: t.CUInt8T = 2
- reserved_sectors: t.CUInt16T = 0
- hidden_sectors: t.CUInt32T = 0
- winsect: t.CUInt64T = 0xFFFFFFFFFFFFFFFF
- win_dirty: t.CInt = 0
- win: t.CArray[t.CUInt8T, 512]
- fat_winsect: t.CUInt64T = 0xFFFFFFFFFFFFFFFF
- fat_win_dirty: t.CInt = 0
- fat_win: t.CArray[t.CUInt8T, 512]
- metadata: t.CUInt32T = 0
- last_error: t.CUInt32T = 0
-
- def win_read(self, sector: t.CUInt64T) -> FRESULT:
- if self.winsect == sector: return FRESULT.FR_OK
- if self.win_dirty:
- res: FRESULT = self.win_flush()
- if res != FRESULT.FR_OK: return res
- abs_sector: t.CUInt64T = sector + t.CUInt64T(self.hidden_sectors)
- self.lock.lock()
- win_addr: t.CPtr = c.Addr(self.win[0])
- res2: DRESULT = diskio.read(self.pdrv, win_addr, t.CUInt32T(abs_sector), 1)
- self.lock.unlock()
- if res2 != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.winsect = sector
- return FRESULT.FR_OK
-
- def win_flush(self) -> FRESULT:
- if not self.win_dirty: return FRESULT.FR_OK
- abs_sector: t.CUInt64T = self.winsect + t.CUInt64T(self.hidden_sectors)
- self.lock.lock()
- res: DRESULT = diskio.write(self.pdrv, c.Addr(self.win[0]), t.CUInt32T(abs_sector), 1)
- self.lock.unlock()
- if res != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.win_dirty = 0
- return FRESULT.FR_OK
-
- def fat_win_read(self, sector: t.CUInt64T) -> FRESULT:
- if self.fat_winsect == sector: return FRESULT.FR_OK
- if self.fat_win_dirty:
- res: FRESULT = self.fat_win_flush()
- if res != FRESULT.FR_OK: return res
- abs_sector: t.CUInt64T = sector + t.CUInt64T(self.hidden_sectors)
- self.lock.lock()
- res2: DRESULT = diskio.read(self.pdrv, c.Addr(self.fat_win[0]), t.CUInt32T(abs_sector), 1)
- self.lock.unlock()
- if res2 != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.fat_winsect = sector
- return FRESULT.FR_OK
-
- def fat_win_flush(self) -> FRESULT:
- if not self.fat_win_dirty: return FRESULT.FR_OK
- abs_sector: t.CUInt64T = self.fat_winsect + t.CUInt64T(self.hidden_sectors)
- self.lock.lock()
- res: DRESULT = diskio.write(self.pdrv, c.Addr(self.fat_win[0]), t.CUInt32T(abs_sector), 1)
- self.lock.unlock()
- if res != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.fat_win_dirty = 0
- return FRESULT.FR_OK
-
- def flush_all(self) -> FRESULT:
- res: FRESULT = self.win_flush()
- if res != FRESULT.FR_OK: return res
- return self.fat_win_flush()
-
- def fat_read(self, cluster: t.CUInt32T) -> t.CUInt32T:
- if cluster < 2 or cluster >= self.total_clusters + 2: return 0
- fat_offset: t.CUInt64T = t.CUInt64T(cluster) * 4
- fat_sector: t.CUInt64T = self.fat_start + (fat_offset / 512)
- fat_offset_in_sector: t.CUInt32T = t.CUInt32T(fat_offset % 512)
- res: FRESULT = self.fat_win_read(fat_sector)
- if res != FRESULT.FR_OK: return 0
- return _read32(c.Addr(self.fat_win[0]), fat_offset_in_sector) & FAT_MASK
-
- def fat_write(self, cluster: t.CUInt32T, value: t.CUInt32T) -> FRESULT:
- if cluster < 2 or cluster >= self.total_clusters + 2: return FRESULT.FR_INVALID_PARAMETER
- fat_offset: t.CUInt64T = t.CUInt64T(cluster) * 4
- fat_sector: t.CUInt64T = self.fat_start + (fat_offset / 512)
- fat_offset_in_sector: t.CUInt32T = t.CUInt32T(fat_offset % 512)
- res: FRESULT = self.fat_win_read(fat_sector)
- if res != FRESULT.FR_OK: return res
- old: t.CUInt32T = _read32(c.Addr(self.fat_win[0]), fat_offset_in_sector)
- new_val: t.CUInt32T = (old & FAT_RESERVED) | (value & FAT_MASK)
- _write32(c.Addr(self.fat_win[0]), fat_offset_in_sector, new_val)
- self.fat_win_dirty = 1
- res = self.fat_win_flush()
- if res != FRESULT.FR_OK: return res
- if self.num_fats >= 2:
- mirror_sector: t.CUInt64T = fat_sector + t.CUInt64T(self.fat_size)
- res2: FRESULT = self.fat_win_read(mirror_sector)
- if res2 != FRESULT.FR_OK: return res2
- mirror_old: t.CUInt32T = _read32(c.Addr(self.fat_win[0]), fat_offset_in_sector)
- mirror_new: t.CUInt32T = (mirror_old & FAT_RESERVED) | (value & FAT_MASK)
- _write32(c.Addr(self.fat_win[0]), fat_offset_in_sector, mirror_new)
- self.fat_win_dirty = 1
- res3: FRESULT = self.fat_win_flush()
- if res3 != FRESULT.FR_OK: return res3
- return FRESULT.FR_OK
-
- def cluster_alloc(self) -> t.CUInt32T:
- clust: t.CUInt32T = self.last_alloc
- i: t.CUInt32T
- for i in range(self.total_clusters):
- clust += 1
- if clust >= self.total_clusters + 2: clust = 2
- entry: t.CUInt32T = self.fat_read(clust)
- if entry == CLUSTER_FREE:
- res: FRESULT = self.fat_write(clust, CLUSTER_EOC_MAX)
- if res != FRESULT.FR_OK: return 0
- self.last_alloc = clust
- if self.free_clusters != 0xFFFFFFFF: self.free_clusters -= 1
- return clust
- return 0
-
- def cluster_free_chain(self, start_cluster: t.CUInt32T) -> FRESULT:
- if start_cluster < 2: return FRESULT.FR_OK
- clust: t.CUInt32T = start_cluster
- while clust >= 2 and clust < CLUSTER_EOC_MIN:
- next_clust: t.CUInt32T = self.fat_read(clust)
- if next_clust == 0: break
- res: FRESULT = self.fat_write(clust, CLUSTER_FREE)
- if res != FRESULT.FR_OK: return res
- if self.free_clusters != 0xFFFFFFFF: self.free_clusters += 1
- clust = next_clust
- return FRESULT.FR_OK
-
- def cluster_extend(self, cluster: t.CUInt32T) -> t.CUInt32T:
- new_clust: t.CUInt32T = self.cluster_alloc()
- if new_clust == 0: return 0
- if cluster >= 2:
- res: FRESULT = self.fat_write(cluster, new_clust)
- if res != FRESULT.FR_OK:
- self.fat_write(new_clust, CLUSTER_FREE)
- return 0
- return new_clust
-
- def cluster_get_next(self, cluster: t.CUInt32T) -> t.CUInt32T:
- if cluster < 2: return 0
- entry: t.CUInt32T = self.fat_read(cluster)
- if entry >= CLUSTER_EOC_MIN and entry <= CLUSTER_EOC_MAX: return 0
- if entry == CLUSTER_FREE or entry == CLUSTER_BAD: return 0
- return entry
-
- def cluster_to_sector(self, cluster: t.CUInt32T) -> t.CUInt64T:
- if cluster < 2: return 0
- return self.data_start + t.CUInt64T(cluster - 2) * t.CUInt64T(self.cluster_sectors)
-
- def entries_per_cluster(self) -> t.CUInt32T:
- return t.CUInt32T(self.cluster_sectors) * (512 / ENTRY_SIZE)
-
- def is_eoc(self, cluster: t.CUInt32T) -> t.CInt:
- return 1 if (cluster >= CLUSTER_EOC_MIN and cluster <= CLUSTER_EOC_MAX) else 0
-
- def fsinfo_read(self) -> FRESULT:
- if self.fsinfo_sector == 0: return FRESULT.FR_OK
- res: FRESULT = self.win_read(t.CUInt64T(self.fsinfo_sector))
- if res != FRESULT.FR_OK: return res
- lead_sig: t.CUInt32T = _read32(c.Addr(self.win[0]), 0)
- struc_sig: t.CUInt32T = _read32(c.Addr(self.win[0]), 484)
- trail_sig: t.CUInt32T = _read32(c.Addr(self.win[0]), 508)
- if lead_sig != 0x41615252 or struc_sig != 0x61417272 or trail_sig != 0xAA550000:
- self.free_clusters = 0xFFFFFFFF
- self.last_alloc = 2
- return FRESULT.FR_OK
- free_count: t.CUInt32T = _read32(c.Addr(self.win[0]), 488)
- nxt_free: t.CUInt32T = _read32(c.Addr(self.win[0]), 492)
- if free_count <= self.total_clusters: self.free_clusters = free_count
- if nxt_free >= 2 and nxt_free < self.total_clusters + 2: self.last_alloc = nxt_free
- return FRESULT.FR_OK
-
- def fsinfo_write(self) -> FRESULT:
- if self.fsinfo_sector == 0: return FRESULT.FR_OK
- res: FRESULT = self.win_read(t.CUInt64T(self.fsinfo_sector))
- if res != FRESULT.FR_OK: return res
- _write32(c.Addr(self.win[0]), 0, 0x41615252)
- _write32(c.Addr(self.win[0]), 484, 0x61417272)
- _write32(c.Addr(self.win[0]), 488, self.free_clusters)
- _write32(c.Addr(self.win[0]), 492, self.last_alloc)
- _write32(c.Addr(self.win[0]), 508, 0xAA550000)
- self.win_dirty = 1
- return self.win_flush()
-
- def count_free_clusters(self) -> t.CUInt32T:
- free_cnt: t.CUInt32T = 0
- clust: t.CUInt32T
- for clust in range(2, self.total_clusters + 2):
- entry: t.CUInt32T = self.fat_read(clust)
- if entry == CLUSTER_FREE: free_cnt += 1
- self.free_clusters = free_cnt
- return free_cnt
-
- def mount(self) -> FRESULT:
- if self.mounted: return FRESULT.FR_OK
- res: DRESULT = diskio.status(self.pdrv)
- if res != DRESULT.RES_OK:
- res = diskio.init(self.pdrv)
- if res != DRESULT.RES_OK: return FRESULT.FR_NOT_READY
- res2: FRESULT = self.win_read(0)
- if res2 != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- bps: t.CUInt16T = _read16(c.Addr(self.win[0]), 11)
- spc: t.CUInt8T = self.win[13]
- rsc: t.CUInt16T = _read16(c.Addr(self.win[0]), 14)
- nf: t.CUInt8T = self.win[16]
- root_ent: t.CUInt16T = _read16(c.Addr(self.win[0]), 17)
- fat16sz: t.CUInt16T = _read16(c.Addr(self.win[0]), 22)
- tot32: t.CUInt32T = _read32(c.Addr(self.win[0]), 32)
- fat32sz: t.CUInt32T = _read32(c.Addr(self.win[0]), 36)
- root_clus: t.CUInt32T = _read32(c.Addr(self.win[0]), 44)
- sig0: t.CUInt8T = self.win[510]
- sig1: t.CUInt8T = self.win[511]
- if bps != 512: return FRESULT.FR_NO_FILESYSTEM
- if spc == 0 or (spc & (spc - 1)) != 0: return FRESULT.FR_NO_FILESYSTEM
- if rsc == 0: return FRESULT.FR_NO_FILESYSTEM
- if nf == 0: return FRESULT.FR_NO_FILESYSTEM
- if root_ent != 0 or fat16sz != 0: return FRESULT.FR_NO_FILESYSTEM
- if fat32sz == 0: return FRESULT.FR_NO_FILESYSTEM
- if tot32 == 0: return FRESULT.FR_NO_FILESYSTEM
- if sig0 != 0x55 or sig1 != 0xAA: return FRESULT.FR_NO_FILESYSTEM
- fsinfo_sec: t.CUInt16T = _read16(c.Addr(self.win[0]), 48)
- bkboot_sec: t.CUInt16T = _read16(c.Addr(self.win[0]), 50)
- self.sector_size = 512
- self.cluster_sectors = spc
- self.cluster_size = t.CUInt32T(spc) * 512
- self.num_fats = nf
- self.reserved_sectors = rsc
- self.fat_size = fat32sz
- self.fat_start = t.CUInt64T(rsc)
- self.total_sectors = t.CUInt64T(tot32)
- self.root_cluster = root_clus
- self.fsinfo_sector = fsinfo_sec
- self.backup_sector = bkboot_sec
- self.vol_id = _read32(c.Addr(self.win[0]), 67)
- data_sectors: t.CUInt64T = self.total_sectors - t.CUInt64T(rsc) - t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
- self.total_clusters = t.CUInt32T(data_sectors / t.CUInt64T(spc))
- self.data_start = self.fat_start + t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
- self.last_alloc = 2
- self.free_clusters = 0xFFFFFFFF
- self.fsinfo_read()
- self.mounted = 1
- return FRESULT.FR_OK
-
- def unmount(self) -> FRESULT:
- if not self.mounted: return FRESULT.FR_OK
- res: FRESULT = self.flush_all()
- if res != FRESULT.FR_OK: return res
- self.fsinfo_write()
- self.mounted = 0
- self.winsect = 0xFFFFFFFFFFFFFFFF
- self.win_dirty = 0
- self.fat_winsect = 0xFFFFFFFFFFFFFFFF
- self.fat_win_dirty = 0
- return FRESULT.FR_OK
-
- def _zero_cluster(self, cluster: t.CUInt32T) -> FRESULT:
- sector: t.CUInt64T = self.cluster_to_sector(cluster)
- s: t.CUInt32T
- for s in range(self.cluster_sectors):
- res: FRESULT = self.win_read(sector + t.CUInt64T(s))
- if res != FRESULT.FR_OK: return res
- string.memset(c.Addr(self.win[0]), 0, 512)
- self.win_dirty = 1
- res2: FRESULT = self.win_flush()
- if res2 != FRESULT.FR_OK: return res2
- return FRESULT.FR_OK
-
- def file_cluster_seek(self, first_cluster: t.CUInt32T, pos: t.CUInt32T) -> t.CUInt32T:
- if first_cluster < 2: return 0
- cluster: t.CUInt32T = first_cluster
- cluster_num: t.CUInt32T = pos / self.cluster_size
- i: t.CUInt32T
- for i in range(cluster_num):
- next_c: t.CUInt32T = self.cluster_get_next(cluster)
- if next_c == 0: return 0
- cluster = next_c
- return cluster
-
- def file_find_last_cluster(self, first_cluster: t.CUInt32T) -> t.CUInt32T:
- if first_cluster < 2: return 0
- cluster: t.CUInt32T = first_cluster
- while True:
- next_c: t.CUInt32T = self.cluster_get_next(cluster)
- if next_c == 0: return cluster
- cluster = next_c
-
- def _read_entry_from_dir(self, dp: dirobj | t.CPtr) -> FRESULT:
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- return self.win_read(entry_sector)
-
- def _write_dirent_now(self, eo: t.CUInt32T):
- now: t.CUInt32T = ftime.get_fattime()
- fat_time: t.CUInt16T = t.CUInt16T(now & 0xFFFF)
- fat_date: t.CUInt16T = t.CUInt16T((now >> 16) & 0xFFFF)
- _write16(c.Addr(self.win[0]), eo + 14, fat_time)
- _write16(c.Addr(self.win[0]), eo + 16, fat_date)
- _write16(c.Addr(self.win[0]), eo + 18, fat_date)
- _write16(c.Addr(self.win[0]), eo + 22, fat_time)
- _write16(c.Addr(self.win[0]), eo + 24, fat_date)
-
- def dir_offset_to_sector(self, start_cluster: t.CUInt32T, offset: t.CUInt32T) -> t.CUInt64T:
- epc: t.CUInt32T = self.entries_per_cluster()
- cluster: t.CUInt32T = start_cluster
- cluster_idx: t.CUInt32T = offset / epc
- i: t.CUInt32T
- for i in range(cluster_idx):
- next_c: t.CUInt32T = self.cluster_get_next(cluster)
- if next_c == 0: return 0
- cluster = next_c
- off_in_cluster: t.CUInt32T = offset % epc
- return self.cluster_to_sector(cluster) + t.CUInt64T(off_in_cluster / (512 / ENTRY_SIZE))
-
- def dir_next_cluster(self, dp: dirobj | t.CPtr) -> FRESULT:
- next_clust: t.CUInt32T = self.cluster_get_next(dp.cluster)
- if next_clust == 0: return FRESULT.FR_NO_FILE
- dp.cluster = next_clust
- dp.sector = self.cluster_to_sector(next_clust)
- dp.offset = 0
- return FRESULT.FR_OK
-
- def dir_open(self, dp: dirobj | t.CPtr, cluster: t.CUInt32T) -> FRESULT:
- dp.vol = self
- dp.start_cluster = cluster
- dp.cluster = cluster
- dp.sector = self.cluster_to_sector(cluster)
- dp.offset = 0
- dp.is_open = 1
- dp.lfn_ofs = 0xFFFFFFFF
- dp.lfn_cluster = 0
- self.winsect = 0xFFFFFFFFFFFFFFFF
- return FRESULT.FR_OK
-
- def dir_read_entry(self, dp: dirobj | t.CPtr, lfn_buf: t.CUInt16T | t.CPtr) -> FRESULT:
- lfn_started: t.CInt = 0
- dp.lfn_ofs = 0xFFFFFFFF
- dp.lfn_cluster = 0
- while True:
- epc: t.CUInt32T = self.entries_per_cluster()
- if dp.offset >= epc:
- res: FRESULT = self.dir_next_cluster(dp)
- if res != FRESULT.FR_OK: return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res2: FRESULT = self.win_read(entry_sector)
- if res2 != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- first_byte: t.CUInt8T = self.win[entry_offset_in_sector]
- if first_byte == SFN_FREE:
- return FRESULT.FR_NO_FILE
- attr: t.CUInt8T = self.win[entry_offset_in_sector + 11]
- if first_byte == SFN_DELETED:
- lfn_started = 0
- dp.lfn_ofs = 0xFFFFFFFF
- dp.lfn_cluster = 0
- dp.offset += 1
- continue
- if attr == LFN_ATTR:
- if lfn_buf:
- ord_val: t.CUInt8T = first_byte
- if ord_val & LFN_FLAG_LAST:
- lfn_started = 1
- dp.lfn_ofs = dp.offset
- dp.lfn_cluster = dp.cluster
- if lfn_started:
- entry_bytes: t.CUInt8T | t.CPtr = t.CUInt8T(c.Addr(self.win[entry_offset_in_sector]), t.CPtr)
- lfn_extract(entry_bytes, lfn_buf, ord_val)
- dp.offset += 1
- continue
- if attr == AM_VOL:
- dp.offset += 1
- continue
- if dp.lfn_ofs == 0xFFFFFFFF:
- dp.lfn_ofs = dp.offset
- dp.lfn_cluster = dp.cluster
- return FRESULT.FR_OK
-
- def dir_find(self, dp: dirobj | t.CPtr, name: t.CConst | t.CChar | t.CPtr, lfn_buf: t.CUInt16T | t.CPtr) -> FRESULT:
- sfn: t.CArray[t.CChar, 12]
- sfn_from_lfn(name, c.Addr(sfn[0]))
- _dbg_sfn: t.CArray[t.CChar, 16]
- _si: t.CInt
- for _si in range(11):
- _dbg_sfn[_si] = sfn[_si]
- _dbg_sfn[11] = 0
- serial.puts("[dir_find] searching for: ")
- serial.puts(name)
- serial.puts(" sfn=")
- serial.puts(c.Addr(_dbg_sfn[0]))
- serial.puts("\n")
- _db0: t.CArray[t.CChar, 120]
- viperlib.snprintf(c.Addr(_db0), 120, "[dir_find] dp: sect=0x%lx off=%lu clust=%lu winsect=0x%lx\n", dp.sector, dp.offset, dp.cluster, self.winsect)
- serial.puts(_db0)
- _find_count: t.CInt = 0
- while True:
- res: FRESULT = self.dir_read_entry(dp, lfn_buf)
- if res != FRESULT.FR_OK:
- _db2: t.CArray[t.CChar, 80]
- viperlib.snprintf(c.Addr(_db2), 80, "[dir_find] dir_read_entry failed res=%d offset=%lu\n", t.CInt(res), dp.offset)
- serial.puts(_db2)
- return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res2: FRESULT = self.win_read(entry_sector)
- if res2 != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- match_found: t.CInt = 1
- i: t.CInt
- for i in range(11):
- a: t.CChar = self.win[entry_offset_in_sector + i]
- b: t.CChar = sfn[i]
- if a >= 'a' and a <= 'z': a = a - 32
- if b >= 'a' and b <= 'z': b = b - 32
- if a != b:
- match_found = 0
- break
- if match_found: return FRESULT.FR_OK
- if dp.offset < 10:
- _db3: t.CArray[t.CChar, 80]
- _fb: t.CUInt8T = self.win[entry_offset_in_sector]
- _at: t.CUInt8T = self.win[entry_offset_in_sector + 11]
- viperlib.snprintf(c.Addr(_db3), 80, "[dir_find] off=%lu fb=0x%02x attr=0x%02x sfn=%.11s\n", dp.offset, _fb, _at, c.Addr(self.win[entry_offset_in_sector]))
- serial.puts(_db3)
- if lfn_buf and dp.lfn_ofs != 0xFFFFFFFF and dp.lfn_ofs < dp.offset:
- lfn_matched: t.CInt = 1
- li: t.CInt = 0
- for name_ch in name:
- lfn_ch: t.CUInt16T = c.Deref(t.CUInt16T(t.CUInt64T(lfn_buf) + li * 2, t.CPtr))
- lfn_low: t.CUInt16T = lfn_ch
- if lfn_low >= 65 and lfn_low <= 90: lfn_low = lfn_low + 32
- n_low: t.CUInt16T = t.CUInt16T(name_ch)
- if n_low >= 65 and n_low <= 90: n_low = n_low + 32
- if lfn_low != n_low:
- lfn_matched = 0
- break
- li += 1
- if lfn_matched:
- lfn_end: t.CUInt16T = c.Deref(t.CUInt16T(t.CUInt64T(lfn_buf) + li * 2, t.CPtr))
- if lfn_end == 0 or lfn_end == 0xFFFF:
- return FRESULT.FR_OK
- dp.offset += 1
-
- def dir_get_entry_info(self, dp: dirobj | t.CPtr, info: fileinfo | t.CPtr, lfn_buf: t.CUInt16T | t.CPtr) -> FRESULT:
- res: FRESULT = self._read_entry_from_dir(dp)
- if res != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- off: t.CUInt32T = entry_offset_in_sector
- raw_attr: t.CUInt8T = self.win[off + 11]
- info.attr = raw_attr
- info.ctime = _read16(c.Addr(self.win[0]), off + 14)
- info.cdate = _read16(c.Addr(self.win[0]), off + 16)
- info.adate = _read16(c.Addr(self.win[0]), off + 18)
- info.mtime = _read16(c.Addr(self.win[0]), off + 22)
- info.mdate = _read16(c.Addr(self.win[0]), off + 24)
- info.file_size = _read32(c.Addr(self.win[0]), off + 28)
- sfn_ptr: t.CChar | t.CPtr = t.CChar(c.Addr(self.win[0]) + off, t.CPtr)
- sfn_to_str(sfn_ptr, c.Addr(info.altname[0]))
- if dp.lfn_ofs != 0xFFFFFFFF and dp.lfn_ofs < dp.offset and lfn_buf:
- lfn_ptr: t.CUInt16T | t.CPtr = lfn_buf
- oi: t.CInt = 0
- for i in range(MAX_LFN):
- ch: t.CUInt16T = c.Deref(lfn_ptr)
- if ch == 0: break
- if ch < 0x80:
- info.fname[oi] = t.CChar(ch)
- else:
- oem_ch: t.CUInt16T = uni2oem_placeholder(ch, 0)
- if oem_ch < 0x80: info.fname[oi] = t.CChar(oem_ch)
- else: info.fname[oi] = '?'
- oi += 1
- lfn_ptr = t.CUInt16T(t.CUInt64T(lfn_ptr) + 2, t.CPtr)
- info.fname[oi] = 0
- else:
- sfn_to_str(sfn_ptr, c.Addr(info.fname[0]))
- return FRESULT.FR_OK
-
- def dir_add_entry(self, dp: dirobj | t.CPtr, name: t.CConst | t.CChar | t.CPtr, attr: t.CUInt8T, first_cluster: t.CUInt32T, file_size: t.CUInt32T, dir_sector_out: t.CUInt64T | t.CPtr, dir_offset_out: t.CUInt32T | t.CPtr) -> FRESULT:
- sfn: t.CArray[t.CChar, 12]
- sfn_from_lfn(name, c.Addr(sfn[0]))
- lfn_entries: t.CInt = 0
- len_: t.CInt = 0
- for _ in name: len_ += 1
- if len_ > 12:
- lfn_entries = (len_ + LFN_ENTRY_CHARS - 1) / LFN_ENTRY_CHARS
- total_entries: t.CInt = lfn_entries + 1
- cur_cluster: t.CUInt32T = dp.cluster
- cur_sector: t.CUInt64T = dp.sector
- cur_offset: t.CUInt32T = dp.offset
- found: t.CInt = 0
- consecutive: t.CInt = 0
- start_offset: t.CUInt32T = 0
- start_cluster: t.CUInt32T = 0
- epc: t.CUInt32T = self.entries_per_cluster()
- while not found:
- if cur_offset >= epc:
- next_clust: t.CUInt32T = self.cluster_get_next(cur_cluster)
- if next_clust == 0:
- new_clust: t.CUInt32T = self.cluster_extend(cur_cluster)
- if new_clust == 0: return FRESULT.FR_DENIED
- self._zero_cluster(new_clust)
- cur_cluster = new_clust
- cur_sector = self.cluster_to_sector(new_clust)
- cur_offset = 0
- else:
- cur_cluster = next_clust
- cur_sector = self.cluster_to_sector(next_clust)
- cur_offset = 0
- es: t.CUInt64T = cur_sector + (cur_offset / (512 / ENTRY_SIZE))
- eo: t.CUInt32T = (cur_offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res: FRESULT = self.win_read(es)
- if res != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- first_byte: t.CUInt8T = self.win[eo]
- if first_byte == SFN_FREE or first_byte == SFN_DELETED:
- if consecutive == 0:
- start_offset = cur_offset
- start_cluster = cur_cluster
- consecutive += 1
- if consecutive >= total_entries:
- found = 1
- break
- else:
- consecutive = 0
- cur_offset += 1
- write_cluster: t.CUInt32T = start_cluster
- write_sector: t.CUInt64T = self.cluster_to_sector(start_cluster)
- write_offset: t.CUInt32T = start_offset
- if lfn_entries > 0:
- le: t.CInt
- for le in range(lfn_entries):
- if write_offset >= epc:
- next_c: t.CUInt32T = self.cluster_get_next(write_cluster)
- if next_c == 0: return FRESULT.FR_INT_ERR
- write_cluster = next_c
- write_sector = self.cluster_to_sector(next_c)
- write_offset = 0
- es2: t.CUInt64T = write_sector + (write_offset / (512 / ENTRY_SIZE))
- eo2: t.CUInt32T = (write_offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res2: FRESULT = self.win_read(es2)
- if res2 != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- ord_val: t.CUInt8T = t.CUInt8T(lfn_entries - le)
- if le == 0: ord_val |= LFN_FLAG_LAST
- self.win[eo2 + 0] = ord_val
- self.win[eo2 + 11] = LFN_ATTR
- self.win[eo2 + 12] = 0
- self.win[eo2 + 13] = sfn_checksum(c.Addr(sfn[0]))
- self.win[eo2 + 26] = 0
- self.win[eo2 + 27] = 0
- base: t.CInt = (lfn_entries - 1 - le) * LFN_ENTRY_CHARS
- j: t.CInt
- for j in range(LFN_ENTRY_CHARS):
- idx: t.CInt = base + j
- ch: t.CUInt16T
- if idx < len_: ch = t.CUInt16T(name[idx])
- elif idx == len_: ch = 0x0000
- else: ch = 0xFFFF
- if j < 5:
- self.win[eo2 + 1 + j * 2] = t.CUInt8T(ch & 0xFF)
- self.win[eo2 + 2 + j * 2] = t.CUInt8T((ch >> 8) & 0xFF)
- elif j < 11:
- self.win[eo2 + 14 + (j - 5) * 2] = t.CUInt8T(ch & 0xFF)
- self.win[eo2 + 15 + (j - 5) * 2] = t.CUInt8T((ch >> 8) & 0xFF)
- else:
- self.win[eo2 + 28 + (j - 11) * 2] = t.CUInt8T(ch & 0xFF)
- self.win[eo2 + 29 + (j - 11) * 2] = t.CUInt8T((ch >> 8) & 0xFF)
- self.win_dirty = 1
- self.win_flush()
- write_offset += 1
- if write_offset >= epc:
- next_c2: t.CUInt32T = self.cluster_get_next(write_cluster)
- if next_c2 == 0: return FRESULT.FR_INT_ERR
- write_cluster = next_c2
- write_sector = self.cluster_to_sector(next_c2)
- write_offset = 0
- es3: t.CUInt64T = write_sector + (write_offset / (512 / ENTRY_SIZE))
- eo3: t.CUInt32T = (write_offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res3: FRESULT = self.win_read(es3)
- if res3 != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- string.memset(c.Addr(self.win[eo3]), 0, 32)
- i: t.CInt
- for i in range(11): self.win[eo3 + i] = sfn[i]
- self.win[eo3 + 11] = attr
- self.win[eo3 + 12] = 0
- self.win[eo3 + 13] = 0
- self._write_dirent_now(eo3)
- _write16(c.Addr(self.win[0]), eo3 + 20, t.CUInt16T((first_cluster >> 16) & 0xFFFF))
- _write16(c.Addr(self.win[0]), eo3 + 26, t.CUInt16T(first_cluster & 0xFFFF))
- _write32(c.Addr(self.win[0]), eo3 + 28, file_size)
- self.win_dirty = 1
- self.win_flush()
- c.Set(t.CUInt64T(dir_sector_out, t.CPtr), es3)
- c.Set(t.CUInt32T(dir_offset_out, t.CPtr), eo3)
- return FRESULT.FR_OK
-
- def dir_update_entry(self, dir_sector: t.CUInt64T, dir_offset: t.CUInt32T, first_cluster: t.CUInt32T, file_size: t.CUInt32T, attr: t.CUInt8T) -> FRESULT:
- res: FRESULT = self.win_read(dir_sector)
- if res != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- self.win[dir_offset + 11] = attr
- _write16(c.Addr(self.win[0]), dir_offset + 20, t.CUInt16T((first_cluster >> 16) & 0xFFFF))
- _write16(c.Addr(self.win[0]), dir_offset + 26, t.CUInt16T(first_cluster & 0xFFFF))
- _write32(c.Addr(self.win[0]), dir_offset + 28, file_size)
- self._write_dirent_now(dir_offset)
- self.win_dirty = 1
- return self.win_flush()
-
- def dir_delete_entry(self, dp: dirobj | t.CPtr) -> FRESULT:
- start_off: t.CUInt32T = dp.lfn_ofs if dp.lfn_ofs != 0xFFFFFFFF else dp.offset
- end_off: t.CUInt32T = dp.offset
- cur_off: t.CUInt32T = start_off
- cur_cluster: t.CUInt32T = dp.lfn_cluster if dp.lfn_ofs != 0xFFFFFFFF else dp.cluster
- epc: t.CUInt32T = self.entries_per_cluster()
- while cur_off <= end_off:
- off_in_clus: t.CUInt32T = cur_off % epc
- if off_in_clus == 0 and cur_off != start_off:
- next_c: t.CUInt32T = self.cluster_get_next(cur_cluster)
- if next_c == 0: return FRESULT.FR_INT_ERR
- cur_cluster = next_c
- sector_base: t.CUInt64T = self.cluster_to_sector(cur_cluster)
- es: t.CUInt64T = sector_base + t.CUInt64T(off_in_clus / (512 / ENTRY_SIZE))
- eo: t.CUInt32T = (off_in_clus % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res: FRESULT = self.win_read(es)
- if res != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- self.win[eo] = SFN_DELETED
- self.win_dirty = 1
- res2: FRESULT = self.win_flush()
- if res2 != FRESULT.FR_OK: return res2
- cur_off += 1
- return FRESULT.FR_OK
-
- def follow_path(self, dp: dirobj | t.CPtr, path: t.CConst | t.CChar | t.CPtr, lfn_buf: t.CUInt16T | t.CPtr) -> FRESULT:
- cluster: t.CUInt32T = self.root_cluster
- pi: t.CInt = 0
- if path[0] >= '0' and path[0] <= '9':
- if path[1] == ':':
- pi = 2
- elif path[1] == 0:
- self.dir_open(dp, cluster)
- return FRESULT.FR_OK
- elif (path[0] >= 'A' and path[0] <= 'Z') or (path[0] >= 'a' and path[0] <= 'z'):
- if path[1] == ':':
- pi = 2
- if path[pi] == '/' or path[pi] == '\\': pi += 1
- while path[pi] == '/' or path[pi] == '\\': pi += 1
- if path[pi] == 0:
- self.dir_open(dp, cluster)
- return FRESULT.FR_OK
- while True:
- component: t.CArray[t.CChar, 256]
- ci: t.CInt = 0
- while path[pi] != 0 and path[pi] != '/' and path[pi] != '\\' and ci < 255:
- component[ci] = path[pi]
- ci += 1; pi += 1
- component[ci] = 0
- if ci == 0: break
- while path[pi] == '/' or path[pi] == '\\': pi += 1
- if ci == 2 and component[0] == '.' and component[1] == '.':
- if cluster == self.root_cluster:
- pass
- else:
- self.dir_open(dp, cluster)
- dotdot_name: t.CArray[t.CChar, 256]
- dotdot_name[0] = '.'; dotdot_name[1] = '.'; dotdot_name[2] = 0
- res_dd: FRESULT = self.dir_find(dp, c.Addr(dotdot_name[0]), lfn_buf)
- if res_dd == FRESULT.FR_OK:
- self._read_entry_from_dir(dp)
- dd_eo: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- dd_off: t.CUInt32T = dd_eo
- dd_ch: t.CUInt32T = t.CUInt32T(self.win[dd_off + 20]) | (t.CUInt32T(self.win[dd_off + 21]) << 8)
- dd_cl: t.CUInt32T = t.CUInt32T(self.win[dd_off + 26]) | (t.CUInt32T(self.win[dd_off + 27]) << 8)
- dd_clus: t.CUInt32T = (dd_ch << 16) | dd_cl
- if dd_clus == 0: dd_clus = self.root_cluster
- cluster = dd_clus
- if path[pi] == 0:
- self.dir_open(dp, cluster)
- return FRESULT.FR_OK
- continue
- else:
- cluster = self.root_cluster
- if path[pi] == 0:
- self.dir_open(dp, cluster)
- return FRESULT.FR_OK
- continue
- if path[pi] == 0:
- self.dir_open(dp, cluster)
- return FRESULT.FR_OK
- continue
- if ci == 1 and component[0] == '.':
- if path[pi] == 0:
- self.dir_open(dp, cluster)
- return FRESULT.FR_OK
- continue
- self.dir_open(dp, cluster)
- res: FRESULT = self.dir_find(dp, c.Addr(component[0]), lfn_buf)
- if res != FRESULT.FR_OK: return res
- self._read_entry_from_dir(dp)
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- off: t.CUInt32T = entry_offset_in_sector
- entry_attr: t.CUInt8T = self.win[off + 11]
- clus_hi: t.CUInt32T = t.CUInt32T(self.win[off + 20]) | (t.CUInt32T(self.win[off + 21]) << 8)
- clus_lo: t.CUInt32T = t.CUInt32T(self.win[off + 26]) | (t.CUInt32T(self.win[off + 27]) << 8)
- entry_cluster: t.CUInt32T = (clus_hi << 16) | clus_lo
- if path[pi] == 0: return FRESULT.FR_OK
- if not (entry_attr & AM_DIR): return FRESULT.FR_NO_PATH
- cluster = entry_cluster
- return FRESULT.FR_NO_PATH
-
- def mkdir_create_dir_entries(self, new_cluster: t.CUInt32T, parent_cluster: t.CUInt32T) -> FRESULT:
- sector: t.CUInt64T = self.cluster_to_sector(new_cluster)
- res: FRESULT = self.win_read(sector)
- if res != FRESULT.FR_OK: return res
- string.memset(c.Addr(self.win[0]), 0, 512)
- self.win[0] = '.'; self.win[1] = ' '; self.win[2] = ' '; self.win[3] = ' '
- self.win[4] = ' '; self.win[5] = ' '; self.win[6] = ' '; self.win[7] = ' '
- self.win[8] = ' '; self.win[9] = ' '; self.win[10] = ' '
- self.win[11] = AM_DIR
- _write16(c.Addr(self.win[0]), 20, t.CUInt16T((new_cluster >> 16) & 0xFFFF))
- _write16(c.Addr(self.win[0]), 26, t.CUInt16T(new_cluster & 0xFFFF))
- self._write_dirent_now(0)
- self.win[32] = '.'; self.win[33] = '.'; self.win[34] = ' '; self.win[35] = ' '
- self.win[36] = ' '; self.win[37] = ' '; self.win[38] = ' '; self.win[39] = ' '
- self.win[40] = ' '; self.win[41] = ' '; self.win[42] = ' '
- self.win[11 + 32] = AM_DIR
- _write16(c.Addr(self.win[0]), 20 + 32, t.CUInt16T((parent_cluster >> 16) & 0xFFFF))
- _write16(c.Addr(self.win[0]), 26 + 32, t.CUInt16T(parent_cluster & 0xFFFF))
- self._write_dirent_now(32)
- self.win_dirty = 1
- return self.win_flush()
-
- def file_open(self, path: t.CConst | t.CChar | t.CPtr, mode: t.CUInt8T) -> fileobj | t.CPtr:
- self.last_error = FRESULT.FR_OK
- if not self.mounted:
- self.last_error = FRESULT.FR_NOT_ENABLED
- return None
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if mode & FA_CREATE_NEW:
- if res == FRESULT.FR_OK:
- self.last_error = FRESULT.FR_EXIST
- return None
- if res != FRESULT.FR_NO_FILE and res != FRESULT.FR_NO_PATH:
- self.last_error = res
- return None
- need_create: t.CInt = 0
- if (mode & FA_CREATE_NEW): need_create = 1
- if (mode & FA_OPEN_ALWAYS) and res == FRESULT.FR_NO_FILE: need_create = 1
- if (mode & FA_CREATE_ALWAYS) and res == FRESULT.FR_NO_FILE: need_create = 1
- if need_create:
- pp: t.CArray[t.CChar, 260]
- fn: t.CArray[t.CChar, 256]
- _split_path(path, c.Addr(pp[0]), c.Addr(fn[0]))
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res2: FRESULT = self.follow_path(c.Addr(dp), c.Addr(pp[0]), t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res2 != FRESULT.FR_OK:
- self.last_error = res2
- return None
- nc: t.CUInt32T = 0
- if mode & FA_WRITE:
- nc = self.cluster_alloc()
- if nc == 0:
- self.last_error = FRESULT.FR_DENIED
- return None
- self._zero_cluster(nc)
- ds: t.CUInt64T = 0
- do: t.CUInt32T = 0
- res3: FRESULT = self.dir_add_entry(c.Addr(dp), c.Addr(fn[0]), AM_ARC, nc, 0, c.Addr(ds), c.Addr(do))
- if res3 != FRESULT.FR_OK:
- if nc >= 2: self.cluster_free_chain(nc)
- self.last_error = res3
- return None
- fp: fileobj | t.CPtr = handle_alloc()
- if fp is None:
- if nc >= 2: self.cluster_free_chain(nc)
- self.last_error = FRESULT.FR_TOO_MANY_OPEN_FILES
- return None
- fp.vol = self
- fp.is_open = 1
- fp.is_dir = 0
- fp.first_cluster = nc
- fp.current_cluster = nc
- fp.file_size = 0
- fp.file_pos = 0
- fp.dir_sector = ds
- fp.dir_offset = do
- fp.attr = AM_ARC
- fp.flags = mode
- fp.err = 0
- fp.lock_count = 0
- fp.buf_sect = 0xFFFFFFFFFFFFFFFF
- fp.buf_dirty = 0
- if mode & FA_WRITE:
- lock_acquire(ds, do, 1)
- fp.lock_count = 1
- return fp
- if res != FRESULT.FR_OK:
- self.last_error = res
- return None
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK:
- self.last_error = res_wr
- return None
- off: t.CUInt32T = entry_offset_in_sector
- entry_attr: t.CUInt8T = self.win[off + 11]
- if entry_attr & AM_DIR:
- self.last_error = FRESULT.FR_DENIED
- return None
- if mode & FA_WRITE:
- if entry_attr & AM_RDO:
- self.last_error = FRESULT.FR_DENIED
- return None
- lres: FRESULT = lock_check(entry_sector, entry_offset_in_sector, mode)
- if lres != FRESULT.FR_OK:
- self.last_error = lres
- return None
- clus_hi: t.CUInt32T = t.CUInt32T(self.win[off + 20]) | (t.CUInt32T(self.win[off + 21]) << 8)
- clus_lo: t.CUInt32T = t.CUInt32T(self.win[off + 26]) | (t.CUInt32T(self.win[off + 27]) << 8)
- entry_cluster: t.CUInt32T = (clus_hi << 16) | clus_lo
- entry_size: t.CUInt32T = _read32(c.Addr(self.win[0]), off + 28)
- fp2: fileobj | t.CPtr = handle_alloc()
- if fp2 is None:
- self.last_error = FRESULT.FR_TOO_MANY_OPEN_FILES
- return None
- fp2.vol = self
- fp2.is_open = 1
- fp2.is_dir = 0
- fp2.first_cluster = entry_cluster
- fp2.current_cluster = entry_cluster
- fp2.file_size = entry_size
- fp2.file_pos = 0
- fp2.dir_sector = entry_sector
- fp2.dir_offset = entry_offset_in_sector
- fp2.attr = entry_attr
- fp2.flags = mode
- fp2.err = 0
- fp2.lock_count = 0
- fp2.buf_sect = 0xFFFFFFFFFFFFFFFF
- fp2.buf_dirty = 0
- if mode & FA_WRITE:
- lock_acquire(entry_sector, entry_offset_in_sector, 1)
- fp2.lock_count = 1
- if mode & FA_CREATE_ALWAYS:
- if entry_cluster >= 2: self.cluster_free_chain(entry_cluster)
- fp2.first_cluster = 0
- fp2.current_cluster = 0
- fp2.file_size = 0
- fp2.file_pos = 0
- self.dir_update_entry(entry_sector, entry_offset_in_sector, 0, 0, entry_attr)
- if mode & FA_OPEN_APPEND:
- fp2.file_pos = entry_size
- fp2.current_cluster = self.file_cluster_seek(entry_cluster, entry_size)
- return fp2
-
- def file_delete(self, path: t.CConst | t.CChar | t.CPtr) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- off: t.CUInt32T = entry_offset_in_sector
- entry_attr: t.CUInt8T = self.win[off + 11]
- if entry_attr & AM_RDO: return FRESULT.FR_DENIED
- if entry_attr & AM_DIR: return FRESULT.FR_DENIED
- lres: FRESULT = lock_check(entry_sector, entry_offset_in_sector, FA_WRITE)
- if lres != FRESULT.FR_OK: return FRESULT.FR_LOCKED
- clus_hi: t.CUInt32T = t.CUInt32T(self.win[off + 20]) | (t.CUInt32T(self.win[off + 21]) << 8)
- clus_lo: t.CUInt32T = t.CUInt32T(self.win[off + 26]) | (t.CUInt32T(self.win[off + 27]) << 8)
- entry_cluster: t.CUInt32T = (clus_hi << 16) | clus_lo
- res2: FRESULT = self.dir_delete_entry(c.Addr(dp))
- if res2 != FRESULT.FR_OK: return res2
- if entry_cluster >= 2: self.cluster_free_chain(entry_cluster)
- return FRESULT.FR_OK
-
- def file_rename(self, old_path: t.CConst | t.CChar | t.CPtr, new_path: t.CConst | t.CChar | t.CPtr) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), old_path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- off: t.CUInt32T = entry_offset_in_sector
- entry_attr: t.CUInt8T = self.win[off + 11]
- clus_hi: t.CUInt32T = t.CUInt32T(self.win[off + 20]) | (t.CUInt32T(self.win[off + 21]) << 8)
- clus_lo: t.CUInt32T = t.CUInt32T(self.win[off + 26]) | (t.CUInt32T(self.win[off + 27]) << 8)
- entry_cluster: t.CUInt32T = (clus_hi << 16) | clus_lo
- entry_size: t.CUInt32T = _read32(c.Addr(self.win[0]), off + 28)
- lres: FRESULT = lock_check(entry_sector, entry_offset_in_sector, FA_WRITE)
- if lres != FRESULT.FR_OK: return FRESULT.FR_LOCKED
- new_parent: t.CArray[t.CChar, 260]
- new_fname: t.CArray[t.CChar, 256]
- _split_path(new_path, c.Addr(new_parent[0]), c.Addr(new_fname[0]))
- dp2: dirobj
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res2: FRESULT = self.follow_path(c.Addr(dp2), c.Addr(new_parent[0]), t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res2 != FRESULT.FR_OK: return FRESULT.FR_NO_PATH
- new_dir_sector: t.CUInt64T = 0
- new_dir_offset: t.CUInt32T = 0
- res3: FRESULT = self.dir_add_entry(c.Addr(dp2), c.Addr(new_fname[0]), entry_attr, entry_cluster, entry_size, c.Addr(new_dir_sector), c.Addr(new_dir_offset))
- if res3 != FRESULT.FR_OK: return res3
- res4: FRESULT = self.dir_delete_entry(c.Addr(dp))
- if res4 != FRESULT.FR_OK: return res4
- return FRESULT.FR_OK
-
- def file_stat(self, path: t.CConst | t.CChar | t.CPtr, info: fileinfo | t.CPtr) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- return self.dir_get_entry_info(c.Addr(dp), info, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
-
- def dir_make(self, path: t.CConst | t.CChar | t.CPtr) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res == FRESULT.FR_OK: return FRESULT.FR_EXIST
- parent_path: t.CArray[t.CChar, 260]
- dir_name: t.CArray[t.CChar, 256]
- _split_path(path, c.Addr(parent_path[0]), c.Addr(dir_name[0]))
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res2: FRESULT = self.follow_path(c.Addr(dp), c.Addr(parent_path[0]), t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res2 != FRESULT.FR_OK: return FRESULT.FR_NO_PATH
- parent_cluster: t.CUInt32T = dp.cluster
- new_cluster: t.CUInt32T = self.cluster_alloc()
- if new_cluster == 0: return FRESULT.FR_DENIED
- self._zero_cluster(new_cluster)
- dir_sector: t.CUInt64T = 0
- dir_offset: t.CUInt32T = 0
- res3: FRESULT = self.dir_add_entry(c.Addr(dp), c.Addr(dir_name[0]), AM_DIR, new_cluster, 0, c.Addr(dir_sector), c.Addr(dir_offset))
- if res3 != FRESULT.FR_OK:
- self.cluster_free_chain(new_cluster)
- return res3
- res4: FRESULT = self.mkdir_create_dir_entries(new_cluster, parent_cluster)
- if res4 != FRESULT.FR_OK:
- self.cluster_free_chain(new_cluster)
- return res4
- return FRESULT.FR_OK
-
- def dir_open_path(self, path: t.CConst | t.CChar | t.CPtr, dp: dirobj | t.CPtr) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- pi: t.CInt = 0
- if path[0] >= '0' and path[0] <= '9':
- if path[1] == ':' or path[1] == 0:
- pi = 2
- if path[1] == 0:
- self.dir_open(dp, self.root_cluster)
- return FRESULT.FR_OK
- if path[pi] == '/' or path[pi] == '\\': pi += 1
- while path[pi] == '/' or path[pi] == '\\': pi += 1
- is_root: t.CInt = 1 if path[pi] == 0 else 0
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(dp, path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- if is_root: return FRESULT.FR_OK
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- off: t.CUInt32T = entry_offset_in_sector
- entry_attr: t.CUInt8T = self.win[off + 11]
- if not (entry_attr & AM_DIR): return FRESULT.FR_NO_PATH
- clus_hi: t.CUInt32T = t.CUInt32T(self.win[off + 20]) | (t.CUInt32T(self.win[off + 21]) << 8)
- clus_lo: t.CUInt32T = t.CUInt32T(self.win[off + 26]) | (t.CUInt32T(self.win[off + 27]) << 8)
- entry_cluster: t.CUInt32T = (clus_hi << 16) | clus_lo
- return self.dir_open(dp, entry_cluster)
-
- def dir_read(self, dp: dirobj | t.CPtr, info: fileinfo | t.CPtr) -> FRESULT:
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.dir_read_entry(dp, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- res2: FRESULT = self.dir_get_entry_info(dp, info, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- dp.offset += 1
- return res2
-
- def dir_remove(self, path: t.CConst | t.CChar | t.CPtr) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- off: t.CUInt32T = entry_offset_in_sector
- entry_attr: t.CUInt8T = self.win[off + 11]
- if not (entry_attr & AM_DIR): return FRESULT.FR_NO_PATH
- clus_hi: t.CUInt32T = t.CUInt32T(self.win[off + 20]) | (t.CUInt32T(self.win[off + 21]) << 8)
- clus_lo: t.CUInt32T = t.CUInt32T(self.win[off + 26]) | (t.CUInt32T(self.win[off + 27]) << 8)
- entry_cluster: t.CUInt32T = (clus_hi << 16) | clus_lo
- if entry_cluster >= 2:
- check_dp: dirobj
- self.dir_open(c.Addr(check_dp), entry_cluster)
- lfn_buf2: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf2), 0, 256 * 2)
- while True:
- check_res: FRESULT = self.dir_read_entry(c.Addr(check_dp), t.CUInt16T(c.Addr(lfn_buf2[0]), t.CPtr))
- if check_res != FRESULT.FR_OK: break
- c_off: t.CUInt32T = (check_dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- c_sec: t.CUInt64T = check_dp.sector + (check_dp.offset / (512 / ENTRY_SIZE))
- self.win_read(c_sec)
- c_name0: t.CUInt8T = self.win[c_off]
- c_name1: t.CUInt8T = self.win[c_off + 1]
- check_dp.offset += 1
- if c_name0 == '.' and (c_name1 == '.' or c_name1 == 0x20):
- continue
- return FRESULT.FR_DENIED
- lres: FRESULT = lock_check(entry_sector, entry_offset_in_sector, FA_WRITE)
- if lres != FRESULT.FR_OK: return FRESULT.FR_LOCKED
- res2: FRESULT = self.dir_delete_entry(c.Addr(dp))
- if res2 != FRESULT.FR_OK: return res2
- if entry_cluster >= 2: self.cluster_free_chain(entry_cluster)
- return FRESULT.FR_OK
-
- def chmod(self, path: t.CConst | t.CChar | t.CPtr, attr: t.CUInt8T, mask: t.CUInt8T) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- off: t.CUInt32T = entry_offset_in_sector
- old_attr: t.CUInt8T = self.win[off + 11]
- new_attr: t.CUInt8T = (old_attr & ~mask) | (attr & mask)
- self.win[off + 11] = new_attr
- self.win_dirty = 1
- return self.win_flush()
-
- def utime(self, path: t.CConst | t.CChar | t.CPtr, mtime: t.CUInt16T, mdate: t.CUInt16T) -> FRESULT:
- if not self.mounted: return FRESULT.FR_NOT_ENABLED
- dp: dirobj
- lfn_buf: t.CArray[t.CUInt16T, 256]
- string.memset(c.Addr(lfn_buf), 0, 256 * 2)
- res: FRESULT = self.follow_path(c.Addr(dp), path, t.CUInt16T(c.Addr(lfn_buf[0]), t.CPtr))
- if res != FRESULT.FR_OK: return res
- entry_sector: t.CUInt64T = dp.sector + (dp.offset / (512 / ENTRY_SIZE))
- entry_offset_in_sector: t.CUInt32T = (dp.offset % (512 / ENTRY_SIZE)) * ENTRY_SIZE
- res_wr: FRESULT = self.win_read(entry_sector)
- if res_wr != FRESULT.FR_OK: return FRESULT.FR_DISK_ERR
- off: t.CUInt32T = entry_offset_in_sector
- self.win[off + 22] = t.CUInt8T(mtime & 0xFF)
- self.win[off + 23] = t.CUInt8T((mtime >> 8) & 0xFF)
- self.win[off + 24] = t.CUInt8T(mdate & 0xFF)
- self.win[off + 25] = t.CUInt8T((mdate >> 8) & 0xFF)
- self.win[off + 18] = t.CUInt8T(mdate & 0xFF)
- self.win[off + 19] = t.CUInt8T((mdate >> 8) & 0xFF)
- self.win_dirty = 1
- return self.win_flush()
-
-
-@t.Object
-class fileobj:
- vol: volinfo | t.CPtr
- is_open: t.CInt = 0
- is_dir: t.CInt = 0
- first_cluster: t.CUInt32T = 0
- current_cluster: t.CUInt32T = 0
- file_size: t.CUInt32T = 0
- file_pos: t.CUInt32T = 0
- dir_sector: t.CUInt64T = 0
- dir_offset: t.CUInt32T = 0
- attr: t.CUInt8T = 0
- ctime: t.CUInt16T = 0
- cdate: t.CUInt16T = 0
- mtime: t.CUInt16T = 0
- mdate: t.CUInt16T = 0
- adate: t.CUInt16T = 0
- flags: t.CUInt8T = 0
- err: t.CUInt8T = 0
- lock_count: t.CInt = 0
- buf: t.CArray[t.CUInt8T, 512]
- buf_sect: t.CUInt64T = 0
- buf_dirty: t.CInt = 0
-
- def buf_flush(self) -> FRESULT:
- if not self.buf_dirty: return FRESULT.FR_OK
- abs_sect: t.CUInt64T = t.CUInt64T(self.buf_sect) + t.CUInt64T(self.vol.hidden_sectors)
- self.vol.lock.lock()
- res: DRESULT = diskio.write(self.vol.pdrv, c.Addr(self.buf[0]), t.CUInt32T(abs_sect), 1)
- self.vol.lock.unlock()
- if res != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.buf_dirty = 0
- return FRESULT.FR_OK
-
- def buf_read(self, sector: t.CUInt64T) -> FRESULT:
- if self.buf_sect == sector: return FRESULT.FR_OK
- if self.buf_dirty:
- res: FRESULT = self.buf_flush()
- if res != FRESULT.FR_OK: return res
- abs_sect: t.CUInt64T = sector + t.CUInt64T(self.vol.hidden_sectors)
- self.vol.lock.lock()
- res2: DRESULT = diskio.read(self.vol.pdrv, c.Addr(self.buf[0]), t.CUInt32T(abs_sect), 1)
- self.vol.lock.unlock()
- if res2 != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.buf_sect = sector
- return FRESULT.FR_OK
-
- def close(self) -> FRESULT:
- if not self.is_open: return FRESULT.FR_INVALID_OBJECT
- res: FRESULT = self.buf_flush()
- if res != FRESULT.FR_OK: return res
- if self.flags & FA_WRITE:
- self.vol.dir_update_entry(self.dir_sector, self.dir_offset, self.first_cluster, self.file_size, self.attr)
- if self.lock_count > 0: lock_release(self.dir_sector, self.dir_offset)
- self.is_open = 0
- self.lock_count = 0
- return FRESULT.FR_OK
-
- def read(self, buff: t.CVoid | t.CPtr, btr: t.CUInt32T, br: t.CUInt32T | t.CPtr) -> FRESULT:
- if not self.is_open: return FRESULT.FR_INVALID_OBJECT
- if not (self.flags & FA_READ): return FRESULT.FR_DENIED
- c.Set(t.CUInt32T(br, t.CPtr), 0)
- vol: volinfo | t.CPtr = self.vol
- remaining: t.CUInt32T = btr
- buf_ptr: t.CUInt8T | t.CPtr = t.CUInt8T(buff, t.CPtr)
- total_read: t.CUInt32T = 0
- while remaining > 0:
- if self.file_pos >= self.file_size: break
- if self.first_cluster < 2: break
- if self.current_cluster < 2 or vol.is_eoc(self.current_cluster): break
- cluster_offset: t.CUInt32T = self.file_pos % vol.cluster_size
- sector_in_cluster: t.CUInt32T = cluster_offset / 512
- offset_in_sector: t.CUInt32T = cluster_offset % 512
- sector: t.CUInt64T = vol.cluster_to_sector(self.current_cluster) + t.CUInt64T(sector_in_cluster)
- can_read_in_sector: t.CUInt32T = 512 - offset_in_sector
- can_read: t.CUInt32T = can_read_in_sector
- if can_read > remaining: can_read = remaining
- if can_read > self.file_size - self.file_pos: can_read = self.file_size - self.file_pos
- if can_read == 0: break
- if offset_in_sector == 0 and can_read >= 512:
- abs_sect: t.CUInt64T = sector + t.CUInt64T(vol.hidden_sectors)
- vol.lock.lock()
- res: DRESULT = diskio.read(vol.pdrv, buf_ptr, t.CUInt32T(abs_sect), 1)
- vol.lock.unlock()
- if res != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- else:
- res2: FRESULT = self.buf_read(sector)
- if res2 != FRESULT.FR_OK: return res2
- string.memcpy(buf_ptr, c.Addr(self.buf[offset_in_sector]), can_read)
- buf_ptr += can_read
- self.file_pos += can_read
- total_read += can_read
- remaining -= can_read
- if self.file_pos % vol.cluster_size == 0:
- next_c: t.CUInt32T = vol.cluster_get_next(self.current_cluster)
- if next_c == 0: break
- self.current_cluster = next_c
- c.Set(t.CUInt32T(br, t.CPtr), total_read)
- return FRESULT.FR_OK
-
- def _extend_to(self, target_pos: t.CUInt32T) -> FRESULT:
- if self.first_cluster < 2:
- new_c: t.CUInt32T = self.vol.cluster_alloc()
- if new_c == 0: return FRESULT.FR_DENIED
- self.first_cluster = new_c
- self.current_cluster = new_c
- self.vol._zero_cluster(new_c)
- cur_pos: t.CUInt32T = 0
- clust: t.CUInt32T = self.first_cluster
- while cur_pos + self.vol.cluster_size <= target_pos:
- next_c: t.CUInt32T = self.vol.cluster_get_next(clust)
- if next_c == 0:
- new_c2: t.CUInt32T = self.vol.cluster_extend(clust)
- if new_c2 == 0: return FRESULT.FR_DENIED
- self.vol._zero_cluster(new_c2)
- next_c = new_c2
- clust = next_c
- cur_pos += self.vol.cluster_size
- self.current_cluster = clust
- return FRESULT.FR_OK
-
- def write(self, buff: t.CConst | t.CVoid | t.CPtr, btw: t.CUInt32T, bw: t.CUInt32T | t.CPtr) -> FRESULT:
- if not self.is_open: return FRESULT.FR_INVALID_OBJECT
- if not (self.flags & FA_WRITE): return FRESULT.FR_DENIED
- c.Set(t.CUInt32T(bw, t.CPtr), 0)
- vol: volinfo | t.CPtr = self.vol
- remaining: t.CUInt32T = btw
- buf_ptr: t.CConst | t.CUInt8T | t.CPtr = t.CUInt8T(buff, t.CPtr)
- total_written: t.CUInt32T = 0
- while remaining > 0:
- if self.first_cluster < 2:
- new_c: t.CUInt32T = vol.cluster_alloc()
- if new_c == 0: return FRESULT.FR_DENIED
- self.first_cluster = new_c
- self.current_cluster = new_c
- vol._zero_cluster(new_c)
- if self.current_cluster < 2 or vol.is_eoc(self.current_cluster):
- last_c: t.CUInt32T = self.current_cluster
- if self.first_cluster >= 2 and self.current_cluster < 2:
- last_c = vol.file_find_last_cluster(self.first_cluster)
- new_c2: t.CUInt32T = vol.cluster_extend(last_c)
- if new_c2 == 0: return FRESULT.FR_DENIED
- if self.first_cluster < 2: self.first_cluster = new_c2
- self.current_cluster = new_c2
- vol._zero_cluster(new_c2)
- cluster_offset: t.CUInt32T = self.file_pos % vol.cluster_size
- sector_in_cluster: t.CUInt32T = cluster_offset / 512
- offset_in_sector: t.CUInt32T = cluster_offset % 512
- sector: t.CUInt64T = vol.cluster_to_sector(self.current_cluster) + t.CUInt64T(sector_in_cluster)
- can_write_in_sector: t.CUInt32T = 512 - offset_in_sector
- can_write: t.CUInt32T = can_write_in_sector
- if can_write > remaining: can_write = remaining
- if can_write == 0: break
- if offset_in_sector == 0 and can_write >= 512:
- abs_sect: t.CUInt64T = sector + t.CUInt64T(vol.hidden_sectors)
- vol.lock.lock()
- res: DRESULT = diskio.write(vol.pdrv, buf_ptr, t.CUInt32T(abs_sect), 1)
- vol.lock.unlock()
- if res != DRESULT.RES_OK: return FRESULT.FR_DISK_ERR
- self.buf_sect = 0xFFFFFFFFFFFFFFFF
- self.buf_dirty = 0
- else:
- res2: FRESULT = self.buf_read(sector)
- if res2 != FRESULT.FR_OK: return res2
- string.memcpy(c.Addr(self.buf[offset_in_sector]), buf_ptr, can_write)
- self.buf_dirty = 1
- res3: FRESULT = self.buf_flush()
- if res3 != FRESULT.FR_OK: return res3
- buf_ptr += can_write
- self.file_pos += can_write
- total_written += can_write
- remaining -= can_write
- if self.file_pos > self.file_size: self.file_size = self.file_pos
- if self.file_pos % vol.cluster_size == 0:
- next_c: t.CUInt32T = vol.cluster_get_next(self.current_cluster)
- if next_c != 0: self.current_cluster = next_c
- c.Set(t.CUInt32T(bw, t.CPtr), total_written)
- return FRESULT.FR_OK
-
- def seek(self, offset: t.CUInt32T) -> FRESULT:
- if not self.is_open: return FRESULT.FR_INVALID_OBJECT
- if offset > self.file_size:
- if not (self.flags & FA_WRITE): return FRESULT.FR_DENIED
- gap: t.CUInt32T = offset - self.file_size
- res: FRESULT = self._extend_to(offset)
- if res != FRESULT.FR_OK: return res
- old_size: t.CUInt32T = self.file_size
- zero_buf: t.CArray[t.CUInt8T, 512]
- string.memset(c.Addr(zero_buf[0]), 0, 512)
- self.file_pos = old_size
- while gap > 0:
- chunk: t.CUInt32T = gap
- if chunk > 512: chunk = 512
- written: t.CUInt32T = 0
- res2: FRESULT = self.write(c.Addr(zero_buf[0]), chunk, c.Addr(written))
- if res2 != FRESULT.FR_OK: return res2
- if written == 0: return FRESULT.FR_DENIED
- gap -= written
- self.file_size = offset
- self.vol.dir_update_entry(self.dir_sector, self.dir_offset, self.first_cluster, self.file_size, self.attr)
- return FRESULT.FR_OK
- self.file_pos = offset
- if self.first_cluster < 2:
- self.current_cluster = 0
- return FRESULT.FR_OK
- self.current_cluster = self.vol.file_cluster_seek(self.first_cluster, offset)
- return FRESULT.FR_OK
-
- def truncate(self) -> FRESULT:
- if not self.is_open: return FRESULT.FR_INVALID_OBJECT
- if not (self.flags & FA_WRITE): return FRESULT.FR_DENIED
- if self.file_pos >= self.file_size: return FRESULT.FR_OK
- vol: volinfo | t.CPtr = self.vol
- new_size: t.CUInt32T = self.file_pos
- if new_size == 0:
- if self.first_cluster >= 2: vol.cluster_free_chain(self.first_cluster)
- self.first_cluster = 0
- self.current_cluster = 0
- self.file_size = 0
- self.file_pos = 0
- vol.dir_update_entry(self.dir_sector, self.dir_offset, 0, 0, self.attr)
- return FRESULT.FR_OK
- cluster_at_pos: t.CUInt32T = vol.file_cluster_seek(self.first_cluster, new_size)
- if cluster_at_pos < 2: return FRESULT.FR_INT_ERR
- next_c: t.CUInt32T = vol.cluster_get_next(cluster_at_pos)
- vol.fat_write(cluster_at_pos, CLUSTER_EOC_MAX)
- if next_c >= 2 and next_c < CLUSTER_EOC_MIN:
- vol.cluster_free_chain(next_c)
- self.file_size = new_size
- self.current_cluster = cluster_at_pos
- vol.dir_update_entry(self.dir_sector, self.dir_offset, self.first_cluster, new_size, self.attr)
- return FRESULT.FR_OK
-
- def tell(self) -> t.CUInt32T:
- return self.file_pos
-
- def size(self) -> t.CUInt32T:
- return self.file_size
-
-
-@t.Object
-class dirobj:
- vol: volinfo | t.CPtr
- cluster: t.CUInt32T = 0
- start_cluster: t.CUInt32T = 0
- sector: t.CUInt64T = 0
- offset: t.CUInt32T = 0
- is_open: t.CInt = 0
- lfn_ofs: t.CUInt32T = 4294967295
- lfn_cluster: t.CUInt32T = 0
- sfn: t.CArray[t.CChar, 12]
-
- def close(self):
- self.is_open = 0
-
-
-handle_table: t.CArray[fileobj, MAX_HANDLES]
-lock_table: t.CArray[filelock, MAX_LOCKS]
-handles_initialized: t.CStatic | t.CInt = 0
-
-def handles_init():
- if handles_initialized: return
- for i in range(MAX_HANDLES):
- handle_table[i].is_open = 0
- handle_table[i].lock_count = 0
- for j in range(MAX_LOCKS):
- lock_table[j].in_use = 0
- handles_initialized = 1
-
-def handle_alloc() -> fileobj | t.CPtr:
- handles_init()
- for i in range(MAX_HANDLES):
- if not handle_table[i].is_open:
- return c.Addr(handle_table[i])
- return None
-
-def lock_check(dir_sector: t.CUInt64T, dir_offset: t.CUInt32T, mode: t.CUInt8T) -> FRESULT:
- handles_init()
- for i in range(MAX_LOCKS):
- lk: filelock | t.CPtr = c.Addr(lock_table[i])
- if lk.in_use and lk.dir_sector == dir_sector and lk.dir_offset == dir_offset:
- if mode & FA_WRITE: return FRESULT.FR_LOCKED
- if lk.exclusive: return FRESULT.FR_LOCKED
- return FRESULT.FR_OK
-
-def lock_acquire(dir_sector: t.CUInt64T, dir_offset: t.CUInt32T, exclusive: t.CInt) -> FRESULT:
- handles_init()
- for i in range(MAX_LOCKS):
- lk: filelock | t.CPtr = c.Addr(lock_table[i])
- if not lk.in_use:
- lk.in_use = 1
- lk.dir_sector = dir_sector
- lk.dir_offset = dir_offset
- lk.exclusive = exclusive
- lk.shared_count = 1 if not exclusive else 0
- return FRESULT.FR_OK
- return FRESULT.FR_TOO_MANY_OPEN_FILES
-
-def lock_release(dir_sector: t.CUInt64T, dir_offset: t.CUInt32T):
- handles_init()
- for i in range(MAX_LOCKS):
- lk: filelock | t.CPtr = c.Addr(lock_table[i])
- if lk.in_use and lk.dir_sector == dir_sector and lk.dir_offset == dir_offset:
- lk.shared_count -= 1
- if lk.shared_count <= 0: lk.in_use = 0
- return
diff --git a/Test/Kernel/drivers/fs/fat32/fileio.vp b/Test/Kernel/drivers/fs/fat32/fileio.vp
deleted file mode 100644
index 1ff5896a..00000000
--- a/Test/Kernel/drivers/fs/fat32/fileio.vp
+++ /dev/null
@@ -1,3 +0,0 @@
-import fat32
-
-
diff --git a/Test/Kernel/drivers/input/keyboard/keyboard.vp b/Test/Kernel/drivers/input/keyboard/keyboard.vp
deleted file mode 100644
index fce10397..00000000
--- a/Test/Kernel/drivers/input/keyboard/keyboard.vp
+++ /dev/null
@@ -1,146 +0,0 @@
-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")
diff --git a/Test/Kernel/drivers/input/mouse/mouse.vp b/Test/Kernel/drivers/input/mouse/mouse.vp
deleted file mode 100644
index aee483fe..00000000
--- a/Test/Kernel/drivers/input/mouse/mouse.vp
+++ /dev/null
@@ -1,134 +0,0 @@
-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")
diff --git a/Test/Kernel/drivers/serial/uart/serial.vp b/Test/Kernel/drivers/serial/uart/serial.vp
deleted file mode 100644
index 35ad868f..00000000
--- a/Test/Kernel/drivers/serial/uart/serial.vp
+++ /dev/null
@@ -1,46 +0,0 @@
-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)
diff --git a/Test/Kernel/drivers/serial/uart/su8250.vp b/Test/Kernel/drivers/serial/uart/su8250.vp
deleted file mode 100644
index 568a41be..00000000
--- a/Test/Kernel/drivers/serial/uart/su8250.vp
+++ /dev/null
@@ -1,116 +0,0 @@
-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)
diff --git a/Test/Kernel/drivers/storage/ide/ide.vp b/Test/Kernel/drivers/storage/ide/ide.vp
deleted file mode 100644
index d04d89e1..00000000
--- a/Test/Kernel/drivers/storage/ide/ide.vp
+++ /dev/null
@@ -1,161 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/usb/hid/hid.vp b/Test/Kernel/drivers/usb/hid/hid.vp
deleted file mode 100644
index a771b42f..00000000
--- a/Test/Kernel/drivers/usb/hid/hid.vp
+++ /dev/null
@@ -1,37 +0,0 @@
-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))
diff --git a/Test/Kernel/drivers/usb/hid/usb_kbd.vp b/Test/Kernel/drivers/usb/hid/usb_kbd.vp
deleted file mode 100644
index 0c953fc4..00000000
--- a/Test/Kernel/drivers/usb/hid/usb_kbd.vp
+++ /dev/null
@@ -1,111 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/usb/hid/usb_mouse.vp b/Test/Kernel/drivers/usb/hid/usb_mouse.vp
deleted file mode 100644
index 96fdd49b..00000000
--- a/Test/Kernel/drivers/usb/hid/usb_mouse.vp
+++ /dev/null
@@ -1,77 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/usb/pci.vp b/Test/Kernel/drivers/usb/pci.vp
deleted file mode 100644
index 97fd0fcc..00000000
--- a/Test/Kernel/drivers/usb/pci.vp
+++ /dev/null
@@ -1,93 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/usb/uhci.vp b/Test/Kernel/drivers/usb/uhci.vp
deleted file mode 100644
index 72183efd..00000000
--- a/Test/Kernel/drivers/usb/uhci.vp
+++ /dev/null
@@ -1,415 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/usb/usb.vp b/Test/Kernel/drivers/usb/usb.vp
deleted file mode 100644
index d0f8d47c..00000000
--- a/Test/Kernel/drivers/usb/usb.vp
+++ /dev/null
@@ -1,330 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/video/ui/sheet.vp b/Test/Kernel/drivers/video/ui/sheet.vp
deleted file mode 100644
index 7b70613c..00000000
--- a/Test/Kernel/drivers/video/ui/sheet.vp
+++ /dev/null
@@ -1,85 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/video/ui/ui.vp b/Test/Kernel/drivers/video/ui/ui.vp
deleted file mode 100644
index d3ed8ef0..00000000
--- a/Test/Kernel/drivers/video/ui/ui.vp
+++ /dev/null
@@ -1,152 +0,0 @@
-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
diff --git a/Test/Kernel/drivers/video/vesafb/gfx.vp b/Test/Kernel/drivers/video/vesafb/gfx.vp
deleted file mode 100644
index 5292d3f0..00000000
--- a/Test/Kernel/drivers/video/vesafb/gfx.vp
+++ /dev/null
@@ -1,305 +0,0 @@
-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)
diff --git a/Test/Kernel/drivers/video/vesafb/vga.vp b/Test/Kernel/drivers/video/vesafb/vga.vp
deleted file mode 100644
index ef6206ce..00000000
--- a/Test/Kernel/drivers/video/vesafb/vga.vp
+++ /dev/null
@@ -1,504 +0,0 @@
-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':
- # 换行:重置X,Y增加字符高度
- 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
diff --git a/Test/Kernel/execrunner/elf.vp b/Test/Kernel/execrunner/elf.vp
deleted file mode 100644
index 8e620eab..00000000
--- a/Test/Kernel/execrunner/elf.vp
+++ /dev/null
@@ -1,757 +0,0 @@
-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
diff --git a/Test/Kernel/intr/__init__.vp b/Test/Kernel/intr/__init__.vp
deleted file mode 100644
index eede1234..00000000
--- a/Test/Kernel/intr/__init__.vp
+++ /dev/null
@@ -1,2 +0,0 @@
-from . import gdt
-from . import idt
diff --git a/Test/Kernel/intr/gdt.vp b/Test/Kernel/intr/gdt.vp
deleted file mode 100644
index 524573e0..00000000
--- a/Test/Kernel/intr/gdt.vp
+++ /dev/null
@@ -1,142 +0,0 @@
-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
diff --git a/Test/Kernel/intr/idt.vp b/Test/Kernel/intr/idt.vp
deleted file mode 100644
index 416bca49..00000000
--- a/Test/Kernel/intr/idt.vp
+++ /dev/null
@@ -1,415 +0,0 @@
-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.State: pass
-def isr1() -> t.State: pass
-def isr2() -> t.State: pass
-def isr3() -> t.State: pass
-def isr4() -> t.State: pass
-def isr5() -> t.State: pass
-def isr6() -> t.State: pass
-def isr7() -> t.State: pass
-def isr8() -> t.State: pass
-def isr9() -> t.State: pass
-def isr10() -> t.State: pass
-def isr11() -> t.State: pass
-def isr12() -> t.State: pass
-def isr13() -> t.State: pass
-def isr14() -> t.State: pass
-def isr15() -> t.State: pass
-def isr16() -> t.State: pass
-def isr17() -> t.State: pass
-def isr18() -> t.State: pass
-def isr19() -> t.State: pass
-def isr20() -> t.State: pass
-def isr21() -> t.State: pass
-def isr22() -> t.State: pass
-def isr23() -> t.State: pass
-def isr24() -> t.State: pass
-def isr25() -> t.State: pass
-def isr26() -> t.State: pass
-def isr27() -> t.State: pass
-def isr28() -> t.State: pass
-def isr29() -> t.State: pass
-def isr30() -> t.State: pass
-def isr31() -> t.State: pass
-def isr32() -> t.State: pass
-def isr33() -> t.State: pass
-def isr34() -> t.State: pass
-def isr35() -> t.State: pass
-def isr36() -> t.State: pass
-def isr37() -> t.State: pass
-def isr38() -> t.State: pass
-def isr39() -> t.State: pass
-def isr40() -> t.State: pass
-def isr41() -> t.State: pass
-def isr42() -> t.State: pass
-def isr43() -> t.State: pass
-def isr44() -> t.State: pass
-def isr45() -> t.State: pass
-def isr46() -> t.State: pass
-def isr47() -> t.State: pass
-
-def isr80() -> t.State: pass
-
-def isr_default() -> 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])
diff --git a/Test/Kernel/intr/isr.s b/Test/Kernel/intr/isr.s
deleted file mode 100644
index c03757f7..00000000
--- a/Test/Kernel/intr/isr.s
+++ /dev/null
@@ -1,595 +0,0 @@
-.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
diff --git a/Test/Kernel/intr/syscall.vp b/Test/Kernel/intr/syscall.vp
deleted file mode 100644
index d77cd3fa..00000000
--- a/Test/Kernel/intr/syscall.vp
+++ /dev/null
@@ -1,470 +0,0 @@
-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")
diff --git a/Test/Kernel/mm/mm.vp b/Test/Kernel/mm/mm.vp
deleted file mode 100644
index c6c11095..00000000
--- a/Test/Kernel/mm/mm.vp
+++ /dev/null
@@ -1,764 +0,0 @@
-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 >= (memory_block | t.CPtr)(self.buddy.end_addr):
- 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:
- global vm_areas
- # 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):
- global vm_areas
- # 查找虚拟内存区域
- 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
diff --git a/Test/Kernel/paging/paging.vp b/Test/Kernel/paging/paging.vp
deleted file mode 100644
index 267a4318..00000000
--- a/Test/Kernel/paging/paging.vp
+++ /dev/null
@@ -1,296 +0,0 @@
-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 AllocatedPages, 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 AllocatedPages, 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 (_p | t.CPtr)(cr3 & ~t.CUInt64T(0xFFF))
-
-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)
diff --git a/Test/Kernel/platform/pch/__init__.vp b/Test/Kernel/platform/pch/__init__.vp
deleted file mode 100644
index e1581f91..00000000
--- a/Test/Kernel/platform/pch/__init__.vp
+++ /dev/null
@@ -1,4 +0,0 @@
-from . import pic
-from . import pit
-from . import timer
-from . import rtc
diff --git a/Test/Kernel/platform/pch/pic.vp b/Test/Kernel/platform/pch/pic.vp
deleted file mode 100644
index 239fd69a..00000000
--- a/Test/Kernel/platform/pch/pic.vp
+++ /dev/null
@@ -1,120 +0,0 @@
-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()
-
- # 发送ICW4:8086模式
- 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,读取ISR(Interrupt 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() # 确保命令生效
diff --git a/Test/Kernel/platform/pch/pit.vp b/Test/Kernel/platform/pch/pit.vp
deleted file mode 100644
index f4a76a39..00000000
--- a/Test/Kernel/platform/pch/pit.vp
+++ /dev/null
@@ -1,26 +0,0 @@
-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()
diff --git a/Test/Kernel/platform/pch/rtc.vp b/Test/Kernel/platform/pch/rtc.vp
deleted file mode 100644
index 52d98509..00000000
--- a/Test/Kernel/platform/pch/rtc.vp
+++ /dev/null
@@ -1,97 +0,0 @@
-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
diff --git a/Test/Kernel/platform/pch/timer.vp b/Test/Kernel/platform/pch/timer.vp
deleted file mode 100644
index 9b45895b..00000000
--- a/Test/Kernel/platform/pch/timer.vp
+++ /dev/null
@@ -1,102 +0,0 @@
-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()
diff --git a/Test/Kernel/sched/coroutine.vp b/Test/Kernel/sched/coroutine.vp
deleted file mode 100644
index 506e6a8b..00000000
--- a/Test/Kernel/sched/coroutine.vp
+++ /dev/null
@@ -1,202 +0,0 @@
-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()
diff --git a/Test/Kernel/sched/process.vp b/Test/Kernel/sched/process.vp
deleted file mode 100644
index 18c59e52..00000000
--- a/Test/Kernel/sched/process.vp
+++ /dev/null
@@ -1,277 +0,0 @@
-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__(self):
- 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])
diff --git a/Test/Kernel/sched/sched.vp b/Test/Kernel/sched/sched.vp
deleted file mode 100644
index 606d5dc9..00000000
--- a/Test/Kernel/sched/sched.vp
+++ /dev/null
@@ -1,299 +0,0 @@
-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__(self):
- 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)
diff --git a/Test/Kernel/services/desktop.vp b/Test/Kernel/services/desktop.vp
deleted file mode 100644
index 6f34f75b..00000000
--- a/Test/Kernel/services/desktop.vp
+++ /dev/null
@@ -1,2714 +0,0 @@
-from stdint import *
-import asm
-import drivers.video.vesafb.gfx as gfx
-import drivers.video.vesafb.vga as vga
-import drivers.input.mouse.mouse as mouse
-import drivers.input.keyboard.keyboard as keyboard
-import drivers.usb.hid.usb_mouse as usb_mouse
-import drivers.usb.hid.usb_kbd as usb_kbd
-import drivers.serial.uart.serial as serial
-import platform.pch.pic as pic
-import platform.pch.timer as timer
-import platform.pch.rtc as rtc
-import sched.sched as sched
-import sched.process as process
-import mm.mm as mm
-import string
-import viperlib
-import t, c
-
-
-TASKBAR_HEIGHT: t.CDefine = 50
-CURSOR_SIZE: t.CDefine = 16
-CURSOR_W: t.CDefine = 16
-CURSOR_H: t.CDefine = 16
-CURSOR_SAVE_SIZE: t.CDefine = 256
-TITLE_HEIGHT_CLASSIC: t.CDefine = 24
-TITLE_HEIGHT_WIN: t.CDefine = 32
-MAX_APP_WINDOWS: t.CDefine = 16
-CLOSE_BTN_SIZE: t.CDefine = 16
-CLOSE_BTN_W_WIN: t.CDefine = 46
-CLOSE_BTN_W7_W: t.CDefine = 28
-CLOSE_BTN_W7_H: t.CDefine = 20
-CLOSE_BTN_W7_R: t.CDefine = 3
-CLOSE_BTN_XP_SZ: t.CDefine = 21
-TITLE_BTN_W_WIN: t.CDefine = 46
-TITLE_BTN_W7: t.CDefine = 28
-TITLE_BTN_XP: t.CDefine = 21
-TASKBAR_ICON_SZ: t.CDefine = 36
-TASKBAR_ICON_PAD: t.CDefine = 6
-TASKBAR_LOGO_SZ: t.CDefine = 32
-WIN_RADIUS: t.CDefine = 8
-SHADOW_ENABLED: t.CDefine = False
-SHADOW_LEFT: t.CDefine = 8
-SHADOW_RIGHT: t.CDefine = 12
-SHADOW_TOP: t.CDefine = 4
-SHADOW_BOTTOM: t.CDefine = 14
-SHADOW_ALPHA: t.CDefine = 100
-CURSOR_SHADOW_ALPHA: t.CDefine = 50
-
-STYLE_CLASSIC: t.CDefine = 0
-STYLE_WIN10: t.CDefine = 1
-STYLE_WIN11: t.CDefine = 2
-STYLE_WIN7: t.CDefine = 3
-STYLE_WINXP: t.CDefine = 4
-
-_fb: UINT32PTR
-_screen_w: t.CInt = 0
-_screen_h: t.CInt = 0
-_fb_pitch: t.CInt = 0
-_cursor_x: t.CInt = 512
-_cursor_y: t.CInt = 300
-_cursor_buttons: t.CUInt8T = 0
-_back_fb: UINT32PTR
-_last_time_sec: t.CUInt32T = 0
-_row_buf: UINT32PTR
-_bg_row_buf: UINT32PTR
-@t.Object
-class AppWindow:
- active: t.CInt
- x: t.CInt
- y: t.CInt
- w: t.CInt
- h: t.CInt
- title: t.CArray[t.CChar, 32]
- orig_title: t.CArray[t.CChar, 32]
- content_h: t.CInt
- fb: UINT32PTR
- fb_w: t.CInt
- fb_h: t.CInt
- z_order: t.CInt
- style: t.CInt
- close_hover: t.CInt
- min_hover: t.CInt
- max_hover: t.CInt
- is_maximized: t.CInt
- orig_x: t.CInt
- orig_y: t.CInt
- orig_w: t.CInt
- orig_h: t.CInt
- pid: t.CInt
- cursor_type: t.CInt
- app_cursor_type: t.CInt
- ping_pending: t.CInt
- no_resp: t.CInt
- no_resp_sec: t.CUInt32T
- minimized: t.CInt
- resizable_w: t.CInt
- resizable_h: t.CInt
- resize_w: t.CInt
- resize_h: t.CInt
- old_fb: UINT32PTR
-
-_wins: t.CArray[AppWindow, MAX_APP_WINDOWS]
-_win_count: t.CInt = 0
-_next_z: t.CInt = 1
-_current_app_pid: t.CInt = 0
-HB_INTERVAL_SEC: t.CUInt32T = 5
-HB_NO_RESP_SEC: t.CUInt32T = 30
-_hb_last_sec: t.CUInt32T = 0
-_dirty_rows: t.CUInt8T | t.CPtr = t.CUInt8T(0, t.CPtr)
-_dirty_count: t.CInt = 0
-_dirty_y_min: t.CInt = 0
-_dirty_y_max: t.CInt = -1
-_vblank_ok: t.CInt = -1
-_prev_cursor_x: t.CInt = 512
-_prev_cursor_y: t.CInt = 300
-_cursor_save_buf: t.CArray[t.CUInt32T, 256]
-_cursor_saved: t.CInt = 0
-
-_CURSOR_ARROW: t.CArray[t.CUInt8T, 256] = [
- 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,
- 1,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,
- 1,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,
- 1,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,
- 1,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,
- 1,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,
- 1,2,2,2,1,1,1,1,1,1,0,0,0,0,0,0,
- 1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,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,0,0,0,0,0,0,0,
-]
-
-_CURSOR_IBEAM: t.CArray[t.CUInt8T, 256] = [
- 0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
- 0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
- 0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
-]
-
-_CURSOR_RESIZE_EW: t.CArray[t.CUInt8T, 256] = [
- 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,1,1,1,0,1,1,1,0,0,0,0,0,
- 0,0,0,1,2,2,1,1,1,2,2,1,0,0,0,0,
- 0,0,1,2,2,2,2,2,2,2,2,2,1,0,0,0,
- 0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
- 0,0,0,0,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,0,0,0,0,0,
- 0,1,2,2,2,2,2,2,2,2,2,2,2,1,0,0,
- 0,0,1,2,2,2,2,2,2,2,2,2,1,0,0,0,
- 0,0,0,1,2,2,1,1,1,2,2,1,0,0,0,0,
- 0,0,0,0,1,1,1,0,1,1,1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,
-]
-
-_CURSOR_RESIZE_NS: t.CArray[t.CUInt8T, 256] = [
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,
- 0,0,1,2,2,2,2,1,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
- 0,0,1,2,2,2,2,1,0,0,0,0,0,0,0,0,
- 0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,1,1,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,0,
-]
-
-_CURSOR_RESIZE_NWSE: t.CArray[t.CUInt8T, 256] = [
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,1,2,2,1,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,2,2,1,1,0,0,0,0,0,0,0,
- 0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,1,2,2,1,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,1,1,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,0,0,0,0,0,0,0,0,0,0,0,
-]
-_last_clock_sec: t.CUInt32T = 0
-_prev_btn: t.CUInt8T = 0
-
-EVENT_QUEUE_SIZE: t.CDefine = 32
-EVENT_TYPE_NONE: t.CDefine = 0
-EVENT_TYPE_CLICK: t.CDefine = 1
-EVENT_TYPE_HOVER: t.CDefine = 2
-EVENT_TYPE_RELEASE: t.CDefine = 3
-EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
-EVENT_TYPE_KEY: t.CDefine = 5
-EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
-EVENT_TYPE_PING: t.CDefine = 7
-EVENT_TYPE_RESIZE: t.CDefine = 8
-
-RESIZE_EDGE_NONE: t.CDefine = 0
-RESIZE_EDGE_RIGHT: t.CDefine = 1
-RESIZE_EDGE_BOTTOM: t.CDefine = 2
-RESIZE_EDGE_CORNER: t.CDefine = 3
-RESIZE_BORDER: t.CDefine = 6
-RESIZE_MIN_W: t.CDefine = 100
-RESIZE_MIN_H: t.CDefine = 60
-
-CURSOR_DEFAULT: t.CDefine = 0
-CURSOR_IBEAM: t.CDefine = 1
-CURSOR_RESIZE_EW: t.CDefine = 2
-CURSOR_RESIZE_NS: t.CDefine = 3
-CURSOR_RESIZE_NWSE: t.CDefine = 4
-
-KEY_STATE_PRESS: t.CDefine = 1
-KEY_STATE_RELEASE: t.CDefine = 2
-KEY_STATE_REPEAT: t.CDefine = 3
-
-TYPEMATIC_DELAY: t.CDefine = 500
-TYPEMATIC_RATE: t.CDefine = 40
-
-HELD_KEY_MAX: t.CDefine = 8
-
-class held_key_info(t.CStruct):
- keycode: t.CUInt8T
- is_usb: t.CUInt8T
- press_time: t.CUInt64T
- last_repeat: t.CUInt64T
-
-_held_keys: t.CArray[held_key_info, HELD_KEY_MAX]
-_held_key_count: t.CInt = 0
-
-@c.Attribute(t.attr.packed)
-class InputEvent:
- type: t.CUInt32T
- win_id: t.CInt
- x: t.CInt
- y: t.CInt
- button: t.CUInt8T
- _pad0: t.CUInt8T
- _pad1: t.CUInt8T
- _pad2: t.CUInt8T
-
-INPUT_EVENT_SIZE: t.CDefine = 20
-
-_event_queue: t.CArray[InputEvent, EVENT_QUEUE_SIZE]
-_event_head: t.CInt = 0
-_event_tail: t.CInt = 0
-_last_hover_win: t.CInt = -1
-_focused_win: t.CInt = -1
-
-KBD_DEV_PS2: t.CDefine = 0
-KBD_DEV_USB: t.CDefine = 1
-
-_ps2_shift_l: t.CUInt8T = 0
-_ps2_shift_r: t.CUInt8T = 0
-_ps2_caps: t.CUInt8T = 0
-_ps2_e0_pending: t.CUInt8T = 0
-_kbd_irq_masked: t.CInt = 0
-
-VK_LEFT: t.CDefine = -1
-VK_RIGHT: t.CDefine = -2
-VK_UP: t.CDefine = -3
-VK_DOWN: t.CDefine = -4
-VK_HOME: t.CDefine = -5
-VK_END: t.CDefine = -6
-VK_DELETE: t.CDefine = -7
-
-_ps2_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', '-', '\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', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0'
-]
-
-_ps2_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', '-', '\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', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0'
-]
-
-def _ps2_scancode_to_ascii(scancode: t.CUInt8T) -> t.CInt:
- code: t.CUInt8T = scancode & t.CUInt8T(0x7F)
- if code >= 128: return 0
- shifted: t.CInt = 0
- if (_ps2_shift_l or _ps2_shift_r) != 0:
- shifted = 1
- if _ps2_caps != 0:
- if code >= 0x10 and code <= 0x32:
- shifted = shifted ^ 1
- if shifted:
- return t.CInt(_ps2_set1_shift[code])
- return t.CInt(_ps2_set1[code])
-
-
-def _push_event(evt: InputEvent):
- global _event_head, _event_tail
- if evt.type == EVENT_TYPE_RESIZE:
- i: t.CInt = _event_head
- while i != _event_tail:
- if _event_queue[i].type == EVENT_TYPE_RESIZE and _event_queue[i].win_id == evt.win_id:
- _event_queue[i].type = EVENT_TYPE_NONE
- i = (i + 1) % EVENT_QUEUE_SIZE
- next_tail: t.CInt = (_event_tail + 1) % EVENT_QUEUE_SIZE
- if next_tail == _event_head:
- _event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
- string.memcpy(c.Addr(_event_queue[_event_tail]), c.Addr(evt), INPUT_EVENT_SIZE)
- _event_tail = next_tail
-
-def poll_event(buf_ptr: t.CVoid | t.CPtr, caller_pid: t.CInt) -> t.CInt:
- global _event_head, _event_tail
- while _event_head != _event_tail:
- if _event_queue[_event_head].type == EVENT_TYPE_NONE:
- _event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
- continue
- evt_win: t.CInt = _event_queue[_event_head].win_id
- evt_pid: t.CInt = 0
- win_ok: t.CInt = 0
- if evt_win >= 0 and evt_win < _win_count:
- evt_pid = _wins[evt_win].pid
- win_ok = 1
- if evt_pid == caller_pid:
- string.memcpy(buf_ptr, c.Addr(_event_queue[_event_head]), INPUT_EVENT_SIZE)
- _event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
- return 1
- if win_ok and not _wins[evt_win].active:
- _event_head = (_event_head + 1) % EVENT_QUEUE_SIZE
- continue
- scan: t.CInt = (_event_head + 1) % EVENT_QUEUE_SIZE
- while scan != _event_tail:
- if _event_queue[scan].type == EVENT_TYPE_NONE:
- scan = (scan + 1) % EVENT_QUEUE_SIZE
- continue
- evt_win2: t.CInt = _event_queue[scan].win_id
- evt_pid2: t.CInt = 0
- if evt_win2 >= 0 and evt_win2 < _win_count:
- evt_pid2 = _wins[evt_win2].pid
- if evt_pid2 == caller_pid:
- string.memcpy(buf_ptr, c.Addr(_event_queue[scan]), INPUT_EVENT_SIZE)
- i: t.CInt = scan
- while i != _event_tail:
- next_i: t.CInt = (i + 1) % EVENT_QUEUE_SIZE
- if next_i != _event_head:
- string.memcpy(c.Addr(_event_queue[i]), c.Addr(_event_queue[next_i]), INPUT_EVENT_SIZE)
- i = next_i
- if _event_tail == 0:
- _event_tail = EVENT_QUEUE_SIZE - 1
- else:
- _event_tail = _event_tail - 1
- return 1
- scan = (scan + 1) % EVENT_QUEUE_SIZE
- break
- return 0
-
-def _get_title_height(style: t.CInt) -> t.CInt:
- if style == STYLE_CLASSIC:
- return TITLE_HEIGHT_CLASSIC
- return TITLE_HEIGHT_WIN
-
-def _mark_rows_dirty(start_y: t.CInt, count: t.CInt):
- global _dirty_count, _dirty_y_min, _dirty_y_max
- for i in range(start_y, start_y + count):
- if i >= 0 and i < _screen_h:
- if not _dirty_rows[i]:
- _dirty_rows[i] = 1
- _dirty_count += 1
- if i < _dirty_y_min or _dirty_count == 1:
- _dirty_y_min = i
- if i > _dirty_y_max or _dirty_count == 1:
- _dirty_y_max = i
-
-def _mark_all_dirty():
- global _dirty_count, _dirty_y_min, _dirty_y_max
- string.memset(_dirty_rows, 1, _screen_h)
- _dirty_count = _screen_h
- _dirty_y_min = 0
- _dirty_y_max = _screen_h - 1
-
-def _has_dirty_rows() -> t.CInt:
- return _dirty_count
-
-def _clear_dirty_flags():
- global _dirty_count, _dirty_y_min, _dirty_y_max
- string.memset(_dirty_rows, 0, _screen_h)
- _dirty_count = 0
- _dirty_y_min = _screen_h
- _dirty_y_max = -1
-
-def _wait_vblank():
- global _vblank_ok
- if _vblank_ok == 0:
- return
- timeout: t.CInt = 50000
- while (asm.inb(0x3DA) & 0x08) != 0:
- timeout -= 1
- if timeout <= 0:
- _vblank_ok = 0
- return
- while (asm.inb(0x3DA) & 0x08) == 0:
- timeout -= 1
- if timeout <= 0:
- _vblank_ok = 0
- return
- _vblank_ok = 1
-
-def _fill_rect(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
- if rx < 0: rw += rx; rx = 0
- if ry < 0: rh += ry; ry = 0
- if rx + rw > bw: rw = bw - rx
- if ry + rh > bh: rh = bh - ry
- if rw <= 0 or rh <= 0: return
- if _row_buf:
- for i in range(rw):
- _row_buf[i] = color
- row_bytes: t.CInt = rw * 4
- for py in range(ry, ry + rh):
- string.memcpy(t.CVoid(t.CUInt64T(buf) + (py * bw + rx) * 4, t.CPtr), _row_buf, row_bytes)
-
-def _alpha_blend(bg: t.CUInt32T, fg: t.CUInt32T, alpha: t.CInt) -> t.CUInt32T:
- a: t.CInt = alpha
- ia: t.CInt = 255 - a
- bg_r: t.CInt = t.CInt(bg & 0xFF)
- bg_g: t.CInt = t.CInt((bg >> 8) & 0xFF)
- bg_b: t.CInt = t.CInt((bg >> 16) & 0xFF)
- fg_r: t.CInt = t.CInt(fg & 0xFF)
- fg_g: t.CInt = t.CInt((fg >> 8) & 0xFF)
- fg_b: t.CInt = t.CInt((fg >> 16) & 0xFF)
- r: t.CInt = (fg_r * a + bg_r * ia) >> 8
- g: t.CInt = (fg_g * a + bg_g * ia) >> 8
- b: t.CInt = (fg_b * a + bg_b * ia) >> 8
- return t.CUInt32T(r | (g << 8) | (b << 16) | 0xFF000000)
-
-def _is_in_corner(px: t.CInt, py: t.CInt, cx: t.CInt, cy: t.CInt, r: t.CInt) -> t.CInt:
- dx: t.CInt = px - cx
- dy: t.CInt = py - cy
- if dx < 0: dx = -dx
- if dy < 0: dy = -dy
- if dx <= r and dy <= r:
- dist2: t.CInt = dx * dx + dy * dy
- r2: t.CInt = r * r
- if dist2 > r2:
- return 0
- return 1
-
-def _is_on_border(rx: t.CInt, ry: t.CInt, ww: t.CInt, wh: t.CInt, r: t.CInt) -> t.CInt:
- if rx == 0 or rx == ww - 1 or ry == 0 or ry == wh - 1:
- return 1
- if ry < r:
- if rx < r:
- dx: t.CInt = rx - r
- dy: t.CInt = ry - r
- dist2: t.CInt = dx * dx + dy * dy
- if dist2 >= (r - 1) * (r - 1): return 1
- elif rx >= ww - r:
- dx = rx - (ww - r - 1)
- dy = ry - r
- dist2 = dx * dx + dy * dy
- if dist2 >= (r - 1) * (r - 1): return 1
- elif ry >= wh - r:
- if rx < r:
- dx = rx - r
- dy = ry - (wh - r - 1)
- dist2 = dx * dx + dy * dy
- if dist2 >= (r - 1) * (r - 1): return 1
- elif rx >= ww - r:
- dx = rx - (ww - r - 1)
- dy = ry - (wh - r - 1)
- dist2 = dx * dx + dy * dy
- if dist2 >= (r - 1) * (r - 1): return 1
- return 0
-
-def _corner_alpha(px: t.CInt, py: t.CInt, cx: t.CInt, cy: t.CInt, r: t.CInt) -> t.CInt:
- dx: t.CInt = px - cx
- dy: t.CInt = py - cy
- if dx < 0: dx = -dx
- if dy < 0: dy = -dy
- if dx <= r and dy <= r:
- dist2: t.CInt = dx * dx + dy * dy
- r2: t.CInt = r * r
- if dist2 > r2:
- return 0
- outer: t.CInt = (r + 1) * (r + 1)
- if dist2 >= outer:
- return 160
- return 255
- return 255
-
-def _draw_char(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, x: t.CInt, y: t.CInt, ch: t.CChar, color: t.CUInt32T):
- cval: t.CUInt8T = t.CUInt8T(ch)
- if cval >= 128: cval = 0
- for fy in range(16):
- if y + fy < 0 or y + fy >= bh: continue
- row: t.CUInt8T = vga.font[cval][fy]
- if row == 0: continue
- for fx in range(8):
- if row & (0x80 >> fx):
- px: t.CInt = x + fx
- if px >= 0 and px < bw:
- buf[(y + fy) * bw + px] = color
-
-def _draw_text(buf: UINT32PTR, bw: t.CInt, bh: t.CInt, x: t.CInt, y: t.CInt, s: t.CConst | str, color: t.CUInt32T):
- cx: t.CInt = x
- cy: t.CInt = y
- for ch in s:
- if ch == 10:
- cy += 16
- cx = x
- else:
- _draw_char(buf, bw, bh, cx, cy, ch, color)
- cx += 8
-
-_drag_idx: t.CInt = -1
-
-def _eff_w(aw2: AppWindow | t.CPtr) -> t.CInt:
- if aw2.resize_w != 0: return aw2.resize_w
- return aw2.w
-
-def _eff_h(aw2: AppWindow | t.CPtr) -> t.CInt:
- if aw2.resize_h != 0: return aw2.resize_h
- return aw2.content_h
-_drag_off_x: t.CInt = 0
-_drag_off_y: t.CInt = 0
-_rsz_drag_idx: t.CInt = -1
-_rsz_edge: t.CInt = 0
-_rsz_start_x: t.CInt = 0
-_rsz_start_y: t.CInt = 0
-_rsz_start_w: t.CInt = 0
-_rsz_start_h: t.CInt = 0
-_rsz_last_w: t.CInt = 0
-_rsz_last_h: t.CInt = 0
-_rsz_last_tick: t.CUInt64T = 0
-_mouse_moved: t.CInt = 0
-
-def _bring_to_front(idx: t.CInt):
- global _next_z
- if idx < 0 or idx >= _win_count: return
- aw: AppWindow | t.CPtr = c.Addr(_wins[idx])
- if not aw.active or aw.minimized: return
- _next_z += 1
- aw.z_order = _next_z
-
-def _hit_test_window(mx: t.CInt, my: t.CInt) -> t.CInt:
- best: t.CInt = -1
- best_z: t.CInt = -1
- for ai in range(_win_count):
- if _wins[ai].active and not _wins[ai].minimized:
- ax: t.CInt = _wins[ai].x
- ay: t.CInt = _wins[ai].y
- aw: t.CInt = _eff_w(c.Addr(_wins[ai]))
- ah: t.CInt = _wins[ai].h
- if mx >= ax and mx < ax + aw and my >= ay and my < ay + ah:
- z: t.CInt = _wins[ai].z_order
- if z > best_z:
- best_z = z
- best = ai
- return best
-
-def _hit_test_resize(mx: t.CInt, my: t.CInt, idx: t.CInt) -> t.CInt:
- if idx < 0 or idx >= _win_count: return RESIZE_EDGE_NONE
- aw: AppWindow | t.CPtr = c.Addr(_wins[idx])
- if not aw.active or aw.minimized: return RESIZE_EDGE_NONE
- if not aw.resizable_w and not aw.resizable_h: return RESIZE_EDGE_NONE
- on_right: t.CInt = 0
- on_bottom: t.CInt = 0
- if aw.resizable_w:
- if mx >= aw.x + _eff_w(aw) - RESIZE_BORDER and mx < aw.x + _eff_w(aw):
- on_right = 1
- if aw.resizable_h:
- if my >= aw.y + aw.h - RESIZE_BORDER and my < aw.y + aw.h:
- on_bottom = 1
- if on_right and on_bottom: return RESIZE_EDGE_CORNER
- if on_right: return RESIZE_EDGE_RIGHT
- if on_bottom: return RESIZE_EDGE_BOTTOM
- return RESIZE_EDGE_NONE
-
-def _hid_to_ascii(keycode: t.CUInt8T, modifier: t.CUInt8T) -> t.CInt:
- global _ps2_caps
- shift: t.CInt = 0
- if (modifier & 0x22) != 0:
- shift = 1
- kc: t.CInt = t.CInt(keycode)
- if kc >= 4 and kc <= 29:
- if _ps2_caps != 0:
- shift = shift ^ 1
- if shift:
- return kc - 4 + 65
- return kc - 4 + 97
- if kc >= 30 and kc <= 38:
- if shift:
- shifts9: t.CArray[t.CInt, 9]
- shifts9[0] = 33; shifts9[1] = 64; shifts9[2] = 35
- shifts9[3] = 36; shifts9[4] = 37; shifts9[5] = 94
- shifts9[6] = 38; shifts9[7] = 42; shifts9[8] = 40
- return shifts9[kc - 30]
- return kc - 30 + 49
- if kc == 39:
- if shift: return 41
- return 48
- if kc == 44: return 32
- if kc == 40: return 13
- if kc == 42: return 8
- if kc == 43: return 9
- if kc == 41: return 27
- if kc == 45:
- if shift: return 95
- return 45
- if kc == 46:
- if shift: return 43
- return 61
- if kc == 47:
- if shift: return 123
- return 91
- if kc == 48:
- if shift: return 125
- return 93
- if kc == 49:
- if shift: return 124
- return 92
- if kc == 51:
- if shift: return 58
- return 59
- if kc == 52:
- if shift: return 34
- return 39
- if kc == 53:
- if shift: return 126
- return 96
- if kc == 54:
- if shift: return 60
- return 44
- if kc == 55:
- if shift: return 62
- return 46
- if kc == 56:
- if shift: return 63
- return 47
- return 0
-
-def _held_key_add(keycode: t.CUInt8T, is_usb: t.CUInt8T):
- global _held_key_count
- if _held_key_count >= HELD_KEY_MAX: return
- for i in range(_held_key_count):
- if _held_keys[i].keycode == keycode and _held_keys[i].is_usb == is_usb:
- return
- now: t.CUInt64T = timer.timer_get_ticks()
- _held_keys[_held_key_count].keycode = keycode
- _held_keys[_held_key_count].is_usb = is_usb
- _held_keys[_held_key_count].press_time = now
- _held_keys[_held_key_count].last_repeat = now
- _held_key_count += 1
-
-def _held_key_remove(keycode: t.CUInt8T, is_usb: t.CUInt8T):
- global _held_key_count
- for i in range(_held_key_count):
- if _held_keys[i].keycode == keycode and _held_keys[i].is_usb == is_usb:
- for j in range(i, _held_key_count - 1):
- _held_keys[j].keycode = _held_keys[j + 1].keycode
- _held_keys[j].is_usb = _held_keys[j + 1].is_usb
- _held_keys[j].press_time = _held_keys[j + 1].press_time
- _held_keys[j].last_repeat = _held_keys[j + 1].last_repeat
- _held_key_count -= 1
- return
-
-def _check_key_repeat():
- global _held_key_count
- if _focused_win < 0 or _focused_win >= _win_count: return
- if not _wins[_focused_win].active: return
- now: t.CUInt64T = timer.timer_get_ticks()
- for i in range(_held_key_count):
- hk: held_key_info | t.CPtr = c.Addr(_held_keys[i])
- elapsed: t.CUInt64T = now - hk.press_time
- if elapsed < t.CUInt64T(TYPEMATIC_DELAY):
- continue
- since_last: t.CUInt64T = now - hk.last_repeat
- if since_last >= t.CUInt64T(TYPEMATIC_RATE):
- hk.last_repeat = now
- ascii_ch: t.CInt = 0
- if hk.is_usb:
- mod: t.CUInt8T = 0
- if _ps2_shift_l or _ps2_shift_r:
- mod = mod | 0x22
- if _ps2_caps:
- mod = mod | 0x01
- ascii_ch = _hid_to_ascii(hk.keycode, mod)
- else:
- ascii_ch = _ps2_scancode_to_ascii(hk.keycode)
- if ascii_ch != 0:
- rep_evt: InputEvent
- rep_evt.type = EVENT_TYPE_KEY
- rep_evt.win_id = _focused_win
- rep_evt.x = ascii_ch
- rep_evt.y = t.CInt(hk.keycode)
- rep_evt.button = KEY_STATE_REPEAT
- rep_evt._pad0 = 0
- rep_evt._pad1 = 0
- rep_evt._pad2 = 0
- _push_event(rep_evt)
-
-def _update_keyboard():
- global _focused_win, _kbd_irq_masked
- global _ps2_shift_l, _ps2_shift_r, _ps2_caps
- global _ps2_e0_pending
- # Quick check: skip if no PS/2 data and no USB data
- ps2_status: t.CUInt8T = asm.inb(0x64)
- if (ps2_status & 0x01) == 0 and not usb_kbd.has_data():
- _check_key_repeat()
- return
- if _kbd_irq_masked == 0:
- pic.clearMask(1)
- _kbd_irq_masked = 1
- kbd_cnt: t.CInt = 0
- while usb_kbd.has_data() and kbd_cnt < 32:
- kbd_cnt += 1
- kevt: usb_kbd.usb_kbd_event
- usb_kbd.read_event(c.Addr(kevt))
- if kevt.keycode == 0x39 and kevt.event_type == usb_kbd.KBD_EVT_PRESS:
- _ps2_caps = _ps2_caps ^ t.CUInt8T(1)
- if kevt.event_type == usb_kbd.KBD_EVT_PRESS:
- _held_key_add(kevt.keycode, 1)
- usb_ascii: t.CInt = _hid_to_ascii(kevt.keycode, kevt.modifier)
- if usb_ascii == 0:
- kc2: t.CInt = t.CInt(kevt.keycode)
- if kc2 == 0x50: usb_ascii = VK_LEFT
- elif kc2 == 0x4F: usb_ascii = VK_RIGHT
- elif kc2 == 0x52: usb_ascii = VK_UP
- elif kc2 == 0x51: usb_ascii = VK_DOWN
- elif kc2 == 0x4A: usb_ascii = VK_HOME
- elif kc2 == 0x4D: usb_ascii = VK_END
- elif kc2 == 0x4C: usb_ascii = VK_DELETE
- if usb_ascii != 0 and _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
- usb_evt: InputEvent
- usb_evt.type = EVENT_TYPE_KEY
- usb_evt.win_id = _focused_win
- usb_evt.x = usb_ascii
- usb_evt.y = t.CInt(kevt.keycode)
- usb_evt.button = KEY_STATE_PRESS
- usb_evt._pad0 = 0
- usb_evt._pad1 = 0
- usb_evt._pad2 = 0
- _push_event(usb_evt)
- elif kevt.event_type == usb_kbd.KBD_EVT_RELEASE:
- _held_key_remove(kevt.keycode, 1)
- if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
- rel_evt: InputEvent
- rel_evt.type = EVENT_TYPE_KEY_RELEASE
- rel_evt.win_id = _focused_win
- rel_evt.x = 0
- rel_evt.y = t.CInt(kevt.keycode)
- rel_evt.button = KEY_STATE_RELEASE
- rel_evt._pad0 = 0
- rel_evt._pad1 = 0
- rel_evt._pad2 = 0
- _push_event(rel_evt)
- ps2_poll_count: t.CInt = 0
- while ps2_poll_count < 16:
- ps2_status: t.CUInt8T = asm.inb(0x64)
- if (ps2_status & 0x01) == 0:
- break
- if (ps2_status & 0x20) != 0:
- asm.inb(0x60)
- ps2_poll_count += 1
- continue
- sc: t.CUInt8T = asm.inb(0x60)
- ps2_poll_count += 1
- if sc == 0x00 or sc == 0xFA or sc == 0xFE or sc == 0xFF:
- _ps2_e0_pending = 0
- continue
- if sc == 0xE0:
- _ps2_e0_pending = 1
- continue
- if sc == 0xE1:
- _ps2_e0_pending = 0
- continue
- if _ps2_e0_pending != 0:
- _ps2_e0_pending = 0
- e0_code: t.CUInt8T = sc & t.CUInt8T(0x7F)
- if (sc & 0x80) != 0:
- _held_key_remove(e0_code | 0x80, 0)
- if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
- ps2_rel2: InputEvent
- ps2_rel2.type = EVENT_TYPE_KEY_RELEASE
- ps2_rel2.win_id = _focused_win
- ps2_rel2.x = 0
- ps2_rel2.y = t.CInt(e0_code | 0x80)
- ps2_rel2.button = KEY_STATE_RELEASE
- ps2_rel2._pad0 = 0
- ps2_rel2._pad1 = 0
- ps2_rel2._pad2 = 0
- _push_event(ps2_rel2)
- continue
- vk: t.CInt = 0
- if e0_code == 0x4B: vk = VK_LEFT
- elif e0_code == 0x4D: vk = VK_RIGHT
- elif e0_code == 0x48: vk = VK_UP
- elif e0_code == 0x50: vk = VK_DOWN
- elif e0_code == 0x47: vk = VK_HOME
- elif e0_code == 0x4F: vk = VK_END
- elif e0_code == 0x53: vk = VK_DELETE
- if vk != 0:
- _held_key_add(e0_code | 0x80, 0)
- if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
- e0_evt: InputEvent
- e0_evt.type = EVENT_TYPE_KEY
- e0_evt.win_id = _focused_win
- e0_evt.x = vk
- e0_evt.y = t.CInt(e0_code | 0x80)
- e0_evt.button = KEY_STATE_PRESS
- e0_evt._pad0 = 0
- e0_evt._pad1 = 0
- e0_evt._pad2 = 0
- _push_event(e0_evt)
- continue
- if sc == 0x2A:
- _ps2_shift_l = 1
- continue
- if sc == 0xAA:
- _ps2_shift_l = 0
- continue
- if sc == 0x36:
- _ps2_shift_r = 1
- continue
- if sc == 0xB6:
- _ps2_shift_r = 0
- continue
- if sc == 0x3A:
- _ps2_caps = _ps2_caps ^ t.CUInt8T(1)
- continue
- if (sc & 0x80) != 0:
- release_sc: t.CUInt8T = sc & t.CUInt8T(0x7F)
- _held_key_remove(release_sc, 0)
- if _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
- ps2_rel: InputEvent
- ps2_rel.type = EVENT_TYPE_KEY_RELEASE
- ps2_rel.win_id = _focused_win
- ps2_rel.x = 0
- ps2_rel.y = t.CInt(release_sc)
- ps2_rel.button = KEY_STATE_RELEASE
- ps2_rel._pad0 = 0
- ps2_rel._pad1 = 0
- ps2_rel._pad2 = 0
- _push_event(ps2_rel)
- continue
- _held_key_add(sc, 0)
- ascii_ch: t.CInt = _ps2_scancode_to_ascii(sc)
- if ascii_ch != 0 and _focused_win >= 0 and _focused_win < _win_count and _wins[_focused_win].active:
- push_evt: InputEvent
- push_evt.type = EVENT_TYPE_KEY
- push_evt.win_id = _focused_win
- push_evt.x = ascii_ch
- push_evt.y = t.CInt(sc)
- push_evt.button = KEY_STATE_PRESS
- push_evt._pad0 = 0
- push_evt._pad1 = 0
- push_evt._pad2 = 0
- _push_event(push_evt)
- _check_key_repeat()
-
-def set_cursor_type(win_id: t.CInt, cursor_t: t.CInt):
- if win_id >= 0 and win_id < _win_count:
- _wins[win_id].app_cursor_type = cursor_t
- _wins[win_id].cursor_type = cursor_t
-
-def _update_mouse() -> t.CInt:
- global _cursor_x, _cursor_y, _cursor_buttons
- global _drag_idx, _drag_off_x, _drag_off_y
- global _mouse_moved, _prev_btn, _last_hover_win, _focused_win
- global _rsz_drag_idx, _rsz_edge, _rsz_start_x, _rsz_start_y
- global _rsz_start_w, _rsz_start_h, _rsz_last_w, _rsz_last_h, _rsz_last_tick
- moved: t.CInt = 0
- poll_cnt: t.CInt = 0
- while (mouse.has_data() or usb_mouse.has_data()) and poll_cnt < 32:
- poll_cnt += 1
- pkt_dx: t.CInt32T = 0
- pkt_dy: t.CInt32T = 0
- pkt_btn: t.CUInt8T = 0
- if mouse.has_data():
- pkt: mouse.mouse_packet
- mouse.read_packet(c.Addr(pkt))
- pkt_dx = t.CInt32T(pkt.dx)
- pkt_dy = -t.CInt32T(pkt.dy)
- pkt_btn = pkt.buttons
- elif usb_mouse.has_data():
- upkt: usb_mouse.usb_mouse_packet
- usb_mouse.read_packet(c.Addr(upkt))
- pkt_dx = t.CInt32T(upkt.dx)
- pkt_dy = -t.CInt32T(upkt.dy)
- pkt_btn = upkt.buttons
- if pkt_dx != 0 or pkt_dy != 0:
- _cursor_x = _cursor_x + pkt_dx
- _cursor_y = _cursor_y + pkt_dy
- if _cursor_x < 0: _cursor_x = 0
- if _cursor_y < 0: _cursor_y = 0
- if _cursor_x >= _screen_w: _cursor_x = _screen_w - 1
- if _cursor_y >= _screen_h: _cursor_y = _screen_h - 1
- moved = 1
- _mouse_moved = 1
- btn_down: t.CUInt8T = pkt_btn & 0x01
- prev_down: t.CUInt8T = _prev_btn & 0x01
- _cursor_buttons = pkt_btn
- _prev_btn = pkt_btn
- if btn_down and not prev_down:
- hit_app: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
- if hit_app >= 0:
- aw: AppWindow | t.CPtr = c.Addr(_wins[hit_app])
- th: t.CInt = _get_title_height(aw.style)
- btn_w: t.CInt = CLOSE_BTN_SIZE
- btn_h: t.CInt = CLOSE_BTN_SIZE
- ew: t.CInt = _eff_w(aw)
- btn_x: t.CInt = aw.x + ew - btn_w - 4
- btn_y: t.CInt = aw.y + (th - btn_h) // 2
- if aw.style == STYLE_WIN7:
- btn_w = CLOSE_BTN_W7_W
- btn_h = CLOSE_BTN_W7_H
- btn_x = aw.x + ew - btn_w - 5
- btn_y = aw.y + (th - btn_h) // 2
- elif aw.style == STYLE_WINXP:
- btn_w = CLOSE_BTN_XP_SZ
- btn_h = CLOSE_BTN_XP_SZ
- btn_x = aw.x + ew - btn_w - 5
- btn_y = aw.y + (th - btn_h) // 2
- elif aw.style == STYLE_WIN10 or aw.style == STYLE_WIN11:
- btn_w = CLOSE_BTN_W_WIN
- btn_h = th - 2
- btn_x = aw.x + ew - btn_w
- btn_y = aw.y + 1
- if _cursor_x >= btn_x and _cursor_x < btn_x + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
- aw.active = 0
- if _focused_win == hit_app:
- _focused_win = -1
- j: t.CInt = _win_count - 1
- while j >= 0:
- if _wins[j].active and not _wins[j].minimized:
- _focused_win = j
- break
- j -= 1
- if _last_hover_win == hit_app:
- _last_hover_win = -1
- _mark_all_dirty()
- else:
- max_bx2: t.CInt = btn_x - btn_w
- if aw.style == STYLE_WIN7 or aw.style == STYLE_WINXP:
- max_bx2 = btn_x - btn_w - 1
- if _cursor_x >= max_bx2 and _cursor_x < max_bx2 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
- if aw.is_maximized:
- aw.is_maximized = 0
- aw.x = aw.orig_x
- aw.y = aw.orig_y
- aw.h = aw.orig_h
- aw.resize_w = aw.orig_w
- aw.resize_h = aw.orig_h - _get_title_height(aw.style) - 2
- else:
- aw.is_maximized = 1
- aw.orig_x = aw.w
- aw.orig_y = aw.y
- aw.orig_w = aw.w
- aw.orig_h = aw.h
- aw.x = 0
- aw.y = 0
- tb_h_mx: t.CInt = TASKBAR_HEIGHT
- aw.h = _screen_h - tb_h_mx
- aw.resize_w = _screen_w
- aw.resize_h = _screen_h - tb_h_mx - _get_title_height(aw.style) - 2
- rs_evt3: InputEvent
- rs_evt3.type = EVENT_TYPE_RESIZE
- rs_evt3.win_id = hit_app
- rs_evt3.x = aw.resize_w
- rs_evt3.y = aw.resize_h
- rs_evt3.button = 0
- rs_evt3._pad0 = 0
- rs_evt3._pad1 = 0
- rs_evt3._pad2 = 0
- _push_event(rs_evt3)
- _mark_all_dirty()
- else:
- min_bx2: t.CInt = max_bx2 - btn_w
- if aw.style == STYLE_WIN7 or aw.style == STYLE_WINXP:
- min_bx2 = max_bx2 - btn_w - 1
- if _cursor_x >= min_bx2 and _cursor_x < min_bx2 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
- aw.minimized = 1
- if _focused_win == hit_app:
- _focused_win = -1
- j2: t.CInt = _win_count - 1
- while j2 >= 0:
- if _wins[j2].active and not _wins[j2].minimized:
- _focused_win = j2
- break
- j2 -= 1
- _mark_all_dirty()
- else:
- re: t.CInt = _hit_test_resize(_cursor_x, _cursor_y, hit_app)
- if re != RESIZE_EDGE_NONE:
- _rsz_drag_idx = hit_app
- _rsz_edge = re
- _rsz_start_x = _cursor_x
- _rsz_start_y = _cursor_y
- _rsz_start_w = _eff_w(aw)
- _rsz_start_h = aw.h
- _rsz_last_w = _eff_w(aw)
- _rsz_last_h = aw.h
- _rsz_last_tick = timer.timer_get_ticks()
- _bring_to_front(hit_app)
- _focused_win = hit_app
- _mark_all_dirty()
- elif _cursor_y >= aw.y and _cursor_y < aw.y + th:
- _drag_idx = hit_app
- _drag_off_x = _cursor_x - aw.x
- _drag_off_y = _cursor_y - aw.y
- _bring_to_front(hit_app)
- _focused_win = hit_app
- _mark_all_dirty()
- else:
- _bring_to_front(hit_app)
- _focused_win = hit_app
- _mark_all_dirty()
- evt: InputEvent
- evt.type = EVENT_TYPE_CLICK
- evt.win_id = hit_app
- evt.x = _cursor_x - aw.x
- evt.y = _cursor_y - aw.y - _get_title_height(aw.style)
- evt.button = 1
- evt._pad0 = 0
- evt._pad1 = 0
- evt._pad2 = 0
- _push_event(evt)
- else:
- tb_h_cl: t.CInt = TASKBAR_HEIGHT
- bar_y2: t.CInt = _screen_h - tb_h_cl
- if _cursor_y >= bar_y2:
- logo_x2: t.CInt = 4
- logo_sz2: t.CInt = TASKBAR_LOGO_SZ
- logo_r2: t.CInt = logo_x2 + logo_sz2
- logo_b2: t.CInt = bar_y2 + tb_h_cl
- if _cursor_x >= logo_x2 and _cursor_x < logo_r2 and _cursor_y >= bar_y2 and _cursor_y < logo_b2:
- if _focused_win >= 0 and _focused_win < _win_count:
- if _wins[_focused_win].active:
- _wins[_focused_win].active = 0
- _focused_win = -1
- _mark_all_dirty()
- else:
- icon_sz2: t.CInt = TASKBAR_ICON_SZ
- icon_pad2: t.CInt = TASKBAR_ICON_PAD
- icon_x2: t.CInt = logo_x2 + logo_sz2 + 80
- icon_cnt2: t.CInt = 0
- for ti2 in range(_win_count):
- if _wins[ti2].active:
- ix2: t.CInt = icon_x2 + icon_cnt2 * (icon_sz2 + icon_pad2)
- iy2: t.CInt = bar_y2 + (tb_h_cl - icon_sz2) // 2
- if _cursor_x >= ix2 and _cursor_x < ix2 + icon_sz2 and _cursor_y >= iy2 and _cursor_y < iy2 + icon_sz2:
- if _wins[ti2].minimized:
- _wins[ti2].minimized = 0
- _bring_to_front(ti2)
- _focused_win = ti2
- elif _focused_win == ti2:
- _wins[ti2].minimized = 1
- _focused_win = -1
- for j3 in range(_win_count - 1, -1, -1):
- if _wins[j3].active and not _wins[j3].minimized:
- _focused_win = j3
- break
- else:
- _bring_to_front(ti2)
- _focused_win = ti2
- _mark_all_dirty()
- break
- icon_cnt2 += 1
- if not btn_down:
- if prev_down:
- if _rsz_drag_idx >= 0:
- rs_aw: AppWindow | t.CPtr = c.Addr(_wins[_rsz_drag_idx])
- final_w: t.CInt = _rsz_last_w
- final_h: t.CInt = _rsz_last_h
- old_h_mu: t.CInt = _eff_h(rs_aw) + _get_title_height(rs_aw.style) + 2
- _mark_rows_dirty(rs_aw.y, old_h_mu)
- final_ch: t.CInt = final_h - _get_title_height(rs_aw.style) - 2
- rs_aw.resize_w = final_w
- rs_aw.resize_h = final_ch
- rs_aw.h = final_h
- _mark_rows_dirty(rs_aw.y, final_h)
- rs_evt: InputEvent
- rs_evt.type = EVENT_TYPE_RESIZE
- rs_evt.win_id = _rsz_drag_idx
- rs_evt.x = final_w
- rs_evt.y = final_ch
- rs_evt.button = 0
- rs_evt._pad0 = 0
- rs_evt._pad1 = 0
- rs_evt._pad2 = 0
- _push_event(rs_evt)
- _rsz_drag_idx = -1
- _rsz_edge = RESIZE_EDGE_NONE
- else:
- rel_hit: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
- if rel_hit >= 0:
- aw_rel: AppWindow | t.CPtr = c.Addr(_wins[rel_hit])
- rel_evt: InputEvent
- rel_evt.type = EVENT_TYPE_RELEASE
- rel_evt.win_id = rel_hit
- rel_evt.x = _cursor_x - aw_rel.x
- rel_evt.y = _cursor_y - aw_rel.y - _get_title_height(aw_rel.style)
- rel_evt.button = 0
- rel_evt._pad0 = 0
- rel_evt._pad1 = 0
- rel_evt._pad2 = 0
- _push_event(rel_evt)
- if _drag_idx >= 0:
- moved = 1
- _mark_rows_dirty(_wins[_drag_idx].y, _wins[_drag_idx].h)
- _drag_idx = -1
- if moved and _drag_idx < 0:
- hit_hov: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
- if hit_hov >= 0:
- if _last_hover_win >= 0 and _last_hover_win != hit_hov and _last_hover_win < _win_count:
- if _wins[_last_hover_win].active:
- leave_evt3: InputEvent
- leave_evt3.type = EVENT_TYPE_HOVER_LEAVE
- leave_evt3.win_id = _last_hover_win
- leave_evt3.x = -1
- leave_evt3.y = -1
- leave_evt3.button = 0
- leave_evt3._pad0 = 0
- leave_evt3._pad1 = 0
- leave_evt3._pad2 = 0
- _push_event(leave_evt3)
- aw_hov: AppWindow | t.CPtr = c.Addr(_wins[hit_hov])
- th_hov: t.CInt = _get_title_height(aw_hov.style)
- hov_evt: InputEvent
- hov_evt.type = EVENT_TYPE_HOVER
- hov_evt.win_id = hit_hov
- hov_evt.x = _cursor_x - aw_hov.x
- hov_evt.y = _cursor_y - aw_hov.y - th_hov
- hov_evt.button = 0
- hov_evt._pad0 = 0
- hov_evt._pad1 = 0
- hov_evt._pad2 = 0
- _push_event(hov_evt)
- _last_hover_win = hit_hov
- re_hov: t.CInt = _hit_test_resize(_cursor_x, _cursor_y, hit_hov)
- if re_hov == RESIZE_EDGE_RIGHT:
- aw_hov.cursor_type = CURSOR_RESIZE_EW
- elif re_hov == RESIZE_EDGE_BOTTOM:
- aw_hov.cursor_type = CURSOR_RESIZE_NS
- elif re_hov == RESIZE_EDGE_CORNER:
- aw_hov.cursor_type = CURSOR_RESIZE_NWSE
- else:
- aw_hov.cursor_type = aw_hov.app_cursor_type
- else:
- if _last_hover_win >= 0 and _last_hover_win < _win_count:
- if _wins[_last_hover_win].active:
- leave_evt: InputEvent
- leave_evt.type = EVENT_TYPE_HOVER_LEAVE
- leave_evt.win_id = _last_hover_win
- leave_evt.x = -1
- leave_evt.y = -1
- leave_evt.button = 0
- leave_evt._pad0 = 0
- leave_evt._pad1 = 0
- leave_evt._pad2 = 0
- _push_event(leave_evt)
- _last_hover_win = -1
- if _drag_idx >= 0:
- aw2: AppWindow | t.CPtr = c.Addr(_wins[_drag_idx])
- _drag_old_y: t.CInt = aw2.y
- _mark_rows_dirty(_drag_old_y, aw2.h)
- aw2.x = _cursor_x - _drag_off_x
- aw2.y = _cursor_y - _drag_off_y
- _mark_rows_dirty(aw2.y, aw2.h)
- if _rsz_drag_idx >= 0:
- rs_aw2: AppWindow | t.CPtr = c.Addr(_wins[_rsz_drag_idx])
- dx: t.CInt = _cursor_x - _rsz_start_x
- dy: t.CInt = _cursor_y - _rsz_start_y
- new_w: t.CInt = _rsz_start_w
- new_h: t.CInt = _rsz_start_h
- if _rsz_edge == RESIZE_EDGE_RIGHT or _rsz_edge == RESIZE_EDGE_CORNER:
- new_w = _rsz_start_w + dx
- if new_w < RESIZE_MIN_W: new_w = RESIZE_MIN_W
- if _rsz_edge == RESIZE_EDGE_BOTTOM or _rsz_edge == RESIZE_EDGE_CORNER:
- new_h = _rsz_start_h + dy
- if new_h < RESIZE_MIN_H: new_h = RESIZE_MIN_H
- if new_w != rs_aw2.w or new_h != rs_aw2.h:
- dw: t.CInt = new_w - _rsz_last_w
- if dw < 0: dw = -dw
- dh: t.CInt = new_h - _rsz_last_h
- if dh < 0: dh = -dh
- now_tick: t.CUInt64T = timer.timer_get_ticks()
- elapsed: t.CUInt64T = now_tick - _rsz_last_tick
- need_update: t.CInt = 0
- if dw >= 32 or dh >= 32:
- need_update = 1
- elif elapsed >= 100 and (dw >= 4 or dh >= 4):
- need_update = 1
- if need_update:
- _rsz_last_w = new_w
- _rsz_last_h = new_h
- _rsz_last_tick = now_tick
- old_h_rs: t.CInt = _eff_h(rs_aw2) + _get_title_height(rs_aw2.style) + 2
- _mark_rows_dirty(rs_aw2.y, old_h_rs)
- new_ch: t.CInt = new_h - _get_title_height(rs_aw2.style) - 2
- rs_aw2.resize_w = new_w
- rs_aw2.resize_h = new_ch
- rs_aw2.h = new_h
- _mark_rows_dirty(rs_aw2.y, new_h)
- rs_evt2: InputEvent
- rs_evt2.type = EVENT_TYPE_RESIZE
- rs_evt2.win_id = _rsz_drag_idx
- rs_evt2.x = new_w
- rs_evt2.y = new_ch
- rs_evt2.button = 0
- rs_evt2._pad0 = 0
- rs_evt2._pad1 = 0
- rs_evt2._pad2 = 0
- _push_event(rs_evt2)
- if not moved and _last_hover_win < 0:
- hit_hov2: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
- if hit_hov2 >= 0 and _wins[hit_hov2].active:
- aw_hov2: AppWindow | t.CPtr = c.Addr(_wins[hit_hov2])
- th_hov2: t.CInt = _get_title_height(aw_hov2.style)
- hov_evt2: InputEvent
- hov_evt2.type = EVENT_TYPE_HOVER
- hov_evt2.win_id = hit_hov2
- hov_evt2.x = _cursor_x - aw_hov2.x
- hov_evt2.y = _cursor_y - aw_hov2.y - th_hov2
- hov_evt2.button = 0
- hov_evt2._pad0 = 0
- hov_evt2._pad1 = 0
- hov_evt2._pad2 = 0
- _push_event(hov_evt2)
- _last_hover_win = hit_hov2
- if not moved and _last_hover_win >= 0:
- if _last_hover_win >= _win_count or not _wins[_last_hover_win].active:
- leave_evt2: InputEvent
- leave_evt2.type = EVENT_TYPE_HOVER_LEAVE
- leave_evt2.win_id = _last_hover_win
- leave_evt2.x = -1
- leave_evt2.y = -1
- leave_evt2.button = 0
- leave_evt2._pad0 = 0
- leave_evt2._pad1 = 0
- leave_evt2._pad2 = 0
- _push_event(leave_evt2)
- _last_hover_win = -1
- return moved
-
-_render_count: t.CInt = 0
-_cached_top_win: t.CInt = -1
-_perf_t_mouse: t.CUInt64T = 0
-_perf_t_kbd: t.CUInt64T = 0
-_perf_t_render: t.CUInt64T = 0
-_perf_t_flush: t.CUInt64T = 0
-_perf_t_total: t.CUInt64T = 0
-_perf_frames: t.CUInt32T = 0
-_perf_start_ticks: t.CUInt64T = 0
-_perf_t_bg: t.CUInt64T = 0
-_perf_t_win: t.CUInt64T = 0
-_perf_t_cur: t.CUInt64T = 0
-_perf_t_fb: t.CUInt64T = 0
-
-def _render():
- global _render_count, _cached_top_win
- global _perf_t_bg, _perf_t_win, _perf_t_cur, _perf_t_fb
- w: t.CInt = _screen_w
- h: t.CInt = _screen_h
- pitch: t.CInt = _fb_pitch
- back: UINT32PTR = _back_fb
-
- _cached_top_win = _get_top_window()
-
- # No need to erase cursor - dirty row mechanism redraws background + windows from scratch
-
- t0: t.CUInt64T = timer.timer_get_ticks()
- row_bytes: t.CInt = w * 4
- if _bg_row_buf and _dirty_count > 0:
- py_bg: t.CInt = _dirty_y_min
- while py_bg <= _dirty_y_max:
- if _dirty_rows[py_bg]:
- string.memcpy(t.CVoid(t.CUInt64T(back) + py_bg * row_bytes, t.CPtr), _bg_row_buf, row_bytes)
- py_bg += 1
- t1: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_bg += (t1 - t0)
-
- _draw_taskbar(back)
-
- t2: t.CUInt64T = timer.timer_get_ticks()
- sorted: t.CArray[t.CInt, MAX_APP_WINDOWS]
- cnt: t.CInt = 0
- for si in range(_win_count):
- if _wins[si].active and not _wins[si].minimized:
- sorted[cnt] = si
- cnt += 1
- for si in range(cnt - 1):
- for sj in range(si + 1, cnt):
- zi: t.CInt = _wins[sorted[si]].z_order
- zj: t.CInt = _wins[sorted[sj]].z_order
- if zi > zj:
- tmp: t.CInt = sorted[si]
- sorted[si] = sorted[sj]
- sorted[sj] = tmp
- for si in range(cnt):
- _draw_app_window(back, c.Addr(_wins[sorted[si]]))
- t3: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_win += (t3 - t2)
-
- # Mark cursor rows as dirty so cursor gets flushed to framebuffer
- _mark_rows_dirty(_cursor_y, CURSOR_H)
-
- _draw_cursor(back)
- t4: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_cur += (t4 - t3)
-
- _wait_vblank()
- if _dirty_count > 0:
- py_fb: t.CInt = _dirty_y_min
- while py_fb <= _dirty_y_max:
- if _dirty_rows[py_fb]:
- run_start: t.CInt = py_fb
- while py_fb <= _dirty_y_max and _dirty_rows[py_fb]:
- py_fb += 1
- run_bytes: t.CInt = (py_fb - run_start) * row_bytes
- string.memcpy(t.CVoid(t.CUInt64T(_fb) + run_start * pitch, t.CPtr), t.CVoid(t.CUInt64T(back) + run_start * row_bytes, t.CPtr), run_bytes)
- else:
- py_fb += 1
- t5: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_fb += (t5 - t4)
-
- _render_count += 1
-
-def _draw_taskbar(back: UINT32PTR):
- w: t.CInt = _screen_w
- h: t.CInt = _screen_h
- tb_h: t.CInt = TASKBAR_HEIGHT
- bar_y: t.CInt = h - tb_h
- if bar_y + tb_h <= _dirty_y_min or bar_y > _dirty_y_max:
- return
- bar_col: t.CUInt32T = gfx.COLOR_RGB(32, 32, 32)
- line_col: t.CUInt32T = gfx.COLOR_RGB(60, 60, 60)
-
- _fill_rect(back, w, h, 0, bar_y, w, tb_h, bar_col)
- _fill_rect(back, w, h, 0, bar_y, w, 1, line_col)
-
- logo_x: t.CInt = 4
- logo_sz: t.CInt = TASKBAR_LOGO_SZ
- logo_y: t.CInt = bar_y + (tb_h - logo_sz) // 2
- lc1: t.CUInt32T = gfx.COLOR_RGB(80, 120, 220)
- lc2: t.CUInt32T = gfx.COLOR_RGB(50, 80, 180)
- lc3: t.CUInt32T = gfx.COLOR_RGB(100, 160, 255)
- for lx in range(logo_sz):
- for ly in range(logo_sz):
- px: t.CInt = logo_x + lx
- py: t.CInt = logo_y + ly
- if px >= 0 and px < w and py >= 0 and py < h:
- col: t.CUInt32T = lc2
- cx: t.CInt = logo_sz // 2
- cy: t.CInt = logo_sz // 2
- dx: t.CInt = lx - cx
- dy: t.CInt = ly - cy
- dist: t.CInt = dx * dx + dy * dy
- r2: t.CInt = cx * cx
- if dist <= r2:
- col = lc1
- if dist <= r2 // 2:
- col = lc3
- back[py * w + px] = col
-
- _draw_text(back, w, h, logo_x + logo_sz + 8, bar_y + (tb_h - 16) // 2, "ViperOS", 0xFFFFFFFF)
-
- icon_sz: t.CInt = TASKBAR_ICON_SZ
- icon_pad: t.CInt = TASKBAR_ICON_PAD
- icon_x: t.CInt = logo_x + logo_sz + 80
- icon_cnt: t.CInt = 0
- for ti in range(_win_count):
- if _wins[ti].active:
- ix: t.CInt = icon_x + icon_cnt * (icon_sz + icon_pad)
- iy: t.CInt = bar_y + (tb_h - icon_sz) // 2
- is_focused: t.CInt = 1 if ti == _focused_win else 0
- is_minimized: t.CInt = _wins[ti].minimized
- ic_bg: t.CUInt32T = gfx.COLOR_RGB(40, 40, 70)
- if is_focused:
- ic_bg = gfx.COLOR_RGB(60, 60, 120)
- elif is_minimized:
- ic_bg = gfx.COLOR_RGB(30, 30, 50)
- _fill_rect(back, w, h, ix, iy, icon_sz, icon_sz, ic_bg)
- ic_border: t.CUInt32T = gfx.COLOR_RGB(80, 80, 140)
- if is_focused:
- ic_border = gfx.COLOR_RGB(120, 120, 220)
- _fill_rect(back, w, h, ix, iy, icon_sz, 1, ic_border)
- _fill_rect(back, w, h, ix, iy + icon_sz - 1, icon_sz, 1, ic_border)
- _fill_rect(back, w, h, ix, iy, 1, icon_sz, ic_border)
- _fill_rect(back, w, h, ix + icon_sz - 1, iy, 1, icon_sz, ic_border)
- if _wins[ti].title[0] != 0:
- first_ch: t.CChar = _wins[ti].title[0]
- ch_col: t.CUInt32T = 0xFFFFFFFF
- if not is_focused:
- ch_col = gfx.COLOR_RGB(180, 180, 200)
- ch_x: t.CInt = ix + (icon_sz - 8) // 2
- ch_y: t.CInt = iy + (icon_sz - 16) // 2
- _draw_char(back, w, h, ch_x, ch_y, first_ch, ch_col)
- icon_cnt += 1
-
- if _render_count % 30 == 0:
- rtc.rtc_read_time()
-
- hr: t.CUInt8T = rtc.rtc_get_hours()
- mn: t.CUInt8T = rtc.rtc_get_minutes()
- sc: t.CUInt8T = rtc.rtc_get_seconds()
- day: t.CUInt8T = rtc.rtc_get_day()
- mon: t.CUInt8T = rtc.rtc_get_month()
- yr: t.CUInt16T = rtc.rtc_get_year()
- time_buf: t.CArray[t.CChar, 64]
- string.memset(c.Addr(time_buf), 0, 64)
- viperlib.snprintf(c.Addr(time_buf), 64, "%04u-%02u-%02u %02u:%02u:%02u", t.CUnsignedInt(yr), t.CUnsignedInt(mon), t.CUnsignedInt(day), t.CUnsignedInt(hr), t.CUnsignedInt(mn), t.CUnsignedInt(sc))
- time_str_x: t.CInt = w - 180
- _draw_text(back, w, h, time_str_x, bar_y + (tb_h - 16) // 2, time_buf, 0xFFFFFFFF)
-
-def _draw_window_shadow(back: UINT32PTR, bw: t.CInt, bh: t.CInt, wx: t.CInt, wy: t.CInt, ww: t.CInt, wh: t.CInt, is_rounded: t.CInt, rad: t.CInt):
- if not SHADOW_ENABLED: return
- sl: t.CInt = SHADOW_LEFT
- sr: t.CInt = SHADOW_RIGHT
- st: t.CInt = SHADOW_TOP
- sb: t.CInt = SHADOW_BOTTOM
- sa: t.CInt = SHADOW_ALPHA
- shadow_col: t.CUInt32T = gfx.COLOR_RGB(0, 0, 0)
- for py in range(wy - st, wy + wh + sb):
- if py >= 0 and py < bh:
- if not _dirty_rows[py]:
- continue
- for px in range(wx - sl, wx + ww + sr):
- if px >= 0 and px < bw:
- in_win: t.CInt = 0
- if px >= wx and px < wx + ww and py >= wy and py < wy + wh:
- in_win = 1
- if is_rounded:
- rx: t.CInt = px - wx
- ry: t.CInt = py - wy
- if rx < rad and ry < rad:
- if (rx - rad) * (rx - rad) + (ry - rad) * (ry - rad) > rad * rad:
- in_win = 0
- elif rx >= ww - rad and ry < rad:
- if (rx - (ww - rad - 1)) * (rx - (ww - rad - 1)) + (ry - rad) * (ry - rad) > rad * rad:
- in_win = 0
- elif rx < rad and ry >= wh - rad:
- if (rx - rad) * (rx - rad) + (ry - (wh - rad - 1)) * (ry - (wh - rad - 1)) > rad * rad:
- in_win = 0
- elif rx >= ww - rad and ry >= wh - rad:
- if (rx - (ww - rad - 1)) * (rx - (ww - rad - 1)) + (ry - (wh - rad - 1)) * (ry - (wh - rad - 1)) > rad * rad:
- in_win = 0
- if in_win:
- continue
- cpx: t.CInt = px
- if cpx < wx: cpx = wx
- elif cpx > wx + ww - 1: cpx = wx + ww - 1
- cpy: t.CInt = py
- if cpy < wy: cpy = wy
- elif cpy > wy + wh - 1: cpy = wy + wh - 1
- if is_rounded and rad > 0:
- if cpx < wx + rad and cpy < wy + rad:
- acx: t.CInt = wx + rad
- acy: t.CInt = wy + rad
- adx: t.CInt = cpx - acx
- ady: t.CInt = cpy - acy
- ad_sq: t.CInt = adx * adx + ady * ady
- if ad_sq > rad * rad and ad_sq > 0:
- aax: t.CInt = adx
- if aax < 0: aax = 0 - aax
- aay: t.CInt = ady
- if aay < 0: aay = 0 - aay
- am: t.CInt = aax
- if aay > am: am = aay
- an: t.CInt = aax
- if aay < an: an = aay
- ad: t.CInt = am + (an * 3) / 8
- if ad > 0:
- cpx = acx + (adx * rad) / ad
- cpy = acy + (ady * rad) / ad
- elif cpx >= wx + ww - rad and cpy < wy + rad:
- acx = wx + ww - rad - 1
- acy = wy + rad
- adx = cpx - acx
- ady = cpy - acy
- ad_sq = adx * adx + ady * ady
- if ad_sq > rad * rad and ad_sq > 0:
- aax = adx
- if aax < 0: aax = 0 - aax
- aay = ady
- if aay < 0: aay = 0 - aay
- am = aax
- if aay > am: am = aay
- an = aax
- if aay < an: an = aay
- ad = am + (an * 3) / 8
- if ad > 0:
- cpx = acx + (adx * rad) / ad
- cpy = acy + (ady * rad) / ad
- elif cpx < wx + rad and cpy >= wy + wh - rad:
- acx = wx + rad
- acy = wy + wh - rad - 1
- adx = cpx - acx
- ady = cpy - acy
- ad_sq = adx * adx + ady * ady
- if ad_sq > rad * rad and ad_sq > 0:
- aax = adx
- if aax < 0: aax = 0 - aax
- aay = ady
- if aay < 0: aay = 0 - aay
- am = aax
- if aay > am: am = aay
- an = aax
- if aay < an: an = aay
- ad = am + (an * 3) / 8
- if ad > 0:
- cpx = acx + (adx * rad) / ad
- cpy = acy + (ady * rad) / ad
- elif cpx >= wx + ww - rad and cpy >= wy + wh - rad:
- acx = wx + ww - rad - 1
- acy = wy + wh - rad - 1
- adx = cpx - acx
- ady = cpy - acy
- ad_sq = adx * adx + ady * ady
- if ad_sq > rad * rad and ad_sq > 0:
- aax = adx
- if aax < 0: aax = 0 - aax
- aay = ady
- if aay < 0: aay = 0 - aay
- am = aax
- if aay > am: am = aay
- an = aax
- if aay < an: an = aay
- ad = am + (an * 3) / 8
- if ad > 0:
- cpx = acx + (adx * rad) / ad
- cpy = acy + (ady * rad) / ad
- dx: t.CInt = px - cpx
- dy: t.CInt = py - cpy
- adx_d: t.CInt = dx
- if adx_d < 0: adx_d = 0 - adx_d
- ady_d: t.CInt = dy
- if ady_d < 0: ady_d = 0 - ady_d
- dist: t.CInt = adx_d
- if ady_d > dist: dist = ady_d
- dist = dist + ((adx_d + ady_d - dist) * 3) / 8
- me_x: t.CInt = sl
- if dx > 0: me_x = sr
- me_y: t.CInt = st
- if dy > 0: me_y = sb
- me: t.CInt = me_x
- if adx_d + ady_d > 0:
- me = (me_x * adx_d + me_y * ady_d) / (adx_d + ady_d)
- if me > 0 and dist > 0 and dist < me:
- t_val: t.CInt = (256 * dist) / me
- t_inv: t.CInt = 256 - t_val
- a: t.CInt = (sa * t_inv * t_inv) / 65536
- if a > 0:
- back[py * bw + px] = _alpha_blend(back[py * bw + px], shadow_col, a)
-
-def _cursor_save_bg(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt):
- global _cursor_saved
- cw: t.CInt = CURSOR_W
- ch: t.CInt = CURSOR_H
- for dy in range(ch):
- for dx in range(cw):
- sx: t.CInt = cx + dx
- sy: t.CInt = cy + dy
- if sx >= 0 and sx < w and sy >= 0 and sy < h:
- _cursor_save_buf[dy * cw + dx] = back[sy * w + sx]
- else:
- _cursor_save_buf[dy * cw + dx] = 0
- _cursor_saved = 1
-
-def _cursor_restore_bg(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt):
- global _cursor_saved
- if _cursor_saved == 0: return
- cw: t.CInt = CURSOR_W
- ch: t.CInt = CURSOR_H
- for dy in range(ch):
- for dx in range(cw):
- sx: t.CInt = cx + dx
- sy: t.CInt = cy + dy
- if sx >= 0 and sx < w and sy >= 0 and sy < h:
- back[sy * w + sx] = _cursor_save_buf[dy * cw + dx]
- _cursor_saved = 0
-
-def _cursor_draw_bitmap(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt, bmp: t.CArray[t.CUInt8T, 256]):
- cw: t.CInt = CURSOR_W
- ch: t.CInt = CURSOR_H
- white: t.CUInt32T = gfx.COLOR_RGB(255, 255, 255)
- black: t.CUInt32T = gfx.COLOR_RGB(0, 0, 0)
- for dy in range(ch):
- for dx in range(cw):
- pixel: t.CUInt8T = bmp[dy * cw + dx]
- if pixel != 0:
- px: t.CInt = cx + dx
- py: t.CInt = cy + dy
- if px >= 0 and px < w and py >= 0 and py < h:
- if pixel == 1:
- back[py * w + px] = black
- elif pixel == 2:
- back[py * w + px] = white
-
-def _cursor_draw_xor(back: UINT32PTR, cx: t.CInt, cy: t.CInt, w: t.CInt, h: t.CInt, bmp: t.CArray[t.CUInt8T, 256]):
- cw: t.CInt = CURSOR_W
- ch: t.CInt = CURSOR_H
- xor_val: t.CUInt32T = t.CUInt32T(0x00FFFFFF)
- for dy in range(ch):
- for dx in range(cw):
- pixel: t.CUInt8T = bmp[dy * cw + dx]
- if pixel != 0:
- px: t.CInt = cx + dx
- py: t.CInt = cy + dy
- if px >= 0 and px < w and py >= 0 and py < h:
- back[py * w + px] = back[py * w + px] ^ xor_val
-
-def _draw_cursor(back: UINT32PTR):
- cx: t.CInt = _cursor_x
- cy: t.CInt = _cursor_y
- w: t.CInt = _screen_w
- h: t.CInt = _screen_h
- cur_type: t.CInt = CURSOR_DEFAULT
- if _last_hover_win >= 0 and _last_hover_win < _win_count:
- cur_type = _wins[_last_hover_win].cursor_type
- if cur_type == CURSOR_IBEAM:
- _cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_IBEAM)
- elif cur_type == CURSOR_RESIZE_EW:
- _cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_RESIZE_EW)
- elif cur_type == CURSOR_RESIZE_NS:
- _cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_RESIZE_NS)
- elif cur_type == CURSOR_RESIZE_NWSE:
- _cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_RESIZE_NWSE)
- else:
- _cursor_draw_bitmap(back, cx, cy, w, h, _CURSOR_ARROW)
-
-def _erase_cursor(back: UINT32PTR):
- global _cursor_saved
- if _cursor_saved == 0: return
- _cursor_restore_bg(back, _prev_cursor_x, _prev_cursor_y, _screen_w, _screen_h)
-
-def desktop_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
- global _last_clock_sec, _mouse_moved
- global _prev_cursor_x, _prev_cursor_y
- global _perf_t_mouse, _perf_t_kbd, _perf_t_render, _perf_t_flush, _perf_t_total, _perf_frames, _perf_start_ticks
- global _perf_t_bg, _perf_t_win, _perf_t_cur, _perf_t_fb
- serial.puts("[desktop] thread started\n")
- _mark_all_dirty()
- _dt_hb_sec: t.CUInt32T = 0
- tb_h_dt: t.CInt = TASKBAR_HEIGHT
- _perf_buf: t.CArray[t.CChar, 256]
- _perf_start_ticks = timer.timer_get_ticks()
- _kbd_poll_ticks: t.CUInt64T = 0
- _mouse_poll_ticks: t.CUInt64T = 0
- while True:
- _loop_t0: t.CUInt64T = timer.timer_get_ticks()
- # Poll mouse at most every 4ms to avoid excessive I/O port overhead
- _now_ticks: t.CUInt64T = timer.timer_get_ticks()
- if _now_ticks - _mouse_poll_ticks >= 4:
- _mouse_poll_ticks = _now_ticks
- _mt0: t.CUInt64T = timer.timer_get_ticks()
- mouse_active: t.CInt = _update_mouse()
- _mt1: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_mouse += (_mt1 - _mt0)
- # Poll keyboard at most every 4ms to avoid excessive I/O port overhead
- if _now_ticks - _kbd_poll_ticks >= 4:
- _kbd_poll_ticks = _now_ticks
- _kt0: t.CUInt64T = timer.timer_get_ticks()
- _update_keyboard()
- _kt1: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_kbd += (_kt1 - _kt0)
- _heartbeat_check()
- sched.Scheduler.try_reschedule()
- _dt_cur_sec: t.CUInt32T = timer.timer_get_seconds()
- if _dt_cur_sec != _dt_hb_sec:
- _dt_hb_sec = _dt_cur_sec
- cur_sec: t.CUInt32T = timer.timer_get_seconds()
- if cur_sec != _last_clock_sec:
- _last_clock_sec = cur_sec
- _mark_rows_dirty(_screen_h - tb_h_dt, tb_h_dt)
- if _mouse_moved:
- _mouse_moved = 0
- sz: t.CInt = CURSOR_H
- _mark_rows_dirty(_prev_cursor_y, sz)
- _mark_rows_dirty(_cursor_y, sz)
- _prev_cursor_x = _cursor_x
- _prev_cursor_y = _cursor_y
- top_win: t.CInt = _hit_test_window(_cursor_x, _cursor_y)
- for ai in range(_win_count):
- if _wins[ai].active and not _wins[ai].minimized:
- th: t.CInt = _get_title_height(_wins[ai].style)
- btn_w: t.CInt = CLOSE_BTN_SIZE
- btn_h: t.CInt = CLOSE_BTN_SIZE
- ew_hov: t.CInt = _eff_w(c.Addr(_wins[ai]))
- btn_x: t.CInt = _wins[ai].x + ew_hov - btn_w - 4
- btn_y: t.CInt = _wins[ai].y + (th - btn_h) // 2
- if _wins[ai].style == STYLE_WIN7:
- btn_w = CLOSE_BTN_W7_W
- btn_h = CLOSE_BTN_W7_H
- btn_x = _wins[ai].x + ew_hov - btn_w - 5
- btn_y = _wins[ai].y + (th - btn_h) // 2
- elif _wins[ai].style == STYLE_WINXP:
- btn_w = CLOSE_BTN_XP_SZ
- btn_h = CLOSE_BTN_XP_SZ
- btn_x = _wins[ai].x + ew_hov - btn_w - 5
- btn_y = _wins[ai].y + (th - btn_h) // 2
- elif _wins[ai].style == STYLE_WIN10 or _wins[ai].style == STYLE_WIN11:
- btn_w = CLOSE_BTN_W_WIN
- btn_h = th - 2
- btn_x = _wins[ai].x + ew_hov - btn_w
- btn_y = _wins[ai].y + 1
- max_bx3: t.CInt = btn_x - btn_w
- if _wins[ai].style == STYLE_WIN7 or _wins[ai].style == STYLE_WINXP:
- max_bx3 = btn_x - btn_w - 1
- min_bx3: t.CInt = max_bx3 - btn_w
- if _wins[ai].style == STYLE_WIN7 or _wins[ai].style == STYLE_WINXP:
- min_bx3 = max_bx3 - btn_w - 1
- is_over_close: t.CInt = 0
- is_over_max: t.CInt = 0
- is_over_min: t.CInt = 0
- if ai == top_win:
- if _cursor_x >= btn_x and _cursor_x < btn_x + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
- is_over_close = 1
- elif _cursor_x >= max_bx3 and _cursor_x < max_bx3 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
- is_over_max = 1
- elif _cursor_x >= min_bx3 and _cursor_x < min_bx3 + btn_w and _cursor_y >= btn_y and _cursor_y < btn_y + btn_h:
- is_over_min = 1
- if is_over_close and _wins[ai].close_hover < 255:
- _old_hov: t.CInt = _wins[ai].close_hover
- _wins[ai].close_hover += 60
- if _wins[ai].close_hover > 255:
- _wins[ai].close_hover = 255
- if _wins[ai].close_hover != _old_hov:
- _mark_rows_dirty(btn_y, btn_h)
- elif not is_over_close and _wins[ai].close_hover > 0:
- _old_hov2: t.CInt = _wins[ai].close_hover
- _wins[ai].close_hover -= 45
- if _wins[ai].close_hover < 0:
- _wins[ai].close_hover = 0
- if _wins[ai].close_hover != _old_hov2:
- _mark_rows_dirty(btn_y, btn_h)
- if is_over_max and _wins[ai].max_hover < 255:
- _old_mh: t.CInt = _wins[ai].max_hover
- _wins[ai].max_hover += 60
- if _wins[ai].max_hover > 255:
- _wins[ai].max_hover = 255
- if _wins[ai].max_hover != _old_mh:
- _mark_rows_dirty(btn_y, btn_h)
- elif not is_over_max and _wins[ai].max_hover > 0:
- _old_mh2: t.CInt = _wins[ai].max_hover
- _wins[ai].max_hover -= 45
- if _wins[ai].max_hover < 0:
- _wins[ai].max_hover = 0
- if _wins[ai].max_hover != _old_mh2:
- _mark_rows_dirty(btn_y, btn_h)
- if is_over_min and _wins[ai].min_hover < 255:
- _old_nh: t.CInt = _wins[ai].min_hover
- _wins[ai].min_hover += 60
- if _wins[ai].min_hover > 255:
- _wins[ai].min_hover = 255
- if _wins[ai].min_hover != _old_nh:
- _mark_rows_dirty(btn_y, btn_h)
- elif not is_over_min and _wins[ai].min_hover > 0:
- _old_nh2: t.CInt = _wins[ai].min_hover
- _wins[ai].min_hover -= 45
- if _wins[ai].min_hover < 0:
- _wins[ai].min_hover = 0
- if _wins[ai].min_hover != _old_nh2:
- _mark_rows_dirty(btn_y, btn_h)
- if _has_dirty_rows():
- _rt0: t.CUInt64T = timer.timer_get_ticks()
- _render()
- _rt1: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_render += (_rt1 - _rt0)
- _ft0: t.CUInt64T = timer.timer_get_ticks()
- _clear_dirty_flags()
- _ft1: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_flush += (_ft1 - _ft0)
- _perf_frames += 1
- _loop_t1: t.CUInt64T = timer.timer_get_ticks()
- _perf_t_total += (_loop_t1 - _loop_t0)
- _now_ticks: t.CUInt64T = timer.timer_get_ticks()
- _elapsed_ms: t.CUInt64T = _now_ticks - _perf_start_ticks
- if _elapsed_ms >= 1000:
- _fps_val: t.CUInt32T = 0
- if _elapsed_ms > 0:
- _fps_val = t.CUInt32T(t.CUInt64T(_perf_frames) * 1000 / _elapsed_ms)
- string.memset(c.Addr(_perf_buf), 0, 256)
- viperlib.snprintf(c.Addr(_perf_buf), 256, "[perf] fps=%u wall=%lu work=%lu mouse=%lu kbd=%lu render=%lu(bg=%lu win=%lu cur=%lu fb=%lu) dirty=%d vsync=%d\n", _fps_val, t.CUInt64T(_elapsed_ms), t.CUInt64T(_perf_t_total), t.CUInt64T(_perf_t_mouse), t.CUInt64T(_perf_t_kbd), t.CUInt64T(_perf_t_render), t.CUInt64T(_perf_t_bg), t.CUInt64T(_perf_t_win), t.CUInt64T(_perf_t_cur), t.CUInt64T(_perf_t_fb), _dirty_count, _vblank_ok)
- serial.puts(c.Addr(_perf_buf))
- _perf_t_mouse = 0
- _perf_t_kbd = 0
- _perf_t_render = 0
- _perf_t_flush = 0
- _perf_t_total = 0
- _perf_t_bg = 0
- _perf_t_win = 0
- _perf_t_cur = 0
- _perf_t_fb = 0
- _perf_frames = 0
- _perf_start_ticks = _now_ticks
- sched.Scheduler.try_reschedule()
- return 0
-
-def start(fb_ptr: t.CVoid | t.CPtr, w: t.CInt, h: t.CInt, pitch: t.CInt = 0) -> sched.Thread | t.CPtr:
- global _fb, _screen_w, _screen_h, _fb_pitch, _cursor_x, _cursor_y
- global _back_fb, _row_buf
- global _dirty_rows, _prev_cursor_x, _prev_cursor_y
- _fb = fb_ptr
- _screen_w = w
- _screen_h = h
- if pitch > 0:
- _fb_pitch = pitch
- else:
- _fb_pitch = w * 4
- _cursor_x = w // 2
- _cursor_y = h // 2
- _prev_cursor_x = _cursor_x
- _prev_cursor_y = _cursor_y
-
- _dirty_rows = mm.malloc(h)
- if _dirty_rows:
- string.memset(_dirty_rows, 0, h)
- else:
- serial.puts("[desktop] dirty_rows malloc FAILED\n")
- return None
-
- _back_fb = mm.malloc(w * h * 4)
- if _back_fb:
- string.memset(_back_fb, 0, w * h * 4)
- else:
- serial.puts("[desktop] back_fb malloc FAILED\n")
- return None
-
- _row_buf = mm.malloc(w * 4)
- if _row_buf:
- string.memset(_row_buf, 0, w * 4)
- else:
- serial.puts("[desktop] row_buf malloc FAILED!\n")
-
- _bg_row_buf = mm.malloc(w * 4)
- if _bg_row_buf:
- desktop_init_col: t.CUInt32T = gfx.COLOR_RGB(25, 25, 35)
- for ri in range(w):
- _bg_row_buf[ri] = desktop_init_col
- else:
- serial.puts("[desktop] bg_row_buf malloc FAILED!\n")
-
- _mark_all_dirty()
- p: process.Process | t.CPtr = process.ProcessManager.create_process("desktop", None)
- desktop_pid: t.CInt = 0
- if p:
- desktop_pid = p.pid
- th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(desktop_thread, None, desktop_pid)
- if p and th:
- p.addThread(th.tid)
- return th
-
-def _get_top_window() -> t.CInt:
- best: t.CInt = -1
- best_z: t.CInt = -1
- for ai in range(_win_count):
- if _wins[ai].active and not _wins[ai].minimized:
- z: t.CInt = _wins[ai].z_order
- if z > best_z:
- best_z = z
- best = ai
- return best
-
-def _draw_min_btn(back: UINT32PTR, bw: t.CInt, bh: t.CInt, bx: t.CInt, by: t.CInt, btn_w: t.CInt, btn_h: t.CInt, hover_alpha: t.CInt, style: t.CInt):
- if hover_alpha > 0:
- hover_col: t.CUInt32T = gfx.COLOR_RGB(80, 80, 80)
- if style == STYLE_WIN7:
- hover_col = gfx.COLOR_RGB(200, 220, 240)
- elif style == STYLE_WINXP:
- hover_col = gfx.COLOR_RGB(180, 210, 240)
- for py in range(by, by + btn_h):
- if py >= 0 and py < bh:
- for px in range(bx, bx + btn_w):
- if px >= 0 and px < bw:
- bg_pixel: t.CUInt32T = back[py * bw + px]
- back[py * bw + px] = _alpha_blend(bg_pixel, hover_col, hover_alpha)
- line_col: t.CUInt32T = gfx.COLOR_RGB(180, 180, 180)
- if hover_alpha > 0:
- line_col = gfx.COLOR_RGB(255, 255, 255)
- cx: t.CInt = bx + btn_w // 2
- cy: t.CInt = by + btn_h // 2
- lw: t.CInt = 5
- if btn_w >= 30:
- lw = 8
- ly: t.CInt = cy + 3
- if ly >= 0 and ly < bh:
- for lx in range(cx - lw, cx + lw + 1):
- if lx >= 0 and lx < bw:
- back[ly * bw + lx] = line_col
-
-def _draw_max_btn(back: UINT32PTR, bw: t.CInt, bh: t.CInt, bx: t.CInt, by: t.CInt, btn_w: t.CInt, btn_h: t.CInt, hover_alpha: t.CInt, style: t.CInt, is_maximized: t.CInt):
- if hover_alpha > 0:
- hover_col2: t.CUInt32T = gfx.COLOR_RGB(80, 80, 80)
- if style == STYLE_WIN7:
- hover_col2 = gfx.COLOR_RGB(200, 220, 240)
- elif style == STYLE_WINXP:
- hover_col2 = gfx.COLOR_RGB(180, 210, 240)
- for py2 in range(by, by + btn_h):
- if py2 >= 0 and py2 < bh:
- for px2 in range(bx, bx + btn_w):
- if px2 >= 0 and px2 < bw:
- bg_pixel2: t.CUInt32T = back[py2 * bw + px2]
- back[py2 * bw + px2] = _alpha_blend(bg_pixel2, hover_col2, hover_alpha)
- rect_col: t.CUInt32T = gfx.COLOR_RGB(180, 180, 180)
- if hover_alpha > 0:
- rect_col = gfx.COLOR_RGB(255, 255, 255)
- cx2: t.CInt = bx + btn_w // 2
- cy2: t.CInt = by + btn_h // 2
- sz: t.CInt = 4
- if btn_w >= 30:
- sz = 6
- if is_maximized:
- off: t.CInt = 2
- for ry1 in range(cy2 - sz + off, cy2 + sz + off + 1):
- if ry1 >= 0 and ry1 < bh:
- for rx1 in range(cx2 - sz + off, cx2 + sz + off + 1):
- if rx1 >= 0 and rx1 < bw:
- is_top: t.CInt = 0
- if ry1 == cy2 - sz + off or ry1 == cy2 - sz + off + 1:
- is_top = 1
- is_border: t.CInt = 0
- if ry1 == cy2 - sz + off or ry1 == cy2 + sz + off or rx1 == cx2 - sz + off or rx1 == cx2 + sz + off:
- is_border = 1
- if is_top or is_border:
- back[ry1 * bw + rx1] = rect_col
- for ry2 in range(cy2 - sz, cy2 + sz + 1):
- if ry2 >= 0 and ry2 < bh:
- for rx2 in range(cx2 - sz, cx2 + sz + 1):
- if rx2 >= 0 and rx2 < bw:
- if ry2 == cy2 - sz or ry2 == cy2 - sz + 1 or rx2 == cx2 - sz or rx2 == cx2 + sz:
- back[ry2 * bw + rx2] = rect_col
- else:
- for ry3 in range(cy2 - sz, cy2 + sz + 1):
- if ry3 >= 0 and ry3 < bh:
- for rx3 in range(cx2 - sz, cx2 + sz + 1):
- if rx3 >= 0 and rx3 < bw:
- if ry3 == cy2 - sz or ry3 == cy2 + sz or rx3 == cx2 - sz or rx3 == cx2 + sz:
- back[ry3 * bw + rx3] = rect_col
- top_y: t.CInt = cy2 - sz
- if top_y >= 0 and top_y < bh:
- for tx in range(cx2 - sz, cx2 + sz + 1):
- if tx >= 0 and tx < bw:
- back[top_y * bw + tx] = rect_col
- if top_y + 1 < bh:
- for tx2 in range(cx2 - sz, cx2 + sz + 1):
- if tx2 >= 0 and tx2 < bw:
- back[(top_y + 1) * bw + tx2] = rect_col
-
-def _draw_close_btn(back: UINT32PTR, bw: t.CInt, bh: t.CInt, bx: t.CInt, by: t.CInt, btn_w: t.CInt, btn_h: t.CInt, hover_alpha: t.CInt, style: t.CInt, clip_wx: t.CInt, clip_wy: t.CInt, clip_ww: t.CInt, clip_r: t.CInt):
- x_col: t.CUInt32T = gfx.COLOR_RGB(200, 200, 200)
- if style == STYLE_CLASSIC:
- bg: t.CUInt32T = gfx.COLOR_RGB(40, 40, 70)
- if hover_alpha > 0:
- red: t.CUInt32T = gfx.COLOR_RGB(200, 50, 50)
- bg = _alpha_blend(bg, red, hover_alpha)
- _fill_rect(back, bw, bh, bx, by, btn_w, btn_h, bg)
- if hover_alpha > 128:
- x_col = gfx.COLOR_RGB(255, 255, 255)
- elif style == STYLE_WIN7:
- br: t.CInt = CLOSE_BTN_W7_R
- bg_r: t.CInt = 200
- bg_g: t.CInt = 50
- bg_b: t.CInt = 50
- if hover_alpha > 0:
- bg_r = 200 + ((232 - 200) * hover_alpha) / 255
- bg_g = 50 + ((17 - 50) * hover_alpha) / 255
- bg_b = 50 + ((35 - 50) * hover_alpha) / 255
- bg_col7: t.CUInt32T = gfx.COLOR_RGB(bg_r, bg_g, bg_b)
- for py2 in range(by, by + btn_h):
- if py2 >= 0 and py2 < bh:
- for px2 in range(bx, bx + btn_w):
- if px2 >= 0 and px2 < bw:
- lrx: t.CInt = px2 - bx
- lry: t.CInt = py2 - by
- if lry < br:
- if lrx < br:
- if (lrx - br) * (lrx - br) + (lry - br) * (lry - br) > br * br:
- continue
- elif lrx >= btn_w - br:
- if (lrx - (btn_w - br - 1)) * (lrx - (btn_w - br - 1)) + (lry - br) * (lry - br) > br * br:
- continue
- elif lry >= btn_h - br:
- if lrx < br:
- if (lrx - br) * (lrx - br) + (lry - (btn_h - br - 1)) * (lry - (btn_h - br - 1)) > br * br:
- continue
- elif lrx >= btn_w - br:
- if (lrx - (btn_w - br - 1)) * (lrx - (btn_w - br - 1)) + (lry - (btn_h - br - 1)) * (lry - (btn_h - br - 1)) > br * br:
- continue
- if clip_r > 0:
- crx: t.CInt = px2 - clip_wx
- cry: t.CInt = py2 - clip_wy
- if cry < clip_r and crx >= clip_ww - clip_r:
- cdx: t.CInt = crx - (clip_ww - clip_r - 1)
- cdy: t.CInt = cry - clip_r
- if cdx * cdx + cdy * cdy > clip_r * clip_r:
- continue
- back[py2 * bw + px2] = bg_col7
- x_col = gfx.COLOR_RGB(255, 255, 255)
- if hover_alpha > 0:
- x_col = _alpha_blend(gfx.COLOR_RGB(255, 255, 255), gfx.COLOR_RGB(255, 240, 240), hover_alpha)
- elif style == STYLE_WINXP:
- br_xp: t.CInt = 3
- bg_r_xp: t.CInt = 200
- bg_g_xp: t.CInt = 50
- bg_b_xp: t.CInt = 50
- if hover_alpha > 0:
- bg_r_xp = 200 + ((232 - 200) * hover_alpha) / 255
- bg_g_xp = 50 + ((17 - 50) * hover_alpha) / 255
- bg_b_xp = 50 + ((35 - 50) * hover_alpha) / 255
- bg_col_xp: t.CUInt32T = gfx.COLOR_RGB(bg_r_xp, bg_g_xp, bg_b_xp)
- for py_xp in range(by, by + btn_h):
- if py_xp >= 0 and py_xp < bh:
- for px_xp in range(bx, bx + btn_w):
- if px_xp >= 0 and px_xp < bw:
- lrx_xp: t.CInt = px_xp - bx
- lry_xp: t.CInt = py_xp - by
- if lry_xp < br_xp:
- if lrx_xp < br_xp:
- if (lrx_xp - br_xp) * (lrx_xp - br_xp) + (lry_xp - br_xp) * (lry_xp - br_xp) > br_xp * br_xp:
- continue
- elif lrx_xp >= btn_w - br_xp:
- if (lrx_xp - (btn_w - br_xp - 1)) * (lrx_xp - (btn_w - br_xp - 1)) + (lry_xp - br_xp) * (lry_xp - br_xp) > br_xp * br_xp:
- continue
- elif lry_xp >= btn_h - br_xp:
- if lrx_xp < br_xp:
- if (lrx_xp - br_xp) * (lrx_xp - br_xp) + (lry_xp - (btn_h - br_xp - 1)) * (lry_xp - (btn_h - br_xp - 1)) > br_xp * br_xp:
- continue
- elif lrx_xp >= btn_w - br_xp:
- if (lrx_xp - (btn_w - br_xp - 1)) * (lrx_xp - (btn_w - br_xp - 1)) + (lry_xp - (btn_h - br_xp - 1)) * (lry_xp - (btn_h - br_xp - 1)) > br_xp * br_xp:
- continue
- back[py_xp * bw + px_xp] = bg_col_xp
- x_col = gfx.COLOR_RGB(255, 255, 255)
- if hover_alpha > 0:
- x_col = _alpha_blend(gfx.COLOR_RGB(255, 255, 255), gfx.COLOR_RGB(255, 240, 240), hover_alpha)
- else:
- if hover_alpha > 0:
- red = gfx.COLOR_RGB(232, 17, 35)
- for py3 in range(by, by + btn_h):
- if py3 >= 0 and py3 < bh:
- for px3 in range(bx, bx + btn_w):
- if px3 >= 0 and px3 < bw:
- if clip_r > 0:
- crx3: t.CInt = px3 - clip_wx
- cry3: t.CInt = py3 - clip_wy
- if cry3 < clip_r and crx3 >= clip_ww - clip_r:
- cdx3: t.CInt = crx3 - (clip_ww - clip_r - 1)
- cdy3: t.CInt = cry3 - clip_r
- if cdx3 * cdx3 + cdy3 * cdy3 > clip_r * clip_r:
- continue
- bg_pixel: t.CUInt32T = back[py3 * bw + px3]
- back[py3 * bw + px3] = _alpha_blend(bg_pixel, red, hover_alpha)
- x_col = gfx.COLOR_RGB(150, 150, 150)
- if hover_alpha > 0:
- x_col = _alpha_blend(gfx.COLOR_RGB(150, 150, 150), gfx.COLOR_RGB(255, 255, 255), hover_alpha)
- cx: t.CInt = bx + btn_w // 2
- cy: t.CInt = by + btn_h // 2
- d: t.CInt = 3
- if btn_w >= 30:
- d = 4
- i: t.CInt = -d
- while i <= d:
- px1: t.CInt = cx + i
- py1: t.CInt = cy + i
- px2b: t.CInt = cx + i
- py2b: t.CInt = cy - i
- if px1 >= 0 and px1 < bw and py1 >= 0 and py1 < bh:
- if clip_r > 0:
- crx1: t.CInt = px1 - clip_wx
- cry1: t.CInt = py1 - clip_wy
- if cry1 < clip_r and crx1 >= clip_ww - clip_r:
- cdx1: t.CInt = crx1 - (clip_ww - clip_r - 1)
- cdy1: t.CInt = cry1 - clip_r
- if cdx1 * cdx1 + cdy1 * cdy1 > clip_r * clip_r:
- i += 1
- continue
- back[py1 * bw + px1] = x_col
- if px2b >= 0 and px2b < bw and py2b >= 0 and py2b < bh:
- if clip_r > 0:
- crx2: t.CInt = px2b - clip_wx
- cry2: t.CInt = py2b - clip_wy
- if cry2 < clip_r and crx2 >= clip_ww - clip_r:
- cdx2: t.CInt = crx2 - (clip_ww - clip_r - 1)
- cdy2: t.CInt = cry2 - clip_r
- if cdx2 * cdx2 + cdy2 * cdy2 > clip_r * clip_r:
- i += 1
- continue
- back[py2b * bw + px2b] = x_col
- i += 1
-
-def _draw_app_window(back: UINT32PTR, win: AppWindow | t.CPtr):
- w: t.CInt = _screen_w
- h: t.CInt = _screen_h
- wx: t.CInt = win.x
- wy: t.CInt = win.y
- ww: t.CInt = _eff_w(win)
- wh: t.CInt = win.h
- ch: t.CInt = _eff_h(win)
- style: t.CInt = win.style
- th: t.CInt = _get_title_height(style)
-
- if wy + wh <= _dirty_y_min or wy > _dirty_y_max:
- return
-
- top_idx: t.CInt = _cached_top_win
- is_active: t.CInt = 0
- if top_idx >= 0:
- top_z: t.CInt = _wins[top_idx].z_order
- if win.z_order == top_z:
- is_active = 1
-
- title_col: t.CUInt32T = gfx.COLOR_RGB(50, 50, 90)
- border_col: t.CUInt32T = gfx.COLOR_RGB(100, 100, 180)
- content_col: t.CUInt32T = gfx.COLOR_RGB(30, 30, 50)
- outline_col: t.CUInt32T = gfx.COLOR_RGB(100, 100, 180)
- title_alpha: t.CInt = 255
- has_separator: t.CInt = 1
- if style == STYLE_WIN10:
- has_separator = 0
- if is_active:
- title_col = gfx.COLOR_RGB(0, 0, 0)
- border_col = gfx.COLOR_RGB(0, 0, 0)
- content_col = gfx.COLOR_RGB(32, 32, 32)
- outline_col = gfx.COLOR_RGB(80, 80, 80)
- else:
- title_col = gfx.COLOR_RGB(32, 32, 32)
- border_col = gfx.COLOR_RGB(32, 32, 32)
- content_col = gfx.COLOR_RGB(24, 24, 24)
- outline_col = gfx.COLOR_RGB(60, 60, 60)
- elif style == STYLE_WIN11:
- has_separator = 0
- if is_active:
- title_col = gfx.COLOR_RGB(32, 32, 32)
- border_col = gfx.COLOR_RGB(32, 32, 32)
- content_col = gfx.COLOR_RGB(32, 32, 32)
- outline_col = gfx.COLOR_RGB(70, 70, 70)
- else:
- title_col = gfx.COLOR_RGB(40, 40, 40)
- border_col = gfx.COLOR_RGB(40, 40, 40)
- content_col = gfx.COLOR_RGB(40, 40, 40)
- outline_col = gfx.COLOR_RGB(60, 60, 60)
- elif style == STYLE_WIN7:
- has_separator = 0
- if is_active:
- title_col = gfx.COLOR_RGB(156, 181, 209)
- border_col = gfx.COLOR_RGB(156, 181, 209)
- content_col = gfx.COLOR_RGB(240, 240, 240)
- outline_col = gfx.COLOR_RGB(100, 130, 170)
- else:
- title_col = gfx.COLOR_RGB(180, 195, 210)
- border_col = gfx.COLOR_RGB(180, 195, 210)
- content_col = gfx.COLOR_RGB(240, 240, 240)
- outline_col = gfx.COLOR_RGB(140, 155, 175)
- title_alpha = 102
- elif style == STYLE_WINXP:
- has_separator = 0
- if is_active:
- title_col = gfx.COLOR_RGB(107, 158, 212)
- border_col = gfx.COLOR_RGB(107, 158, 212)
- content_col = gfx.COLOR_RGB(235, 235, 235)
- outline_col = gfx.COLOR_RGB(43, 87, 151)
- else:
- title_col = gfx.COLOR_RGB(140, 160, 195)
- border_col = gfx.COLOR_RGB(140, 160, 195)
- content_col = gfx.COLOR_RGB(235, 235, 235)
- outline_col = gfx.COLOR_RGB(100, 115, 145)
- else:
- if is_active:
- title_col = gfx.COLOR_RGB(70, 70, 130)
- border_col = gfx.COLOR_RGB(130, 130, 220)
- outline_col = gfx.COLOR_RGB(130, 130, 220)
-
- rounded: t.CInt = 0
- if style == STYLE_WIN11 or style == STYLE_WIN7 or style == STYLE_WINXP:
- rounded = 1
- r: t.CInt = WIN_RADIUS
-
- _draw_window_shadow(back, w, h, wx, wy, ww, wh, rounded, r)
-
- if rounded:
- for py in range(wy, wy + wh):
- if py < 0 or py >= h: continue
- if not _dirty_rows[py]: continue
- ry: t.CInt = py - wy
- row_col: t.CUInt32T = content_col
- row_is_title: t.CInt = 0
- row_is_sep: t.CInt = 0
- if ry < th:
- row_is_title = 1
- if style == STYLE_WIN7:
- ratio: t.CInt = (ry * 100) / th
- if ratio > 100: ratio = 100
- if is_active:
- gr: t.CInt = 156 + ((186 - 156) * ratio) / 100
- gg: t.CInt = 181 + ((209 - 181) * ratio) / 100
- gb: t.CInt = 209 + ((233 - 209) * ratio) / 100
- else:
- gr = 180 + ((200 - 180) * ratio) / 100
- gg = 195 + ((210 - 195) * ratio) / 100
- gb = 210 + ((225 - 210) * ratio) / 100
- row_col = gfx.COLOR_RGB(gr, gg, gb)
- if ry == 0:
- row_col = _alpha_blend(row_col, gfx.COLOR_RGB(220, 235, 255), 50)
- elif ry == 1:
- row_col = _alpha_blend(row_col, gfx.COLOR_RGB(210, 225, 250), 20)
- if ry == th - 1:
- row_col = _alpha_blend(row_col, gfx.COLOR_RGB(130, 160, 200), 25)
- elif style == STYLE_WINXP:
- ratio = (ry * 100) / th
- if ratio > 100: ratio = 100
- if is_active:
- gr = 107 + ((58 - 107) * ratio) / 100
- gg = 158 + ((124 - 158) * ratio) / 100
- gb = 212 + ((195 - 212) * ratio) / 100
- else:
- gr = 150 + ((115 - 150) * ratio) / 100
- gg = 170 + ((135 - 170) * ratio) / 100
- gb = 205 + ((175 - 205) * ratio) / 100
- row_col = gfx.COLOR_RGB(gr, gg, gb)
- if ry == 0:
- row_col = _alpha_blend(row_col, gfx.COLOR_RGB(200, 225, 255), 50)
- elif ry == 1:
- row_col = _alpha_blend(row_col, gfx.COLOR_RGB(200, 225, 255), 25)
- if ry == th - 1:
- row_col = _alpha_blend(row_col, gfx.COLOR_RGB(100, 160, 230), 40)
- else:
- row_col = title_col
- elif ry == th and has_separator:
- row_is_sep = 1
- row_col = outline_col
- in_corner_zone: t.CInt = 0
- if ry < r or ry >= wh - r:
- in_corner_zone = 1
- if not in_corner_zone:
- left_border: t.CInt = wx
- right_border: t.CInt = wx + ww - 1
- if left_border >= 0 and left_border < w:
- back[py * w + left_border] = outline_col
- if right_border >= 0 and right_border < w:
- back[py * w + right_border] = outline_col
- fill_left: t.CInt = wx + 1
- fill_right: t.CInt = wx + ww - 1
- if fill_left < 0: fill_left = 0
- if fill_right > w: fill_right = w
- fill_w: t.CInt = fill_right - fill_left
- if fill_w > 0:
- if row_is_title and (style == STYLE_WIN7 or style == STYLE_WINXP) and title_alpha < 255:
- for fx in range(fill_left, fill_right):
- bg_p: t.CUInt32T = back[py * w + fx]
- back[py * w + fx] = _alpha_blend(bg_p, row_col, title_alpha)
- else:
- _fill_rect(back, w, h, fill_left, py, fill_w, 1, row_col)
- else:
- for px in range(wx, wx + ww):
- if px < 0 or px >= w: continue
- rx: t.CInt = px - wx
- in_corner: t.CInt = 1
- on_border: t.CInt = 0
- if ry < r:
- if rx < r:
- in_corner = _is_in_corner(rx, ry, r, r, r)
- elif rx >= ww - r:
- in_corner = _is_in_corner(rx, ry, ww - r - 1, r, r)
- elif ry >= wh - r:
- if rx < r:
- in_corner = _is_in_corner(rx, ry, r, wh - r - 1, r)
- elif rx >= ww - r:
- in_corner = _is_in_corner(rx, ry, ww - r - 1, wh - r - 1, r)
- if not in_corner:
- on_border = _is_on_border(rx, ry, ww, wh, r)
- if not on_border:
- continue
- col: t.CUInt32T = row_col
- is_border_pixel: t.CInt = 0
- if on_border or _is_on_border(rx, ry, ww, wh, r):
- col = outline_col
- is_border_pixel = 1
- ca: t.CInt = 255
- if ry < r:
- if rx < r:
- ca = _corner_alpha(rx, ry, r, r, r)
- elif rx >= ww - r:
- ca = _corner_alpha(rx, ry, ww - r - 1, r, r)
- elif ry >= wh - r:
- if rx < r:
- ca = _corner_alpha(rx, ry, r, wh - r - 1, r)
- elif rx >= ww - r:
- ca = _corner_alpha(rx, ry, ww - r - 1, wh - r - 1, r)
- if is_border_pixel and ca > 0 and ca < 255:
- ca = 255
- if row_is_title and (style == STYLE_WIN7 or style == STYLE_WINXP) and ry >= 1 and rx >= 1 and rx < ww - 1 and ca == 255 and not is_border_pixel:
- ca = title_alpha
- if ca < 255:
- bg_pixel: t.CUInt32T = back[py * w + px]
- col = _alpha_blend(bg_pixel, col, ca)
- back[py * w + px] = col
- else:
- _fill_rect(back, w, h, wx, wy, ww, th, title_col)
- _fill_rect(back, w, h, wx, wy + th + 1, ww, ch, content_col)
- if not has_separator:
- _fill_rect(back, w, h, wx, wy + th, ww, 1, content_col)
- if wx >= 0 and wx < w:
- for py in range(wy, wy + wh):
- if py >= 0 and py < h:
- back[py * w + wx] = border_col
- if wx + ww - 1 >= 0 and wx + ww - 1 < w:
- for py in range(wy, wy + wh):
- if py >= 0 and py < h:
- back[py * w + wx + ww - 1] = border_col
- _fill_rect(back, w, h, wx, wy, ww, 1, border_col)
- _fill_rect(back, w, h, wx, wy + wh - 1, ww, 1, border_col)
- if has_separator:
- _fill_rect(back, w, h, wx, wy + th, ww, 1, border_col)
-
- win_fb: UINT32PTR = win.fb
- if win_fb:
- fb_stride: t.CInt = win.fb_w
- fbh: t.CInt = win.fb_h
- if fb_stride <= 0 or fbh <= 0:
- win_fb = t.CVoid(0, t.CPtr)
- if win_fb:
- draw_rows: t.CInt = ch
- if draw_rows > fbh: draw_rows = fbh
- if draw_rows < 0: draw_rows = 0
- content_y: t.CInt = wy + th + 1
- fb_total: t.CInt = fb_stride * fbh
- for row in range(draw_rows):
- dst_y: t.CInt = content_y + row
- if dst_y < 0 or dst_y >= h: continue
- if not _dirty_rows[dst_y]: continue
- ry: t.CInt = th + 1 + row
- if rounded:
- if ry >= r and ry < wh - r:
- src_x: t.CInt = 1
- dst_x: t.CInt = wx + 1
- if dst_x < 0:
- src_x = src_x - dst_x
- dst_x = 0
- end_x: t.CInt = wx + ww - 1
- if end_x > w: end_x = w
- actual_w: t.CInt = end_x - dst_x
- if actual_w <= 0: continue
- if src_x + actual_w > fb_stride: actual_w = fb_stride - src_x
- if actual_w <= 0: continue
- src_off: t.CInt = row * fb_stride + src_x
- if src_off + actual_w > fb_total: continue
- string.memcpy(t.CVoid(t.CUInt64T(back) + (dst_y * w + dst_x) * 4, t.CPtr), t.CVoid(t.CUInt64T(win_fb) + src_off * 4, t.CPtr), actual_w * 4)
- else:
- copy_w: t.CInt = fb_stride - 1
- if copy_w > ww - 1: copy_w = ww - 1
- for col_px in range(1, copy_w):
- if ry < r:
- if col_px < r:
- if not _is_in_corner(col_px, ry, r, r, r): continue
- elif col_px >= ww - r:
- if not _is_in_corner(col_px, ry, ww - r - 1, r, r): continue
- elif ry >= wh - r:
- if col_px < r:
- if not _is_in_corner(col_px, ry, r, wh - r - 1, r): continue
- elif col_px >= ww - r:
- if not _is_in_corner(col_px, ry, ww - r - 1, wh - r - 1, r): continue
- if _is_on_border(col_px, ry, ww, wh, r): continue
- dst_x2: t.CInt = wx + col_px
- if dst_x2 < 0 or dst_x2 >= w: continue
- if col_px >= fb_stride: continue
- px_off: t.CInt = row * fb_stride + col_px
- if px_off < 0 or px_off >= fb_total: continue
- back[dst_y * w + dst_x2] = win_fb[px_off]
- else:
- src_x2: t.CInt = 1
- dst_x3: t.CInt = wx + 1
- if dst_x3 < 0:
- src_x2 = src_x2 - dst_x3
- dst_x3 = 0
- end_x2: t.CInt = wx + ww - 1
- if end_x2 > w: end_x2 = w
- actual_w2: t.CInt = end_x2 - dst_x3
- if actual_w2 <= 0: continue
- if src_x2 + actual_w2 > fb_stride: actual_w2 = fb_stride - src_x2
- if actual_w2 <= 0: continue
- src_off2: t.CInt = row * fb_stride + src_x2
- if src_off2 + actual_w2 > fb_total: continue
- string.memcpy(t.CVoid(t.CUInt64T(back) + (dst_y * w + dst_x3) * 4, t.CPtr), t.CVoid(t.CUInt64T(win_fb) + src_off2 * 4, t.CPtr), actual_w2 * 4)
-
- btn_w: t.CInt = CLOSE_BTN_SIZE
- btn_h: t.CInt = CLOSE_BTN_SIZE
- btn_x: t.CInt = wx + ww - btn_w - 4
- btn_y: t.CInt = wy + (th - btn_h) // 2
- clip_r: t.CInt = 0
- if style == STYLE_WIN7:
- btn_w = CLOSE_BTN_W7_W
- btn_h = CLOSE_BTN_W7_H
- btn_x = wx + ww - btn_w - 5
- btn_y = wy + (th - btn_h) // 2
- if rounded:
- clip_r = r
- elif style == STYLE_WINXP:
- btn_w = CLOSE_BTN_XP_SZ
- btn_h = CLOSE_BTN_XP_SZ
- btn_x = wx + ww - btn_w - 5
- btn_y = wy + (th - btn_h) // 2
- elif style == STYLE_WIN10 or style == STYLE_WIN11:
- btn_w = CLOSE_BTN_W_WIN
- btn_h = th - 2
- btn_x = wx + ww - btn_w
- btn_y = wy + 1
- if rounded:
- clip_r = r
- _draw_close_btn(back, w, h, btn_x, btn_y, btn_w, btn_h, win.close_hover, style, wx, wy, ww, clip_r)
- max_bx: t.CInt = btn_x - btn_w
- if style == STYLE_WIN7 or style == STYLE_WINXP:
- max_bx = btn_x - btn_w - 1
- _draw_max_btn(back, w, h, max_bx, btn_y, btn_w, btn_h, win.max_hover, style, win.is_maximized)
- min_bx: t.CInt = max_bx - btn_w
- if style == STYLE_WIN7 or style == STYLE_WINXP:
- min_bx = max_bx - btn_w - 1
- _draw_min_btn(back, w, h, min_bx, btn_y, btn_w, btn_h, win.min_hover, style)
-
- text_col: t.CUInt32T = 0xFFFFFFFF
- if not is_active:
- text_col = gfx.COLOR_RGB(170, 170, 170)
- text_y: t.CInt = wy + (th - 16) // 2
- _draw_text(back, w, h, wx + 8, text_y, c.Addr(win.title[0]), text_col)
-
-def create(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
- global _win_count, _next_z, _focused_win
- if _win_count >= MAX_APP_WINDOWS: return -1
- idx: t.CInt = _win_count
- _win_count += 1
- aw: AppWindow | t.CPtr = c.Addr(_wins[idx])
- aw.active = 1
- aw.x = x
- aw.y = y
- aw.w = w
- aw.h = h
- aw.content_h = h - _get_title_height(style) - 2
- _next_z += 1
- aw.z_order = _next_z
- aw.style = style
- aw.close_hover = 0
- aw.min_hover = 0
- aw.max_hover = 0
- aw.is_maximized = 0
- aw.orig_x = x
- aw.orig_y = y
- aw.orig_w = w
- aw.orig_h = h
- aw.pid = _current_app_pid
- aw.cursor_type = 0
- aw.app_cursor_type = 0
- aw.fb_w = 0
- aw.fb_h = 0
- aw.old_fb = t.CVoid(0, t.CPtr)
- aw.ping_pending = 0
- aw.no_resp = 0
- aw.no_resp_sec = 0
- aw.minimized = 0
- aw.resizable_w = 1
- aw.resizable_h = 1
- aw.resize_w = 0
- aw.resize_h = 0
- string.memset(c.Addr(aw.title), 0, 32)
- string.memset(c.Addr(aw.orig_title), 0, 32)
- for i in range(31):
- ch: t.CChar = title[i]
- if ch == 0: break
- aw.title[i] = ch
- aw.orig_title[i] = ch
- aw.fb = mm.malloc(w * aw.content_h * 4)
- aw.fb_w = w
- aw.fb_h = aw.content_h
- if aw.fb:
- bg_col: t.CUInt32T = gfx.COLOR_RGB(25, 25, 35)
- fb_size: t.CInt = w * aw.content_h
- for fi in range(fb_size):
- aw.fb[fi] = bg_col
- _mark_rows_dirty(y, h)
- _focused_win = idx
- return idx
-
-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:
- if win_id < 0 or win_id >= _win_count: return -1
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return -1
- win_fb: UINT32PTR = aw.fb
- if not win_fb: return -1
- fbw: t.CInt = aw.fb_w
- fbh: t.CInt = aw.fb_h
- _draw_text(win_fb, fbw, fbh, x, y, text, color)
- _mark_rows_dirty(aw.y + _get_title_height(aw.style) + 1 + y, 16)
- return 0
-
-def set_app_pid(pid: t.CInt):
- global _current_app_pid
- _current_app_pid = pid
-
-def is_active(win_id: t.CInt) -> t.CInt:
- if win_id < 0 or win_id >= _win_count: return 0
- return _wins[win_id].active
-
-def get_fb(win_id: t.CInt) -> UINT32PTR:
- if win_id < 0 or win_id >= _win_count: return t.CVoid(0, t.CPtr)
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return t.CVoid(0, t.CPtr)
- if aw.old_fb:
- mm.free(aw.old_fb)
- aw.old_fb = t.CVoid(0, t.CPtr)
- if aw.resize_w != 0 and (aw.fb_w != aw.resize_w or aw.fb_h != aw.resize_h):
- target_w: t.CInt = aw.resize_w
- target_h: t.CInt = aw.resize_h
- if target_w <= 0 or target_h <= 0:
- aw.resize_w = 0
- aw.resize_h = 0
- return aw.fb
- new_fb_sz_gf: t.CInt = target_w * target_h
- new_fb_gf: UINT32PTR = mm.malloc(new_fb_sz_gf * 4)
- if not new_fb_gf:
- aw.resize_w = 0
- aw.resize_h = 0
- return aw.fb
- old_fb_gf: UINT32PTR = aw.fb
- old_fbw_gf: t.CInt = aw.fb_w
- old_fbh_gf: t.CInt = aw.fb_h
- aw.fb = new_fb_gf
- aw.fb_w = target_w
- aw.fb_h = target_h
- aw.w = target_w
- aw.content_h = target_h
- aw.resize_w = 0
- aw.resize_h = 0
- bg_gf: t.CUInt32T = gfx.COLOR_RGB(30, 30, 50)
- for fi_gf in range(new_fb_sz_gf):
- aw.fb[fi_gf] = bg_gf
- if old_fb_gf:
- cph_gf: t.CInt = old_fbh_gf
- if cph_gf > target_h: cph_gf = target_h
- for ri_gf in range(cph_gf):
- rb_gf: t.CInt = old_fbw_gf
- if rb_gf > target_w: rb_gf = target_w
- string.memcpy(t.CVoid(t.CUInt64T(aw.fb) + ri_gf * target_w * 4, t.CPtr), t.CVoid(t.CUInt64T(old_fb_gf) + ri_gf * old_fbw_gf * 4, t.CPtr), rb_gf * 4)
- if aw.old_fb:
- mm.free(aw.old_fb)
- aw.old_fb = old_fb_gf
- return aw.fb
-
-def get_size(win_id: t.CInt) -> t.CInt:
- if win_id < 0 or win_id >= _win_count: return 0
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return 0
- return (aw.fb_w << 16) | (aw.fb_h & 0xFFFF)
-
-_NO_RESP_SUFFIX: t.CArray[t.CChar, 14] = " - (No Resp)"
-
-def _update_no_resp_title(win_id: t.CInt, mark: t.CInt):
- if win_id < 0 or win_id >= _win_count: return
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return
- string.memset(c.Addr(aw.title), 0, 32)
- if mark:
- j: t.CInt = 0
- for ch in aw.orig_title:
- if j >= 31: break
- if ch == 0: break
- aw.title[j] = ch
- j += 1
- for sc in _NO_RESP_SUFFIX:
- if j >= 13: break
- if sc == 0: break
- if j < 31:
- aw.title[j] = sc
- j += 1
- else:
- j2: t.CInt = 0
- for ch2 in aw.orig_title:
- if j2 >= 31: break
- if ch2 == 0: break
- aw.title[j2] = ch2
- j2 += 1
- _mark_rows_dirty(aw.y, _get_title_height(aw.style) + 2)
-
-def _heartbeat_check():
- global _hb_last_sec
- cur_sec: t.CUInt32T = timer.timer_get_seconds()
- if cur_sec - _hb_last_sec < HB_INTERVAL_SEC: return
- _hb_last_sec = cur_sec
- for i in range(_win_count):
- aw: AppWindow | t.CPtr = c.Addr(_wins[i])
- if not aw.active:
- continue
- if aw.pid == 0:
- continue
- if aw.ping_pending:
- if not aw.no_resp:
- aw.no_resp = 1
- aw.no_resp_sec = cur_sec
- _update_no_resp_title(i, 1)
- else:
- elapsed: t.CUInt32T = cur_sec - aw.no_resp_sec
- if elapsed >= HB_NO_RESP_SEC:
- aw.active = 0
- _mark_rows_dirty(aw.y, aw.h)
- p_ref: process.Process | t.CPtr = process.ProcessManager.get_process(aw.pid)
- if p_ref is not None:
- p_ref.exit()
- else:
- aw.ping_pending = 1
- evt: InputEvent
- string.memset(c.Addr(evt), 0, INPUT_EVENT_SIZE)
- evt.type = EVENT_TYPE_PING
- evt.win_id = i
- _push_event(evt)
-
-def flush(win_id: t.CInt):
- if win_id < 0 or win_id >= _win_count: return
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return
- if aw.old_fb:
- mm.free(aw.old_fb)
- aw.old_fb = t.CVoid(0, t.CPtr)
- if aw.ping_pending:
- aw.ping_pending = 0
- if aw.no_resp:
- aw.no_resp = 0
- aw.no_resp_sec = 0
- _update_no_resp_title(win_id, 0)
- _mark_rows_dirty(aw.y + _get_title_height(aw.style) + 1, _eff_h(aw))
-
-def set_title(win_id: t.CInt, title: t.CConst | t.CChar | t.CPtr) -> t.CInt:
- if win_id < 0 or win_id >= _win_count: return -1
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return -1
- string.memset(c.Addr(aw.title), 0, 32)
- string.memset(c.Addr(aw.orig_title), 0, 32)
- for i in range(31):
- ch: t.CChar = title[i]
- if ch == 0: break
- aw.title[i] = ch
- aw.orig_title[i] = ch
- _mark_rows_dirty(aw.y, _get_title_height(aw.style) + 2)
- return 0
-
-def set_geometry(win_id: t.CInt, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.CInt:
- if win_id < 0 or win_id >= _win_count: return -1
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return -1
- old_y: t.CInt = aw.y
- old_h: t.CInt = aw.h
- aw.x = x
- aw.y = y
- aw.resize_w = w
- aw.resize_h = h - _get_title_height(aw.style) - 2
- aw.h = h
- _mark_rows_dirty(old_y, old_h)
- _mark_rows_dirty(y, h)
- return 0
-
-def set_resizable(win_id: t.CInt, rw: t.CInt, rh: t.CInt) -> t.CInt:
- if win_id < 0 or win_id >= _win_count: return -1
- aw: AppWindow | t.CPtr = c.Addr(_wins[win_id])
- if not aw.active: return -1
- aw.resizable_w = rw
- aw.resizable_h = rh
- return 0
-
-def destroy_by_pid(pid: t.CInt):
- global _focused_win, _last_hover_win
- for i in range(_win_count):
- if _wins[i].pid == pid and _wins[i].active:
- _wins[i].active = 0
- _mark_rows_dirty(_wins[i].y, _wins[i].h)
- if _focused_win == i:
- _focused_win = -1
- if _last_hover_win == i:
- _last_hover_win = -1
- if _focused_win < 0:
- for j in range(_win_count - 1, -1, -1):
- if _wins[j].active and not _wins[j].minimized:
- _focused_win = j
- break
diff --git a/Test/Kernel/services/keyboard.vp b/Test/Kernel/services/keyboard.vp
deleted file mode 100644
index e7aae90b..00000000
--- a/Test/Kernel/services/keyboard.vp
+++ /dev/null
@@ -1,50 +0,0 @@
-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
diff --git a/Test/Kernel/services/mouse.vp b/Test/Kernel/services/mouse.vp
deleted file mode 100644
index 53e07f81..00000000
--- a/Test/Kernel/services/mouse.vp
+++ /dev/null
@@ -1,13 +0,0 @@
-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
diff --git a/packages/Viper.png b/packages/Viper.png
new file mode 100644
index 00000000..48ada2b2
Binary files /dev/null and b/packages/Viper.png differ
diff --git a/packages/Viper.svg b/packages/Viper.svg
new file mode 100644
index 00000000..6040b770
--- /dev/null
+++ b/packages/Viper.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/packages/viper/images/viper-icon.svg b/packages/viper/images/viper-icon.svg
index ebb40f2f..6040b770 100644
--- a/packages/viper/images/viper-icon.svg
+++ b/packages/viper/images/viper-icon.svg
@@ -1,4 +1,57 @@
-