Initial import of ViperOS

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

View File

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

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

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

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

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

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

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

View File

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