there you go ki-ear-ron

This commit is contained in:
Aaron Hance 2025-03-16 21:39:47 +00:00
parent 6a3ebf1387
commit f04f8aa411
4 changed files with 252 additions and 73 deletions

View File

@ -91,6 +91,7 @@ function getDeviceInfo(class_code : uint8; subclass_code : uint8; prog_if : uint
procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8); procedure requestConfig(bus : uint8; slot : uint8; func : uint8; row : uint8);
procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32); procedure writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32);
procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean); procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean);
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
implementation implementation
@ -442,4 +443,32 @@ begin
pop_trace; pop_trace;
end; end;
//Enable device inturrupts and set bus master
procedure enableDevice(bus : uint8; slot : uint8; func : uint8);
var
addr : uint32;
cmd : uint32;
begin
push_trace('PCI.enableDevice');
addr := ($1 shl 31);
addr := addr or (bus shl 16);
addr := addr or ((slot) shl 11);
addr := addr or ((func) shl 8);
addr := addr or ($04 and $FC);
outl(PCI_CONFIG_ADDRESS_PORT, addr);
cmd := inl(PCI_CONFIG_DATA_PORT);
cmd := cmd or PCI_COMMAND_MEM_SPACE;
cmd := cmd or PCI_COMMAND_BUS_MASTER;
//enable interrupts, remove disable interrupt bit
cmd := cmd and not PCI_COMMAND_INT_DISABLE;
outl(PCI_CONFIG_ADDRESS_PORT, addr);
outl(PCI_CONFIG_DATA_PORT, cmd);
pop_trace;
end;
end. end.

View File

@ -21,6 +21,23 @@ unit drivertypes;
interface interface
const
PCI_CONFIG_ADDRESS_PORT = $0CF8;
PCI_CONFIG_DATA_PORT = $0CFC;
PCI_COMMAND_IO_SPACE = $0001;
PCI_COMMAND_MEM_SPACE = $0002;
PCI_COMMAND_BUS_MASTER = $0004;
PCI_COMMAND_SPECIAL_CYC = $0008;
PCI_COMMAND_MEM_WRITE = $0010;
PCI_COMMAND_VGA_PALETTE = $0020;
PCI_COMMAND_PARITY = $0040;
PCI_COMMAND_WAIT = $0080;
PCI_COMMAND_SERR = $0100;
PCI_COMMAND_FAST_BACK = $0200;
PCI_COMMAND_INT_DISABLE = $0400;
PCI_COMMAND_SERR_ENABLE = $8000;
type type
PPCI_Device = ^TPCI_Device; PPCI_Device = ^TPCI_Device;
@ -44,6 +61,7 @@ type
address1 : uint32; address1 : uint32;
address2 : uint32; address2 : uint32;
address3 : uint32; address3 : uint32;
address4 : uint32; address4 : uint32;
address5 : uint32; address5 : uint32;
CIS_pointer : uint32; CIS_pointer : uint32;

View File

@ -31,7 +31,9 @@ uses
console, console,
vmemorymanager, vmemorymanager,
AHCITypes, AHCITypes,
lists; lists,
idetypes,
isrmanager;
var var
ahciControllers : PDList; ahciControllers : PDList;
@ -39,6 +41,9 @@ var
procedure init(); procedure init();
function load(ptr : void) : boolean; function load(ptr : void) : boolean;
procedure check_ports(controller : PAHCI_Controller);
procedure identify_device(controller : PAHCI_Controller; port : uint32);
procedure ahci_isr();
implementation implementation
@ -60,44 +65,76 @@ end;
procedure stop_port(port : PHBA_Port); procedure stop_port(port : PHBA_Port);
begin begin
port^.cmd_sts := port^.cmd_sts and not $1; ///maybe also bit 4 port^.cmd := port^.cmd and not $1; ///maybe also bit 4
while (port^.cmd_sts and $1) = 1 do begin while (port^.cmd and $1) = 1 do begin
//wait for the port to stop //wait for the port to stop
end; end;
end; end;
procedure start_port(port : PHBA_Port); procedure start_port(port : PHBA_Port);
begin begin
port^.cmd_sts := port^.cmd_sts or $1; ///maybe also bit 4 port^.cmd := port^.cmd or $1; ///maybe also bit 4
while (port^.cmd_sts and $1) = 0 do begin while (port^.cmd and $1) = 0 do begin
//wait for the port to start //wait for the port to start
end; end;
end; end;
{ {
Check the ports on the controller and setup the command list, FIS, and command table Check the ports on the controller and setup the command list, FIS, and command table
} }
procedure check_ports(controller : PAHCI_Controller); procedure check_ports(controller : PAHCI_Controller);
var var
i : uint32; i : uint32;
ii : uint32;
port : PHBA_Port; port : PHBA_Port;
device : PAHCI_Device; device : PAHCI_Device;
cmd_list_base : puint32; cmd_list_base : puint32;
fis_base : puint32; fis_base : puint32;
cmd_table_base : puint32; cmd_table_base : puint32;
cmd_header : PHBA_CMD_HEADER; command_header : PHBA_CMD_HEADER;
begin begin
console.writestring('AHCI: active ports: ');
console.writehexln(controller^.mio^.ports_implimented);
for i:=0 to 31 do begin for i:=0 to 31 do begin
if (controller^.mio^.port_implemented shr i) = 1 then begin if (controller^.mio^.ports_implimented shr i) = 1 then begin
port := @controller^.mio^.ports[i]; port := @controller^.mio^.ports[i];
console.writestring('AHCI: Port '); console.writestring('AHCI: Port ');
console.writeint(i); console.writeint(i);
console.writestring(' implemented on controller '); console.writestring(' implemented on controller ');
console.writehexln(uint32(controller^.pci_device^.address5)); console.writehexln(uint32(controller^.pci_device^.address5));
//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
// end;
console.writestring('AHCI: signature: ');
console.writehexln(port^.signature);
//check device type
case port^.signature of
SATA_SIG_ATA: begin
console.writestringln('AHCI: Device is SATA');
device^.device_type := SATA;
end;
SATA_SIG_ATAPI: begin
console.writestringln('AHCI: Device is ATAPI');
device^.device_type := ATAPI;
end;
SATA_SIG_SEMB: begin
console.writestringln('AHCI: Device is SEMB');
device^.device_type := SEMB;
end;
SATA_SIG_PM: begin
console.writestringln('AHCI: Device is PM');
device^.device_type := PM;
end;
end;
//NEEED TO STOP the port before doing anything //NEEED TO STOP the port before doing anything
stop_port(port);
device := PAHCI_Device(DL_Add(controller^.devices)); device := PAHCI_Device(DL_Add(controller^.devices));
device^.port := port; device^.port := port;
@ -111,16 +148,16 @@ begin
fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00); fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00);
//set the command list base address //set the command list base address
port^.cmd_list_base := uint32(vtop(cmd_list_base)); //todo set virtual address in device port^.cmdl_basel := vtop(uint32(cmd_list_base)); //todo set virtual address in device
port^.cmd_list_base_upper := 0; port^.cmdl_baseu := 0;
memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER)); memset(uint32(cmd_list_base), 0, sizeof(THBA_CMD_HEADER));
device^.command_list := PHBA_CMD_HEADER(cmd_list_base); device^.command_list := PHBA_CMD_HEADER(cmd_list_base);
//set the FIS base address //set the FIS base address
port^.fis_base := uint32(vtop(fis_base)); port^.fis_basel := vtop(uint32(fis_base));
port^.fis_base_upper := 0; port^.fis_baseu := 0;
memset(uint32(fis_base), 0, sizeof(THBA_FIS)); memset(uint32(fis_base), 0, sizeof(THBA_FIS));
@ -134,32 +171,96 @@ begin
device^.command_table := PHBA_CMD_TABLE(cmd_table_base); device^.command_table := PHBA_CMD_TABLE(cmd_table_base);
//set the command table base address and setup command table //set the command table base address and setup command table
for i:=0 to 31 do begin for ii:=0 to 31 do begin
//set command header locations //set command header locations
command_header := PHBA_CMD_HEADER(uint32(cmd_list_base) + (i * sizeof(THBA_CMD_HEADER))); command_header := PHBA_CMD_HEADER(uint32(cmd_list_base) + (ii * sizeof(THBA_CMD_HEADER)));
command_header^.prdtl := 32; command_header^.prdtl := 32;
//TODO do i need to set prdbc byte count here? //TODO do i need to set prdbc byte count here?
command_header^.cmd_table_base := uint32(vtop(cmd_table_base) + (i * sizeof(THBA_CMD_TABLE)); command_header^.cmd_table_base := vtop(uint32(cmd_table_base)) + (ii * sizeof(THBA_CMD_TABLE));
command_header^.cmd_table_base_upper := 0; command_header^.cmd_table_baseu := 0;
memset(uint32(cmd_table_base) + (i * sizeof(THBA_CMD_TABLE)), 0, sizeof(THBA_CMD_TABLE)); memset(uint32(cmd_table_base) + (ii * sizeof(THBA_CMD_TABLE)), 0, sizeof(THBA_CMD_TABLE));
end; end;
start_port(port); start_port(port);
//pass devices count as second param
identify_device(controller, DL_Size(controller^.devices) - 1);
end; end;
end; end;
end;
procedure identify_device(controller : PAHCI_Controller; port : uint32);
var
fis : PHBA_FIS_REG_H2D;
cmd_header : PHBA_CMD_HEADER;
cmd_table : PHBA_CMD_TABLE;
cmd : uint32;
i : uint32;
buffer :puint32;
device : PAHCI_Device;
begin
device := PAHCI_Device(DL_Get(controller^.devices, port));
buffer := kalloc(512);
memset(uint32(buffer), 0, 512);
cmd_header := device^.command_list;
cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32);
cmd_header^.wrt := 0;
cmd_header^.prdtl := 1;
//just use first command table for identify as no other commands are running
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;
fis := PHBA_FIS_REG_H2D(@device^.command_table^.cmd_fis);
fis^.fis_type := uint8(FIS_TYPE_REG_H2D);
fis^.pmport := 0;
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;
//send the command
cmd := device^.port^.cmd;
cmd := cmd or $1;
device^.port^.cmd := cmd;
//wait for the command to complete
while (cmd and $1) = 1 do begin
cmd := device^.port^.cmd;
end;
//check the status of the command
if (cmd and $2) = 1 then begin
console.writestringln('AHCI: Error sending identify command');
end;
//parse the identify data
for i:=0 to 63 do begin
console.writehex(uint32(buffer[i]));
console.writestring(' ');
end;
console.writestringln('');
end; end;
// procedure identify_device(controller : PAHCI_Controller; port : uint32);
// var
// fis : PFIS_REG_H2D;
// cmd : uint32;
// i : uint32;
// begin
// end;
function load(ptr : void) : boolean; function load(ptr : void) : boolean;
var var
device : PPCI_Device; device : PPCI_Device;
@ -169,6 +270,7 @@ var
cmd_list_base : puint32; cmd_list_base : puint32;
fis_base : puint32; fis_base : puint32;
cmd_table_base : puint32; cmd_table_base : puint32;
int_no : uInt8;
begin begin
console.writestringln('AHCI: initilizing a new controller'); console.writestringln('AHCI: initilizing a new controller');
@ -179,11 +281,18 @@ begin
device := PPCI_Device(ptr); device := PPCI_Device(ptr);
pci.enableDevice(device^.bus, device^.slot, device^.func);
int_no := device^.interrupt_line;
registerISR(int_no, @ahci_isr);
controller := PAHCI_Controller(DL_Add(ahciControllers)); controller := PAHCI_Controller(DL_Add(ahciControllers));
controller^.devices := DL_New(SizeOf(TAHCI_Device)); controller^.devices := DL_New(SizeOf(TAHCI_Device));
controller^.pci_device := PPCI_Device(device); controller^.pci_device := PPCI_Device(device);
// Perform BIOS/OS handoff (if the bit in the extended capabilities is set)
// Reset controller
//get the base address of the controller //get the base address of the controller
page_base := kpalloc(device^.address5); // TODO MEM memory manager need to be improved page_base := kpalloc(device^.address5); // TODO MEM memory manager need to be improved
@ -220,6 +329,13 @@ begin
// exit(true); // exit(true);
end; end;
procedure ahci_isr();
begin
console.writestringln('AHCI: ISR');
//welp there is no way to know what port caused the interrupt or even if it was the controller
//so we will just have to check all ports, and figure the operation that caused the interrupt
end;
end. end.

View File

@ -72,7 +72,7 @@ type
rsv0: uint32; // Reserved rsv0: uint32; // Reserved
tfd: uint32; // Task File Data tfd: uint32; // Task File Data
signature: uint32; // Signature signature: uint32; // Signature
sata_stat: uint32; // SATA Status (SCR0:SStatus) sata_status: uint32; // SATA Status (SCR0:SStatus)
sata_ctrl: uint32; // SATA Control (SCR2:SControl) sata_ctrl: uint32; // SATA Control (SCR2:SControl)
sata_error: uint32; // SATA Error (SCR1:SError) sata_error: uint32; // SATA Error (SCR1:SError)
sata_active: uint32; // SATA Active sata_active: uint32; // SATA Active
@ -111,7 +111,7 @@ type
{ {
AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface
This structure is used to access the AHCI HBA's FIS (Frame Information Structure) This structure is used to access the AHCI HBA's FIS (Frame Information Structure)
memory-mapped registers. memory-mapped registers. RX
} }
THBA_FIS = bitpacked record THBA_FIS = bitpacked record
dsfis: array[0..$1F] of uint32; // DMA Setup FIS dsfis: array[0..$1F] of uint32; // DMA Setup FIS
@ -127,15 +127,53 @@ type
PHBA_FIS = ^THBA_FIS; PHBA_FIS = ^THBA_FIS;
//enum fis type
TFISType = (
FIS_TYPE_REG_H2D = $27, // Register FIS - Host to Device
FIS_TYPE_REG_D2H = $34, // Register FIS - Device to Host
FIS_TYPE_DMA_ACT = $39, // DMA Activate FIS - Device to Host
FIS_TYPE_DMA_SETUP = $41, // DMA Setup FIS - Bidirectional
FIS_TYPE_DATA = $46, // Data FIS - Bidirectional
FIS_TYPE_BIST = $58, // BIST Activate FIS - Bidirectional
FIS_TYPE_PIO_SETUP = $5F, // PIO Setup FIS - Device to Host
FIS_TYPE_DEV_BITS = $A1 // Set Device Bits FIS - Device to Host
);
{
AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface
This structure is used to access the AHCI HBA's FIS (Frame Information Structure)
}
THBA_FIS_REG_H2D = bitpacked record
fis_type: uint8; // FIS Type
pmport: uint8; // Port Multiplier Port
command: uint8; // Command
featurel: uint8; // Feature Lower 8-bits
lba0: uint8; // LBA0
lba1: uint8; // LBA1
lba2: uint8; // LBA2
device: uint8; // Device
lba3: uint8; // LBA3
lba4: uint8; // LBA4
lba5: uint8; // LBA5
featureh: uint8; // Feature Upper 8-bits
countl: uint8; // Count Lower 8-bits
counth: uint8; // Count Upper 8-bits
icc: uint8; // Isochronous Command Completion
control: uint8; // Control
rsv0: array[0..2] of uint8;
end;
PHBA_FIS_REG_H2D = ^THBA_FIS_REG_H2D;
{ {
AHCI Host Bus Adapter (HBA) Command Header Interface AHCI Host Bus Adapter (HBA) Command Header Interface
This structure is used to access the AHCI HBA's Command Header memory-mapped
registers.
} }
THBA_CMD_HEADER = bitpacked record THBA_CMD_HEADER = bitpacked record
cmd_fis_length: uint8; // Command FIS Length cmd_fis_length: uint8; // Command FIS Length
atapi: uint8; // ATAPI atapi: uint8; // ATAPI
write: uint8; // Write wrt: uint8; // Write
prefetchable: uint8; // Prefetchable prefetchable: uint8; // Prefetchable
reset: uint8; // Reset reset: uint8; // Reset
bist: uint8; // BIST bist: uint8; // BIST
@ -152,14 +190,28 @@ type
{ {
AHCI Host Bus Adapter (HBA) Command Table Interface AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped }
registers. The AHCI HBA's Command Table memory-mapped registers are used to THBA_PRD = bitpacked record
configure the HBA and to issue commands to the SATA devices connected to the HBA. dba: uint32; // Data Base Address
dbau: uint32; // Data Base Address Upper 32-bits
rsv0: uint32; // Reserved
reserved: ubit9; // Reserved
dbc: ubit22; // Data Byte Count
int: ubit1; // Interrupt
// dbc: uint32; // Data Byte Count, bit 1 is Interrupt, then 22 bits of Byte Count, then 9 bits of Reserved
end;
TPRDT = array[0..31] of THBA_PRD;
PPRDT = ^TPRDT;
{
AHCI Host Bus Adapter (HBA) Command Table Interface
} }
THBA_CMD_TABLE = bitpacked record THBA_CMD_TABLE = bitpacked record
cmd_fis: THBA_FIS; // Command FIS cmd_fis: array[0..63] of uint8; // Command FIS
acmd: array[0..$1F] of uint8; // ATAPI Command acmd: array[0..15] of uint8; // ATAPI Command
rsv0: array[0..$30] of uint8; rsv0: array[0..47] of uint8;
prdt: TPRDT; // Physical Region Descriptor Table
end; end;
PHBA_CMD_TABLE = ^THBA_CMD_TABLE; PHBA_CMD_TABLE = ^THBA_CMD_TABLE;
@ -167,42 +219,6 @@ type
TCMD_LIST = array[0..255] of THBA_CMD_HEADER; TCMD_LIST = array[0..255] of THBA_CMD_HEADER;
PCMD_LIST = ^TCMD_LIST; PCMD_LIST = ^TCMD_LIST;
{
AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers.
}
THBA_PRD = bitpacked record
dba: uint32; // Data Base Address
dbau: uint32; // Data Base Address Upper 32-bits
rsv0: uint32; // Reserved
dbc: uint32; // Data Byte Count
rsv1: uint32; // Reserved
end;
{
AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers.
}
THBA_CMD = bitpacked record
header: THBA_CMD_HEADER; // Command Header
table: THBA_CMD_TABLE; // Command Table
prd: array[0..31] of THBA_PRD; // Physical Region Descriptor Table
end;
{
AHCI Host Bus Adapter (HBA) Command Table Interface
This structure is used to access the AHCI HBA's Command Table memory-mapped
registers.
}
THBA = bitpacked record
memory: THBA_Memory; // HBA Memory
cmd: array[0..$7FF] of THBA_CMD; // Command List
end;
PHBA = ^THBA;
////////////////////////////////////////// //////////////////////////////////////////
//////////// Asuro AHCI types //////////// //////////// Asuro AHCI types ////////////
////////////////////////////////////////// //////////////////////////////////////////