From 0ee5ec5dcc595701f03f6163900ebea48aa25e0e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 15 Oct 2026 17:14:12 +0800 Subject: [PATCH] =?UTF-8?q?fix(vkernel/ide):=20PIO=20=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E5=9D=97=E5=AF=84=E5=AD=98=E5=99=A8=E8=BF=9E=E5=86=99=E8=A1=A5?= =?UTF-8?q?=20io=5Fwait=20+=20=E8=AF=BB=E5=AE=8C=E6=A0=B8=20ERR=20-=20?= =?UTF-8?q?=E4=BF=AE=E8=AF=BB=E7=9B=98=E8=AF=BB=E9=94=99=E6=89=87=E5=8C=BA?= =?UTF-8?q?(=E6=A0=B9=E7=9B=AE=E5=BD=95=E6=89=87=E5=8C=BA=E8=AF=BB?= =?UTF-8?q?=E5=9B=9E=20ELF=20=E5=A4=B4=E8=87=B4=20app=20spawn=20=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VKernel/Kernel/drivers/storage/ide/ide.vp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/VKernel/Kernel/drivers/storage/ide/ide.vp b/VKernel/Kernel/drivers/storage/ide/ide.vp index 613e0cc..dea9a1a 100644 --- a/VKernel/Kernel/drivers/storage/ide/ide.vp +++ b/VKernel/Kernel/drivers/storage/ide/ide.vp @@ -70,17 +70,30 @@ def readSector(lba: uint32, buffer: rawptr) -> int: if err != IDError.IDE_ERR_NONE: return err asm.outb(0x3F6, 0x00) + asm.io_wait() + # 命令块寄存器**连写之间必须插 I/O 延时**:QEMU 的 IDE 是逐条采样寄存器的,缺延时 + # 会出现"只写入部分寄存器"⇒ LBA 保留上一次的值 ⇒ 读到**另一个扇区**的数据(现场: + # 读根目录扇区 LBA 8192 却读回 ELF 文件头,导致目录项全是垃圾 → spawn 失败)。 asm.outb(0x1F2, 1) + asm.io_wait() asm.outb(0x1F3, uint8(lba & 0xFF)) + asm.io_wait() asm.outb(0x1F4, uint8((lba >> 8) & 0xFF)) + asm.io_wait() asm.outb(0x1F5, uint8((lba >> 16) & 0xFF)) + asm.io_wait() asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F))) + asm.io_wait() asm.outb(0x1F7, 0x20) + asm.io_wait() err = waitDataReady(IDE_baseport_PRIMARY) if err != IDError.IDE_ERR_NONE: st: uint8 = asm.inb(0x1F7) return err st2: uint8 = asm.inb(0x1F7) + # 读完再核一次 ERR:置位说明这次数据无效,不能当成功返回(否则上层会拿到错内容) + if st2 & IDE_STATUS_ERR: + return IDError.IDE_ERR_DEVICE_ERROR buf: uint16* = uint16*(buffer) for j in range(256): *buf = asm.inw(0x1F0) @@ -96,12 +109,21 @@ def writeSector(lba: uint32, buffer: const rawptr) -> int: err: IDError = waitReady(IDE_baseport_PRIMARY) if err != IDError.IDE_ERR_NONE: return err asm.outb(0x3F6, 0x00) + asm.io_wait() + # 与 readSector 同理:命令块寄存器连写之间必须插 I/O 延时,否则 QEMU 只采样到部分寄存器 + # ⇒ LBA 残留旧值 ⇒ 把数据写到**错误的扇区**(写盘路径同样致命)。 asm.outb(0x1F2, 1) + asm.io_wait() asm.outb(0x1F3, uint8(lba & 0xFF)) + asm.io_wait() asm.outb(0x1F4, uint8((lba >> 8) & 0xFF)) + asm.io_wait() asm.outb(0x1F5, uint8((lba >> 16) & 0xFF)) + asm.io_wait() asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F))) + asm.io_wait() asm.outb(0x1F7, 0x30) + asm.io_wait() err = waitDataReady(IDE_baseport_PRIMARY) if err != IDError.IDE_ERR_NONE: return err buf: uint16* = uint16*(buffer)