Initial import of ViperOS
This commit is contained in:
2
VKernel/Kernel/intr/__init__.py
Normal file
2
VKernel/Kernel/intr/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import gdt
|
||||
from . import idt
|
||||
142
VKernel/Kernel/intr/gdt.py
Normal file
142
VKernel/Kernel/intr/gdt.py
Normal 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
415
VKernel/Kernel/intr/idt.py
Normal 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
595
VKernel/Kernel/intr/isr.s
Normal 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
|
||||
470
VKernel/Kernel/intr/syscall.py
Normal file
470
VKernel/Kernel/intr/syscall.py
Normal 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")
|
||||
Reference in New Issue
Block a user