1
0
Fork 0
forked from AbleOS/ableos
ableos/sysdata/programs/diskio_driver/src/main.hb
2024-12-26 02:00:51 +00:00

111 lines
2.7 KiB
Plaintext

.{memory: .{inb, outb, ins, alloc}, log} := @use("stn")
$ATA_PRIMARY_DATA := 0x1F0
$ATA_PRIMARY_ERR := 0x1F1
$ATA_PRIMARY_SECCOUNT := 0x1F2
$ATA_PRIMARY_LBA_LO := 0x1F3
$ATA_PRIMARY_LBA_MID := 0x1F4
$ATA_PRIMARY_LBA_HI := 0x1F5
$ATA_PRIMARY_DRIVE_HEAD := 0x1F6
$ATA_PRIMARY_COMM_REGSTAT := 0x1F7
$ATA_PRIMARY_ALTSTAT_DCR := 0x3F6
$STAT_ERR := 1 << 0
$STAT_DRQ := 1 << 3
$STAT_SRV := 1 << 4
$STAT_DF := 1 << 5
$STAT_RDY := 1 << 6
$STAT_BSY := 1 << 7
Drive := enum {Master, Slave}
select_drive := fn(drive: Drive): void {
match drive {
.Master => outb(ATA_PRIMARY_DRIVE_HEAD, 0xA0),
.Slave => outb(ATA_PRIMARY_DRIVE_HEAD, 0xB0),
}
}
identify := fn(drive: Drive): u8 {
if inb(ATA_PRIMARY_COMM_REGSTAT) == 0xFF {
log.error("(ata: drive not present) status=0xFF")
return 0
}
select_drive(drive)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_SECCOUNT, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_LBA_LO, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_LBA_MID, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_LBA_HI, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_COMM_REGSTAT, 0xEC)
outb(ATA_PRIMARY_COMM_REGSTAT, 0xE7)
status := inb(ATA_PRIMARY_COMM_REGSTAT)
loop if (status & STAT_BSY) == 0 break else {
// if DEBUG_PRINT log.printf("(ata: waiting for status) status={}", .(status), .{radix: 16, log: .Warn})
status = inb(ATA_PRIMARY_COMM_REGSTAT)
}
if status == 0 {
log.error("(ata: drive not present) status=0")
return 0
}
loop if (status & STAT_BSY) == 0 break else {
if DEBUG_PRINT log.printf("(ata: waiting for busy to end) status={}", .(status), .{radix: 16, log: .Warn})
status = inb(ATA_PRIMARY_COMM_REGSTAT)
}
mid := inb(ATA_PRIMARY_LBA_MID)
hi := inb(ATA_PRIMARY_LBA_HI)
if (mid | hi) != 0 {
log.error("the drive is not ata...?")
return 0
}
loop if (status & (STAT_ERR | STAT_DRQ)) != 0 break else {
if DEBUG_PRINT log.printf("(ata: waiting for ERR or DRQ) status={}", .(status), .{radix: 16, log: .Warn})
status = inb(ATA_PRIMARY_COMM_REGSTAT)
}
if (status & STAT_ERR) != 0 {
if DEBUG_PRINT log.printf("(ata: drive error) status={}", .(status), .{radix: 16, log: .Error})
return 0
}
if DEBUG_PRINT log.printf("status={}", .(status), .{radix: 16})
buffer := alloc(u16, 255)[0..255]
read(buffer)
if DEBUG_PRINT {
if (buffer[83] & 1 << 10) != 0 {
log.info("LBA48 mode supported")
log.printf("{} 48 bit addressable sectors", *@as(^uint, @bitcast(buffer[100..].ptr)), .{})
}
log.print(buffer, .{})
}
return 0
}
read := fn(buffer: []u16): void {
i := 0
loop if i == buffer.len break else {
buffer[i] = ins(ATA_PRIMARY_DATA)
i += 1
}
}
// inflates asm a lot
$DEBUG_PRINT := true
main := fn(): void {
identify(.Master)
}