feature (AHCI): implemented port reading

This commit is contained in:
antifallobst 2023-05-07 14:13:07 +02:00
parent 20112833d5
commit 7d104a2745
2 changed files with 208 additions and 124 deletions

View File

@ -47,114 +47,115 @@ typedef enum {
} ahci_fis_type_E; } ahci_fis_type_E;
typedef struct { typedef struct {
uint8_t type; uint8_t type;
uint8_t port_multiplier:4; uint8_t port_multiplier:4;
uint8_t reserved_0:3; uint8_t reserved_0:3;
uint8_t command_control_select:1; uint8_t command_control_select:1;
uint8_t command; uint8_t command;
uint8_t feature_0; uint8_t feature_0;
uint8_t lba_0; uint8_t lba_0;
uint8_t lba_1; uint8_t lba_1;
uint8_t lba_2; uint8_t lba_2;
uint8_t device; uint8_t device;
uint8_t lba_3; uint8_t lba_3;
uint8_t lba_4; uint8_t lba_4;
uint8_t lba_5; uint8_t lba_5;
uint8_t feature_1; uint8_t feature_1;
uint16_t count; uint8_t count_low;
uint8_t icc; uint8_t count_high;
uint8_t control; uint8_t icc;
uint32_t reserved_1; uint8_t control;
uint32_t reserved_1;
} ahci_fis_register_host_to_device_T; } ahci_fis_register_host_to_device_T;
typedef struct { typedef struct {
uint8_t type; uint8_t type;
uint8_t port_multiplier:4; uint8_t port_multiplier:4;
uint8_t reserved_0:2; uint8_t reserved_0:2;
uint8_t interrupt:1; uint8_t interrupt:1;
uint8_t reserved_1:1; uint8_t reserved_1:1;
uint8_t status; uint8_t status;
uint8_t error; uint8_t error;
uint8_t lba_0; uint8_t lba_0;
uint8_t lba_1; uint8_t lba_1;
uint8_t lba_2; uint8_t lba_2;
uint8_t device; uint8_t device;
uint8_t lba_3; uint8_t lba_3;
uint8_t lba_4; uint8_t lba_4;
uint8_t lba_5; uint8_t lba_5;
uint8_t reserved_2; uint8_t reserved_2;
uint16_t count; uint16_t count;
uint16_t reserved_3; uint16_t reserved_3;
uint32_t reserved_4; uint32_t reserved_4;
} ahci_fis_register_device_to_host_T; } ahci_fis_register_device_to_host_T;
typedef struct { typedef struct {
uint8_t type; uint8_t type;
uint8_t port_multiplier:4; uint8_t port_multiplier:4;
uint8_t reserved_0:4; uint8_t reserved_0:4;
uint16_t reserved_1; uint16_t reserved_1;
uint32_t data; // this can be followed by more data uint32_t data; // this can be followed by more data
} ahci_fis_data_T; } ahci_fis_data_T;
typedef struct { typedef struct {
uint8_t type; uint8_t type;
uint8_t port_multiplier:4; uint8_t port_multiplier:4;
uint8_t reserved_0:1; uint8_t reserved_0:1;
uint8_t transfer_direction:1; uint8_t transfer_direction:1;
uint8_t interrupt:1; uint8_t interrupt:1;
uint8_t reserved_1:1; uint8_t reserved_1:1;
uint8_t status; uint8_t status;
uint8_t error; uint8_t error;
uint8_t lba_0; uint8_t lba_0;
uint8_t lba_1; uint8_t lba_1;
uint8_t lba_2; uint8_t lba_2;
uint8_t device; uint8_t device;
uint8_t lba_3; uint8_t lba_3;
uint8_t lba_4; uint8_t lba_4;
uint8_t lba_5; uint8_t lba_5;
uint8_t reserved_2; uint8_t reserved_2;
uint16_t count; uint16_t count;
uint8_t reserved_3; uint8_t reserved_3;
uint8_t new_status; uint8_t new_status;
uint16_t transfer_count; uint16_t transfer_count;
uint16_t reserved_4; uint16_t reserved_4;
} ahci_fis_pio_setup_T; } ahci_fis_pio_setup_T;
typedef struct { typedef struct {
uint8_t type; uint8_t type;
uint8_t port_multiplier:4; uint8_t port_multiplier:4;
uint8_t reserved_0:1; uint8_t reserved_0:1;
uint8_t transfer_direction:1; uint8_t transfer_direction:1;
uint8_t interrupt:1; uint8_t interrupt:1;
uint8_t auto_activate:1; uint8_t auto_activate:1;
uint16_t reserved_1; uint16_t reserved_1;
uint64_t dma_buffer_id; uint64_t dma_buffer_id;
uint32_t reserved_2; uint32_t reserved_2;
uint32_t dma_buffer_offset; uint32_t dma_buffer_offset;
uint32_t transfer_count; uint32_t transfer_count;
uint32_t reserved_3; uint32_t reserved_3;
} ahci_fis_dma_setup_T; } ahci_fis_dma_setup_T;
typedef struct { typedef struct {
uint32_t command_list_base; uint32_t command_list_base;
uint32_t command_list_base_upper; uint32_t command_list_base_upper;
uint32_t fis_base_address; uint32_t fis_base_address;
uint32_t fis_base_address_upper; uint32_t fis_base_address_upper;
uint32_t interrupt_status; uint32_t interrupt_status;
uint32_t interrupt_enable; uint32_t interrupt_enable;
uint32_t command_status; uint32_t command_status;
uint32_t reserved_0; uint32_t reserved_0;
uint32_t task_file_data; uint32_t task_file_data;
uint32_t signature; uint32_t signature;
uint32_t sata_status; uint32_t sata_status;
uint32_t sata_control; uint32_t sata_control;
uint32_t sata_error; uint32_t sata_error;
uint32_t sata_active; uint32_t sata_active;
uint32_t command_issue; uint32_t command_issue;
uint32_t sata_notification; uint32_t sata_notification;
uint32_t fis_switch_control; uint32_t fis_switch_control;
uint32_t reserved_1 [11]; uint32_t reserved_1 [11];
uint32_t vendor [4]; uint32_t vendor [4];
} ahci_hba_port_T; } ahci_hba_port_T;
typedef struct { typedef struct {
@ -175,32 +176,48 @@ typedef struct {
} ahci_hba_memory_T; } ahci_hba_memory_T;
typedef struct { typedef struct {
uint8_t command_fis_length:5; uint8_t command_fis_length:5;
uint8_t atapi:1; uint8_t atapi:1;
uint8_t write:1; uint8_t write:1;
uint8_t prefetchable:1; uint8_t prefetchable:1;
uint8_t reset:1; uint8_t reset:1;
uint8_t bist:1; uint8_t bist:1;
uint8_t clear_busy:1; uint8_t clear_busy:1;
uint8_t reserved_0:1; uint8_t reserved_0:1;
uint8_t port_multiplier:4; uint8_t port_multiplier:4;
uint16_t prdt_length; uint16_t prdt_length;
uint32_t prdb_count; uint32_t prdb_count;
uint32_t command_table_base_address; uint32_t command_table_base_address;
uint32_t command_table_base_address_upper; uint32_t command_table_base_address_upper;
uint32_t reserved_1 [4]; uint32_t reserved_1 [4];
} ahci_hba_command_T; } 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 { typedef struct {
ahci_hba_port_T* hba_port; ahci_hba_port_T* hba_port;
ahci_device_type_E type; ahci_device_type_E type;
uint8_t* buffer; uint8_t* buffer;
uint8_t id; uint8_t id;
void* cmd_list_base; void* cmd_list_base;
void* fis_base; void* fis_base;
void* command_tables [32]; void* command_tables [32];
} ahci_port_T; } ahci_port_T;
typedef struct { typedef struct {
@ -212,11 +229,15 @@ typedef struct {
ahci_controller_T* ahci_controller_alloc (pci_device_T* pci_device); ahci_controller_T* ahci_controller_alloc (pci_device_T* pci_device);
void ahci_controller_destruct (ahci_controller_T* controller); void ahci_controller_destruct (ahci_controller_T* controller);
void ahci_port_init (ahci_port_T* port); void ahci_port_init (ahci_port_T* port);
void ahci_port_destruct (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_stop (ahci_port_T* port);
void ahci_port_command_start (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]; extern string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM];

View File

@ -14,6 +14,8 @@ string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM] = {
"SATAPI" "SATAPI"
}; };
#include "utils/math.h"
ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) { ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) {
ahci_controller_T* controller = memory_allocate(sizeof(ahci_controller_T)); 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++) { for (int i = 0; i < controller->num_ports; i++) {
log(LOG_INFO, " %s", g_ahci_device_type_strings[controller->ports[i].type]); log(LOG_INFO, " %s", g_ahci_device_type_strings[controller->ports[i].type]);
ahci_port_init(&controller->ports[i]); 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; return controller;
@ -101,6 +106,19 @@ void ahci_port_destruct(ahci_port_T* port) {
pframe_free(port->cmd_list_base); 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) { 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_START;
port->hba_port->command_status &= ~HBA_PX_COMMAND_FIS_RECV_ENABLE; 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; port->hba_port->command_status |= HBA_PX_COMMAND_START;
} }
ahci_device_type_E ahci_port_get_type(ahci_hba_port_T* port) { // reads num_sector*512 bytes from offset (sector*512) into buffer_out, that needs to be page aligned
if ((port->sata_status & 0b111) != HBA_PORT_DEVICE_PRESENT) return AHCI_DEVICE_NONE; bool ahci_port_read(ahci_port_T* port, uint64_t sector, uint32_t num_sectors, void* buffer_out) {
if (((port->sata_status >> 8) & 0b111) != HBA_PORT_IPM_ACTIVE) return AHCI_DEVICE_NONE; if (port->type == AHCI_DEVICE_SATAPI) return false;
switch (port->signature) { uint64_t blocked = 0;
case SATA_SIG_ATA: return AHCI_DEVICE_SATA; while ((port->hba_port->task_file_data & (ATA_DEVICE_BUSY | ATA_DEVICE_DRQ))) {
case SATA_SIG_ATAPI: return AHCI_DEVICE_SATAPI; if (blocked > 1000000) return false;
case SATA_SIG_SEMB: return AHCI_DEVICE_SEMB; blocked++;
case SATA_SIG_PORT_MULTIPLIER: return AHCI_DEVICE_PORT_MULTIPLIER;
default: return AHCI_DEVICE_NONE;
} }
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;
} }