fix(usb): 控制传输短读判失败+描述符链完整性校验;CCB 读改写屏蔽 IRQ1;清理已验证探针
uhci.control_transfer:除错误位外再比对 DATA TD 的 Actual Length(bit10:0)。短读时错误位可能全 0(QEMU/硬件不把短包当错误),只查错误位会漏 —— 现场是 USB 鼠标的 25 字节配置描述符只落下前 9 字节 ⇒ 接口解析为 0 ⇒ [usb_mse] no USB mouse found。 usb._parse_config 改为返回实际走完的偏移,enumerate_port 要求恰好走完 total_len,否则重读、仍不完整即报错返回(fail-fast,不带着半截描述符继续);同时删除两条探针。 keyboard.init/mouse.init 读-改-写 CCB 全程 pic.setMask(1):读 CCB 的 0x20 会把 CCB 值放进 0x60 输出缓冲并拉高 IRQ1,IRQ1 handler 会把它当扫描码抢走(现场 sc=0x47),使回读拿到残留值。改为只在校验失败时打印错误,去掉全部 [kbd] 探针。 清理已验证调试输出:idt 的 IRQ1 handler 探针及其计数器、desktop 的 [dbg] back_fb/row_buf/bg_row_buf、main 的 [DBG] LAPIC/idt32/swint/pic_isr 与 [DB] BootInfo 转储、timer 的 [PIT] 与自旋打印及随之无用的 import。
This commit is contained in:
1 parent
82e951ee84
commit
3a497e38ec
8 files changed
+77
-130
No files matched your search
@@ -3,7 +3,6 @@ import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import platform.pch.pic as pic
|
||||
import string
|
||||
import viperlib
|
||||
import t, c
|
||||
|
||||
|
||||
@@ -53,6 +52,14 @@ scancode_set1_shift: [128]char = [
|
||||
'\0'
|
||||
]
|
||||
|
||||
# 清空 8042 输出缓冲(上电自检字节 / 遗留 ACK / 读 CCB 时压入的值)
|
||||
def _drain_outbuf():
|
||||
drain: uint32 = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
def _wait_read():
|
||||
timeout: uint32 = 100000
|
||||
while timeout > 0:
|
||||
@@ -74,11 +81,6 @@ def irq_handler() -> int:
|
||||
if (st & 0x20) != 0:
|
||||
return 0
|
||||
scancode: uint8 = asm.inb(KBD_DATA)
|
||||
# 按键验证:把 IRQ1 收到的扫描码打到串口(高位 0x80 = 释放),
|
||||
# 用来确认"键盘中断是否到达"这一环。
|
||||
_kmsg: [48]char
|
||||
viperlib.snprintf(&_kmsg, 48, "[kbd] sc=0x%x\n", int(scancode))
|
||||
serial.puts(&_kmsg)
|
||||
if buf_count < KBD_BUF_SIZE:
|
||||
buffer[buf_tail] = scancode
|
||||
buf_tail = buf_tail + 1
|
||||
@@ -123,12 +125,7 @@ def init():
|
||||
_kbd_inited = 1
|
||||
|
||||
# 清空控制器输出缓冲(上电自检字节 / 上一次遗留的 ACK 等)
|
||||
drain: uint32
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
_drain_outbuf()
|
||||
|
||||
# 读-改-写 CCB(与 mouse.init 同款写法):
|
||||
# bit0=1 使能键盘 IRQ1;bit6=1 启用 scancode set1 翻译;bit4=0 使能键盘时钟。
|
||||
@@ -136,11 +133,18 @@ def init():
|
||||
# 经常失败(键盘数据串入 CCB 读取、回读为 0),0xAE 便恢复不了 ⇒ 键盘接口停在
|
||||
# 禁用态 ⇒ 之后按键完全不产生任何字节/IRQ1(现场:ki 恒为 2/3、无任何键盘字节)。
|
||||
# 鼠标没有这个序列,所以它一直正常 —— 键盘对齐鼠标的写法即可。
|
||||
#
|
||||
# 全程屏蔽 IRQ1:读 CCB 的 0x20 命令会把 CCB 值放进 0x60 输出缓冲并拉高 IRQ1,
|
||||
# IRQ1 handler 一旦运行就会把这个字节当扫描码读走(现场:handler 装上后读到
|
||||
# sc=0x47,正是鼠标清 bit5 后的 CCB),这里的 inb(0x60) 便只能拿到残留值 ⇒ 可能把
|
||||
# 错误的 CCB 写回。屏蔽期 8259 仍会锁存请求,所以解屏蔽前先清空输出缓冲,
|
||||
# 避免解屏蔽瞬间摄入一个陈旧字节。
|
||||
pic.setMask(1)
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
ccb: uint8 = asm.inb(KBD_DATA)
|
||||
|
||||
ccb = ccb | 0x01
|
||||
ccb = ccb | 0x40
|
||||
ccb = ccb & 0xEF
|
||||
@@ -150,12 +154,25 @@ def init():
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, ccb)
|
||||
|
||||
# 使能键盘扫描(0xF4),并读走 ACK
|
||||
# 回读校验:CCB 没写进去 ⇒ 扫描不使能 ⇒ 按键永不产生字节(必须报错,不能静默继续)
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
rb: uint8 = asm.inb(KBD_DATA)
|
||||
if rb != ccb:
|
||||
serial.puts("[kbd] CCB write verify failed\n")
|
||||
pic.clearMask(1)
|
||||
return
|
||||
|
||||
# 使能键盘扫描(0xF4):非 0xFA ⇒ 命令没送达键盘
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, 0xF4)
|
||||
_wait_read()
|
||||
asm.inb(KBD_DATA)
|
||||
ack: uint8 = asm.inb(KBD_DATA)
|
||||
if ack != 0xFA:
|
||||
serial.puts("[kbd] scan-enable not ACKed\n")
|
||||
|
||||
_drain_outbuf()
|
||||
# 解屏蔽 IRQ1(对齐 mouse.init 的 pic.clearMask(12)),再装 handler
|
||||
pic.clearMask(1)
|
||||
idt.irqInstallHandler(1, irq_handler, "keyboard")
|
||||
@@ -122,6 +122,10 @@ def get_buttons() -> uint8:
|
||||
def init():
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xA8)
|
||||
# 读-改-写 CCB 期间屏蔽 IRQ1:与 keyboard.init 同理 —— 0x20 读 CCB 会把 CCB 值放进
|
||||
# 0x60 输出缓冲并拉高 IRQ1,键盘 ISR 一旦运行就会把它当扫描码抢走(现场:sc=0x47
|
||||
# 正是这里清 bit5 后的 CCB),于是下面的 inb(0x60) 只能拿到残留值 ⇒ 可能把错误 CCB 写回。
|
||||
pic.setMask(1)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
@@ -132,6 +136,7 @@ def init():
|
||||
asm.outb(MOUSE_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, status)
|
||||
pic.clearMask(1)
|
||||
_write_cmd(0xF6)
|
||||
# 分辨率设为 8 counts/mm:0xF6(Set Defaults) 会把它重置为最粗的 4 counts/mm,
|
||||
# 于是每个计数对应的位移偏大。设细一档后光标更稳、不易“飞”。
|
||||
|
||||
@@ -55,6 +55,10 @@ define TD_CTRL_CERR_MASK = 0x18000000
|
||||
define TD_CTRL_ERR_MASK = 0x00760000
|
||||
# bit19 NAK:C_ERR(3) 用尽后仍被 NAK ⇒ 设备一直不给数据
|
||||
define TD_CTRL_NAK_MASK = 0x00080000
|
||||
# Actual Length(bit10:0,编码为 n-1):IN 传输"短读"时错误位可能全 0(QEMU/硬件不把短包
|
||||
# 当错误),只查错误位会漏 ⇒ 必须比对实际字节数(现场:USB 鼠标的 25 字节配置描述符只落下
|
||||
# 前 9 字节,iface 解析为 0 ⇒ usb_mse 找不到鼠标)。
|
||||
define TD_CTRL_ACTLEN_MASK = 0x000007FF
|
||||
|
||||
define TD_TOKEN_SETUP = 0x2D
|
||||
define TD_TOKEN_IN = 0x69
|
||||
@@ -456,6 +460,10 @@ def control_transfer(dev_addr: uint8, endpoint: uint8, ls: int, max_pkt: uint8,
|
||||
if e_data != 0:
|
||||
fail = 0 - 20 - e_data
|
||||
which = 1
|
||||
elif data_in != 0 and ((st_data & TD_CTRL_ACTLEN_MASK) + 1) < uint32(data_len):
|
||||
# 短读:实际字节数少于请求(ACTLEN 编码为 n-1)。错误位可能全 0,不能当成功。
|
||||
fail = 0 - 20 - 4
|
||||
which = 1
|
||||
e_status: int = _td_error(status_td)
|
||||
if e_status != 0:
|
||||
fail = 0 - 30 - e_status
|
||||
|
||||
@@ -139,9 +139,18 @@ def hid_set_idle(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, duratio
|
||||
_setup_packet(0x21, HID_REQ_SET_IDLE, uint16(duration) << 8, uint16(iface), 0, &setup)
|
||||
return _send_control(dev_addr, ls, max_pkt, &setup, None, 0, 0)
|
||||
|
||||
def _parse_config(dev: usb_device*, config_buf: rawptr, total_len: uint16):
|
||||
def _parse_config(dev: usb_device*, config_buf: rawptr, total_len: uint16) -> int:
|
||||
offset: int = 0
|
||||
found_hid: int = 0
|
||||
# 每次解析都从干净状态开始:调用方可能在"描述符没读全"时重试,残留的 iface/ep 字段
|
||||
# 会让上一次的半截结果串到这一次(例如 iface_class=3 但 ep_in=0 的不一致组合)。
|
||||
dev.iface_class = 0
|
||||
dev.iface_subclass = 0
|
||||
dev.iface_protocol = 0
|
||||
dev.iface_num = 0
|
||||
dev.ep_in = 0
|
||||
dev.ep_in_max = 0
|
||||
dev.ep_in_interval = 0
|
||||
while offset < int(total_len):
|
||||
p: uint8* = config_buf + uint64(offset)
|
||||
desc_len: uint8 = *p
|
||||
@@ -167,6 +176,8 @@ def _parse_config(dev: usb_device*, config_buf: rawptr, total_len: uint16):
|
||||
dev.ep_in_interval = ep.bInterval
|
||||
found_hid = 0
|
||||
offset = offset + int(desc_len)
|
||||
# 返回实际走完的偏移:调用方据此判断描述符链是否完整(== total_len 才算读全)
|
||||
return offset
|
||||
|
||||
def enumerate_port(port: int) -> int:
|
||||
global _device_count
|
||||
@@ -204,12 +215,6 @@ def enumerate_port(port: int) -> int:
|
||||
desc: usb_dev_desc* = dev_buf
|
||||
max_pkt: uint8 = desc.bMaxPacketSize0
|
||||
if max_pkt < 8: max_pkt = 8
|
||||
# 探针:设备描述符只要读回 18/8 字节,bLength 必为 18、bDescriptorType 必为 1。
|
||||
# 全 0 ⇒ 控制传输的 DATA 阶段没落盘(而非解析问题)。
|
||||
_db0: [96]char
|
||||
viperlib.snprintf(&_db0, 96, "[usb] devdesc blen=%d btype=%d maxpkt0=%d\n",
|
||||
int(desc.bLength), int(desc.bDescriptorType), int(desc.bMaxPacketSize0))
|
||||
serial.puts(&_db0)
|
||||
|
||||
new_addr: uint8 = uint8(_device_count + 1)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
@@ -256,27 +261,25 @@ def enumerate_port(port: int) -> int:
|
||||
total_len: uint16 = cfg.wTotalLength
|
||||
if total_len > 256: total_len = 256
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -8
|
||||
|
||||
_parse_config(dev, config_buf, total_len)
|
||||
# 读完整配置描述符:不能只看控制传输是否"报成功"——短读时错误位可能全 0,缓冲区里只
|
||||
# 落下前一段(现场:USB 鼠标的 25 字节描述符只到前 9 字节),描述符链会在中途遇到
|
||||
# bLength==0 提前结束 ⇒ 接口描述符解析不到 ⇒ iface_class=0 ⇒ 驱动找不到设备。
|
||||
# 因此用"描述符链是否恰好走完 total_len"来判定,不满足就重读;重读仍不完整直接报错
|
||||
# (fail-fast,不带着半截描述符继续)。
|
||||
result = -1
|
||||
consumed: int = 0
|
||||
for retry in range(3):
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
if result == 0:
|
||||
consumed = _parse_config(dev, config_buf, total_len)
|
||||
if consumed == int(total_len): break
|
||||
timer.timer_msleep(50)
|
||||
if result != 0 or consumed != int(total_len):
|
||||
serial.puts("[usb] config descriptor incomplete\n")
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -8
|
||||
|
||||
# 探针:配置描述符读回后,wTotalLength 应为 0x22/0x23、首字节应为 09 02(bLength=9, CONFIG)。
|
||||
# total=0 或首字节为 0 ⇒ DATA 阶段没传回来;有内容但 iface 仍为 0 ⇒ 解析/布局问题。
|
||||
_cb: uint8* = config_buf
|
||||
_db1: [128]char
|
||||
viperlib.snprintf(&_db1, 128, "[usb] cfgdesc total=%d b0=%02X t0=%02X iface=%02X proto=%02X ep=%d\n",
|
||||
int(total_len), int(_cb[0]), int(_cb[1]),
|
||||
int(dev.iface_class), int(dev.iface_protocol), int(dev.ep_in))
|
||||
serial.puts(&_db1)
|
||||
|
||||
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
|
||||
@@ -198,16 +198,7 @@ export def isr31_handler(): isrCommonhandler(31)
|
||||
export def isr32_handler(): timer.timer_handler()
|
||||
|
||||
export def isr33_handler():
|
||||
global _kbd_irq_seen
|
||||
handler: irq_handler_t = irqGetHandler(1)
|
||||
# 键盘验证:IRQ1 是否真的到达 IDT,以及 handler 是否已安装。
|
||||
# handler=0x0 → 到达了但没装上(键盘仍不可用,问题在安装侧);
|
||||
# 整行不出现 → IRQ1 根本没到(问题在控制器/设备侧)。只打前 8 次。
|
||||
if _kbd_irq_seen < 8:
|
||||
_kbd_irq_seen += 1
|
||||
_kb: [64]char
|
||||
viperlib.snprintf(&_kb, 64, "[kbd] irq1 handler=%lx\n", uint64(handler))
|
||||
serial.puts(&_kb)
|
||||
if handler:
|
||||
__asm__(f"""call {asminp(handler, ASM_DESCR.REG_ANY)}""",
|
||||
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
|
||||
@@ -418,9 +409,7 @@ def init_irqs():
|
||||
setGate(46, uint64(isr46), CODE_SEG, 0x8E)
|
||||
setGate(47, uint64(isr47), CODE_SEG, 0x8E)
|
||||
|
||||
irq_handlers: static [16]irq_handler_t = [None]
|
||||
# 键盘验证:IRQ1 到达次数(仅用于打印前若干次)
|
||||
_kbd_irq_seen: static int = 0
|
||||
irq_handlers: static [16]irq_handler_t = [None]
|
||||
|
||||
def irqInstallHandler(irq: int, handler: irq_handler_t, name: str) -> int:
|
||||
global irq_handlers
|
||||
|
||||
@@ -98,43 +98,9 @@ class ViperKernel:
|
||||
apic.early_init()
|
||||
serial.puts("[main] apic init done\n")
|
||||
|
||||
# [DBG] 综合诊断:判定 LAPIC MMIO 是否真正可访问/可写(用后移除)
|
||||
_dbg_base: uint64 = apic.get_base()
|
||||
_dbg_ver: uint32 = apic.read(0x030) # LAPIC_VERSION:真 LAPIC 应为 0x50014
|
||||
_dbg_svr: uint32 = apic.read(0x0F0) # LAPIC_SVR:init 已写 0x1FF
|
||||
apic.write(0x350, 0x700) # 再次写 LINT0,验证写粘性
|
||||
_dbg_lint0: uint32 = apic.read(0x350)
|
||||
_dbg_feat: uint32 = cpu.detect_features_static()
|
||||
_dbg_buf: [160]char
|
||||
viperlib.snprintf(&_dbg_buf, 160,
|
||||
"[DBG] base=0x%lx ver=0x%x svr=0x%x lint0=0x%x feat=0x%x apic=%d\n",
|
||||
_dbg_base, _dbg_ver, _dbg_svr, _dbg_lint0, _dbg_feat,
|
||||
1 if (_dbg_feat & cpu.CPU_FEATURE_APIC) else 0)
|
||||
serial.puts(&_dbg_buf)
|
||||
|
||||
# [DBG] 读回 IDT 门 32,验证 isr32 分发地址是否正确安装(用后移除)
|
||||
_g32: uint64 = (uint64(intr.idt.idt[32].base_low) | (uint64(intr.idt.idt[32].base_middle) << 16) | (uint64(intr.idt.idt[32].base_high) << 32))
|
||||
_g32buf: [96]char
|
||||
viperlib.snprintf(&_g32buf, 96, "[DBG] idt32 base=0x%lx sel=0x%x type=0x%x\n", _g32, intr.idt.idt[32].selector, intr.idt.idt[32].type_attr)
|
||||
serial.puts(&_g32buf)
|
||||
|
||||
asm.sti()
|
||||
serial.puts("[main] sti done\n")
|
||||
|
||||
# [DBG] 软件触发 int 0x20:门 32 有效则分发到 isr32→timer_handler 打印 H 并返回;
|
||||
# 门无效则 #GP(isrCommonhandler 打印 [GP] err=0x20),一次性区分分发路径(用后移除)
|
||||
serial.puts("[DBG] before swint\n")
|
||||
__asm__("int 0x20", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||||
serial.puts("[DBG] after swint\n")
|
||||
|
||||
# [DBG] 读 PIC1 ISR:bit0 置位说明 PIT IRQ0 已到达 PIC 并被响应(用后移除)
|
||||
asm.outb(0x20, 0x0B) # OCW3 读 ISR
|
||||
asm.io_wait()
|
||||
_pic_isr: uint8 = asm.inb(0x20)
|
||||
_isrbuf: [48]char
|
||||
viperlib.snprintf(&_isrbuf, 48, "[DBG] pic_isr=0x%x\n", _pic_isr)
|
||||
serial.puts(&_isrbuf)
|
||||
|
||||
timer.timer_msleep(100)
|
||||
serial.puts("[main] msleep done\n")
|
||||
rtc.rtc_init()
|
||||
@@ -154,22 +120,11 @@ class ViperKernel:
|
||||
fb_format: int = int(BootInfo.framebuffer_format)
|
||||
fb_size: uint64 = BootInfo.framebuffer_size
|
||||
_SetFrameShadow(fb, width, height, pitch)
|
||||
# [DBG] 打印 BootInfo 指针与 memmap 原始字段,定位全 0 根因(用后移除)
|
||||
_dbbuf: [140]char
|
||||
viperlib.snprintf(&_dbbuf, 140, "[main] BootInfo=0x%lx mmap=0x%lx mmsz=%lu mmd=%lu fb=0x%lx\n",
|
||||
uint64(BootInfo), BootInfo.MemmapAddr, BootInfo.MemmapSize,
|
||||
BootInfo.MemmapDescSize, BootInfo.framebuffer_addr)
|
||||
serial.puts(&_dbbuf)
|
||||
# [DBG] 转储 BootInfo 地址处原始 88 字节(用后移除)
|
||||
_dbraw: [16]char
|
||||
for _dbi in range(88):
|
||||
if (_dbi % 16) == 0:
|
||||
viperlib.snprintf(&_dbraw, 16, "\n[DB] %04x:", _dbi)
|
||||
serial.puts(&_dbraw)
|
||||
_dbv: uint8 = *(uint8*(uint64(BootInfo) + uint64(_dbi)))
|
||||
viperlib.snprintf(&_dbraw, 16, " %02x", _dbv)
|
||||
serial.puts(&_dbraw)
|
||||
serial.puts("\n[DB] dump end\n")
|
||||
|
||||
# 内核镜像末端(含 .bss;__bss_end 见 VKernel/linker.ld):传给 mm.init 使其在挑选
|
||||
# 堆 arena 时排除整块内核镜像 —— .bss 不占文件大小,bootloader 只按文件大小预留页,
|
||||
|
||||
@@ -2,8 +2,6 @@ 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
|
||||
|
||||
|
||||
@@ -15,7 +13,6 @@ static ticks: volatile uint64 = 0
|
||||
static seconds: volatile uint32 = 0
|
||||
static milliseconds: volatile uint32 = 0
|
||||
static timer_running: volatile bool = False
|
||||
_dbg_once: int = 0
|
||||
|
||||
def timer_init():
|
||||
global ticks, seconds, milliseconds, timer_running
|
||||
@@ -26,21 +23,9 @@ def timer_init():
|
||||
timer_running = True
|
||||
__asm__("mfence", op=[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: [40]char
|
||||
viperlib.snprintf(&_cb, 40, "[PIT] cnt=%d\n", _cnt)
|
||||
serial.puts(&_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")
|
||||
global ticks, seconds, milliseconds, timer_running
|
||||
if not timer_running:
|
||||
pic.eoi(0)
|
||||
apic.eoi()
|
||||
@@ -110,13 +95,7 @@ def timer_get_time(out_seconds: uint32*, out_milliseconds: uint32*):
|
||||
|
||||
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()
|
||||
|
||||
@@ -1957,9 +1957,6 @@ def start(fb_ptr: rawptr, w: int, h: int, pitch: int = 0) -> sched.Thread*:
|
||||
return None
|
||||
|
||||
_back_fb = mm.malloc(uint64(w) * uint64(h) * 4)
|
||||
_dbg_bf: [96]char
|
||||
viperlib.snprintf(&_dbg_bf, 96, "[dbg] back_fb ret=0x%lx w=%d h=%d\n", uint64(_back_fb), w, h)
|
||||
serial.puts(&_dbg_bf)
|
||||
if _back_fb:
|
||||
string.memset(_back_fb, 0, w * h * 4)
|
||||
else:
|
||||
@@ -1967,9 +1964,6 @@ def start(fb_ptr: rawptr, w: int, h: int, pitch: int = 0) -> sched.Thread*:
|
||||
return None
|
||||
|
||||
_row_buf = mm.malloc(uint64(w) * 4)
|
||||
_dbg_rb: [96]char
|
||||
viperlib.snprintf(&_dbg_rb, 96, "[dbg] row_buf ret=0x%lx\n", uint64(_row_buf))
|
||||
serial.puts(&_dbg_rb)
|
||||
if _row_buf:
|
||||
string.memset(_row_buf, 0, w * 4)
|
||||
else:
|
||||
@@ -1978,9 +1972,6 @@ def start(fb_ptr: rawptr, w: int, h: int, pitch: int = 0) -> sched.Thread*:
|
||||
# mm.malloc(w*4) 走裸名回退生成 call @malloc(i32),形参 i64 不匹配(第 4 次
|
||||
# 调用 RAX 返回值被破坏收到 0)。显式 CUInt64T 让参数按 i64 传递。
|
||||
_bg_row_buf = mm.malloc(uint64(w) * 4)
|
||||
_dbg_br: [96]char
|
||||
viperlib.snprintf(&_dbg_br, 96, "[dbg] bg_row_buf ret=0x%lx\n", uint64(_bg_row_buf))
|
||||
serial.puts(&_dbg_br)
|
||||
if _bg_row_buf:
|
||||
desktop_init_col: uint32 = gfx.COLOR_RGB(25, 25, 35)
|
||||
for ri in range(w):
|
||||
|
||||
Reference in new issue
Block a user