Files
ViperOS/VKernel/Kernel/drivers/storage/ide/ide.vp
T
TermiNexus a518f75b24 chore(vkernel): 重置基线 — 纳入 TPV codegen 修复配合的内核侧调整与既有工作区内容
- devfs.vp: string.split 传 PATH_BUFFER_SIZE(配合 split 新增容量参数)

- fat32_types.vp: lfn_extract 越界钳制(base+i > MAX_LFN 返回 -1)

- sheet.vp: gfx.Renderer 实参修正为 (fb, zb, w, h)(原单参导致 w/h=0 渲染空操作)

- 同批包含 VKernel 其余既有移植改动与 vpsdk/Apps/Libs 工作区内容
2026-09-11 14:27:01 +08:00

165 lines
6.3 KiB
Plaintext

import asm
import t, c
import drivers.usb.pci as pci
import drivers.serial.uart.serial as serial
import viperlib
class IDError(t.CEnum):
IDE_ERR_NONE: t.State = 0
IDE_ERR_TIMEOUT: t.State
IDE_ERR_DEVICE_ERROR: t.State
IDE_ERR_DEVICE_BUSY: t.State
IDE_ERR_INVALID_PARAM: t.State
IDE_ERR_BUFFER_NULL: t.State
IDE_ERR_SECTOR_COUNT: t.State
IDE_ERR_DEVICE_NOT_READY: t.State
IDE_ERR_DEVICE_FAILURE: t.State
IDE_ERR_COMMAND_FAILED: t.State
IDE_ERR_INVALID_LBA: t.State
IDE_baseport_PRIMARY: t.CDefine = 0x1F0
IDE_baseport_SECONDARY: t.CDefine = 0x170
IDE_STATUS_BSY: t.CDefine = 0x80
IDE_STATUS_DRDY: t.CDefine = 0x40
IDE_STATUS_DF: t.CDefine = 0x20
IDE_STATUS_DRQ: t.CDefine = 0x08
IDE_STATUS_ERR: t.CDefine = 0x01
SECTOR_SIZE: t.CDefine = 512
_ide_initialized: int = 0
def waitReady(baseport: uint16) -> t.CStatic | IDError:
timeout: int = 100000
while timeout > 0:
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
timeout -= 1
return IDError.IDE_ERR_TIMEOUT
def waitDataReady(baseport: uint16) -> t.CStatic | IDError:
timeout: int = 100000
while timeout > 0:
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
timeout -= 1
return IDError.IDE_ERR_TIMEOUT
def init() -> int:
global _ide_initialized
if _ide_initialized: return IDError.IDE_ERR_NONE
dbg: t.CArray[t.CChar, 120]
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))
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", int(bus), int(dev_n), int(func), uint32(pci.pci_read16(bus, dev_n, func, 0x04)))
serial.puts(dbg)
asm.outb(0x3F6, 0x04)
i: int
for i in range(10000):
asm.nop()
asm.outb(0x3F6, 0x00)
for i in range(10000):
asm.nop()
status: uint8 = asm.inb(0x1F7)
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", uint32(status))
serial.puts(dbg)
_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
dbg: t.CArray[t.CChar, 120]
err: IDError = waitReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE:
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", int(err))
serial.puts(dbg)
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)
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", int(err), uint32(st))
serial.puts(dbg)
return err
st2: uint8 = asm.inb(0x1F7)
buf: uint16 | t.CPtr = uint16(buffer, t.CPtr)
for j in range(256):
c.Set(c.Deref(buf), asm.inw(0x1F0))
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
buf = buf + 2
first_byte: uint8 = c.Deref(uint8(buffer, t.CPtr))
# 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: t.CConst | 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, 0x30)
err = waitDataReady(IDE_baseport_PRIMARY)
if err != IDError.IDE_ERR_NONE: return err
buf: uint16 | t.CPtr = uint16(buffer, t.CPtr)
for j in range(256):
val: uint16 = c.Deref(buf)
asm.outw(0x1F0, val)
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
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