Files
ViperOS/VKernel/Kernel/platform/pch/timer.vp
T
TermiNexus 471cfa16bf debug(timer): timer_init 读 PIT 计数器,验证 PIT 是否在走
中断仍不送达 timer_handler(无 H)。读 PIT 计数器(latch+读 0x40)打印:
- 计数在 1~1193 之间变化 → PIT 正常,问题在中断送达(PIC/APIC/IDT)
- 计数为 0/不变 → PIT 本身没跑(outb 未生效/环境问题)
用后移除。
2026-08-26 18:29:20 +08:00

130 lines
4.4 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.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 | t.CUInt64T = 0
seconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
milliseconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
timer_running: t.CStatic | t.CVolatile | bool = False
_dbg_once: t.CInt = 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: t.CUInt8T = asm.inb(0x40)
_hi: t.CUInt8T = asm.inb(0x40)
_cnt: t.CInt = t.CInt(_lo) | (t.CInt(_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() -> t.CUInt64T:
current_ticks: t.CUInt64T
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() -> t.CUInt32T:
current_seconds: t.CUInt32T
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() -> t.CUInt32T:
current_milliseconds: t.CUInt32T
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: t.CUInt32T | t.CPtr, out_milliseconds: t.CUInt32T | 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: t.CUInt32T):
target: t.CUInt64T = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
_spin: t.CUInt64T = 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: t.CUInt32T):
target: t.CUInt64T = ticks + sec * TICKS_PER_SECOND
while ticks < target:
asm.sti()
asm.hlt()
sched.Scheduler._yield()