isr.s: ISR_NOERR/ISR_ERR 的 _frame_ready 里把 r8(RIP)/r9(CS)/rax(RSP) 写进新增的 _intr_rip/_intr_cs/_intr_rsp(只读这三个寄存器,不影响随后压栈)。timer.vp: 心跳行追加 3 个 hex32 字段。定时器 1kHz,所以这三个值几乎总是最后一次定时中断打断的现场:intr_cs=2B 表示该线程卡在用户态 intr_rip 处,=08 表示卡在内核。
184 lines
6.7 KiB
Plaintext
184 lines
6.7 KiB
Plaintext
import platform.pch.pic as pic
|
||
import platform.pch.pit as pit
|
||
import sched.sched as sched
|
||
import drivers.core.cpu.apic as apic
|
||
import asm
|
||
|
||
|
||
define TIMER_FREQUENCY = 1000
|
||
define TICKS_PER_SECOND = TIMER_FREQUENCY
|
||
define MILLISECONDS_PER_TICK = (1000 / TIMER_FREQUENCY)
|
||
|
||
static ticks: volatile uint64 = 0
|
||
static seconds: volatile uint32 = 0
|
||
static milliseconds: volatile uint32 = 0
|
||
static timer_running: volatile bool = False
|
||
|
||
# ============================================================================
|
||
# 【诊断·临时,定位后必须删除】IRQ0 心跳 + 调度器快照。
|
||
#
|
||
# 症状:某个 app 退出([syscall] exit called)之后 [perf]/[chk] 永不再打印。
|
||
# 桌面线程的渲染/打印完全依赖调度器切它回来,而调度器只在 needs_reschedule
|
||
# 被 sched_tick(IRQ0)置位、且有线程调用 try_reschedule 时才切换 ⇒ 三种可能:
|
||
# A) 本探针也一起停 → IRQ0 / EOI 死了(定时器不再推进)
|
||
# B) 探针继续、cur 恒定且该 tid 的 st=1(RUNNING) → 那个线程死循环且不再调用带
|
||
# try_reschedule 的 syscall ⇒ needs_reschedule 无人消费 ⇒ 全系统不再切换
|
||
# C) 探针继续、cur 在变 → 调度器活着,问题在桌面线程自身
|
||
#
|
||
# 直接写 COM1 0x3F8(自带 LSR 超时,绝不依赖 serial 驱动、绝不挂住 ISR)。
|
||
# 每行格式(`_intr_*` 由 isr.s 在每次中断入口写入 = 最后一次定时中断打断的那条指令):
|
||
# `[t] <ticks:8hex> <current_tid:8hex> <thread_count:8hex> <各线程 state 1 位hex> <intr_rip:8hex> <intr_cs:8hex> <intr_rsp:8hex>`
|
||
# 卡死线程的现场就是 intr_rip/intr_cs:cs=2B 表示卡在用户态该 rip 处,cs=08 表示卡在内核。
|
||
# ============================================================================
|
||
_dbg_tick: uint64 = 0
|
||
|
||
def _dbg_putc(ch: uint8):
|
||
tmo: int = 200000
|
||
while tmo > 0:
|
||
if (asm.inb(0x3FD) & 0x20) != 0:
|
||
break
|
||
tmo -= 1
|
||
asm.outb(0x3F8, ch)
|
||
|
||
def _dbg_hex32(v: uint64):
|
||
sh: int = 28
|
||
while sh >= 0:
|
||
d: int = int((v >> uint64(sh)) & uint64(15))
|
||
if d < 10:
|
||
_dbg_putc(uint8(48 + d))
|
||
else:
|
||
_dbg_putc(uint8(55 + d))
|
||
sh -= 4
|
||
|
||
def _dbg_snapshot():
|
||
s: sched.Scheduler* = sched._sched_ptr
|
||
_dbg_putc(uint8(10)) # \n
|
||
_dbg_putc(uint8(91)) # [
|
||
_dbg_putc(uint8(116)) # t
|
||
_dbg_putc(uint8(93)) # ]
|
||
_dbg_putc(uint8(32)) # ' '
|
||
_dbg_hex32(uint64(ticks))
|
||
_dbg_putc(uint8(32))
|
||
_dbg_hex32(uint64(s.current_tid))
|
||
_dbg_putc(uint8(32))
|
||
_dbg_hex32(uint64(s.thread_count))
|
||
_dbg_putc(uint8(32))
|
||
i: int
|
||
for i in range(s.thread_count):
|
||
st: int = s.threads[i].state
|
||
if st < 10:
|
||
_dbg_putc(uint8(48 + st))
|
||
else:
|
||
_dbg_putc(uint8(55 + st))
|
||
# 被中断代码的 RIP/CS/RSP(isr.s 写入 _intr_*)——定位"卡在哪条指令"的关键。
|
||
ir: uint64 = 0
|
||
ic: uint64 = 0
|
||
iu: uint64 = 0
|
||
__asm__(f"mov {asmout(ir, ASM_DESCR.OUTPUT_REG)}, [_intr_rip]", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
__asm__(f"mov {asmout(ic, ASM_DESCR.OUTPUT_REG)}, [_intr_cs]", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
__asm__(f"mov {asmout(iu, ASM_DESCR.OUTPUT_REG)}, [_intr_rsp]", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
_dbg_putc(uint8(32))
|
||
_dbg_hex32(ir)
|
||
_dbg_putc(uint8(32))
|
||
_dbg_hex32(ic)
|
||
_dbg_putc(uint8(32))
|
||
_dbg_hex32(iu)
|
||
_dbg_putc(uint8(10))
|
||
|
||
def timer_init():
|
||
global ticks, seconds, milliseconds, timer_running
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
ticks = 0
|
||
seconds = 0
|
||
milliseconds = 0
|
||
timer_running = True
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
pit.pit_init(TIMER_FREQUENCY)
|
||
|
||
def timer_handler():
|
||
global ticks, seconds, milliseconds, timer_running, _dbg_tick
|
||
if not timer_running:
|
||
pic.eoi(0)
|
||
apic.eoi()
|
||
return
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
ticks = ticks + 1
|
||
milliseconds = milliseconds + MILLISECONDS_PER_TICK
|
||
if milliseconds >= 1000:
|
||
seconds = seconds + 1
|
||
milliseconds = milliseconds - 1000
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
sched.Scheduler.sched_tick()
|
||
pic.eoi(0)
|
||
# LAPIC EOI:APIC 启用后中断经 LINT0(EXTINT) 送达会置 LAPIC ISR,
|
||
# 只发 PIC EOI 不清 LAPIC ISR → 首个定时中断后后续中断被屏蔽 →
|
||
# ticks 不推进 → msleep 永久挂起(QEMU/OVMF 下 APIC 必启用)。
|
||
apic.eoi()
|
||
# 【诊断·临时】每 1000 tick(≈1s)打一行心跳+调度器快照,见文件头说明。
|
||
_dbg_tick = _dbg_tick + 1
|
||
if (_dbg_tick % 1000) == 0:
|
||
_dbg_snapshot()
|
||
|
||
def timer_start():
|
||
global timer_running
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
timer_running = True
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
|
||
def timer_stop():
|
||
global timer_running
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
timer_running = False
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
|
||
def timer_reset():
|
||
global ticks, seconds, milliseconds
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
ticks = 0
|
||
seconds = 0
|
||
milliseconds = 0
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
|
||
def timer_get_ticks() -> uint64:
|
||
current_ticks: uint64
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
current_ticks = ticks
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
return current_ticks
|
||
|
||
def timer_get_seconds() -> uint32:
|
||
current_seconds: uint32
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
current_seconds = seconds
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
return current_seconds
|
||
|
||
def timer_get_milliseconds() -> uint32:
|
||
current_milliseconds: uint32
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
current_milliseconds = milliseconds
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
return current_milliseconds
|
||
|
||
def timer_get_time(out_seconds: uint32*, out_milliseconds: uint32*):
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
if out_seconds:
|
||
*out_seconds = seconds
|
||
if out_milliseconds:
|
||
*out_milliseconds = milliseconds
|
||
__asm__("mfence", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
|
||
def timer_msleep(ms: uint32):
|
||
target: uint64 = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
|
||
while ticks < target:
|
||
asm.sti()
|
||
asm.hlt()
|
||
sched.Scheduler._yield()
|
||
|
||
def timer_sleep(sec: uint32):
|
||
target: uint64 = ticks + sec * TICKS_PER_SECOND
|
||
while ticks < target:
|
||
asm.sti()
|
||
asm.hlt()
|
||
sched.Scheduler._yield()
|