schedule_int_transfer 第 6 形参原为 toggle_ptr: uint8*,却直接转发给 _td_set_token 的值形参 toggle: uint8,命中指针隐式转整数禁令(uhci.vp:160 CastError)。改为 toggle: uint8 值传递,四个调用点去掉取地址,buf 仍以 & 传。同时纳入工作区既有的指针语法迁移:t.CPtr 改 X*、c.Addr 改 &、c.Set(c.Deref(...)) 改 *p = v。
146 lines
6.0 KiB
Plaintext
146 lines
6.0 KiB
Plaintext
import asm
|
|
import drivers.usb.pci as pci
|
|
|
|
|
|
enum IDError:
|
|
IDE_ERR_NONE, IDE_ERR_TIMEOUT, IDE_ERR_DEVICE_ERROR
|
|
IDE_ERR_DEVICE_BUSY, IDE_ERR_INVALID_PARAM, IDE_ERR_BUFFER_NULL
|
|
IDE_ERR_SECTOR_COUNT, IDE_ERR_DEVICE_NOT_READY, IDE_ERR_DEVICE_FAILURE
|
|
IDE_ERR_COMMAND_FAILED, IDE_ERR_INVALID_LBA
|
|
|
|
define IDE_baseport_PRIMARY = 0x1F0
|
|
define IDE_baseport_SECONDARY = 0x170
|
|
|
|
define IDE_STATUS_BSY = 0x80
|
|
define IDE_STATUS_DRDY = 0x40
|
|
define IDE_STATUS_DF = 0x20
|
|
define IDE_STATUS_DRQ = 0x08
|
|
define IDE_STATUS_ERR = 0x01
|
|
|
|
define SECTOR_SIZE = 512
|
|
|
|
_ide_initialized: int = 0
|
|
|
|
def waitReady(baseport: uint16) -> static IDError:
|
|
timeout: int = 100000
|
|
for _ in range(timeout, 0, -1):
|
|
status: uint8 = asm.inb(baseport + 7)
|
|
if status & IDE_STATUS_DF:
|
|
return IDError.IDE_ERR_DEVICE_FAILURE
|
|
if not status & IDE_STATUS_BSY and status & IDE_STATUS_DRDY:
|
|
return IDError.IDE_ERR_NONE
|
|
return IDError.IDE_ERR_TIMEOUT
|
|
|
|
def waitDataReady(baseport: uint16) -> static IDError:
|
|
timeout: int = 100000
|
|
for _ in range(timeout, 0, -1):
|
|
status: uint8 = asm.inb(baseport + 7)
|
|
if status & IDE_STATUS_ERR: return IDError.IDE_ERR_DEVICE_ERROR
|
|
if status & IDE_STATUS_DF: return IDError.IDE_ERR_DEVICE_FAILURE
|
|
if not status & IDE_STATUS_BSY and (status & IDE_STATUS_DRQ or status & IDE_STATUS_DRDY):
|
|
return IDError.IDE_ERR_NONE
|
|
return IDError.IDE_ERR_TIMEOUT
|
|
|
|
def init() -> int:
|
|
global _ide_initialized
|
|
if _ide_initialized: return IDError.IDE_ERR_NONE
|
|
bus: uint8
|
|
dev_n: uint8
|
|
func: uint8
|
|
for bus in range(2):
|
|
for dev_n in range(32):
|
|
for func in range(8):
|
|
vendor: uint16 = pci.pci_read16(bus, dev_n, func, 0x00)
|
|
if vendor == 0xFFFF: continue
|
|
cls: uint32 = pci.pci_get_class(bus, dev_n, func)
|
|
if cls == 0x010180 or cls == 0x0101:
|
|
cmd: uint16 = pci.pci_read16(bus, dev_n, func, 0x04)
|
|
pci.pci_write32(bus, dev_n, func, 0x04, uint32(cmd | 0x0007))
|
|
asm.outb(0x3F6, 0x04)
|
|
for _ in range(10000): asm.nop()
|
|
asm.outb(0x3F6, 0x00)
|
|
for _ in range(10000): asm.nop()
|
|
status: uint8 = asm.inb(0x1F7)
|
|
_ide_initialized = 1
|
|
return IDError.IDE_ERR_NONE
|
|
|
|
def readSector(lba: uint32, buffer: t.CPtr) -> int:
|
|
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
|
|
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
|
if err != IDError.IDE_ERR_NONE:
|
|
return err
|
|
asm.outb(0x3F6, 0x00)
|
|
asm.outb(0x1F2, 1)
|
|
asm.outb(0x1F3, uint8(lba & 0xFF))
|
|
asm.outb(0x1F4, uint8((lba >> 8) & 0xFF))
|
|
asm.outb(0x1F5, uint8((lba >> 16) & 0xFF))
|
|
asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F)))
|
|
asm.outb(0x1F7, 0x20)
|
|
err = waitDataReady(IDE_baseport_PRIMARY)
|
|
if err != IDError.IDE_ERR_NONE:
|
|
st: uint8 = asm.inb(0x1F7)
|
|
return err
|
|
st2: uint8 = asm.inb(0x1F7)
|
|
buf: uint16* = uint16*(buffer)
|
|
for j in range(256):
|
|
*buf = asm.inw(0x1F0)
|
|
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
|
|
buf = buf + 2
|
|
first_byte: uint8 = *(uint8*(buffer))
|
|
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, uint32(st2), uint32(first_byte))
|
|
# serial.puts(dbg)
|
|
return IDError.IDE_ERR_NONE
|
|
|
|
def writeSector(lba: uint32, buffer: const rawptr) -> int:
|
|
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
|
|
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
|
if err != IDError.IDE_ERR_NONE: return err
|
|
asm.outb(0x3F6, 0x00)
|
|
asm.outb(0x1F2, 1)
|
|
asm.outb(0x1F3, uint8(lba & 0xFF))
|
|
asm.outb(0x1F4, uint8((lba >> 8) & 0xFF))
|
|
asm.outb(0x1F5, uint8((lba >> 16) & 0xFF))
|
|
asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F)))
|
|
asm.outb(0x1F7, 0x30)
|
|
err = waitDataReady(IDE_baseport_PRIMARY)
|
|
if err != IDError.IDE_ERR_NONE: return err
|
|
buf: uint16* = uint16*(buffer)
|
|
for j in range(256):
|
|
val: uint16 = *buf
|
|
asm.outw(0x1F0, val)
|
|
# [待复核·指针缩放] 下面这行注释声称 "uint16|t.CPtr → i8*(字节指针),每次前进 2 字节",
|
|
# 但 `X | t.CPtr` 的联合类型当前解析为 Ptr(X)(见联合类型解析与 includes/memhub.vp 中
|
|
# `t.CUInt64T(x, t.CPtr)` 的既有用法)——若 `buf` 实际是 u16*,则 `buf + 2` 前进的是
|
|
# 4 字节(GEP 按元素缩放),本循环 256 次会读满 1KB 而不是 512B,且越界读到缓冲区之后。
|
|
# 结论待定(需一次 IR 取证:看 `buf + 2` 生成的是 getelementptr i16 还是 i8)。
|
|
# 与按整数加法推进地址、不依赖指针元素类型的写法(同仓另有此类)对齐后再改;
|
|
# `| t.CPtr` → `rawptr[T]` 迁移时一并复核,见 Debugger/rawptr-migration-and-fastfail.md。
|
|
buf = buf + 2
|
|
asm.outb(0x1F7, 0xE7)
|
|
waitReady(IDE_baseport_PRIMARY)
|
|
return IDError.IDE_ERR_NONE
|
|
|
|
def getDiskSize() -> uint64:
|
|
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
|
if err != IDError.IDE_ERR_NONE: return 0
|
|
asm.outb(0x1F6, 0xE0)
|
|
asm.outb(0x1F7, 0xEC)
|
|
err = waitDataReady(IDE_baseport_PRIMARY)
|
|
if err != IDError.IDE_ERR_NONE: return 0
|
|
status: uint8 = asm.inb(0x1F7)
|
|
if not status & IDE_STATUS_DRDY: return 0
|
|
if status & IDE_STATUS_ERR: return 0
|
|
identify_data: t.CArray[uint16, 256]
|
|
for i in range(256):
|
|
identify_data[i] = asm.inw(0x1F0)
|
|
totalSectors: uint64 = identify_data[60] | uint64(identify_data[61]) << 16
|
|
if identify_data[83] & (1 << 10):
|
|
lba48_sectors: uint64 = (
|
|
uint64(identify_data[100]) |
|
|
uint64(identify_data[101]) << 16 |
|
|
uint64(identify_data[102]) << 32 |
|
|
uint64(identify_data[103]) << 48)
|
|
if lba48_sectors > totalSectors:
|
|
totalSectors = lba48_sectors
|
|
return totalSectors
|