原先写的是诊断端口 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)。
156 lines
4.6 KiB
Plaintext
156 lines
4.6 KiB
Plaintext
def cli(): __asm__("cli", [ASM_DESCR.CLOBBER_MEMORY])
|
||
def sti(): __asm__("sti", [ASM_DESCR.CLOBBER_MEMORY])
|
||
def hlt(): __asm__("hlt", [ASM_DESCR.CLOBBER_MEMORY])
|
||
def nop(): __asm__("nop", [ASM_DESCR.CLOBBER_MEMORY])
|
||
def pause(): __asm__("pause", op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
|
||
def inb(port: uint16) -> uint8:
|
||
value: uint32
|
||
__asm__(f"""mov edx, {asminp(uint32(port), ASM_DESCR.REG_ANY)}
|
||
in al, dx
|
||
movzx $0, al""",
|
||
out = [asmout(value, ASM_DESCR.OUTPUT_REG)],
|
||
op =[ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||
return uint8(value)
|
||
|
||
def outb(port: uint16, value: uint8):
|
||
__asm__(f"""mov edx, {asminp(uint32(port), ASM_DESCR.REG_ANY)}
|
||
mov eax, {asminp(uint32(value), ASM_DESCR.REG_ANY)}
|
||
out dx, al""",
|
||
op = [ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||
|
||
|
||
def inw(port: uint16) -> uint16:
|
||
value: uint32
|
||
__asm__(f"""mov edx, {asminp(uint32(port), ASM_DESCR.REG_ANY)}
|
||
in ax, dx
|
||
movzx eax, ax
|
||
mov {asmout(value, ASM_DESCR.OUTPUT_REG)}, eax""",
|
||
out = [asmout(value, ASM_DESCR.OUTPUT_REG)],
|
||
op =[ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||
return uint16(value)
|
||
|
||
def outw(port: uint16, value: uint16):
|
||
__asm__(f"""mov edx, {asminp(uint32(port), ASM_DESCR.REG_ANY)}
|
||
mov eax, {asminp(uint32(value), ASM_DESCR.REG_ANY)}
|
||
out dx, ax""",
|
||
op = [ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||
|
||
def inl(port: uint16) -> uint32:
|
||
value: uint32
|
||
__asm__(f"""mov edx, {asminp(uint32(port), ASM_DESCR.REG_ANY)}
|
||
in eax, dx
|
||
mov {asmout(value, ASM_DESCR.OUTPUT_REG)}, eax""",
|
||
out = [asmout(value, ASM_DESCR.OUTPUT_REG)],
|
||
op =[ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||
return value
|
||
|
||
def outl(port: uint16, value: uint32):
|
||
__asm__(f"""mov edx, {asminp(uint32(port), ASM_DESCR.REG_ANY)}
|
||
mov eax, {asminp(value, ASM_DESCR.REG_ANY)}
|
||
out dx, eax""",
|
||
op = [ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_RAX])
|
||
|
||
def io_wait():
|
||
# 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():
|
||
__asm__(f"""
|
||
push rax
|
||
push rbx
|
||
push rcx
|
||
push rdx
|
||
push rsi
|
||
push rdi
|
||
push rbp
|
||
push r8
|
||
push r9
|
||
push r10
|
||
push r11
|
||
push r12
|
||
push r13
|
||
push r14
|
||
push r15""",
|
||
[ASM_DESCR.CLOBBER_MEMORY]
|
||
)
|
||
|
||
inline def popall():
|
||
__asm__(f"""
|
||
pop r15
|
||
pop r14
|
||
pop r13
|
||
pop r12
|
||
pop r11
|
||
pop r10
|
||
pop r9
|
||
pop r8
|
||
pop rbp
|
||
pop rdi
|
||
pop rsi
|
||
pop rdx
|
||
pop rcx
|
||
pop rbx
|
||
pop rax""",
|
||
[ASM_DESCR.CLOBBER_MEMORY]
|
||
)
|
||
|
||
|
||
def cpu_switch_context(old_stack: uint64*, new_stack: uint64):
|
||
__asm__(f"""
|
||
push rax
|
||
push rbx
|
||
push rcx
|
||
push rdx
|
||
push rsi
|
||
push rdi
|
||
push rbp
|
||
push r8
|
||
push r9
|
||
push r10
|
||
push r11
|
||
push r12
|
||
push r13
|
||
push r14
|
||
push r15
|
||
mov [{asminp(old_stack, ASM_DESCR.REG_ANY)}], rsp
|
||
mov rsp, {asminp(new_stack, ASM_DESCR.REG_ANY)}
|
||
pop r15
|
||
pop r14
|
||
pop r13
|
||
pop r12
|
||
pop r11
|
||
pop r10
|
||
pop r9
|
||
pop r8
|
||
pop rbp
|
||
pop rdi
|
||
pop rsi
|
||
pop rdx
|
||
pop rcx
|
||
pop rbx
|
||
pop rax""",
|
||
op=[ASM_DESCR.CLOBBER_MEMORY])
|
||
|
||
def BSSClean():
|
||
__asm__(
|
||
"lea rdi, [rip + __bss_start]\n"
|
||
"lea rcx, [rip + __bss_end]\n"
|
||
"sub rcx, rdi\n"
|
||
"xor eax, eax\n"
|
||
"cld\n"
|
||
"rep stosb",
|
||
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RDI, ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RAX]
|
||
)
|