From f04f8aa411a4d491267356bdbf94252162467f7d Mon Sep 17 00:00:00 2001 From: Aaron Date: Sun, 16 Mar 2025 21:39:47 +0000 Subject: [PATCH] there you go ki-ear-ron --- src/driver/bus/PCI.pas | 29 +++++ src/driver/include/drivertypes.pas | 18 +++ src/driver/storage/AHCI/AHCI.pas | 168 ++++++++++++++++++++++---- src/driver/storage/AHCI/AHCITypes.pas | 110 ++++++++++------- 4 files changed, 252 insertions(+), 73 deletions(-) diff --git a/src/driver/bus/PCI.pas b/src/driver/bus/PCI.pas index 9a6618ec..13439b68 100644 --- a/src/driver/bus/PCI.pas +++ b/src/driver/bus/PCI.pas @@ -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 writeConfig(bus: uint8; slot : uint8; func : uint8; row : uint8; val : uint32); procedure setBusMaster(bus : uint8; slot : uint8; func : uint8; master : boolean); +procedure enableDevice(bus : uint8; slot : uint8; func : uint8); implementation @@ -442,4 +443,32 @@ begin pop_trace; 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. \ No newline at end of file diff --git a/src/driver/include/drivertypes.pas b/src/driver/include/drivertypes.pas index 9bc8f701..d03c9f6a 100644 --- a/src/driver/include/drivertypes.pas +++ b/src/driver/include/drivertypes.pas @@ -21,6 +21,23 @@ unit drivertypes; 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 PPCI_Device = ^TPCI_Device; @@ -44,6 +61,7 @@ type address1 : uint32; address2 : uint32; address3 : uint32; + address4 : uint32; address5 : uint32; CIS_pointer : uint32; diff --git a/src/driver/storage/AHCI/AHCI.pas b/src/driver/storage/AHCI/AHCI.pas index ab62ac25..f4cb8e6f 100644 --- a/src/driver/storage/AHCI/AHCI.pas +++ b/src/driver/storage/AHCI/AHCI.pas @@ -31,7 +31,9 @@ uses console, vmemorymanager, AHCITypes, - lists; + lists, + idetypes, + isrmanager; var ahciControllers : PDList; @@ -39,6 +41,9 @@ var procedure init(); function load(ptr : void) : boolean; +procedure check_ports(controller : PAHCI_Controller); +procedure identify_device(controller : PAHCI_Controller; port : uint32); +procedure ahci_isr(); implementation @@ -60,44 +65,76 @@ end; procedure stop_port(port : PHBA_Port); begin - port^.cmd_sts := port^.cmd_sts and not $1; ///maybe also bit 4 - while (port^.cmd_sts and $1) = 1 do begin + port^.cmd := port^.cmd and not $1; ///maybe also bit 4 + while (port^.cmd and $1) = 1 do begin //wait for the port to stop end; end; procedure start_port(port : PHBA_Port); begin - port^.cmd_sts := port^.cmd_sts or $1; ///maybe also bit 4 - while (port^.cmd_sts and $1) = 0 do 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 end; end; - { Check the ports on the controller and setup the command list, FIS, and command table } procedure check_ports(controller : PAHCI_Controller); var i : uint32; + ii : uint32; port : PHBA_Port; device : PAHCI_Device; cmd_list_base : puint32; fis_base : puint32; cmd_table_base : puint32; - cmd_header : PHBA_CMD_HEADER; + command_header : PHBA_CMD_HEADER; begin + console.writestring('AHCI: active ports: '); + console.writehexln(controller^.mio^.ports_implimented); + 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]; console.writestring('AHCI: Port '); console.writeint(i); console.writestring(' implemented on controller '); 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 + stop_port(port); device := PAHCI_Device(DL_Add(controller^.devices)); device^.port := port; @@ -111,16 +148,16 @@ begin fis_base := puint32((uint32(fis_base) + 255) and $FFFFFF00); //set the command list base address - port^.cmd_list_base := uint32(vtop(cmd_list_base)); //todo set virtual address in device - port^.cmd_list_base_upper := 0; + 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); //set the FIS base address - port^.fis_base := uint32(vtop(fis_base)); - port^.fis_base_upper := 0; + port^.fis_basel := vtop(uint32(fis_base)); + port^.fis_baseu := 0; memset(uint32(fis_base), 0, sizeof(THBA_FIS)); @@ -134,32 +171,96 @@ begin device^.command_table := PHBA_CMD_TABLE(cmd_table_base); //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 - 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; //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_upper := 0; - memset(uint32(cmd_table_base) + (i * sizeof(THBA_CMD_TABLE)), 0, sizeof(THBA_CMD_TABLE)); + 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; start_port(port); + + //pass devices count as second param + identify_device(controller, DL_Size(controller^.devices) - 1); 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; -// procedure identify_device(controller : PAHCI_Controller; port : uint32); -// var -// fis : PFIS_REG_H2D; -// cmd : uint32; -// i : uint32; -// begin -// end; - function load(ptr : void) : boolean; var device : PPCI_Device; @@ -169,6 +270,7 @@ var cmd_list_base : puint32; fis_base : puint32; cmd_table_base : puint32; + int_no : uInt8; begin console.writestringln('AHCI: initilizing a new controller'); @@ -179,11 +281,18 @@ begin 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^.devices := DL_New(SizeOf(TAHCI_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 page_base := kpalloc(device^.address5); // TODO MEM memory manager need to be improved @@ -220,6 +329,13 @@ begin // exit(true); 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. diff --git a/src/driver/storage/AHCI/AHCITypes.pas b/src/driver/storage/AHCI/AHCITypes.pas index dfce51c5..8a699cc5 100644 --- a/src/driver/storage/AHCI/AHCITypes.pas +++ b/src/driver/storage/AHCI/AHCITypes.pas @@ -72,7 +72,7 @@ type rsv0: uint32; // Reserved tfd: uint32; // Task File Data 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_error: uint32; // SATA Error (SCR1:SError) sata_active: uint32; // SATA Active @@ -111,7 +111,7 @@ type { AHCI Host Bus Adapter (HBA) FIS (Frame Information Structure) Interface 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 dsfis: array[0..$1F] of uint32; // DMA Setup FIS @@ -127,15 +127,53 @@ type 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 - This structure is used to access the AHCI HBA's Command Header memory-mapped - registers. } THBA_CMD_HEADER = bitpacked record cmd_fis_length: uint8; // Command FIS Length atapi: uint8; // ATAPI - write: uint8; // Write + wrt: uint8; // Write prefetchable: uint8; // Prefetchable reset: uint8; // Reset bist: uint8; // BIST @@ -152,14 +190,28 @@ type { 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 - configure the HBA and to issue commands to the SATA devices connected to the HBA. + } + THBA_PRD = bitpacked record + 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 - cmd_fis: THBA_FIS; // Command FIS - acmd: array[0..$1F] of uint8; // ATAPI Command - rsv0: array[0..$30] of uint8; + 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 end; PHBA_CMD_TABLE = ^THBA_CMD_TABLE; @@ -167,42 +219,6 @@ type TCMD_LIST = array[0..255] of THBA_CMD_HEADER; 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 //////////// //////////////////////////////////////////