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] <各线程 state 1 位hex> ` # 卡死线程的现场就是 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()