Files
ViperOS/VKernel/Kernel/intr/idt.vp
T
TermiNexus 0c47d81767 feat(diag): 异常现场完整转储(裸串口通路 + 无错误码向量)
- isr.s:ISR_NOERR 也保存 RIP/CS/RFLAGS/RSP,_fault_err 用 -1 表示无错误码;
  两类宏都补存 rbx/rbp/r12(用户态 #PF 时 r12 常为出错 store 的目标对象基址)
- idt.vp:新增不经驱动/缓冲的裸串口输出(asm.outb),打印 rip/rsp/cs/flags、
  u 位、callee-saved、错误码;#UD 附带出错指令字节,#PF 附带 cr2
- 前 32 条异常打印完整现场,之后每次只补 '*',避免异常风暴刷爆串口
2026-10-26 22:41:14 +08:00

611 lines
25 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import platform.pch.pic as pic
import platform.pch.timer as timer
import sched.sched as sched
import sched.process as proc
import drivers.serial.uart.serial as serial
import drivers.core.cpu.apic as apic
import viperlib
import asm
define CODE_SEG: uint16 = 0x08
@__attribute__(packed)
class idt_entry:
base_low: uint16
selector: uint16
ist_attr: uint8
type_attr: uint8
base_middle: uint16
base_high: uint32
reserved1: uint32
export idt: [256]idt_entry = []
typedef irq_handler_t = callable[[], int]
extern def isr0()
extern def isr1()
extern def isr2()
extern def isr3()
extern def isr4()
extern def isr5()
extern def isr6()
extern def isr7()
extern def isr8()
extern def isr9()
extern def isr10()
extern def isr11()
extern def isr12()
extern def isr13()
extern def isr14()
extern def isr15()
extern def isr16()
extern def isr17()
extern def isr18()
extern def isr19()
extern def isr20()
extern def isr21()
extern def isr22()
extern def isr23()
extern def isr24()
extern def isr25()
extern def isr26()
extern def isr27()
extern def isr28()
extern def isr29()
extern def isr30()
extern def isr31()
extern def isr32()
extern def isr33()
extern def isr34()
extern def isr35()
extern def isr36()
extern def isr37()
extern def isr38()
extern def isr39()
extern def isr40()
extern def isr41()
extern def isr42()
extern def isr43()
extern def isr44()
extern def isr45()
extern def isr46()
extern def isr47()
extern def isr80()
extern def isr_default()
# ===========================================================================
# 【诊断】异常现场的"裸串口"输出通路
#
# 为什么不直接用 serial.puts:`[06]` 风暴现场里只能看到裸 `[06]`、看不到任何后续文字,
# 说明 serial.puts 这条路当时是断的(缓冲区/锁/驱动对象状态可能在故障中已损坏,或者它自己
# 再次触发异常)。而 `[06]` 之所以出得来,是因为它由 isrCommonhandler 开头直接用 `out 0x3F8`
# 写出 —— 只要 CPU 还能 out,这条路就一定能出字。
# 因此下面几条诊断函数全部走 `asm.outb`,不经过任何驱动/缓冲/全局状态。
# ===========================================================================
define DIAG_COM1 = 0x3F8
# 已输出的完整现场条数:异常风暴时只详细打前若干条,之后每来一次只补一个 '*',
# 避免把串口刷爆(真正的定位信息全在最前面的几条里)。
_diag_dumps: int = 0
_hex_digits: [17]char = "0123456789ABCDEF"
def _diag_putc(ch: int):
asm.outb(DIAG_COM1, uint8(ch & 0xFF))
def _diag_puts(s: const str):
i: int = 0
while s[i] != 0:
_diag_putc(int(s[i]))
i += 1
# 定宽十六进制:从低位往高位填再正序吐出(与 vpui._ptr_to_hex 同款,避免变长移位)
def _diag_hex(v: uint64, digits: int):
buf: [20]char
i: int = digits - 1
val: uint64 = v
while i >= 0:
nib: int = int(val & uint64(0xF))
buf[i] = _hex_digits[nib]
val = val >> 4
i -= 1
buf[digits] = 0
_diag_puts(&buf[0])
def setGate(num: int, base: uint64, sel: uint16, flags: uint8):
global idt
idt[num].base_low = uint16(base & 0xFFFF)
idt[num].base_middle = uint16((base >> 16) & 0xFFFF)
idt[num].base_high = uint32((base >> 32) & 0xFFFFFFFF)
idt[num].selector = uint16(sel)
idt[num].ist_attr = 0
idt[num].type_attr = uint8(flags)
idt[num].reserved1 = 0
def isrCommonhandler(interrupt: int):
__asm__(f"""mov dx, 0x3F8
mov al, 91
out dx, al
mov ecx, {asminp(interrupt, 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=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX])
# 【诊断·完整现场】紧接上面裸打出的 `[VV]`,用同一条裸串口通路补齐现场。
# isr.s 的两个宏(ISR_NOERR / ISR_ERR)都会填 _fault_*,因此所有向量都有 rip/rsp/cs/flags。
# 只详细打前 32 条:异常风暴时后面的每条只补一个 '*',避免把串口刷爆。
global _diag_dumps
_diag_dumps = _diag_dumps + 1
if _diag_dumps <= 32:
_dg_rip: uint64 = 0
_dg_rsp: uint64 = 0
_dg_cs: uint64 = 0
_dg_fl: uint64 = 0
__asm__(f"mov {asmout(_dg_rip, ASM_DESCR.OUTPUT_REG)}, [_fault_rip]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_dg_rsp, ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_dg_cs, ASM_DESCR.OUTPUT_REG)}, [_fault_cs]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_dg_fl, ASM_DESCR.OUTPUT_REG)}, [_fault_flags]",
op=[ASM_DESCR.CLOBBER_MEMORY])
_diag_puts(" rip=0x")
_diag_hex(_dg_rip, 16)
_diag_puts(" rsp=0x")
_diag_hex(_dg_rsp, 16)
_diag_puts(" cs=0x")
_diag_hex(_dg_cs, 4)
_diag_puts(" fl=0x")
_diag_hex(_dg_fl, 8)
_diag_puts(" u=")
_diag_putc(48 + int(_dg_cs & uint64(3)))
# callee-saved 现场(两个宏都已在入口保存):r12 常是出错 store 的目标对象基址
_dg_r12: uint64 = 0
_dg_rbx: uint64 = 0
_dg_rbp: uint64 = 0
__asm__(f"mov {asmout(_dg_r12, ASM_DESCR.OUTPUT_REG)}, [_fault_r12]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_dg_rbx, ASM_DESCR.OUTPUT_REG)}, [_fault_rbx]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_dg_rbp, ASM_DESCR.OUTPUT_REG)}, [_fault_rbp]",
op=[ASM_DESCR.CLOBBER_MEMORY])
_diag_puts(" rbx=0x")
_diag_hex(_dg_rbx, 16)
_diag_puts(" rbp=0x")
_diag_hex(_dg_rbp, 16)
_diag_puts(" r12=0x")
_diag_hex(_dg_r12, 16)
if (interrupt == 8 or interrupt == 10 or interrupt == 11 or interrupt == 12
or interrupt == 13 or interrupt == 14 or interrupt == 17):
# 只有 ISR_ERR 系列才真的压了错误码;其余向量的 _fault_err 是 -1 哨兵
_dg_err: uint64 = 0
__asm__(f"mov {asmout(_dg_err, ASM_DESCR.OUTPUT_REG)}, [_fault_err]",
op=[ASM_DESCR.CLOBBER_MEMORY])
_diag_puts(" err=0x")
_diag_hex(_dg_err, 4)
else:
_diag_puts(" err=none")
if interrupt == 6:
# #UD:把出错指令的前 8 字节打出来 —— `0F 0B` 就是 ud2(LLVM 插的 trap),
# 其余字节说明是"数据/坏跳转目标被当代码执行"。
ipb: uint8* = uint8*(_dg_rip)
_diag_puts(" insn=")
for bi in range(8):
_diag_hex(uint64(ipb[bi]), 2)
_diag_putc(32)
if interrupt == 14:
_dg_cr2: uint64 = 0
__asm__(f"mov {asmout(_dg_cr2, ASM_DESCR.OUTPUT_REG)}, cr2",
op=[ASM_DESCR.CLOBBER_MEMORY])
_diag_puts(" cr2=0x")
_diag_hex(_dg_cr2, 16)
_diag_putc(10)
else:
_diag_putc(42)
# 【诊断】异常现场:出错 RIP / 错误码 / 出错时 RSP(#PF 另打 cr2)。
# 由 isr.s 的 ISR_NOERR / ISR_ERR 在入口写入 _fault_*(无错误码向量写 -1);
# 这一段走 serial.puts,属于"锦上添花":真正可靠的现场在上面那段裸串口输出里,
# 这里只在带错误码的向量上补充返回槽三连(serial.puts 自身故障时不会出字,属已知局限)。
if (interrupt == 8 or interrupt == 10 or interrupt == 11 or interrupt == 12
or interrupt == 13 or interrupt == 14 or interrupt == 17):
_df_rip: uint64 = 0
_df_err: uint64 = 0
_df_rsp: uint64 = 0
__asm__(f"mov {asmout(_df_rip, ASM_DESCR.OUTPUT_REG)}, [_fault_rip]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_df_err, ASM_DESCR.OUTPUT_REG)}, [_fault_err]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_df_rsp, ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]",
op=[ASM_DESCR.CLOBBER_MEMORY])
_dfbuf: [128]char
viperlib.snprintf(&_dfbuf, 128, " rip=0x%lx err=0x%lx rsp=0x%lx\n", _df_rip, _df_err, _df_rsp)
serial.puts(&_dfbuf)
# callee-saved 现场(ISR_ERR 入口保存):r12 往往就是出错 store 的目标对象基址
# (cr2 = r12 + 常量偏移),据此能直接对上"写的是哪个对象"。
_df_r12: uint64 = 0
_df_rbx: uint64 = 0
_df_rbp: uint64 = 0
__asm__(f"mov {asmout(_df_r12, ASM_DESCR.OUTPUT_REG)}, [_fault_r12]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_df_rbx, ASM_DESCR.OUTPUT_REG)}, [_fault_rbx]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_df_rbp, ASM_DESCR.OUTPUT_REG)}, [_fault_rbp]",
op=[ASM_DESCR.CLOBBER_MEMORY])
viperlib.snprintf(&_dfbuf, 128, " rbx=0x%lx rbp=0x%lx r12=0x%lx\n", _df_rbx, _df_rbp, _df_r12)
serial.puts(&_dfbuf)
# 返回槽三连:出错 RSP 附近的栈字。
# ret=0x… [rsp-8]:若 CPU 是在 `ret` 之后于错地址取指的,这里就是被弹走的坏目标;
# ra=0x… [rsp] :调用者的返回地址(真内核地址)⇒ 反查即可定位"哪个函数的返回槽被写坏";
# ra2=0x… [rsp+8]:再上一层,用于交叉确认。
# 返回槽三连:只在**内核栈**情形下读 —— 用户态出错时 _fault_rsp 是用户栈指针,
# 它下方那一页往往没映射,读 [rsp-8] 会再触发一次 #PF(现场:紧跟一行
# [0E] cr2=0x7fffffde0000,就是这里读出来的次生故障)。
if _df_rsp >= 0x100000 and _df_rsp < 0x80000000:
_df_ret: uint64 = 0
_df_ra: uint64 = 0
_df_ra2: uint64 = 0
__asm__(f"mov {asmout(_df_ret, ASM_DESCR.OUTPUT_REG)}, [{asminp(_df_rsp, ASM_DESCR.REG_ANY)} - 8]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_df_ra, ASM_DESCR.OUTPUT_REG)}, [{asminp(_df_rsp, ASM_DESCR.REG_ANY)}]",
op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov {asmout(_df_ra2, ASM_DESCR.OUTPUT_REG)}, [{asminp(_df_rsp, ASM_DESCR.REG_ANY)} + 8]",
op=[ASM_DESCR.CLOBBER_MEMORY])
viperlib.snprintf(&_dfbuf, 128, " ret=0x%lx ra=0x%lx ra2=0x%lx\n", _df_ret, _df_ra, _df_ra2)
serial.puts(&_dfbuf)
if interrupt == 14:
_df_cr2: uint64 = 0
__asm__(f"mov {asmout(_df_cr2, ASM_DESCR.OUTPUT_REG)}, cr2",
op=[ASM_DESCR.CLOBBER_MEMORY])
viperlib.snprintf(&_dfbuf, 128, " cr2=0x%lx\n", _df_cr2)
serial.puts(&_dfbuf)
s: sched.Scheduler* = sched._sched_ptr
# 如果调度器未初始化,直接进入安全停机状态
if s == 0:
serial.puts(" KERNEL PANIC (sched not init)\n")
while True:
asm.sti()
asm.hlt()
pass
tid: int = s.current_tid
if tid == 0:
serial.puts(" KERNEL PANIC\n")
while True:
asm.sti()
asm.hlt()
pass
# s.threads 为 [16 x Thread](sched.MAX_THREADS),越界写会破坏调度器状态
if tid < 0 or tid >= 16:
serial.puts(" KERNEL PANIC (bad tid)\n")
while True:
asm.sti()
asm.hlt()
pass
buf2: [64]char
viperlib.snprintf(&buf2, 64, " exc in tid=%d, terminating\n", tid)
serial.puts(buf2)
# 用户线程被异常终止时回收其用户栈等资源(主线程/内核线程没有对应槽位,自动跳过)。
proc.free_user_thread(proc.find_user_slot_by_tid(tid))
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.
__asm__(f"""mov ecx, 0xC0000101
rdmsr
shl rdx, 32
or rax, rdx
test rax, rax
jz 1f
swapgs
1:""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX])
# 【修复】本路径是从**异常上下文**进来(用户态异常时 CPU 已把 IF 清 0),而且这里
# **永不 iretq 返回**(直接 _yield 换线程)⇒ 若不在这里开中断,被切到的线程就会带着
# "中断关着"继续跑 ⇒ 定时器再也进不来 ⇒ 整机卡死;后续再出异常就是三重故障。
# (定时器抢占路径没这个问题:它靠 iretq 从原帧恢复 RFLAGS。)
asm.sti()
sched.Scheduler._yield()
while True:
asm.sti()
asm.hlt()
export def isr0_handler(): isrCommonhandler(0)
export def isr1_handler(): isrCommonhandler(1)
export def isr2_handler(): isrCommonhandler(2)
export def isr3_handler(): isrCommonhandler(3)
export def isr4_handler(): isrCommonhandler(4)
export def isr5_handler(): isrCommonhandler(5)
export def isr6_handler(): isrCommonhandler(6)
export def isr7_handler(): isrCommonhandler(7)
export def isr8_handler(): isrCommonhandler(8)
export def isr9_handler(): isrCommonhandler(9)
export def isr10_handler(): isrCommonhandler(10)
export def isr11_handler(): isrCommonhandler(11)
export def isr12_handler(): isrCommonhandler(12)
export def isr13_handler(): isrCommonhandler(13)
export def isr14_handler(): isrCommonhandler(14)
export def isr15_handler(): isrCommonhandler(15)
export def isr16_handler(): isrCommonhandler(16)
export def isr17_handler(): isrCommonhandler(17)
export def isr18_handler(): isrCommonhandler(18)
export def isr19_handler(): isrCommonhandler(19)
export def isr20_handler(): isrCommonhandler(20)
export def isr21_handler(): isrCommonhandler(21)
export def isr22_handler(): isrCommonhandler(22)
export def isr23_handler(): isrCommonhandler(23)
export def isr24_handler(): isrCommonhandler(24)
export def isr25_handler(): isrCommonhandler(25)
export def isr26_handler(): isrCommonhandler(26)
export def isr27_handler(): isrCommonhandler(27)
export def isr28_handler(): isrCommonhandler(28)
export def isr29_handler(): isrCommonhandler(29)
export def isr30_handler(): isrCommonhandler(30)
export def isr31_handler(): isrCommonhandler(31)
export def isr32_handler(from_user: int):
timer.timer_handler()
# 定时 IRQ 已 EOI,处理完毕;仅在返回用户态时消费时间片,内核态不抢占。
if from_user != 0:
sched.Scheduler.try_reschedule()
export def isr33_handler():
handler: irq_handler_t = irqGetHandler(1)
if handler:
__asm__(f"""call {asminp(handler, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(1)
apic.eoi()
export def isr34_handler():
handler2: irq_handler_t = irqGetHandler(2)
if handler2:
__asm__(f"""call {asminp(handler2, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(2)
apic.eoi()
export def isr35_handler():
handler3: irq_handler_t = irqGetHandler(3)
if handler3:
__asm__(f"""call {asminp(handler3, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(3)
apic.eoi()
export def isr36_handler():
handler4: irq_handler_t = irqGetHandler(4)
if handler4:
__asm__(f"""call {asminp(handler4, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(4)
apic.eoi()
export def isr37_handler():
handler5: irq_handler_t = irqGetHandler(5)
if handler5:
__asm__(f"""call {asminp(handler5, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(5)
apic.eoi()
export def isr38_handler():
handler6: irq_handler_t = irqGetHandler(6)
if handler6:
__asm__(f"""call {asminp(handler6, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(6)
apic.eoi()
export def isr39_handler():
if pic.isSpurious(7):
return
handler7: irq_handler_t = irqGetHandler(7)
if handler7:
__asm__(f"""call {asminp(handler7, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(7)
apic.eoi()
export def isr40_handler():
handler8: irq_handler_t = irqGetHandler(8)
if handler8:
__asm__(f"""call {asminp(handler8, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(8)
apic.eoi()
export def isr41_handler():
handler9: irq_handler_t = irqGetHandler(9)
if handler9:
__asm__(f"""call {asminp(handler9, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(9)
apic.eoi()
export def isr42_handler():
handler10: irq_handler_t = irqGetHandler(10)
if handler10:
__asm__(f"""call {asminp(handler10, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(10)
apic.eoi()
export def isr43_handler():
handler11: irq_handler_t = irqGetHandler(11)
if handler11:
__asm__(f"""call {asminp(handler11, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(11)
apic.eoi()
export def isr44_handler():
handler: irq_handler_t = irqGetHandler(12)
if handler:
__asm__(f"""call {asminp(handler, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
pic.eoi(12)
apic.eoi()
export def isr45_handler():
pic.eoi(13)
apic.eoi()
export def isr46_handler():
pic.eoi(14)
apic.eoi()
export def isr47_handler():
if pic.isSpurious(15):
return
pic.eoi(15)
apic.eoi()
def init_exceptions():
setGate(0, uint64(isr0), CODE_SEG, 0x8E)
setGate(1, uint64(isr1), CODE_SEG, 0x8E)
setGate(2, uint64(isr2), CODE_SEG, 0x8E)
setGate(3, uint64(isr3), CODE_SEG, 0x8E)
setGate(4, uint64(isr4), CODE_SEG, 0x8E)
setGate(5, uint64(isr5), CODE_SEG, 0x8E)
setGate(6, uint64(isr6), CODE_SEG, 0x8E)
setGate(7, uint64(isr7), CODE_SEG, 0x8E)
setGate(8, uint64(isr8), CODE_SEG, 0x8E)
setGate(9, uint64(isr9), CODE_SEG, 0x8E)
setGate(10, uint64(isr10), CODE_SEG, 0x8E)
setGate(11, uint64(isr11), CODE_SEG, 0x8E)
setGate(12, uint64(isr12), CODE_SEG, 0x8E)
setGate(13, uint64(isr13), CODE_SEG, 0x8E)
setGate(14, uint64(isr14), CODE_SEG, 0x8E)
setGate(15, uint64(isr15), CODE_SEG, 0x8E)
setGate(16, uint64(isr16), CODE_SEG, 0x8E)
setGate(17, uint64(isr17), CODE_SEG, 0x8E)
setGate(18, uint64(isr18), CODE_SEG, 0x8E)
setGate(19, uint64(isr19), CODE_SEG, 0x8E)
setGate(20, uint64(isr20), CODE_SEG, 0x8E)
setGate(21, uint64(isr21), CODE_SEG, 0x8E)
setGate(22, uint64(isr22), CODE_SEG, 0x8E)
setGate(23, uint64(isr23), CODE_SEG, 0x8E)
setGate(24, uint64(isr24), CODE_SEG, 0x8E)
setGate(25, uint64(isr25), CODE_SEG, 0x8E)
setGate(26, uint64(isr26), CODE_SEG, 0x8E)
setGate(27, uint64(isr27), CODE_SEG, 0x8E)
setGate(28, uint64(isr28), CODE_SEG, 0x8E)
setGate(29, uint64(isr29), CODE_SEG, 0x8E)
setGate(30, uint64(isr30), CODE_SEG, 0x8E)
setGate(31, uint64(isr31), CODE_SEG, 0x8E)
def init_irqs():
setGate(32, uint64(isr32), CODE_SEG, 0x8E)
setGate(33, uint64(isr33), CODE_SEG, 0x8E)
setGate(34, uint64(isr34), CODE_SEG, 0x8E)
setGate(35, uint64(isr35), CODE_SEG, 0x8E)
setGate(36, uint64(isr36), CODE_SEG, 0x8E)
setGate(37, uint64(isr37), CODE_SEG, 0x8E)
setGate(38, uint64(isr38), CODE_SEG, 0x8E)
setGate(39, uint64(isr39), CODE_SEG, 0x8E)
setGate(40, uint64(isr40), CODE_SEG, 0x8E)
setGate(41, uint64(isr41), CODE_SEG, 0x8E)
setGate(42, uint64(isr42), CODE_SEG, 0x8E)
setGate(43, uint64(isr43), CODE_SEG, 0x8E)
setGate(44, uint64(isr44), CODE_SEG, 0x8E)
setGate(45, uint64(isr45), CODE_SEG, 0x8E)
setGate(46, uint64(isr46), CODE_SEG, 0x8E)
setGate(47, uint64(isr47), CODE_SEG, 0x8E)
irq_handlers: static [16]irq_handler_t = [None]
def irqInstallHandler(irq: int, handler: irq_handler_t, name: str) -> int:
global irq_handlers
if irq < 0 or irq > 15: return -1
irq_handlers[irq] = handler
return 0
def irqGetHandler(irq: int) -> 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, uint64(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, uint64(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
__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=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX])