Files
ViperOS/VKernel/Kernel/drivers/storage/ide/ide.vp
T
TermiNexus 0919a058a8 fix(vkernel): 预留内核 .bss 与栈区,修堆 arena 覆盖未预留内核内存
根因:bootloader 只按 kernel 文件大小 AllocatePages(.bss 不占文件),于是 .bss
尾部(ticks/_perf_* 等全局量)与主线程栈区(0x60000~0x80000)在 memmap 里仍是
EfiConventionalMemory,被内核 mm 的堆 arena 当作空闲内存占用 → 内核全局量被写坏、
堆元数据被反向破坏,最终桌面线程栈上的 va_list 被改坏,vsnprintf 读 %d 变参时
#GP(rip=0x130d45, err=0x0)。

- linker.ld: .bss 末尾加 LONG(0) 强制 PROGBITS,使 kernel.bin 的 FileSize 涵盖
  .bss,bootloader 的 PagesNeeded 得以预留整块内核镜像(含 .bss)
- mm.init: 新增 KernelAddr/KernelEnd,挑 arena 时把与内核镜像 [kernel_PhysAddr,
  __bss_end) 重叠的 region 起点抬到镜像末端(不整段丢弃)
- main.vp: 取 __bss_end 并传入 mm.init
- boot.c: ExitBootServices 前用 AllocatePages(AllocateAddress, EfiLoaderData)
  占位内核栈区 0x60000~0x80000,使其在 memmap 中标记已用

另含在途整理:多处补显式收窄转换(uint8()/uint16() 等)、kbd_svc 构造改为
kbd_svc.__init__() 等。
2026-10-14 12:54:43 +08:00

141 lines
5.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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: 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, 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 是 i16*(uint16*):+1 表示前进 1 个元素 = 2 字节,256 次恰好填满 512B
buf = buf + 1
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)
# buf 是 i16*(uint16*):+1 表示前进 1 个元素 = 2 字节,256 次恰好读完 512B
# (IR 取证:`buf + 2` 生成 getelementptr ..., i16,按元素缩放 → +4 字节,越界)
buf = buf + 1
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