- 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 条异常打印完整现场,之后每次只补 '*',避免异常风暴刷爆串口
611 lines
25 KiB
Plaintext
611 lines
25 KiB
Plaintext
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])
|