diff --git a/inc/drivers/ahci.h b/inc/drivers/ahci.h index 2931f0b..fe0cd35 100644 --- a/inc/drivers/ahci.h +++ b/inc/drivers/ahci.h @@ -47,114 +47,115 @@ typedef enum { } ahci_fis_type_E; typedef struct { - uint8_t type; - uint8_t port_multiplier:4; - uint8_t reserved_0:3; - uint8_t command_control_select:1; - uint8_t command; - uint8_t feature_0; - uint8_t lba_0; - uint8_t lba_1; - uint8_t lba_2; - uint8_t device; - uint8_t lba_3; - uint8_t lba_4; - uint8_t lba_5; - uint8_t feature_1; - uint16_t count; - uint8_t icc; - uint8_t control; - uint32_t reserved_1; + uint8_t type; + uint8_t port_multiplier:4; + uint8_t reserved_0:3; + uint8_t command_control_select:1; + uint8_t command; + uint8_t feature_0; + uint8_t lba_0; + uint8_t lba_1; + uint8_t lba_2; + uint8_t device; + uint8_t lba_3; + uint8_t lba_4; + uint8_t lba_5; + uint8_t feature_1; + uint8_t count_low; + uint8_t count_high; + uint8_t icc; + uint8_t control; + uint32_t reserved_1; } ahci_fis_register_host_to_device_T; typedef struct { - uint8_t type; - uint8_t port_multiplier:4; - uint8_t reserved_0:2; - uint8_t interrupt:1; - uint8_t reserved_1:1; - uint8_t status; - uint8_t error; - uint8_t lba_0; - uint8_t lba_1; - uint8_t lba_2; - uint8_t device; - uint8_t lba_3; - uint8_t lba_4; - uint8_t lba_5; - uint8_t reserved_2; - uint16_t count; - uint16_t reserved_3; - uint32_t reserved_4; + uint8_t type; + uint8_t port_multiplier:4; + uint8_t reserved_0:2; + uint8_t interrupt:1; + uint8_t reserved_1:1; + uint8_t status; + uint8_t error; + uint8_t lba_0; + uint8_t lba_1; + uint8_t lba_2; + uint8_t device; + uint8_t lba_3; + uint8_t lba_4; + uint8_t lba_5; + uint8_t reserved_2; + uint16_t count; + uint16_t reserved_3; + uint32_t reserved_4; } ahci_fis_register_device_to_host_T; typedef struct { - uint8_t type; - uint8_t port_multiplier:4; - uint8_t reserved_0:4; - uint16_t reserved_1; - uint32_t data; // this can be followed by more data + uint8_t type; + uint8_t port_multiplier:4; + uint8_t reserved_0:4; + uint16_t reserved_1; + uint32_t data; // this can be followed by more data } ahci_fis_data_T; typedef struct { - uint8_t type; - uint8_t port_multiplier:4; - uint8_t reserved_0:1; - uint8_t transfer_direction:1; - uint8_t interrupt:1; - uint8_t reserved_1:1; - uint8_t status; - uint8_t error; - uint8_t lba_0; - uint8_t lba_1; - uint8_t lba_2; - uint8_t device; - uint8_t lba_3; - uint8_t lba_4; - uint8_t lba_5; - uint8_t reserved_2; - uint16_t count; - uint8_t reserved_3; - uint8_t new_status; - uint16_t transfer_count; - uint16_t reserved_4; + uint8_t type; + uint8_t port_multiplier:4; + uint8_t reserved_0:1; + uint8_t transfer_direction:1; + uint8_t interrupt:1; + uint8_t reserved_1:1; + uint8_t status; + uint8_t error; + uint8_t lba_0; + uint8_t lba_1; + uint8_t lba_2; + uint8_t device; + uint8_t lba_3; + uint8_t lba_4; + uint8_t lba_5; + uint8_t reserved_2; + uint16_t count; + uint8_t reserved_3; + uint8_t new_status; + uint16_t transfer_count; + uint16_t reserved_4; } ahci_fis_pio_setup_T; typedef struct { - uint8_t type; - uint8_t port_multiplier:4; - uint8_t reserved_0:1; - uint8_t transfer_direction:1; - uint8_t interrupt:1; - uint8_t auto_activate:1; - uint16_t reserved_1; - uint64_t dma_buffer_id; - uint32_t reserved_2; - uint32_t dma_buffer_offset; - uint32_t transfer_count; - uint32_t reserved_3; + uint8_t type; + uint8_t port_multiplier:4; + uint8_t reserved_0:1; + uint8_t transfer_direction:1; + uint8_t interrupt:1; + uint8_t auto_activate:1; + uint16_t reserved_1; + uint64_t dma_buffer_id; + uint32_t reserved_2; + uint32_t dma_buffer_offset; + uint32_t transfer_count; + uint32_t reserved_3; } ahci_fis_dma_setup_T; typedef struct { - uint32_t command_list_base; - uint32_t command_list_base_upper; - uint32_t fis_base_address; - uint32_t fis_base_address_upper; - uint32_t interrupt_status; - uint32_t interrupt_enable; - uint32_t command_status; - uint32_t reserved_0; - uint32_t task_file_data; - uint32_t signature; - uint32_t sata_status; - uint32_t sata_control; - uint32_t sata_error; - uint32_t sata_active; - uint32_t command_issue; - uint32_t sata_notification; - uint32_t fis_switch_control; - uint32_t reserved_1 [11]; - uint32_t vendor [4]; + uint32_t command_list_base; + uint32_t command_list_base_upper; + uint32_t fis_base_address; + uint32_t fis_base_address_upper; + uint32_t interrupt_status; + uint32_t interrupt_enable; + uint32_t command_status; + uint32_t reserved_0; + uint32_t task_file_data; + uint32_t signature; + uint32_t sata_status; + uint32_t sata_control; + uint32_t sata_error; + uint32_t sata_active; + uint32_t command_issue; + uint32_t sata_notification; + uint32_t fis_switch_control; + uint32_t reserved_1 [11]; + uint32_t vendor [4]; } ahci_hba_port_T; typedef struct { @@ -175,32 +176,48 @@ typedef struct { } 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]; + 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 { + uint32_t data_base_address; + uint32_t data_base_address_upper; + uint32_t reserved_0; + uint32_t byte_count:22; + uint32_t reserved_1:9; + uint32_t interrupt_on_completion:1; +} ahci_hba_prdt_entry_T; + +typedef struct{ + uint8_t command_fis [64]; + uint8_t atapi_command [16]; + uint8_t reserved [48]; + ahci_hba_prdt_entry_T prdt_entry []; +} ahci_hba_command_table_T; + typedef struct { - ahci_hba_port_T* hba_port; - ahci_device_type_E type; - uint8_t* buffer; - uint8_t id; + 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]; + void* cmd_list_base; + void* fis_base; + void* command_tables [32]; } ahci_port_T; typedef struct { @@ -212,11 +229,15 @@ typedef struct { ahci_controller_T* ahci_controller_alloc (pci_device_T* pci_device); void ahci_controller_destruct (ahci_controller_T* controller); + void ahci_port_init (ahci_port_T* port); void ahci_port_destruct (ahci_port_T* port); +ahci_device_type_E ahci_port_get_type (ahci_hba_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); +bool ahci_port_read (ahci_port_T* port, uint64_t sector, uint32_t num_sectors, void* buffer_out); +bool ahci_port_write (ahci_port_T* port, uint64_t sector, uint32_t num_sectors, void* buffer_in); + 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 54f2b44..35a664d 100644 --- a/src/drivers/ahci.c +++ b/src/drivers/ahci.c @@ -14,6 +14,8 @@ string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM] = { "SATAPI" }; +#include "utils/math.h" + ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) { ahci_controller_T* controller = memory_allocate(sizeof(ahci_controller_T)); @@ -48,6 +50,9 @@ ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) { for (int i = 0; i < controller->num_ports; i++) { log(LOG_INFO, " %s", g_ahci_device_type_strings[controller->ports[i].type]); ahci_port_init(&controller->ports[i]); + uint8_t* buffer = memory_allocate(512 + PFRAME_SIZE); + if (ahci_port_read(&controller->ports[i], 0, 1, CEIL_TO((uint64_t)buffer, PFRAME_SIZE))) + memory_hexdump(CEIL_TO((uint64_t)buffer, PFRAME_SIZE), 512); } return controller; @@ -101,6 +106,19 @@ void ahci_port_destruct(ahci_port_T* port) { pframe_free(port->cmd_list_base); } +ahci_device_type_E ahci_port_get_type(ahci_hba_port_T* port) { + if ((port->sata_status & 0b111) != HBA_PORT_DEVICE_PRESENT) return AHCI_DEVICE_NONE; + if (((port->sata_status >> 8) & 0b111) != HBA_PORT_IPM_ACTIVE) return AHCI_DEVICE_NONE; + + switch (port->signature) { + case SATA_SIG_ATA: return AHCI_DEVICE_SATA; + case SATA_SIG_ATAPI: return AHCI_DEVICE_SATAPI; + case SATA_SIG_SEMB: return AHCI_DEVICE_SEMB; + case SATA_SIG_PORT_MULTIPLIER: return AHCI_DEVICE_PORT_MULTIPLIER; + default: return AHCI_DEVICE_NONE; + } +} + 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; @@ -118,15 +136,60 @@ void ahci_port_command_start(ahci_port_T* port) { port->hba_port->command_status |= HBA_PX_COMMAND_START; } -ahci_device_type_E ahci_port_get_type(ahci_hba_port_T* port) { - if ((port->sata_status & 0b111) != HBA_PORT_DEVICE_PRESENT) return AHCI_DEVICE_NONE; - if (((port->sata_status >> 8) & 0b111) != HBA_PORT_IPM_ACTIVE) return AHCI_DEVICE_NONE; +// reads num_sector*512 bytes from offset (sector*512) into buffer_out, that needs to be page aligned +bool ahci_port_read(ahci_port_T* port, uint64_t sector, uint32_t num_sectors, void* buffer_out) { + if (port->type == AHCI_DEVICE_SATAPI) return false; - switch (port->signature) { - case SATA_SIG_ATA: return AHCI_DEVICE_SATA; - case SATA_SIG_ATAPI: return AHCI_DEVICE_SATAPI; - case SATA_SIG_SEMB: return AHCI_DEVICE_SEMB; - case SATA_SIG_PORT_MULTIPLIER: return AHCI_DEVICE_PORT_MULTIPLIER; - default: return AHCI_DEVICE_NONE; + uint64_t blocked = 0; + while ((port->hba_port->task_file_data & (ATA_DEVICE_BUSY | ATA_DEVICE_DRQ))) { + if (blocked > 1000000) return false; + blocked++; } + + uint64_t buffer = (uint64_t) page_map_get_physical_address(g_kernel_page_map, buffer_out); + uint32_t sector_low = (uint32_t)sector; + uint32_t sector_high = (uint32_t)(sector >> 32); + port->hba_port->interrupt_status = (uint32_t)-1; + + + ahci_hba_command_T* command_header = (ahci_hba_command_T*)(uint64_t)port->hba_port->command_list_base; + command_header->command_fis_length = sizeof(AHCI_FIS_REGISTER_HOST_TO_DEVICE) / sizeof(uint32_t); + command_header->write = 0; + command_header->prdt_length = 1; + + ahci_hba_command_table_T* command_table = (ahci_hba_command_table_T*)((uint64_t)command_header->command_table_base_address); + memory_set(command_table, 0, sizeof(ahci_hba_command_table_T) + (command_header->prdt_length - 1) * sizeof(ahci_hba_prdt_entry_T)); + + command_table->prdt_entry[0].data_base_address = (uint32_t)(uint64_t)buffer; + command_table->prdt_entry[0].data_base_address_upper = (uint32_t)((uint64_t)buffer >> 32); + command_table->prdt_entry[0].byte_count = (num_sectors << 9) - 1; + command_table->prdt_entry[0].interrupt_on_completion = 1; + + + ahci_fis_register_host_to_device_T* command_fis = (ahci_fis_register_host_to_device_T*)(&command_table->command_fis); + command_fis->type = AHCI_FIS_REGISTER_HOST_TO_DEVICE; + command_fis->command_control_select = 1; + command_fis->command = ATA_CMD_READ_DMA_EX; + command_fis->lba_0 = (uint8_t)sector_low; + command_fis->lba_1 = (uint8_t)(sector_low >> 8); + command_fis->lba_2 = (uint8_t)(sector_low >> 16); + command_fis->lba_3 = (uint8_t)sector_high; + command_fis->lba_4 = (uint8_t)(sector_high >> 8); + command_fis->lba_5 = (uint8_t)(sector_high >> 16); + command_fis->device = 1 << 6; + command_fis->count_low = (uint8_t)(num_sectors & 0xFF); + command_fis->count_high = (uint8_t)((num_sectors >> 8) & 0xFF); + + port->hba_port->command_issue = 1; + + while (port->hba_port->command_issue) { + if (port->hba_port->interrupt_status & HBA_PX_IS_TFES) return false; + } + + return true; +} + +bool ahci_port_write(ahci_port_T* port, uint64_t sector, uint32_t num_sectors, void* buffer_in) { + DEBUG("AHCI write N/A"); + return false; } \ No newline at end of file