starting to work
This commit is contained in:
parent
f04f8aa411
commit
05eab23956
@ -461,9 +461,11 @@ begin
|
||||
cmd := inl(PCI_CONFIG_DATA_PORT);
|
||||
cmd := cmd or PCI_COMMAND_MEM_SPACE;
|
||||
cmd := cmd or PCI_COMMAND_BUS_MASTER;
|
||||
cmd := cmd or (3 shl 1);
|
||||
|
||||
//enable interrupts, remove disable interrupt bit
|
||||
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
|
||||
cmd := cmd and not (1 shl 9);
|
||||
|
||||
outl(PCI_CONFIG_ADDRESS_PORT, addr);
|
||||
outl(PCI_CONFIG_DATA_PORT, cmd);
|
||||
|
@ -42,7 +42,7 @@ var
|
||||
procedure init();
|
||||
function load(ptr : void) : boolean;
|
||||
procedure check_ports(controller : PAHCI_Controller);
|
||||
procedure identify_device(controller : PAHCI_Controller; port : uint32);
|
||||
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32);
|
||||
procedure ahci_isr();
|
||||
|
||||
implementation
|
||||
@ -65,18 +65,49 @@ end;
|
||||
|
||||
procedure stop_port(port : PHBA_Port);
|
||||
begin
|
||||
port^.cmd := port^.cmd and not $1; ///maybe also bit 4
|
||||
while (port^.cmd and $1) = 1 do begin
|
||||
port^.cmd := port^.cmd and not $1;
|
||||
port^.cmd := port^.cmd and not $100;
|
||||
while ((port^.cmd and $4000) or (port^.cmd and $8000)) <> 0 do begin
|
||||
//wait for the port to stop
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure start_port(port : PHBA_Port);
|
||||
begin
|
||||
port^.cmd := port^.cmd or $1; ///maybe also bit 4
|
||||
while (port^.cmd and $1) = 0 do begin
|
||||
//wait for the port to start
|
||||
|
||||
while (port^.cmd and $8000) <> 0 do begin
|
||||
//wait for port to not be busy
|
||||
end;
|
||||
port^.cmd := port^.cmd or $100;
|
||||
port^.cmd := port^.cmd or $1;
|
||||
end;
|
||||
|
||||
procedure reset_port(port : PHBA_Port);
|
||||
var
|
||||
ssts, serr, timeout : uint32;
|
||||
begin
|
||||
console.writestringln('AHCI: Performing a full port reset.');
|
||||
|
||||
port^.cmd := port^.cmd and not $1;
|
||||
|
||||
// Wait until CR (bit 15) is cleared.
|
||||
timeout := 0;
|
||||
while (port^.cmd and $8000) <> 0 do begin
|
||||
timeout := timeout + 1;
|
||||
if timeout > 1000000 then begin
|
||||
console.writestringln('AHCI: Port reset timeout.');
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
port^.sata_ctrl := port^.sata_ctrl or $FFFF0000;
|
||||
|
||||
while (port^.sata_status and $F) <> 3 do begin
|
||||
//wait for the port to be ready
|
||||
end;
|
||||
|
||||
// Clear the SERR register by writing 1s to it.
|
||||
port^.sata_error := $FFFFFFFF;
|
||||
end;
|
||||
|
||||
{
|
||||
@ -98,13 +129,22 @@ begin
|
||||
console.writehexln(controller^.mio^.ports_implimented);
|
||||
|
||||
for i:=0 to 31 do begin
|
||||
if (controller^.mio^.ports_implimented shr i) = 1 then begin
|
||||
port := @controller^.mio^.ports[i];
|
||||
console.writehex(port^.signature);
|
||||
console.writestring(' ');
|
||||
end;
|
||||
|
||||
for i:=0 to 31 do begin
|
||||
if ((controller^.mio^.ports_implimented shr i) and 1) = 1 then begin
|
||||
port := @controller^.mio^.ports[i];
|
||||
console.writestring('AHCI: Port ');
|
||||
console.writeint(i);
|
||||
console.writestring(' implemented on controller ');
|
||||
console.writehexln(uint32(controller^.pci_device^.address5));
|
||||
|
||||
device := PAHCI_Device(DL_Add(controller^.devices));
|
||||
device^.port := port;
|
||||
|
||||
//check if the port is active TODO
|
||||
// if ((port^.sata_status shr 8) <> 1) and ((port^.sata_status and $0F) <> 3) then begin
|
||||
// continue; wrong
|
||||
@ -135,26 +175,28 @@ begin
|
||||
|
||||
//NEEED TO STOP the port before doing anything
|
||||
stop_port(port);
|
||||
|
||||
device := PAHCI_Device(DL_Add(controller^.devices));
|
||||
device^.port := port;
|
||||
console.writestringln('AHCI: Port stopped');
|
||||
|
||||
//allocate memory for the command list and ensure it is aligned to 1024 bytes
|
||||
cmd_list_base := kalloc(sizeof(THBA_CMD_HEADER) * 64);
|
||||
cmd_list_base := puint32((uint32(cmd_list_base) + 1023) and $FFFFFC00);
|
||||
|
||||
//allocate memory for the FIS and ensure it is aligned to 256 bytes
|
||||
fis_base := kalloc(sizeof(THBA_FIS) * 8);
|
||||
fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00);
|
||||
memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER) * 32);
|
||||
|
||||
//set the command list base address
|
||||
port^.cmdl_basel := vtop(uint32(cmd_list_base)); //todo set virtual address in device
|
||||
port^.cmdl_baseu := 0;
|
||||
|
||||
memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER));
|
||||
|
||||
device^.command_list := PHBA_CMD_HEADER(cmd_list_base);
|
||||
|
||||
|
||||
//print the command list base address
|
||||
console.writestring('AHCI: Command list base address: ');
|
||||
console.writehexln(uint32(cmd_list_base));
|
||||
|
||||
//allocate memory for the FIS and ensure it is aligned to 256 bytes
|
||||
fis_base := kalloc(sizeof(THBA_FIS) * 8);
|
||||
fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00);
|
||||
|
||||
//set the FIS base address
|
||||
port^.fis_basel := vtop(uint32(fis_base));
|
||||
port^.fis_baseu := 0;
|
||||
@ -164,9 +206,10 @@ begin
|
||||
device^.fis := PHBA_FIS(fis_base);
|
||||
//todo check how many simultaneous commands are supported
|
||||
|
||||
//allocate memory for the command table and ensure it is aligned to 1024 bytes
|
||||
//allocate memory for the command table and ensure it is aligned to 128 bytes
|
||||
cmd_table_base := kalloc(sizeof(THBA_CMD_TABLE) * 64);
|
||||
cmd_table_base := puint32((uint32(cmd_table_base) + 1023) and $FFFFFC00);
|
||||
cmd_table_base := puint32((uint32(cmd_table_base) + 127) and $FFFFFF80);
|
||||
memset(uint32(cmd_table_base), 0, sizeof(THBA_CMD_TABLE) * 32);
|
||||
|
||||
device^.command_table := PHBA_CMD_TABLE(cmd_table_base);
|
||||
|
||||
@ -174,93 +217,148 @@ begin
|
||||
for ii:=0 to 31 do begin
|
||||
//set command header locations
|
||||
command_header := PHBA_CMD_HEADER(uint32(cmd_list_base) + (ii * sizeof(THBA_CMD_HEADER)));
|
||||
|
||||
command_header^.prdtl := 32;
|
||||
//TODO do i need to set prdbc byte count here?
|
||||
command_header^.cmd_table_base := vtop(uint32(cmd_table_base)) + (ii * sizeof(THBA_CMD_TABLE));
|
||||
command_header^.cmd_table_baseu := 0;
|
||||
memset(uint32(cmd_table_base) + (ii * sizeof(THBA_CMD_TABLE)), 0, sizeof(THBA_CMD_TABLE));
|
||||
end;
|
||||
|
||||
//reset the port
|
||||
reset_port(port);
|
||||
start_port(port);
|
||||
|
||||
//print sata status
|
||||
console.writestring('AHCI: sata status: ');
|
||||
console.writehexln(port^.sata_status);
|
||||
|
||||
//pass devices count as second param
|
||||
if (device^.device_type = SATA) then begin
|
||||
identify_device(controller, DL_Size(controller^.devices) - 1);
|
||||
end;
|
||||
|
||||
controller^.mio^.int_status := $FFFFFFFF;
|
||||
|
||||
// identify_device(controller, DL_Size(controller^.devices) - 1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure identify_device(controller : PAHCI_Controller; port : uint32);
|
||||
procedure identify_device(controller : PAHCI_Controller; portIndex : uint32);
|
||||
var
|
||||
fis : PHBA_FIS_REG_H2D;
|
||||
cmd_header : PHBA_CMD_HEADER;
|
||||
cmd_table : PHBA_CMD_TABLE;
|
||||
cmd : uint32;
|
||||
i : uint32;
|
||||
buffer :puint32;
|
||||
i, timeout : uint32;
|
||||
buffer : puint32;
|
||||
device : PAHCI_Device;
|
||||
tfd : uint32;
|
||||
sec_count : uint32;
|
||||
b8 : puint16;
|
||||
begin
|
||||
console.writestringln('AHCI: Identifying device');
|
||||
device := PAHCI_Device(DL_Get(controller^.devices, portIndex));
|
||||
|
||||
device := PAHCI_Device(DL_Get(controller^.devices, port));
|
||||
// (Optional) Print the device type if you store it:
|
||||
console.writestring('AHCI: Device type: ');
|
||||
// For example: if device^.device_type = SATA then ...
|
||||
console.writestring('AHCI: sata status: ');
|
||||
console.writehexln(device^.port^.sata_status);
|
||||
|
||||
//clear any pending interrupts
|
||||
device^.port^.int_status := $FFFFFFFF;
|
||||
device^.port^.int_enable := 0;
|
||||
|
||||
// Allocate a 512-byte DMA buffer for the IDENTIFY data
|
||||
buffer := kalloc(512);
|
||||
memset(uint32(buffer), 0, 512);
|
||||
|
||||
cmd_header := device^.command_list;
|
||||
// Use command slot 0 for the IDENTIFY command.
|
||||
cmd_header := device^.command_list; // Assuming slot 0 is at the beginning.
|
||||
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
|
||||
// cmd_header^.command := ATA_CMD_IDENTIFY;
|
||||
cmd_header^.wrt := 0;
|
||||
cmd_header^.prdtl := 1;
|
||||
cmd_header^.clear_busy := 1;
|
||||
|
||||
//just use first command table for identify as no other commands are running
|
||||
|
||||
// Setup the command table (using slot 0)
|
||||
cmd_table := device^.command_table;
|
||||
cmd_table^.prdt[0].dba := vtop(uint32(buffer));
|
||||
cmd_table^.prdt[0].dbc := 511;
|
||||
cmd_table^.prdt[0].int := 1;
|
||||
cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count)
|
||||
cmd_table^.prdt[0].int := 1; // Interrupt on completion
|
||||
|
||||
// Construct the Command FIS in the command table's CFIS area
|
||||
fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis);
|
||||
memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D));
|
||||
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
|
||||
fis^.pmport := 0;
|
||||
fis^.c := $1;
|
||||
fis^.command := ATA_CMD_IDENTIFY;
|
||||
fis^.device := 0;
|
||||
fis^.lba0 := 0;
|
||||
fis^.lba1 := 0;
|
||||
fis^.lba2 := 0;
|
||||
fis^.lba3 := 0;
|
||||
fis^.lba4 := 0;
|
||||
fis^.lba5 := 0;
|
||||
fis^.countl := 1;
|
||||
fis^.counth := 0;
|
||||
fis^.featurel := 0;
|
||||
fis^.featureh := 0;
|
||||
fis^.device := $A0; // LBA mode 40?
|
||||
|
||||
//send the command
|
||||
cmd := device^.port^.cmd;
|
||||
//waut for the port to be ready, bit 7 in the TFD register and bit 3 tfd
|
||||
while (device^.port^.tfd and $88) <> 0 do begin
|
||||
console.writestring('AHCI: tfd: ');
|
||||
console.writehexln(device^.port^.tfd);
|
||||
end;
|
||||
|
||||
// Issue the command by setting bit 0 in the port's Command Issue register.
|
||||
cmd := device^.port^.cmd_issue;
|
||||
cmd := cmd or $1;
|
||||
device^.port^.cmd := cmd;
|
||||
device^.port^.cmd_issue := cmd;
|
||||
|
||||
//wait for the command to complete
|
||||
while (cmd and $1) = 1 do begin
|
||||
cmd := device^.port^.cmd;
|
||||
console.writestringln('AHCI: Sent identify command');
|
||||
|
||||
|
||||
// Wait for command completion with a timeout.
|
||||
timeout := 0;
|
||||
repeat
|
||||
cmd := device^.port^.cmd_issue; // Command Issue register
|
||||
tfd := device^.port^.tfd; // Task File Data often contains error/status info.
|
||||
timeout := timeout + 10;
|
||||
if timeout > 100000 then begin
|
||||
console.writestringln('AHCI: IDENTIFY command timeout');
|
||||
break;
|
||||
end;
|
||||
// check for bit 30 in the tfd register
|
||||
if (tfd and $40000000) <> 0 then begin
|
||||
console.writestringln('AHCI: error');
|
||||
break;
|
||||
end;
|
||||
|
||||
//check the status of the command
|
||||
if (cmd and $2) = 1 then begin
|
||||
until ((device^.port^.cmd_issue and $1) = 0); // Wait until slot 0 is cleared
|
||||
|
||||
console.writestringln('AHCI: Command complete');
|
||||
|
||||
// Check for an error flag in the command register (bit 1)
|
||||
if (cmd and $2) <> 0 then begin
|
||||
console.writestringln('AHCI: Error sending identify command');
|
||||
|
||||
// Check the error register for more information
|
||||
console.writestring('AHCI: Error register: ');
|
||||
console.writehexln(device^.port^.sata_error);
|
||||
end;
|
||||
|
||||
//parse the identify data
|
||||
for i:=0 to 63 do begin
|
||||
// Dump the 512-byte IDENTIFY data for debugging (display 64 DWORDs)
|
||||
for i := 0 to 63 do begin
|
||||
console.writehex(uint32(buffer[i]));
|
||||
console.writestring(' ');
|
||||
end;
|
||||
|
||||
console.writestringln('');
|
||||
|
||||
b8 := puint16(buffer);
|
||||
sec_count := (b8[61] shl 16) or b8[60];
|
||||
console.writestring('AHCI: Sector count: ');
|
||||
console.writeintln(sec_count);
|
||||
console.writestring('AHCI: Device size: ');
|
||||
console.writeint(sec_count * 512 div 1024 div 1024);
|
||||
console.writestringln(' MB');
|
||||
|
||||
|
||||
|
||||
|
||||
console.writestringln('');
|
||||
end;
|
||||
|
||||
|
||||
function load(ptr : void) : boolean;
|
||||
var
|
||||
device : PPCI_Device;
|
||||
@ -271,6 +369,8 @@ var
|
||||
fis_base : puint32;
|
||||
cmd_table_base : puint32;
|
||||
int_no : uInt8;
|
||||
timeout : uint32;
|
||||
bohc : uint32;
|
||||
begin
|
||||
console.writestringln('AHCI: initilizing a new controller');
|
||||
|
||||
@ -284,7 +384,10 @@ begin
|
||||
pci.enableDevice(device^.bus, device^.slot, device^.func);
|
||||
int_no := device^.interrupt_line;
|
||||
|
||||
registerISR(int_no, @ahci_isr);
|
||||
|
||||
//print interrupt number
|
||||
console.writestring('AHCI: Interrupt number: ');
|
||||
console.writehexln(int_no);
|
||||
|
||||
controller := PAHCI_Controller(DL_Add(ahciControllers));
|
||||
controller^.devices := DL_New(SizeOf(TAHCI_Device));
|
||||
@ -299,19 +402,53 @@ begin
|
||||
base := PHBA_Memory(device^.address5);
|
||||
controller^.mio := base;
|
||||
|
||||
if (controller^.mio^.capabilites2 and $28) <> 0 then begin
|
||||
console.writestringln('AHCI: Controller needs to be handed off to the OS');
|
||||
end;
|
||||
|
||||
console.writestring('AHCI: Controller at: ');
|
||||
console.writehexln(device^.address5);
|
||||
console.writehexln(uint32(page_base));
|
||||
|
||||
bohc := controller^.mio^.bohc;
|
||||
|
||||
if (bohc and $1) <> 0 or (bohc and not (1 shl 1)) then begin
|
||||
console.writestringln('AHCI: BIOS Owned Semaphore is set, initiating handoff.');
|
||||
|
||||
// Set the OS Owned Semaphore (typically bit 1).
|
||||
bohc := bohc or (1 shl 1);
|
||||
controller^.mio^.bohc := bohc;
|
||||
|
||||
// Wait until the BIOS Owned Semaphore (bit 0) is cleared.
|
||||
timeout := 0;
|
||||
while ((controller^.mio^.bohc and $1) <> 0) and (timeout < 1000000) do begin
|
||||
timeout := timeout + 1;
|
||||
end;
|
||||
|
||||
if timeout = 1000000 then begin
|
||||
console.writestringln('AHCI: BIOS/OS handoff timed out.');
|
||||
end else begin
|
||||
console.writestringln('AHCI: BIOS/OS handoff successful.');
|
||||
end;
|
||||
end else begin
|
||||
console.writestringln('AHCI: BIOS not holding controller or handoff already complete.');
|
||||
end;
|
||||
|
||||
base^.global_ctrl := base^.global_ctrl or 1;
|
||||
|
||||
while (base^.global_ctrl and 1) <> 0 do begin
|
||||
end;
|
||||
|
||||
registerISR(int_no, @ahci_isr);
|
||||
|
||||
//enable AHCI mode, TODO check if is not already in AHCI mode and enable it, also perhaps remove if loaded as IDE
|
||||
base^.global_ctrl := base^.global_ctrl or AHCI_CONTROLLER_MODE;
|
||||
base^.global_ctrl := base^.global_ctrl or $2; //enable interrupts
|
||||
|
||||
|
||||
//clear any pending interrupts
|
||||
base^.int_status := $FFFFFFFF;
|
||||
|
||||
|
||||
|
||||
|
||||
check_ports(controller);
|
||||
|
||||
|
||||
|
@ -80,6 +80,7 @@ type
|
||||
sata_noti: uint32; // SATA Notification
|
||||
fis_switch_ctrl: uint32;// FIS-based Switch Control
|
||||
rsv1: array[0..10] of uint32;
|
||||
vendor: array[0..3] of uint32;
|
||||
end;
|
||||
|
||||
PHBA_Port = ^THBA_Port;
|
||||
@ -102,8 +103,16 @@ type
|
||||
em_control: uint32; // Enclosure Management Control
|
||||
capabilites2: uint32; // Host Capabilities Extended
|
||||
bohc: uint32; // BIOS/OS Handoff Control and Status
|
||||
rsv0: array[0..$210] of boolean;
|
||||
|
||||
//0x2c to 0x9f reserved
|
||||
rsv0: array[0..115] of uint8;
|
||||
|
||||
//vendor specific
|
||||
vendor: array[0..95] of uint8;
|
||||
|
||||
//port registers
|
||||
ports: array[0..31] of THBA_Port;
|
||||
|
||||
end;
|
||||
|
||||
PHBA_Memory = ^THBA_Memory;
|
||||
@ -145,7 +154,10 @@ type
|
||||
}
|
||||
THBA_FIS_REG_H2D = bitpacked record
|
||||
fis_type: uint8; // FIS Type
|
||||
pmport: uint8; // Port Multiplier Port
|
||||
// pmport: uint8; // Port Multiplier Port is pmport:4 and rsv0:3 and i:1
|
||||
pmport: ubit4; // Port Multiplier Port
|
||||
rsv: ubit3; // Reserved
|
||||
c: ubit1; // command or control
|
||||
command: uint8; // Command
|
||||
featurel: uint8; // Feature Lower 8-bits
|
||||
lba0: uint8; // LBA0
|
||||
@ -160,7 +172,7 @@ type
|
||||
counth: uint8; // Count Upper 8-bits
|
||||
icc: uint8; // Isochronous Command Completion
|
||||
control: uint8; // Control
|
||||
rsv0: array[0..2] of uint8;
|
||||
rsv0: array[0..3] of uint8;
|
||||
end;
|
||||
|
||||
PHBA_FIS_REG_H2D = ^THBA_FIS_REG_H2D;
|
||||
@ -171,19 +183,22 @@ type
|
||||
AHCI Host Bus Adapter (HBA) Command Header Interface
|
||||
}
|
||||
THBA_CMD_HEADER = bitpacked record
|
||||
cmd_fis_length: uint8; // Command FIS Length
|
||||
atapi: uint8; // ATAPI
|
||||
wrt: uint8; // Write
|
||||
prefetchable: uint8; // Prefetchable
|
||||
reset: uint8; // Reset
|
||||
bist: uint8; // BIST
|
||||
clear_busy: uint8; // Clear Busy
|
||||
reserved0: uint8; // Reserved
|
||||
cmd_fis_length: UBit5; // Command FIS Length
|
||||
atapi: UBit1; // ATAPI
|
||||
wrt: UBit1; // Write
|
||||
prefetchable: UBit1; // Prefetchable
|
||||
|
||||
reset: UBit1; // Reset
|
||||
bist: UBit1; // BIST
|
||||
clear_busy: UBit1; // Clear Busy
|
||||
reserved0: UBit1; // Reserved
|
||||
port_multiplier: UBit4; // Port Multiplier Port
|
||||
|
||||
prdtl: uint16; // Physical Region Descriptor Table Length
|
||||
prdbc: uint32; // Physical Region Descriptor Byte Count
|
||||
cmd_table_base: uint32; // Command Table Base Address
|
||||
cmd_table_baseu: uint32; // Command Table Base Address Upper 32-bits
|
||||
rsv0: array[0..4] of uint32;
|
||||
rsv0: array[0..3] of uint32;
|
||||
end;
|
||||
|
||||
PHBA_CMD_HEADER = ^THBA_CMD_HEADER;
|
||||
@ -195,8 +210,8 @@ type
|
||||
dba: uint32; // Data Base Address
|
||||
dbau: uint32; // Data Base Address Upper 32-bits
|
||||
rsv0: uint32; // Reserved
|
||||
reserved: ubit9; // Reserved
|
||||
dbc: ubit22; // Data Byte Count
|
||||
reserved: ubit9; // Reserved
|
||||
int: ubit1; // Interrupt
|
||||
// dbc: uint32; // Data Byte Count, bit 1 is Interrupt, then 22 bits of Byte Count, then 9 bits of Reserved
|
||||
end;
|
||||
@ -211,7 +226,7 @@ type
|
||||
cmd_fis: array[0..63] of uint8; // Command FIS
|
||||
acmd: array[0..15] of uint8; // ATAPI Command
|
||||
rsv0: array[0..47] of uint8;
|
||||
prdt: TPRDT; // Physical Region Descriptor Table
|
||||
prdt: array[0..31] of THBA_PRD; // Physical Region Descriptor Table
|
||||
end;
|
||||
|
||||
PHBA_CMD_TABLE = ^THBA_CMD_TABLE;
|
||||
@ -227,8 +242,8 @@ type
|
||||
Device type enum
|
||||
}
|
||||
TDeviceType = (
|
||||
SATA,
|
||||
ATAPI,
|
||||
SATA = 1,
|
||||
ATAPI = 2,
|
||||
SEMB,
|
||||
PM
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user