fix(asm): io_wait 改为连续 4 次读备选状态寄存器 0x3F6,提供真实 400ns I/O 延时
原先写的是诊断端口 0x80:该端口背后没有设备,在 QEMU 上几乎不消耗时间,等于没有延时。于是 IDE 命令块寄存器 0x1F2..0x1F7 连写会丢写,LBA 寄存器残留上一次的值,导致读到别的扇区(现场:读根目录扇区 8192 却读回 ELF 文件头,目录项全是垃圾,五个 app 全部 spawn 失败;另有 waitDataReady 超时表现为 diskio.read 返回 FR_DISK_ERR)。0ee5ec5 曾为同一现场补过 io_wait 调用,但当时见效靠的是调用开销与代码节奏的余量;内核变大后被吃掉,故障必现。改为 4 次 in al, 0x3F6(真实设备端口,每次均为真实 I/O 往返),并补 CLOBBER_RAX(in al 会改写 RAX,原实现未声明该 clobber)。
This commit is contained in:
1 parent
6a22633b6b
commit
172af1e172
1 file changed
+12
-2
@@ -52,8 +52,18 @@ def outl(port: uint16, value: uint32):
|
||||
op = [ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def io_wait():
|
||||
__asm__(f"mov dx, 0x80; out dx, al",
|
||||
op = [ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_DX])
|
||||
# ATA 规范的 I/O 延时:**连续 4 次读备选状态寄存器 0x3F6**。它是真实设备端口,每次 in
|
||||
# 都是一次真实 I/O 往返,稳定给出 ≥400ns(规范要求命令块寄存器两次写之间至少 400ns)。
|
||||
# 原先写的是诊断端口 0x80 —— 该端口背后没有设备,在 QEMU 上几乎不消耗时间,等于**没有
|
||||
# 延时**:IDE 命令块寄存器(0x1F2..0x1F7)连写会丢写 ⇒ LBA 寄存器残留上一次的值 ⇒ 读到
|
||||
# **别的扇区**的数据。现场(参见 0ee5ec5 与 serial.log):读根目录扇区 8192 却读回 ELF
|
||||
# 文件头 ⇒ 目录项全是垃圾 ⇒ app spawn 失败;或 waitDataReady 超时 ⇒ diskio.read 报错。
|
||||
__asm__(f"""mov dx, 0x3F6
|
||||
in al, dx
|
||||
in al, dx
|
||||
in al, dx
|
||||
in al, dx""",
|
||||
op = [ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_DX, ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
|
||||
inline def pushall():
|
||||
|
||||
Reference in new issue
Block a user