diff --git a/inc/drivers/ahci.h b/inc/drivers/ahci.h index 4102daf..2931f0b 100644 --- a/inc/drivers/ahci.h +++ b/inc/drivers/ahci.h @@ -6,19 +6,24 @@ #include "utils/stdtypes.h" #include "drivers/pci.h" -#define SATA_SIG_ATA 0x00000101 -#define SATA_SIG_ATAPI 0xEB140101 -#define SATA_SIG_SEMB 0xC33C0101 -#define SATA_SIG_PORT_MULTIPLIER 0x96690101 +#define SATA_SIG_ATA 0x00000101 +#define SATA_SIG_ATAPI 0xEB140101 +#define SATA_SIG_SEMB 0xC33C0101 +#define SATA_SIG_PORT_MULTIPLIER 0x96690101 -#define ATA_DEVICE_BUSY 0x80 -#define ATA_DEVICE_DRQ 0x08 -#define ATA_CMD_READ_DMA_EX 0x25 -#define ATA_CMD_WRITE_DMA_EX 0x35 +#define ATA_DEVICE_BUSY 0x80 +#define ATA_DEVICE_DRQ 0x08 +#define ATA_CMD_READ_DMA_EX 0x25 +#define ATA_CMD_WRITE_DMA_EX 0x35 -#define HBA_PX_IS_TFES (1 << 30) -#define HBA_PORT_DEVICE_PRESENT 0x03 -#define HBA_PORT_IPM_ACTIVE 0x01 +#define HBA_PX_IS_TFES (1 << 30) +#define HBA_PX_COMMAND_CMD_LIST_RUNNING 0x8000 +#define HBA_PX_COMMAND_START 0x0001 +#define HBA_PX_COMMAND_FIS_RECV_ENABLE 0x0010 +#define HBA_PX_COMMAND_FIS_RECV_RUNNING 0x4000 + +#define HBA_PORT_DEVICE_PRESENT 0x03 +#define HBA_PORT_IPM_ACTIVE 0x01 typedef enum { AHCI_DEVICE_NONE, @@ -169,11 +174,33 @@ typedef struct { ahci_hba_port_T ports [1]; } ahci_hba_memory_T; +typedef struct { + uint8_t command_fis_length:5; + uint8_t atapi:1; + uint8_t write:1; + uint8_t prefetchable:1; + uint8_t reset:1; + uint8_t bist:1; + uint8_t clear_busy:1; + uint8_t reserved_0:1; + uint8_t port_multiplier:4; + uint16_t prdt_length; + uint32_t prdb_count; + uint32_t command_table_base_address; + uint32_t command_table_base_address_upper; + uint32_t reserved_1 [4]; +} ahci_hba_command_T; + + typedef struct { ahci_hba_port_T* hba_port; ahci_device_type_E type; uint8_t* buffer; uint8_t id; + + void* cmd_list_base; + void* fis_base; + void* command_tables [32]; } ahci_port_T; typedef struct { @@ -185,7 +212,10 @@ typedef struct { ahci_controller_T* ahci_controller_alloc (pci_device_T* pci_device); void ahci_controller_destruct (ahci_controller_T* controller); -void ahci_port_configure (ahci_port_T* port); +void ahci_port_init (ahci_port_T* port); +void ahci_port_destruct (ahci_port_T* port); +void ahci_port_command_stop (ahci_port_T* port); +void ahci_port_command_start (ahci_port_T* port); ahci_device_type_E ahci_port_get_type (ahci_hba_port_T* port); extern string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM]; diff --git a/src/drivers/ahci.c b/src/drivers/ahci.c index cd4eb60..54f2b44 100644 --- a/src/drivers/ahci.c +++ b/src/drivers/ahci.c @@ -4,6 +4,7 @@ #include "utils/memory.h" #include "utils/logger.h" #include "mm/page_map.h" +#include "mm/page_frame.h" string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM] = { "None", @@ -46,18 +47,75 @@ ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) { log(LOG_INFO, "AHCI devices:"); for (int i = 0; i < controller->num_ports; i++) { log(LOG_INFO, " %s", g_ahci_device_type_strings[controller->ports[i].type]); - ahci_port_configure(&controller->ports[i]); + ahci_port_init(&controller->ports[i]); } return controller; } void ahci_controller_destruct(ahci_controller_T* controller) { + for (int i = 0; i < controller->num_ports; i++) { + ahci_port_destruct(&controller->ports[i]); + } + + page_map_unmap_memory(g_kernel_page_map, controller->abar); + memory_free(controller); } -void ahci_port_configure(ahci_port_T* port) { +void ahci_port_init(ahci_port_T* port) { + ahci_port_command_stop(port); + port->cmd_list_base = pframe_request(); + port->fis_base = pframe_request(); + port->hba_port->command_list_base = (uint32_t)(uint64_t)port->cmd_list_base; + port->hba_port->command_list_base_upper = (uint32_t)((uint64_t)port->cmd_list_base >> 32); + port->hba_port->fis_base_address = (uint32_t)(uint64_t)port->fis_base; + port->hba_port->fis_base_address_upper = (uint32_t)((uint64_t)port->fis_base >> 32); + memory_set(port->cmd_list_base, 0, 0x400); + memory_set(port->fis_base, 0, 0x100); + + ahci_hba_command_T* command_header = (ahci_hba_command_T*)port->cmd_list_base; + + for (uint32_t i = 0; i < 32; i++) { + port->command_tables[i] = pframe_request(); + + uint64_t address = (uint64_t)port->command_tables[i] + (i << 8); + command_header[i].prdt_length = 8; + command_header[i].command_table_base_address = (uint32_t)address; + command_header[i].command_table_base_address_upper = (uint32_t)(address >> 32); + + memory_set((void*)address, 0, 0x100); + } + + ahci_port_command_start(port); +} + +void ahci_port_destruct(ahci_port_T* port) { + + for (uint32_t i = 0; i < 32; i++) { + pframe_free(port->command_tables[i]); + } + + pframe_free(port->fis_base); + pframe_free(port->cmd_list_base); +} + +void ahci_port_command_stop(ahci_port_T* port) { + port->hba_port->command_status &= ~HBA_PX_COMMAND_START; + port->hba_port->command_status &= ~HBA_PX_COMMAND_FIS_RECV_ENABLE; + + while ((port->hba_port->command_status & HBA_PX_COMMAND_CMD_LIST_RUNNING) && + (port->hba_port->command_status & HBA_PX_COMMAND_FIS_RECV_RUNNING)) { + asm("hlt"); + } +} + +void ahci_port_command_start(ahci_port_T* port) { + while (port->hba_port->command_status & HBA_PX_COMMAND_CMD_LIST_RUNNING) asm("hlt"); + + port->hba_port->command_status |= HBA_PX_COMMAND_FIS_RECV_ENABLE; + port->hba_port->command_status |= HBA_PX_COMMAND_START; } ahci_device_type_E ahci_port_get_type(ahci_hba_port_T* port) {