diff --git a/src/driver/bus/PCI.pas b/src/driver/bus/PCI.pas index f07fcd4f..a645382c 100644 --- a/src/driver/bus/PCI.pas +++ b/src/driver/bus/PCI.pas @@ -463,9 +463,9 @@ begin cmd := cmd or PCI_COMMAND_BUS_MASTER; cmd := cmd or (3 shl 1); - //enable interrupts, remove disable interrupt bit + //enable interrupts, remove disable interrupt bit maybe cmd := cmd and not PCI_COMMAND_INT_DISABLE; - cmd := cmd and not (1 shl 9); + // cmd := cmd and not (1 shl 9); outl(PCI_CONFIG_ADDRESS_PORT, addr); outl(PCI_CONFIG_DATA_PORT, cmd); diff --git a/src/driver/include/drivertypes.pas b/src/driver/include/drivertypes.pas index d03c9f6a..443c58cd 100644 --- a/src/driver/include/drivertypes.pas +++ b/src/driver/include/drivertypes.pas @@ -38,6 +38,12 @@ const PCI_COMMAND_INT_DISABLE = $0400; PCI_COMMAND_SERR_ENABLE = $8000; + PCI_CAP_ID_MSI = $05; + + // Bits in the MSI Control register (16-bit): + MSI_CONTROL_ENABLE = 1 shl 0; // Bit 0 + MSI_CONTROL_64BIT = 1 shl 7; // Bit 7 + MSI_CONTROL_PVMASK = 1 shl 8; // Bit 8 (optional: per-vector masking) type PPCI_Device = ^TPCI_Device; diff --git a/src/driver/storage/AHCI/AHCI.pas b/src/driver/storage/AHCI/AHCI.pas index f688d2c1..0f7d7058 100644 --- a/src/driver/storage/AHCI/AHCI.pas +++ b/src/driver/storage/AHCI/AHCI.pas @@ -42,8 +42,13 @@ var procedure init(); function load(ptr : void) : boolean; procedure check_ports(controller : PAHCI_Controller); -procedure identify_device(controller : PAHCI_Controller; portIndex : uint32); +procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean); procedure ahci_isr(); +function find_cmd_slot(device : PAHCI_Device) : uint32; +function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; +// function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; +function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; +function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; implementation @@ -142,7 +147,7 @@ begin console.writestring(' implemented on controller '); console.writehexln(uint32(controller^.pci_device^.address5)); - device := PAHCI_Device(DL_Add(controller^.devices)); + device := PAHCI_Device(@controller^.devices[i]); device^.port := port; //check if the port is active TODO @@ -230,9 +235,13 @@ begin console.writestring('AHCI: sata status: '); console.writehexln(port^.sata_status); - //pass devices count as second param + // //pass devices count as second param if (device^.device_type = SATA) then begin - identify_device(controller, DL_Size(controller^.devices) - 1); + identify_device(controller, i, false); + end else if (device^.device_type = ATAPI) then begin + identify_device(controller, i, true); + end else begin + console.writestringln('AHCI: Unsupported device type'); end; controller^.mio^.int_status := $FFFFFFFF; @@ -242,7 +251,7 @@ begin end; end; -procedure identify_device(controller : PAHCI_Controller; portIndex : uint32); +procedure identify_device(controller : PAHCI_Controller; portIndex : uint32; isATAPI : boolean); var fis : PHBA_FIS_REG_H2D; cmd_header : PHBA_CMD_HEADER; @@ -255,18 +264,23 @@ var sec_count : uint32; b8 : puint16; begin - console.writestringln('AHCI: Identifying device'); - device := PAHCI_Device(DL_Get(controller^.devices, portIndex)); + console.writestring('AHCI: Identifying device '); + console.writeintln(portIndex); + device := PAHCI_Device(@controller^.devices[portIndex]); // (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); + console.writestring('AHCI: signature: '); + console.writehexln(device^.port^.signature); + console.writestring('AHCI: device type: '); + console.writeintln(uint32(device^.device_type)); //clear any pending interrupts - device^.port^.int_status := $FFFFFFFF; - device^.port^.int_enable := 0; + device^.port^.int_status := $0; + device^.port^.int_enable := $FFFFFFFF; // Allocate a 512-byte DMA buffer for the IDENTIFY data buffer := kalloc(512); @@ -279,6 +293,9 @@ begin cmd_header^.wrt := 0; cmd_header^.prdtl := 1; cmd_header^.clear_busy := 1; + if isATAPI then begin + cmd_header^.atapi := 1; + end; // Setup the command table (using slot 0) @@ -287,18 +304,27 @@ begin cmd_table^.prdt[0].dbc := 511; // 512 bytes (0-based count) cmd_table^.prdt[0].int := 1; // Interrupt on completion + if isATAPI then begin + // ATAPI Identify Device command + buffer[0] := $A1; // ATAPI Identify Device + end; + // 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^.c := $1; - fis^.command := ATA_CMD_IDENTIFY; + if isATAPI then begin + fis^.command := ATA_CMD_IDENTIFY_PACKET; + end else begin + fis^.command := ATA_CMD_IDENTIFY; + end; fis^.device := $A0; // LBA mode 40? //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); + // console.writestring('AHCI: tfd: '); + // console.writehexln(device^.port^.tfd); end; // Issue the command by setting bit 0 in the port's Command Issue register. @@ -356,6 +382,25 @@ begin console.writestringln(''); + + buffer := puint32(kalloc(512)); + memset(uint32(buffer), 0, 512); + + //send a read DMA command to the device + if isATAPI then begin + read_atapi(device, 16, 512, buffer); + end else begin + send_read_dma(device, 10, 512, buffer); + end; + + //print the buffer + for i:=0 to 63 do begin + console.writehex(uint32(buffer[i])); + console.writestring(' '); + end; + console.writestringln(''); + + end; @@ -382,7 +427,8 @@ begin device := PPCI_Device(ptr); pci.enableDevice(device^.bus, device^.slot, device^.func); - int_no := device^.interrupt_line; + psleep(5); + int_no := device^.interrupt_line + 32; //print interrupt number @@ -390,7 +436,6 @@ begin console.writehexln(int_no); controller := PAHCI_Controller(DL_Add(ahciControllers)); - controller^.devices := DL_New(SizeOf(TAHCI_Device)); controller^.pci_device := PPCI_Device(device); @@ -438,41 +483,382 @@ begin 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 + // base^.global_ctrl := base^.global_ctrl or $2; //enable interrupts + //disable interrupts + base^.global_ctrl := base^.global_ctrl or $2; //clear any pending interrupts base^.int_status := $FFFFFFFF; check_ports(controller); - - - - - // 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 ahci_isr(); begin console.writestringln('AHCI: ISR'); + console.redrawWindows(); //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; +function find_cmd_slot(device : PAHCI_Device) : uint32; +var + i : uint32; +begin + // for i:=0 to 31 do begin + // if (device^.port^.cmd_issue[i] and $80000000) = 0 then begin + // exit(i); + // end; + // end; + exit(0); +end; + +function send_read_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; +var + fis : PHBA_FIS_REG_H2D; + cmd_header : PHBA_CMD_HEADER; + cmd_table : PHBA_CMD_TABLE; + cmd : uint32; + i, timeout : uint32; + tfd : uint32; + sec_count : uint32; + prdt_count : uint32; + b8 : puint16; + slot : uint32; +begin + console.writestringln('AHCI: Sending read DMA command'); + + reset_port(device^.port); + start_port(device^.port); + + //prdt count is 22 bits + prdt_count := (count div 4194304) + 1; + + if prdt_count > 32 then begin + send_read_dma := false; + exit; + end; + + // Use command slot 0 for the IDENTIFY command. + slot := find_cmd_slot(device); + cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER))); + cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32); + cmd_header^.wrt := 0; + cmd_header^.prdtl := prdt_count; + cmd_header^.clear_busy := 1; + + // Setup the command table (using slot 0) + cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE))); + + for i:=0 to prdt_count - 1 do begin + cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304)); + + if i = prdt_count - 1 then begin + cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count) + end else begin + cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count) + end; + + cmd_table^.prdt[i].int := 1; // Interrupt on completion + end; + + // Construct the Command FIS in the command table's CFIS area + fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis); + memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D)); + fis^.fis_type := uint8(FIS_TYPE_REG_H2D); + fis^.c := $1; + fis^.command := ATA_CMD_READ_DMA_EXT; + fis^.device := $40; // LBA mode 48? + + fis^.lba0 := lba and $FF; + fis^.lba1 := (lba shr 8) and $FF; + fis^.lba2 := (lba shr 16) and $FF; + fis^.lba3 := (lba shr 24) and $FF; + fis^.lba4 := (lba shr 32) and $FF; + + fis^.countl := count and $FF; + fis^.counth := (count shr 8) and $FF; + + //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 shl slot); + device^.port^.cmd_issue := cmd; + + console.writestringln('AHCI: Sent read DMA 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: Read DMA 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; + + until ((device^.port^.cmd_issue and (1 shl slot)) = 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 (1 shl slot)) <> 0 then begin + console.writestringln('AHCI: Error sending read DMA command'); + + // Check the error register for more information + console.writestring('AHCI: Error register: '); + console.writehexln(device^.port^.sata_error); + end; + + send_read_dma := true; +end; + +function send_write_dma(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; +var + fis : PHBA_FIS_REG_H2D; + cmd_header : PHBA_CMD_HEADER; + cmd_table : PHBA_CMD_TABLE; + cmd : uint32; + i, timeout : uint32; + tfd : uint32; + sec_count : uint32; + prdt_count : uint32; + b8 : puint16; + slot : uint32; +begin + console.writestringln('AHCI: Sending write DMA command'); + + reset_port(device^.port); + start_port(device^.port); + + //prdt count is 22 bits + prdt_count := (count div 4194304) + 1; + + if prdt_count > 32 then begin + send_write_dma := false; + exit; + end; + + // Use command slot 0 for the IDENTIFY command. + slot := find_cmd_slot(device); + cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER))); + cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32); + cmd_header^.wrt := 1; + cmd_header^.prdtl := prdt_count; + cmd_header^.clear_busy := 1; + + // Setup the command table (using slot 0) + cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE))); + + for i:=0 to prdt_count - 1 do begin + cmd_table^.prdt[i].dba := vtop(uint32(buffer) + (i * 4194304)); + + if i = prdt_count - 1 then begin + cmd_table^.prdt[i].dbc := count - (i * 4194304) - 1; // 512 bytes (0-based count) + end else begin + cmd_table^.prdt[i].dbc := 4194304 - 1; // 512 bytes (0-based count) + end; + + cmd_table^.prdt[i].int := 1; // Interrupt on completion + end; + + // Construct the Command FIS in the command table's CFIS area + fis := PHBA_FIS_REG_H2D(@cmd_table^.cmd_fis); + memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D)); + fis^.fis_type := uint8(FIS_TYPE_REG_H2D); + fis^.c := $1; + fis^.command := ATA_CMD_WRITE_DMA_EXT; + fis^.device := $40; // LBA mode 48? + + fis^.lba0 := lba and $FF; + fis^.lba1 := ( + lba shr 8) and $FF; + fis^.lba2 := ( + lba shr 16) and $FF; + fis^.lba3 := ( + lba shr 24) and $FF; + fis^.lba4 := ( + lba shr 32) and $FF; + + fis^.countl := count and $FF; + fis^.counth := ( + count shr 8) and $FF; + + //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 shl slot); + device^.port^.cmd_issue := cmd; + + console.writestringln('AHCI: Sent write DMA 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: Write DMA 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; + + until ((device^.port^.cmd_issue and (1 shl slot)) = 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 (1 shl slot)) <> 0 then begin + console.writestringln('AHCI: Error sending write DMA command'); + + // Check the error register for more information + console.writestring('AHCI: Error register: '); + console.writehexln(device^.port^.sata_error); + end; + + send_write_dma := true; +end; + +//read atapi +function read_atapi(device : PAHCI_Device; lba : uint64; count : uint32; buffer : puint32) : boolean; +var + fis : PHBA_FIS_REG_H2D; + cmd_header : PHBA_CMD_HEADER; + cmd_table : PHBA_CMD_TABLE; + cmd : uint32; + i, timeout : uint32; + tfd : uint32; + sec_count : uint32; + prdt_count : uint32; + b8 : puint16; + slot : uint32; +begin + console.writestringln('AHCI: Sending read ATAPI command'); + + reset_port(device^.port); + start_port(device^.port); + + //prdt count is 22 bits + prdt_count := (count div 4194304) + 1; + + if prdt_count > 32 then begin + read_atapi := false; + exit; + end; + + // Use command slot 0 for the IDENTIFY command. + slot := find_cmd_slot(device); + cmd_header := PHBA_CMD_HEADER(uint32(device^.command_list) + (slot * sizeof(THBA_CMD_HEADER))); + cmd_header^.cmd_fis_length := sizeof(THBA_FIS_REG_H2D) div sizeof(uint32); + cmd_header^.wrt := 0; + cmd_header^.prdtl := 1; + cmd_header^.atapi := 1; + + // Setup the command table (using slot 0) + cmd_table := PHBA_CMD_TABLE(uint32(device^.command_table) + (slot * sizeof(THBA_CMD_TABLE))); + + cmd_table^.prdt[0].dba := vtop(uint32(buffer)); + cmd_table^.prdt[0].dbc := 512 - 1; // 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(@cmd_table^.cmd_fis); + memset(uint32(fis), 0, sizeof(THBA_FIS_REG_H2D)); + fis^.fis_type := uint8(FIS_TYPE_REG_H2D); + fis^.c := $1; + fis^.command := ATA_CMD_PACKET; + fis^.device := $A0; // LBA mode 48? + + fis^.featurel := fis^.featurel or 1; //setting both of these might not work on real hardware + fis^.featurel := fis^.featurel or (1 shl 2); + + cmd_table^.acmd[0] := $A8; //ATAPI command + cmd_table^.acmd[1] := $0; //ATAPI command + + cmd_table^.acmd[2] := uInt8((lba shr 24) and $FF); + cmd_table^.acmd[3] := uInt8((lba shr 16) and $FF); + cmd_table^.acmd[4] := uInt8((lba shr 8) and $FF); + cmd_table^.acmd[5] := uInt8(lba and $FF); + + cmd_table^.acmd[9] := uInt8((1) and $FF); + + + //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 shl slot); + device^.port^.cmd_issue := cmd; + + console.writestringln('AHCI: Sent read ATAPI 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: Read ATAPI 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; + + until ((device^.port^.cmd_issue and (1 shl slot)) = 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 (1 shl slot)) <> 0 then begin + console.writestringln('AHCI: Error sending read ATAPI command'); + + // Check the error register for more information + console.writestring('AHCI: Error register: '); + console.writehexln(device^.port^.sata_error); + end; + + read_atapi := true; + +end; + + + end. diff --git a/src/driver/storage/AHCI/AHCITypes.pas b/src/driver/storage/AHCI/AHCITypes.pas index 52186c84..ecd36a61 100644 --- a/src/driver/storage/AHCI/AHCITypes.pas +++ b/src/driver/storage/AHCI/AHCITypes.pas @@ -269,7 +269,7 @@ type pci_device : PPCI_Device; mio: PHBA_Memory; ata_info : TIdentResponse; - devices : PDList; + devices : array[0..31] of TAHCI_Device; end; PAHCI_Controller = ^TAHCI_Controller;