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 drivers.serial.uart.serial as serial import viperlib import asm import t, c TIMER_FREQUENCY: t.CDefine = 1000 TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY) ticks: t.CStatic | t.CVolatile | uint64 = 0 seconds: t.CStatic | t.CVolatile | uint32 = 0 milliseconds: t.CStatic | t.CVolatile | uint32 = 0 timer_running: t.CStatic | t.CVolatile | bool = False _dbg_once: int = 0 def timer_init(): global ticks, seconds, milliseconds, timer_running c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) ticks = 0 seconds = 0 milliseconds = 0 timer_running = True c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) pit.pit_init(TIMER_FREQUENCY) # [DBG] 读 PIT 计数器验证是否在走(用后移除) asm.outb(0x43, 0x00) # latch channel 0 _lo: uint8 = asm.inb(0x40) _hi: uint8 = asm.inb(0x40) _cnt: int = int(_lo) | (int(_hi) << 8) _cb: t.CArray[t.CChar, 40] viperlib.snprintf(c.Addr(_cb), 40, "[PIT] cnt=%d\n", _cnt) serial.puts(c.Addr(_cb)) def timer_handler(): global ticks, seconds, milliseconds, timer_running, _dbg_once # [DBG] 一次性打印:'H' 出现说明定时 ISR 被调用(用后移除) if _dbg_once == 0: _dbg_once = 1 serial.puts("H") if not timer_running: pic.eoi(0) apic.eoi() return c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) ticks = ticks + 1 milliseconds = milliseconds + MILLISECONDS_PER_TICK if milliseconds >= 1000: seconds = seconds + 1 milliseconds = milliseconds - 1000 c.Asm("mfence", op=[t.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() def timer_start(): global timer_running c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) timer_running = True c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) def timer_stop(): global timer_running c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) timer_running = False c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) def timer_reset(): global ticks, seconds, milliseconds c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) ticks = 0 seconds = 0 milliseconds = 0 c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) def timer_get_ticks() -> uint64: current_ticks: uint64 c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) current_ticks = ticks c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) return current_ticks def timer_get_seconds() -> uint32: current_seconds: uint32 c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) current_seconds = seconds c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) return current_seconds def timer_get_milliseconds() -> uint32: current_milliseconds: uint32 c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) current_milliseconds = milliseconds c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) return current_milliseconds def timer_get_time(out_seconds: uint32 | t.CPtr, out_milliseconds: uint32 | t.CPtr): c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) if out_seconds: c.Set(c.Deref(out_seconds), seconds) if out_milliseconds: c.Set(c.Deref(out_milliseconds), milliseconds) c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) def timer_msleep(ms: uint32): target: uint64 = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK _spin: uint64 = 0 while ticks < target: # [DBG] 自旋计数:每 1M 次迭代打印 s——hlt 能唤醒说明中断触发 # (用后移除) _spin += 1 if (_spin & 0xFFFFF) == 0: serial.puts("s") 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()