diff --git a/src/driver/storage/AHCI.pas b/src/driver/storage/AHCI.pas new file mode 100644 index 00000000..0e81f20c --- /dev/null +++ b/src/driver/storage/AHCI.pas @@ -0,0 +1,286 @@ +{ ************************************************ + * Asuro + * Unit: Drivers/AHCI + * Description: AHCI SATA Driver + ************************************************ + * Author: Aaron Hance + * Contributors: + ************************************************ } + +unit AHCI; + +interface + +uses + util, + PCI, + drivertypes, + drivermanagement, + lmemorymanager, + console, + vmemorymanager; + +type + +//Struct hell + + TFIS_Type = ( + REG_H2D = $27, + REG_D2H = $34, + DMA_ACT = $39, + DMA_SETUP = $41, + DATA = $46, + BIST = $58, + PIO_SETUP = $5F, + DEV_BITS = $A0 + ); + + PFIS_REG_H2D = ^TFIS_REG_H2D; + TFIS_REG_H2D = bitpacked record + fis_type : uint8; + port_mult : UBit4; + rsv0 : UBit3; + coc : boolean; + command : uint8; + feature_low : uint8; + lba0 : uint8; + lba1 : uint8; + lba2 : uint8; + device : uint8; + lba3 : uint8; + lba4 : uint8; + lba5 : uint8; + feature_high : uint8; + count_low : uint8; + count_high : uint8; + icc : uint8; + control : uint8; + rsvl : uint32; + end; + + TFIS_REG_D2H = bitpacked record + fis_type : uint8; + port_mult : UBit4; + rsv0 : UBit2; + i : boolean; + rsvl : boolean; + status : uint8; + error : uint8; + lba0 : uint8; + lba1 : uint8; + lba2 : uint8; + device : uint8; + lba3 : uint8; + lba4 : uint8; + lba5 : uint8; + rsv2 : uint8; + count_low : uint8; + count_high : uint8; + rsv3 : uint16; + rsv4 : uint32; + end; + + TFIS_Data = bitpacked record + fis_type : uint8; + port_mult : UBit4; + rsv0 : UBit4; + rsv1 : uint16; + data : ^uint32; + end; + + TFIS_PIO_Setup = bitpacked record + fis_type : uint8; + pmport : UBit4; + rsv0 : boolean; + d : boolean; + i : boolean; + rsv1 : boolean; + status : uint8; + error : uint8; + lba0 : uint8; + lba1 : uint8; + lba2 : uint8; + device : uint8; + lba3 : uint8; + lba4 : uint8; + lba5 : uint8; + rsv2 : uint8; + countl : uint8; + counth : uint8; + rsv3 : uint8; + e_status : uint8; + tc : uint16; + rsv4 : uint16; + end; + + // TFIS_DMA_Setup = bitpacked record + // end; + + // THBA_Memory = bitpacked record + // end; + + // THBA_Port = bitpacked record + // end; + + // THBA_FIS = bitpacked record + // end; + + PHBA_PORT = ^THBA_PORT; + THBA_PORT = bitpacked record + clb : uint32; + clbu : uint32; + fb : uint32; + fbu : uint32; + istat : uint32; + ie : uint32; + cmd : uint32; + rsv0 : uint32; + tfd : uint32; + sig : uint32; + ssts : uint32; + sctl : uint32; + serr : uint32; + sact : uint32; + ci : uint32; + sntf : uint32; + fbs : uint32; + rsv1 : array[0..11] of uint32; + vendor : array[0..4] of uint32; + end; + + THBA_MEM = bitpacked record + cap : uint32; //0 + global_host_control : uint32; //4 + interrupt_status : uint32; //8 + port_implemented : uint32; //c + version : uint32; //10 + ccc_control : uint32; //14 + ccc_ports : uint32; //18 + em_location : uint32; //1c + em_Control : uint32; //20 + hcap2 : uint32; //24 + bohc : uint32; //28 + rsv0 : array[0..210] of boolean; + ports : array[0..31] of THBA_Port; + end; + + PHBA = ^THBA_MEM; + + PCMDHeader = ^ TCommand_Header; + TCommand_Header = bitpacked record + cfl : ubit5; + a : boolean; + w : boolean; + p : boolean; + r : boolean; + b : boolean; + c : boolean; + rsv0 : boolean; + pmp : ubit4; + PRDTL : uint16; + PRDTBC : uint32; + CTBA : uint32; + CTBAU : uint32; + rsv1 : array[0..3] of uint32; + end; + + TPRD_Entry = bitpacked record + data_base_address : uint32; + data_bade_address_U : uint32; + rsv0 : uint32; + data_byte_count : ubit22; + rsv1 : ubit9; + interrupt_oc : boolean; + end; + + PCommand_Table = ^TCommand_Table; + TCommand_Table = bitpacked record + cfis : array[0..64] of uint8; + acmd : array[0..16] of uint8; + rsv : array[0..48] of uint8; + prdt : array[0..7] of TPRD_Entry; + end; + + TSataDevice = record + controller : uint8; + port : uint8; + end; + +var + //constants + //SATA_SIG_ATA := $101; + //SATA_SIG_ATAPI := $EB140101; + //STA_SIG_SEMB := $C33C0101; + //STAT_SIG_PM := $96690101; + AHCI_BASE: uint32 = $400000; //irrelivent + + //other + ahciControllers : array[0.16] of PuInt32; + ahciControllerCount : uint8 = 0; + hba : array[0..16] of PHBA; + + sataDevices : array[0..127] of TSataDevice; + sataDeviceCount : uint8; + + + +procedure init(); +procedure check_ports(controller : uint8); +procedure enable_cmd(port : uint8); +procedure disable_cmd(port : uint8); +procedure port_rebase(port : uint8); +function load(ptr:void): boolean; +function read(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean; +function write(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean; +function find_cmd_slot(port : uint8) : uint32; + +implementation + +procedure init(); +var + devID : TDeviceIdentifier; +begin + console.writestringln('AHCI: Registering driver'); + devID.bus:= biPCI; + devID.id0:= idANY; + devID.id1:= $00000001; + devID.id2:= $00000006; + devID.id3:= $00000001; + devID.id4:= idANY; + devID.ex:= nil; + drivermanagement.register_driver('AHCI Driver', @devID, @load); +end; + +procedure load(ptr : void); +begin + console.writestringln('AHCI: initilizing a new controller'); + ahciControllers[ahciControllerCount] := ptr; + hba[ahciControllerCount] := PPCI_Device(ptr)^.address5; + new_page_at_address(hba[ahciControllerCount]); + + //here would be any controller setup needed + + check_ports(ahciControllerCount); + ahciControllerCount += 1; + exit(true); +end; + +procedure check_ports(controller : uint8); +var + d : uint32 = 1; + i : uint32; +begin + for i:=0 to 31 do begin + if (d > 0) and (hba[controller]^.port_implemented shr i) = 1 then begin + if (hba[controller]^.ports[i].ssts shr 8) <> 1 and (hba[controller]^.ports[i].ssts and $0F) <> 3 then begin + if hba[controller]^.ports[i].sig = 1 then begin + //device is sata + sataDevices[sataDeviceCount].controller := controller; + sataDevices[sataDeviceCount].port := i; + sataDeviceCount += 1; + end; + //TODO implement ATAPI + end; + end; + end; +end; \ No newline at end of file diff --git a/src/driver/storage/AHCI_OLD.pas b/src/driver/storage/AHCI_OLD.pas new file mode 100644 index 00000000..1606e857 --- /dev/null +++ b/src/driver/storage/AHCI_OLD.pas @@ -0,0 +1,539 @@ +{ ************************************************ + * Asuro + * Unit: Drivers/AHCI + * Description: AHCI SATA Driver + ************************************************ + * Author: Aaron Hance + * Contributors: + ************************************************ } + +unit AHCI; + +interface + +uses + util, + PCI, + drivertypes, + drivermanagement, + lmemorymanager, + console, + vmemorymanager; + +type + +//Struct hell + + TFIS_Type = ( + REG_H2D = $27, + REG_D2H = $34, + DMA_ACT = $39, + DMA_SETUP = $41, + DATA = $46, + BIST = $58, + PIO_SETUP = $5F, + DEV_BITS = $A0 + ); + + PFIS_REG_H2D = ^TFIS_REG_H2D; + TFIS_REG_H2D = bitpacked record + fis_type : uint8; + port_mult : UBit4; + rsv0 : UBit3; + coc : boolean; + command : uint8; + feature_low : uint8; + lba0 : uint8; + lba1 : uint8; + lba2 : uint8; + device : uint8; + lba3 : uint8; + lba4 : uint8; + lba5 : uint8; + feature_high : uint8; + count_low : uint8; + count_high : uint8; + icc : uint8; + control : uint8; + rsvl : uint32; + end; + + TFIS_REG_D2H = bitpacked record + fis_type : uint8; + port_mult : UBit4; + rsv0 : UBit2; + i : boolean; + rsvl : boolean; + status : uint8; + error : uint8; + lba0 : uint8; + lba1 : uint8; + lba2 : uint8; + device : uint8; + lba3 : uint8; + lba4 : uint8; + lba5 : uint8; + rsv2 : uint8; + count_low : uint8; + count_high : uint8; + rsv3 : uint16; + rsv4 : uint32; + end; + + TFIS_Data = bitpacked record + fis_type : uint8; + port_mult : UBit4; + rsv0 : UBit4; + rsv1 : uint16; + data : ^uint32; + end; + + TFIS_PIO_Setup = bitpacked record + fis_type : uint8; + pmport : UBit4; + rsv0 : boolean; + d : boolean; + i : boolean; + rsv1 : boolean; + status : uint8; + error : uint8; + lba0 : uint8; + lba1 : uint8; + lba2 : uint8; + device : uint8; + lba3 : uint8; + lba4 : uint8; + lba5 : uint8; + rsv2 : uint8; + countl : uint8; + counth : uint8; + rsv3 : uint8; + e_status : uint8; + tc : uint16; + rsv4 : uint16; + end; + + // TFIS_DMA_Setup = bitpacked record + // end; + + // THBA_Memory = bitpacked record + // end; + + // THBA_Port = bitpacked record + // end; + + // THBA_FIS = bitpacked record + // end; + + PHBA_PORT = ^THBA_PORT; + THBA_PORT = bitpacked record + clb : uint32; + clbu : uint32; + fb : uint32; + fbu : uint32; + istat : uint32; + ie : uint32; + cmd : uint32; + rsv0 : uint32; + tfd : uint32; + sig : uint32; + ssts : uint32; + sctl : uint32; + serr : uint32; + sact : uint32; + ci : uint32; + sntf : uint32; + fbs : uint32; + rsv1 : array[0..11] of uint32; + vendor : array[0..4] of uint32; + end; + + THBA_MEM = bitpacked record + cap : uint32; //0 + global_host_control : uint32; //4 + interrupt_status : uint32; //8 + port_implemented : uint32; //c + version : uint32; //10 + ccc_control : uint32; //14 + ccc_ports : uint32; //18 + em_location : uint32; //1c + em_Control : uint32; //20 + hcap2 : uint32; //24 + bohc : uint32; //28 + rsv0 : array[0..210] of boolean; + ports : array[0..31] of THBA_Port; + end; + + THBAptr = ^THBA_MEM; + + PCMDHeader = ^ TCommand_Header; + TCommand_Header = bitpacked record + cfl : ubit5; + a : boolean; + w : boolean; + p : boolean; + r : boolean; + b : boolean; + c : boolean; + rsv0 : boolean; + pmp : ubit4; + PRDTL : uint16; + PRDTBC : uint32; + CTBA : uint32; + CTBAU : uint32; + rsv1 : array[0..3] of uint32; + end; + + TPRD_Entry = bitpacked record + data_base_address : uint32; + data_bade_address_U : uint32; + rsv0 : uint32; + data_byte_count : ubit22; + rsv1 : ubit9; + interrupt_oc : boolean; + end; + + PCommand_Table = ^TCommand_Table; + TCommand_Table = bitpacked record + cfis : array[0..64] of uint8; + acmd : array[0..16] of uint8; + rsv : array[0..48] of uint8; + prdt : array[0..7] of TPRD_Entry; + end; + +var + //constants + //SATA_SIG_ATA := $101; + //SATA_SIG_ATAPI := $EB140101; + //STA_SIG_SEMB := $C33C0101; + //STAT_SIG_PM := $96690101; + AHCI_BASE: uint32 = $400000; + + //other + ahciController : PuInt32; + hba : THBAptr; + + sataStorageDevices : array[0..31] of PuInt32; + sataStorageDeviceCount : uint8; + + + +procedure init(); +procedure check_ports(); +procedure enable_cmd(port : uint8); +procedure disable_cmd(port : uint8); +procedure port_rebase(port : uint8); +function load(ptr:void): boolean; +function read(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean; +function write(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean; +function find_cmd_slot(port : uint8) : uint32; + +implementation + +procedure init(); +var + devID : TDeviceIdentifier; +begin + console.writestringln('AHCI: STARTING INIT'); + devID.bus:= biPCI; + devID.id0:= idANY; + devID.id1:= $00000001; + devID.id2:= $00000006; + devID.id3:= $00000001; + devID.ex:= nil; + drivermanagement.register_driver('AHCI Controller', @devID, @load); +end; + +function load(ptr : void) : boolean; +begin + ahciController := ptr; + hba := THBAptr(PPCI_Device(ahciController)^.address5); + new_page_at_address(uint32(hba)); + new_page_at_address(AHCI_BASE); + AHCI_BASE := PPCI_Device(ahciController)^.address5; + check_ports(); + load:= true; + exit; +end; + +procedure check_ports(); +var + d : uint32; + i : uint32; + activePorts : array[0..32] of uint32; + +begin + d:= 1; + for i:= 0 to 31 do begin + if (d > 0) and (hba^.port_implemented <> 0) then begin // port connected + if hba^.ports[i].ssts = 259 then begin // port in use and active + if hba^.ports[i].sig = 1 then begin //device is sata + sataStorageDevices[sataStorageDeviceCount - 1] := @hba^.ports[i]; + sataStorageDeviceCount += 1; + port_rebase(i); + end; + //TODO implement other types + end; + end; + d := d shl 1; + end; +end; + +procedure enable_cmd(port : uint8); +begin + while (hba^.ports[port].cmd and $8000) <> 0 do begin end; + hba^.ports[port].cmd := hba^.ports[port].cmd or $0010; + hba^.ports[port].cmd := hba^.ports[port].cmd or $0001; +end; + +procedure disable_cmd(port : uint8); +begin + hba^.ports[port].cmd := hba^.ports[port].cmd and $0001; + while (hba^.ports[port].cmd and $4000) <> 0 do begin end; + hba^.ports[port].cmd := hba^.ports[port].cmd and $0010; +end; + +procedure port_rebase(port : uint8); +var + cmdHeader : PCMDHeader; + i : uint16; +begin + disable_cmd(port); + hba^.ports[port].clb := AHCI_BASE + (port shl 10); + hba^.ports[port].clbu := 0; + memset(hba^.ports[port].clb, 0, 1024); + + hba^.ports[port].fb := AHCI_BASE + (32 shl 10) + (port shl 8); + hba^.ports[port].fbu := 0; + memset(hba^.ports[port].fb, 0, 256); + + cmdheader := PCMDHeader(hba^.ports[port].clb); + for i:= 0 to 31 do begin + cmdHeader[i].PRDTL := 8; // no of prdt entries per cmd table + cmdheader[i].ctba := AHCI_BASE + (40 shl 10) + (port shl 13) + (i shl 8); + cmdheader[i].CTBAU := 0; + memset(cmdheader[i].ctba, 0, 256); + end; + enable_cmd(port); +end; + +function read(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean; +var + pport : PHBA_PORT; + slot : uint32; + cmdHeader : PCMDHeader; + cmdTable : PCommand_Table; + cmdFis : PFIS_REG_H2D; + i : uint32; + spin : uint32 = 0; +begin + console.writestringln('1'); + pport := @hba^.ports[port]; + //new_page_at_address(uint32(pport)); + pport^.istat := $ffff; + slot := find_cmd_slot(port); + if slot = -1 then exit(false); + + console.writestringln('2'); + cmdHeader := @pport^.clb; + //new_page_at_address(uint32(cmdHeader)); + cmdHeader += slot; + cmdHeader^.w := false; + cmdHeader^.PRDTL := uint16(((count - 1) shr 4) + 1); + + console.writestringln('3'); + cmdTable := @cmdheader^.ctba; + //new_page_at_address(uint32(cmdTable)); + memset(uint32(cmdTable), 0, sizeof(TCommand_Table) + (cmdheader^.PRDTL-1) * sizeof(TPRD_Entry)); + + console.writestringln('4'); + if cmdHeader^.PRDTL > 0 then begin + for i:= 0 to cmdHeader^.PRDTL -1 do begin + cmdTable^.prdt[i].data_base_address := uint32(buf); + cmdTable^.prdt[i].data_byte_count := 8*1024-1; + cmdTable^.prdt[i].interrupt_oc := false; + buf += 4*1024; + count -= 16; + end; + end; + + console.writestringln('5'); + cmdTable^.prdt[cmdHeader^.PRDTL].data_base_address := uint32(buf); + cmdTable^.prdt[cmdHeader^.PRDTL].data_byte_count := (count shl 9)-1; + cmdTable^.prdt[cmdHeader^.PRDTL].interrupt_oc := false; + + console.writestringln('6'); + //setup command + cmdfis := @cmdTable^.cfis; + new_page_at_address(uint32(cmdfis)); + cmdfis^.coc := true; + cmdfis^.command := $25; + cmdfis^.lba0 := uint8(startl); + cmdfis^.lba1 := uint8(startl shr 8); + cmdfis^.lba2 := uint8(startl shr 16); + cmdfis^.device := 1 shl 6; + cmdfis^.lba3 := uint8(startl shr 24); + cmdfis^.lba4 := uint8(starth); + cmdfis^.lba3 := uint8(starth shr 8); + cmdfis^.count_low := count and $FF; + cmdfis^.count_high:= (count shr 8) and $FF; + + console.writestringln('7'); + // while (pport^.tfd and $88) and spin < 1000000 do begin + // spin += 1; + // end; + + console.writestringln('8'); + if spin = 1000000 then begin + console.writestringln('AHCI controller: port is hung!'); + read:= false; + exit; + end; + + console.writestringln('9'); + //pport^.ci := 1 shl slot; + pport^.ci := 1; + + console.writestringln('10'); + while true do begin + if(pport^.ci and (1 shl slot)) = (1 shl slot) then break; + if(pport^.istat and (1 shl 30)) = (1 shl 30) then begin + console.writestringln('AHCI controller: Disk read error!'); + read:= false; + exit; + end; + end; + + console.writestringln('11'); + if(pport^.istat and (1 shl 30)) = (1 shl 30) then begin + console.writestringln('AHCI controller: Disk read error!'); + read:= false; + exit; + end; + + console.writestringln('12'); + read:= true; + exit; +end; + +function write(port : uint8; startl : uint32; starth : uint32; count : uint32; buf : PuInt32) : boolean; +var + pport : PHBA_PORT; + slot : uint32; + cmdHeader : PCMDHeader; + cmdTable : PCommand_Table; + cmdFis : PFIS_REG_H2D; + i : uint32; + spin : uint32 = 0; +begin + console.writestringln('1'); + pport := @hba^.ports[port]; + new_page_at_address(uint32(pport)); + pport^.istat := $ffff; + slot := find_cmd_slot(port); + if slot = -1 then exit(false); + + console.writestringln('2'); + cmdHeader := @pport^.clb; + cmdHeader += slot; + // new_page_at_address(uint32(cmdHeader)); + cmdHeader^.w := false; + cmdHeader^.PRDTL := uint16(((count - 1) shr 4) + 1); + console.writeintln(cmdHeader^.PRDTL); // different value on differnt emulators???? + console.writestringln('3'); + cmdTable := @cmdheader^.ctba; + // new_page_at_address(uint32(cmdTable)); + // new_page_at_address(uint32(@cmdTable^.prdt)); + memset(uint32(cmdTable), 0, sizeof(TCommand_Table) + (cmdheader^.PRDTL-1) * sizeof(TPRD_Entry)); + + console.writestringln('4'); + console.writestring('PRDTL: '); + console.writeintln(cmdHeader^.PRDTL); + if cmdHeader^.PRDTL > 0 then begin + for i:= 0 to cmdHeader^.PRDTL -1 do begin + cmdTable^.prdt[i].data_base_address := uint32(buf); + cmdTable^.prdt[i].data_byte_count := 8*1024-1; + cmdTable^.prdt[i].interrupt_oc := false; + buf += 4*1024; + count -= 16; + end; + end; + + console.writestringln('5'); + cmdTable^.prdt[cmdHeader^.PRDTL].data_base_address := uint32(buf); + console.writestringln('5.1'); + cmdTable^.prdt[cmdHeader^.PRDTL].data_byte_count := (count shl 9)-1; + console.writestringln('5.2'); + cmdTable^.prdt[cmdHeader^.PRDTL].interrupt_oc := false; + + console.writestringln('6'); + cmdfis := @cmdTable^.cfis; + new_page_at_address(uint32(cmdfis)); + cmdfis^.coc := true; + cmdfis^.command := $35; + cmdfis^.lba0 := uint8(startl); + cmdfis^.lba1 := uint8(startl shr 8); + cmdfis^.lba2 := uint8(startl shr 16); + cmdfis^.device := 1 shl 6; + cmdfis^.lba3 := uint8(startl shr 24); + cmdfis^.lba4 := uint8(starth); + cmdfis^.lba3 := uint8(starth shr 8); + cmdfis^.count_low := count and $FF; + cmdfis^.count_high:= (count shr 8) and $FF; + + console.writestringln('7'); + // while (pport^.tfd and $88) and spin < 1000000 do begin + // spin += 1; + // end; + + console.writestringln('8'); + if spin = 1000000 then begin + console.writestringln('AHCI controller: port is hung!'); + write:= false; + exit; + end; + + console.writestringln('9'); + //pport^.ci := 1 shl slot; + pport^.ci := 1; + + console.writestringln('10'); + while true do begin + if(pport^.ci and (1 shl slot)) = (1 shl slot) then break; + if(pport^.istat and (1 shl 30)) = (1 shl 30) then begin + console.writestringln('AHCI controller: Disk write error!'); + write:= false; + exit; + end; + end; + + console.writestringln('11'); + if(pport^.istat and (1 shl 30)) = (1 shl 30) then begin + console.writestringln('AHCI controller: Disk write error!'); + write:= false; + exit; + end; + + console.writestringln('12'); + write:= true; + exit; +end; + +function find_cmd_slot(port : uint8) : uint32; +var + slots : uint32; + i : uint32; +begin + slots := hba^.ports[port].sact or hba^.ports[port].ci; + for i:=0 to 31 do begin + if (slots and 1) = 0 then begin + exit(i); + end; + slots := slots shr 1; + end; + console.writestringln('AHCI Controller: Unable to find free command slots!'); + exit(-1); +end; + +end. + diff --git a/src/driver/storage/ATA_OLD.pas b/src/driver/storage/ATA_OLD.pas new file mode 100644 index 00000000..256ea077 --- /dev/null +++ b/src/driver/storage/ATA_OLD.pas @@ -0,0 +1,271 @@ +{ ************************************************ + * Asuro + * Unit: Drivers/ATA + * Description: ATA DMA Driver + * currently a hack needs to be re-written if works + ************************************************ + * Author: Aaron Hance + * Contributors: + ************************************************ } +unit ATA; + +interface + +uses + util, + drivertypes, + console, + terminal, + isr76, + vmemorymanager; + +type + + intptr = ^uint32; + + ATA_Device = record + reading : boolean; + master : boolean; + primary : boolean; + currentIndex : uint16; + device_lba : uint32; + Command_Register : uint32; + Status_Register : uint32; + PRDT_Address_Reg : uint32; + end; + + Physical_Region_Descriptor = bitpacked record + empty0 : 0..1; + MRPB_Address : 1..32; // memory address + Byte_Count : 32..47; // size in bytes (0 is 64K) + empty1 : 47..63; + EOT : 63..64; // end of table + empty2 : 64..65; + end; + + ATA_Command_Buffer = bitpacked record + start_stop_bit : 0..1; // 0 stopped + read_write_bit : 3..4; // 0 read + end; + + ATA_Status_Buffer = bitpacked record end; + + ATA_IO_PORT = record + data : uint16; + error : uint8; + sector_count : uint8; + lba_low : uint8; + lba_mid : uint8; + lba_hi : uint8; + drive : uint8; + command : uint8; + end; + +var + ports : ATA_IO_PORT; + devices : array[0..4] of ATA_Device; + PRD_Table : array[0..100] of Physical_Region_Descriptor; // up 64K r/w each, upto 8000 supported per table. + controller : TPCI_device; + +procedure init(_controller : TPCI_device); +procedure read(address : uint32; data_lba : uint32; data_bytes : uint32); +procedure write(address : uint32; data_lba : uint32; data_bytes : uint32); +procedure callback(data : void); + +implementation + +procedure init(_controller : TPCI_device); //alloc, pmem; map_page vmem; +begin + console.writestringln('ATA: INIT BEGIN.'); + isr76.hook(uint32(@callback)); + + controller := _controller; + + new_page_at_address(controller.address4); + + devices[0].primary := true; + devices[0].Command_Register := controller.address4; + devices[0].Status_Register := controller.address4 + 2; + devices[0].PRDT_Address_Reg := controller.address4 + 4; + + ports.command := $1F7; + ports.lba_low := $1F3; + ports.lba_mid := $1F4; + ports.lba_hi := $1F5; + ports.drive := $1F6; + ports.sector_count := $F2; + console.writestringln('ATA: INIT END.'); +end; + +procedure read(address : uint32; data_lba : uint32; data_bytes : uint32); +var + PRD : Physical_Region_Descriptor; + empty_table : array[0..100] of Physical_Region_Descriptor; + i : uint32; + ptr : intptr; + sector_count : uint8; + cb : ATA_Command_Buffer; +begin + devices[0].device_lba := data_lba; + devices[0].reading := true; + PRD_Table := empty_table; + PRD.MRPB_Address := address; + + //limit + if data_bytes > 6400000 then exit; + + if data_bytes < 64001 then begin + PRD.EOT := 1; + if data_bytes = 64000 then begin + PRD.Byte_Count := 0 + end else begin + PRD.Byte_Count := data_bytes; + end; + end else begin + while data_bytes > 64000 do begin + PRD.EOT := 0; + PRD.MRPB_Address := address; + PRD.Byte_Count := 0; + + data_bytes := data_bytes - 64000; + address := address + 64000; + end; + + PRD.EOT := 1; + PRD.MRPB_Address := address; + PRD.Byte_Count := data_bytes; + + end; + + ptr := intptr(devices[0].PRDT_Address_Reg); + ptr^ := uint32(@PRD_Table); + + ptr := intptr(devices[0].Status_Register); + ptr^ := 0; + + outb(ports.drive, $A0); + outb(ports.sector_count, 125); + outb(ports.lba_low, (data_lba and $000000FF)); + outb(ports.lba_mid, (data_lba and $0000FF00) SHR 8); + outb(ports.lba_hi, (data_lba and $0000FF00) SHR 16); + outb(ports.command, $C8); + devices[0].currentIndex := 1; + + cb.start_stop_bit := 1; + cb.read_write_bit := 0; + + ptr := intptr(devices[0].Command_Register); + ptr^ := uint8(cb); + +end; + +procedure write(address : uint32; data_lba : uint32; data_bytes : uint32); +var + PRD : Physical_Region_Descriptor; + empty_table : array[0..100] of Physical_Region_Descriptor; + i : uint32; + ptr : intptr; + sector_count : uint8; + cb : ATA_Command_Buffer; +begin + devices[0].device_lba := data_lba; + devices[0].reading := true; + PRD_Table := empty_table; + PRD.MRPB_Address := address; + + //limit + if data_bytes > 6400000 then exit; + + if data_bytes < 64001 then begin + PRD.EOT := 1; + if data_bytes = 64000 then begin + PRD.Byte_Count := 0 + end else begin + PRD.Byte_Count := data_bytes; + end; + end else begin + while data_bytes > 64000 do begin + PRD.EOT := 0; + PRD.MRPB_Address := address; + PRD.Byte_Count := 0; + + data_bytes := data_bytes - 64000; + address := address + 64000; + end; + + PRD.EOT := 1; + PRD.MRPB_Address := address; + PRD.Byte_Count := data_bytes; + + end; + + ptr := intptr(devices[0].PRDT_Address_Reg); + ptr^ := uint32(@PRD_Table); + + ptr := intptr(devices[0].Status_Register); + ptr^ := 0; + + outb(ports.drive, $A0); + outb(ports.sector_count, 125); + outb(ports.lba_low, (data_lba and $000000FF)); + outb(ports.lba_mid, (data_lba and $0000FF00) SHR 8); + outb(ports.lba_hi, (data_lba and $0000FF00) SHR 16); + outb(ports.command, $CA); + devices[0].currentIndex := 1; + + cb.start_stop_bit := 1; + cb.read_write_bit := 1; + + ptr := intptr(devices[0].Command_Register); + ptr^ := uint8(cb); + +end; + +procedure callback(data : void); //need r/w, is last +var + cb : ATA_Command_Buffer; + ptr : intptr; + tmp : uint16; + mode : uint8; +begin + if(PRD_Table[devices[0].currentIndex - 1].EOT = 1) then begin + //other stuff + exit; + end; + + //if(devices[0].reading = true) then begin + if(PRD_Table[devices[0].currentIndex].EOT = 0) then begin + outb(ports.sector_count, 125); + outb(ports.lba_low, (devices[0].device_lba + (64000 * devices[0].currentIndex)) and $000000FF); + outb(ports.lba_mid, (((devices[0].device_lba + (64000 * devices[0].currentIndex))) and $0000FF00) SHR 8); + outb(ports.lba_hi, (((devices[0].device_lba + (64000 * devices[0].currentIndex))) and $0000FF00) SHR 16); + //outb(ports.command, $C8); + end else begin + tmp := uint16((PRD_Table[devices[0].currentIndex].Byte_Count and $FFFF) DIV 512); + outb(ports.sector_count, uint16(tmp)); // wont work if 64k + outb(ports.lba_low, (devices[0].device_lba + (64000 * devices[0].currentIndex)) and $000000FF); + outb(ports.lba_mid, (((devices[0].device_lba + (64000 * devices[0].currentIndex))) and $0000FF00) SHR 8); + outb(ports.lba_hi, (((devices[0].device_lba + (64000 * devices[0].currentIndex))) and $0000FF00) SHR 16); + //outb(ports.command, $C8); + end; + + if(devices[0].reading = true) then begin + outb(ports.command, $C8); + cb.start_stop_bit := 1; + cb.read_write_bit := 0; + end else begin + outb(ports.command, $CA); + cb.start_stop_bit := 1; + cb.read_write_bit := 1; + end; + ptr := intptr(devices[0].Command_Register); + ptr^ := uint8(cb); + + + devices[0].currentIndex := devices[0].currentIndex + 1; + //end; +end; + + + +end. \ No newline at end of file