New working ATA PIO driver

This commit is contained in:
Aaron Hance 2025-03-10 20:09:50 +00:00
parent 837d69a44b
commit 920aca5bbf
5 changed files with 220 additions and 53 deletions

View File

@ -44,7 +44,7 @@ var
function load(ptr: void) : boolean; function load(ptr: void) : boolean;
procedure init(); procedure init();
function get_status(var device : TIDE_Device) : TIDE_Status; function get_status(var device : TIDE_Device) : TIDE_Status;
function wait_for_device(device : TIDE_Device) : boolean; function wait_for_device(device : TIDE_Device; ioop : boolean) : boolean;
procedure no_interrupt(isPrimary : boolean); procedure no_interrupt(isPrimary : boolean);
procedure select_device(device : TIDE_Device); procedure select_device(device : TIDE_Device);
@ -69,7 +69,7 @@ end;
@param(device The device to wait for) @param(device The device to wait for)
@returns(@True if the device is ready, @False otherwise) @returns(@True if the device is ready, @False otherwise)
} }
function wait_for_device(device : TIDE_Device) : boolean; function wait_for_device(device : TIDE_Device; ioop : boolean) : boolean;
var var
status : TIDE_Status; status : TIDE_Status;
i : uint32; i : uint32;
@ -78,10 +78,10 @@ begin
i := 0; i := 0;
while (i < 10000) do begin while (i < 50000) do begin
status := get_status(device); status := get_status(device);
if (status.BUSY = false) then begin //todo test if (status.BUSY = false) and (status.DRQ or (not ioop)) then begin //todo test
wait_for_device := true; wait_for_device := true;
pop_trace(); pop_trace();
exit; exit;
@ -127,17 +127,31 @@ end;
function get_status(var device : TIDE_Device) : TIDE_Status; function get_status(var device : TIDE_Device) : TIDE_Status;
var var
status : TIDE_Status; status : TIDE_Status;
errorReg : uint8;
begin begin
push_trace('ide.get_status()'); push_trace('ide.get_status()');
select_device(device); // select_device(device);
status := TIDE_Status(inb(device.base + ATA_REG_STATUS)); status := TIDE_Status(inb(device.base + ATA_REG_STATUS));
device.status := status; device.status := status;
pop_trace(); if status.ERROR then begin
get_status := status; errorReg := inb(device.base + ATA_REG_ERROR);
console.writestringln('[IDE] ERROR detected!');
console.writestring('[IDE] ERROR REGISTER: ');
console.writebin8ln(errorReg);
if (errorReg and $04) <> 0 then console.writestringln('[IDE] ERROR: Aborted Command');
if (errorReg and $10) <> 0 then console.writestringln('[IDE] ERROR: ID Not Found');
if (errorReg and $40) <> 0 then console.writestringln('[IDE] ERROR: Uncorrectable Data');
if (errorReg and $80) <> 0 then console.writestringln('[IDE] ERROR: Bad Block');
console.redrawWindows();
end;
end; end;
{ {
@ -175,6 +189,19 @@ begin
select_device(device); select_device(device);
//TODO make sure dvice signture is set at this time, else reset it //TODO make sure dvice signture is set at this time, else reset it
//reset any device signature
{
Write 0x04 to the Control Register (0x3F6 for primary bus, 0x376 for secondary).
Wait ~5 microseconds.
Write 0x00 back to Control Register to complete reset.
// }
outb(ATA_PRIMARY_BASE1, $04);
outb(ATA_SECONDARY_BASE1, $04);
sleep(1);
// outb(ATA_PRIMARY_BASE1, $00);
// outb(ATA_SECONDARY_BASE1, $00);
sleep(1);
//read all bytes of LBA address //read all bytes of LBA address
sec := inb(device.base + ATA_REG_SECCOUNT); sec := inb(device.base + ATA_REG_SECCOUNT);
@ -182,14 +209,26 @@ begin
lba1 := inb(device.base + ATA_REG_LBA1); lba1 := inb(device.base + ATA_REG_LBA1);
lba2 := inb(device.base + ATA_REG_LBA2); lba2 := inb(device.base + ATA_REG_LBA2);
//check if the device is an ATAPI device (01, 01, 14, EB) console.writestring('[IDE] (check_device_type) SEC: ');
if (lba1 = $14) and (lba2 = $EB) then begin console.writehexln(sec);
console.writestring('[IDE] (check_device_type) LBA0: ');
console.writehexln(lba0);
console.writestring('[IDE] (check_device_type) LBA1: ');
console.writehexln(lba1);
console.writestring('[IDE] (check_device_type) LBA2: ');
console.writehexln(lba2);
//check if the device is an ATAPI device
if ((sec = 3) or (lba2 = $EB)) then begin
check_device_type := true; check_device_type := true;
device.isATAPI := true;
end else if sec = 1 then begin
check_device_type := true;
device.isATAPI := false;
end else begin end else begin
check_device_type := false; check_device_type := false;
end; end;
device.isATAPI := check_device_type;
end; end;
{ {
@ -207,11 +246,12 @@ var
begin begin
push_trace('ide.load_device()'); push_trace('ide.load_device()');
success := check_device_type(device);
if (is_device_present(device)) then begin if (is_device_present(device) and success) then begin
console.writestringln('[IDE] (load_device) Device is present'); console.writestringln('[IDE] (load_device) Device is present');
if (check_device_type(device)) then begin if (device.isATAPI) then begin
console.writestringln('[IDE] (load_device) Device is ATAPI'); console.writestringln('[IDE] (load_device) Device is ATAPI');
//todo load device info //todo load device info
end else begin end else begin
@ -253,25 +293,27 @@ begin
end; end;
//wrtie test, 1F2F1F2F repeated //wrtie test, 1F2F1F2F repeated
buffer := puint8(kalloc(512)); buffer := puint8(kalloc(1024));
memset(uint32(buffer), 0, 512); memset(uint32(buffer), $02, 1024);
for i:=0 to 200 do begin
if (i mod 4 = 0) then begin uint8(buffer[0]) := $1F;
buffer[i] := $1F; uint8(buffer[1]) := $2F;
end else begin uint8(buffer[2]) := $3F;
buffer[i] := $2F; uint8(buffer[3]) := $4F;
end; uint8(buffer[4]) := $5F;
end; uint8(buffer[5]) := $6F;
uint8(buffer[6]) := $7F;
uint8(buffer[7]) := $8F;
//write to the first sector //write to the first sector
ata.write_pio28(device, 0, 1, puint16(buffer)); ata.write_pio28(device, 10, 2, puint16(buffer));
//read the first sector //read the first sector
memset(uint32(buffer), 0, 512); memset(uint32(buffer), 0, 512);
ata.read_pio28(device, 0, 1, puint16(buffer)); ata.read_pio28(device, 10, 1, puint16(buffer));
//check if the data is the same //check if the data is the same
for i:=0 to 200 do begin for i:=0 to 10 do begin
console.writehexln(buffer[i]); console.writehexln(buffer[i]);
end; end;
end; end;

View File

@ -30,6 +30,14 @@ implementation
uses uses
ide; ide;
procedure outb(port : uint16; value : uint8);
begin
util.outb(port, value);
psleep(1);
// get_status(primaryDevices[0]);
end;
{ {
ensure the address is a valid 28 bit address ensure the address is a valid 28 bit address
@ -72,7 +80,7 @@ begin
console.writestringln('Error identifying device, maybe'); //todo console.writestringln('Error identifying device, maybe'); //todo
end; end;
ready := wait_for_device(device); ready := wait_for_device(device, false);
if not ready then begin if not ready then begin
console.writestringln('Device not ready in time!'); console.writestringln('Device not ready in time!');
@ -123,18 +131,26 @@ begin
end; end;
select_device(device); select_device(device);
psleep(50);
no_interrupt(device.isPrimary); no_interrupt(device.isPrimary);
psleep(50);
set_lba_mode(device, lba); set_lba_mode(device, lba);
psleep(50);
outb(device.base + ATA_REG_SECCOUNT, count); outb(device.base + ATA_REG_SECCOUNT, count);
psleep(50);
outb(device.base + ATA_REG_LBA0, (lba and $000000FF)); outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
psleep(50);
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8); outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
psleep(50);
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16); outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
psleep(50);
outb(device.base + ATA_REG_COMMAND, ATA_CMD_READ_PIO); outb(device.base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
psleep(50);
ready := wait_for_device(device); ready := wait_for_device(device, false);
if not ready then begin if not ready then begin
console.writestringln('Device not ready in time!'); console.writestringln('Device not ready in time!');
@ -142,15 +158,11 @@ begin
end; end;
for i:=0 to count-1 do begin for i:=0 to count-1 do begin
for ii:=0 to 511 do begin //TODO needs to read sector size ii:=0;
buffer[i] := inw(device.base + ATA_REG_DATA); while ii < 256 do begin
buffer[ii+(i*256)] := inw(device.base + ATA_REG_DATA);
ready := wait_for_device(device); ii := ii + 1;
psleep(50);
if not ready then begin
console.writestringln('Device not ready in time!');
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR READ');
end;
end; end;
end; end;
@ -175,17 +187,16 @@ begin
select_device(device); select_device(device);
no_interrupt(device.isPrimary); //maybe not? no_interrupt(device.isPrimary); //maybe not?
set_lba_mode(device, lba); set_lba_mode(device, lba);
outb(device.base + ATA_REG_SECCOUNT, count); outb(device.base + ATA_REG_SECCOUNT, count);
outb(device.base + ATA_REG_LBA0, (lba and $000000FF)); outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8); outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16); outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
outb(device.base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); outb(device.base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
ready := wait_for_device(device); ready := wait_for_device(device, false);
if not ready then begin if not ready then begin
console.writestringln('Device not ready in time!'); console.writestringln('Device not ready in time!');
@ -193,21 +204,23 @@ begin
end; end;
for i:=0 to count-1 do begin for i:=0 to count-1 do begin
for ii:=0 to 511 do begin //TODO needs to read sector size ii:=0;
outw(device.base + ATA_REG_DATA, uint16(buffer[i])); while ii < 256 do begin
outw(ATA_PRIMARY_BASE + ATA_REG_DATA, buffer[ii+(i*256)]);
ii := ii + 1;
psleep(50);
end;
ready := wait_for_device(device); psleep(50); //todo check
outb(device.base + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
ready := wait_for_device(device, false);
if not ready then begin if not ready then begin
console.writestringln('Device not ready in time!'); console.writestringln('Device not ready in time!');
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR WRITE'); BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR WRITE');
end; end;
end; end;
end;
psleep(50); //todo check
outb(device.base + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
ready := wait_for_device(device);
// if not ready then begin // if not ready then begin
// console.writestringln('Device not ready in time!'); // console.writestringln('Device not ready in time!');

View File

@ -0,0 +1,104 @@
unit atapi;
interface
uses
util,
drivertypes,
console,
terminal,
drivermanagement,
vmemorymanager,
lmemorymanager,
storagemanagement,
strings,
tracer,
drivemanager,
storagetypes,
idetypes;
var
test : uint32;
function identify_device(var device : TIDE_Device) : Boolean;
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
implementation
uses
ide;
{
Identify the device on the IDE bus
@param(device The device to identify)
@returns(@True if the device is identified, @False otherwise)
}
function identify_device(var device : TIDE_Device) : Boolean;
var
i : uint8;
status : TIDE_Status;
buffer : TIdentResponse;
ready : boolean;
begin
select_device(device);
no_interrupt(device.isPrimary);
status := get_status(device);
outb(device.base + ATA_REG_SECCOUNT, 0);
outb(device.base + ATA_REG_LBA0, 0);
outb(device.base + ATA_REG_LBA1, 0);
outb(device.base + ATA_REG_LBA2, 0);
psleep(1);
outb(device.base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
status := get_status(device);
if status.ERROR then begin
console.writestringln('Error identifying device, maybe'); //todo
end;
ready := wait_for_device(device, false);
if not ready then begin
console.writestringln('Device not ready in time!');
//teapot time
// BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR IDENT');
exit(false);
end;
for i:=0 to 255 do begin
buffer[i] := inw(device.base + ATA_REG_DATA);
end;
device.info := @buffer;
identify_device := true;
end;
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
var
i : uint16;
ii : uint16;
status : TIDE_Status;
ready : boolean;
begin
end;
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
var
i : uint16;
ii : uint16;
status : TIDE_Status;
ready : boolean;
begin
end;
end.

View File

@ -84,7 +84,7 @@ const
ATA_REG_LBA3 = $09; ATA_REG_LBA3 = $09;
ATA_REG_LBA4 = $0A; ATA_REG_LBA4 = $0A;
ATA_REG_LBA5 = $0B; ATA_REG_LBA5 = $0B;
ATA_REG_CONTROL = $0C; ATA_REG_CONTROL = $0C; //1FC on some systems, 3F6 on all
ATA_REG_ALTSTATUS = $0C; ATA_REG_ALTSTATUS = $0C;
ATA_REG_DEVADDRESS = $0D; ATA_REG_DEVADDRESS = $0D;
@ -134,6 +134,13 @@ type
info : PIdentResponse; info : PIdentResponse;
end; end;
TIDE_PACKET = record
command : uint8;
lba : uint32;
count : uint8;
buffer : puint16;
end;
implementation implementation

View File

@ -335,6 +335,7 @@ begin
//serial.sendString('[outb]'); //serial.sendString('[outb]');
//serial.sendHex(port); //serial.sendHex(port);
//serial.sendHex(val); //serial.sendHex(val);
psleep(1);
asm asm
PUSH EAX PUSH EAX
PUSH EDX PUSH EDX