forked from AbleOS/ableos
111 lines
2.7 KiB
Plaintext
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)
|
|
} |