From 091220ac71d4697ce2f46c3ae820df3097090385 Mon Sep 17 00:00:00 2001 From: antifallobst Date: Thu, 4 May 2023 13:28:55 +0200 Subject: [PATCH] feature (AHCI): implemented ahci controllers and ahci controller device enumeration --- inc/drivers/ahci.h | 83 ++++++++++++++++++++++++++++++++++++++++++++++ inc/drivers/pci.h | 1 + src/drivers/ahci.c | 71 +++++++++++++++++++++++++++++++++++++++ src/drivers/pci.c | 29 ++++++++++++++++ 4 files changed, 184 insertions(+) diff --git a/inc/drivers/ahci.h b/inc/drivers/ahci.h index c3f97b8..4102daf 100644 --- a/inc/drivers/ahci.h +++ b/inc/drivers/ahci.h @@ -4,6 +4,31 @@ #define NOXOS_AHCI_H #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 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 + +typedef enum { + AHCI_DEVICE_NONE, + AHCI_DEVICE_SATA, + AHCI_DEVICE_SEMB, + AHCI_DEVICE_PORT_MULTIPLIER, + AHCI_DEVICE_SATAPI, + + AHCI_DEVICE_TYPE_END_OF_ENUM +} ahci_device_type_E; typedef enum { AHCI_FIS_REGISTER_HOST_TO_DEVICE = 0x27, // host --> device @@ -105,6 +130,64 @@ typedef struct { 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]; +} ahci_hba_port_T; +typedef struct { + uint32_t host_capability; + uint32_t global_host_control; + uint32_t interrupt_status; + uint32_t ports_implemented; + uint32_t version; + uint32_t ccc_control; + uint32_t ccc_ports; + uint32_t enclosure_management_location; + uint32_t enclosure_management_control; + uint32_t host_capabilities_extended; + uint32_t bios_handoff_control_status; + uint8_t reserved_0 [0x74]; + uint8_t vendor [0x60]; + ahci_hba_port_T ports [1]; +} ahci_hba_memory_T; + +typedef struct { + ahci_hba_port_T* hba_port; + ahci_device_type_E type; + uint8_t* buffer; + uint8_t id; +} ahci_port_T; + +typedef struct { + ahci_port_T ports [32]; + int num_ports; + pci_device_T* pci_device; + ahci_hba_memory_T* abar; +} ahci_controller_T; + +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); +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]; #endif //NOXOS_AHCI_H diff --git a/inc/drivers/pci.h b/inc/drivers/pci.h index 334dd42..349daae 100644 --- a/inc/drivers/pci.h +++ b/inc/drivers/pci.h @@ -233,6 +233,7 @@ typedef struct { typedef struct pci_device_T pci_device_T; struct pci_device_T { pci_device_header_T* header; + void* specific; pci_device_T* prev; pci_device_T* next; }; diff --git a/src/drivers/ahci.c b/src/drivers/ahci.c index 7facbd7..cd4eb60 100644 --- a/src/drivers/ahci.c +++ b/src/drivers/ahci.c @@ -1,3 +1,74 @@ // This file is part of noxos and licensed under the MIT open source license #include "drivers/ahci.h" +#include "utils/memory.h" +#include "utils/logger.h" +#include "mm/page_map.h" + +string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM] = { + "None", + "SATA", + "SEMB", + "Port Multiplier", + "SATAPI" +}; + +ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) { + ahci_controller_T* controller = memory_allocate(sizeof(ahci_controller_T)); + + controller->pci_device = pci_device; + controller->abar = (ahci_hba_memory_T*)((pci_header_0_T*)pci_device->header)->bar5; + controller->num_ports = 0; + + page_map_map_memory(g_kernel_page_map, controller->abar, controller->abar, PM_FLAG_READ_WRITE); + + // probe ports + for (int i = 0; i < 32; i++) { + if ((controller->abar->ports_implemented & (1 << i)) == 0) continue; + + ahci_device_type_E type = ahci_port_get_type(&controller->abar->ports[i]); + + switch (type) { + case AHCI_DEVICE_SATAPI: + case AHCI_DEVICE_SATA: { + ahci_port_T* port = &controller->ports[controller->num_ports]; + port->type = type; + port->hba_port = &controller->abar->ports[i]; + port->id = controller->num_ports; + + controller->num_ports += 1; + break; + } + } + } + + // configure ports + 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]); + } + + return controller; +} + +void ahci_controller_destruct(ahci_controller_T* controller) { + memory_free(controller); +} + +void ahci_port_configure(ahci_port_T* port) { + +} + +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; + } +} \ No newline at end of file diff --git a/src/drivers/pci.c b/src/drivers/pci.c index e05c644..b38afe9 100644 --- a/src/drivers/pci.c +++ b/src/drivers/pci.c @@ -3,6 +3,7 @@ #include "drivers/pci.h" #include "drivers/acpi/acpi.h" #include "drivers/acpi/mcfg.h" +#include "drivers/ahci.h" #include "mm/page_map.h" #include "utils/logger.h" #include "utils/memory.h" @@ -310,6 +311,20 @@ void pci_manager_add_device(pci_device_header_T* header) { if (device->next != NULL) { device->next->prev = device; } + + // init controller + switch (header->main_class) { + case PCI_CLASS_MASS_STORAGE_CONTROLLER: { + switch (header->subclass) { + case PCI_SUBCLASS_SERIAL_ATA_CONTROLLER: { + if (header->progif != 0x01) break; + device->specific = ahci_controller_alloc(device); + break; + } + } + break; + } + } } void pci_manager_remove_device(pci_device_T* device) { @@ -320,6 +335,20 @@ void pci_manager_remove_device(pci_device_T* device) { device->next->prev = device->prev; } + // destruct controller + switch (device->header->main_class) { + case PCI_CLASS_MASS_STORAGE_CONTROLLER: { + switch (device->header->subclass) { + case PCI_SUBCLASS_SERIAL_ATA_CONTROLLER: { + if (device->header->progif != 0x01) break; + ahci_controller_destruct(device->specific); + break; + } + } + break; + } + } + memory_free(device); }