feature (AHCI): implemented ahci controllers and ahci controller device enumeration

This commit is contained in:
antifallobst 2023-05-04 13:28:55 +02:00
parent 62bbc52205
commit 091220ac71
4 changed files with 184 additions and 0 deletions

View File

@ -4,6 +4,31 @@
#define NOXOS_AHCI_H #define NOXOS_AHCI_H
#include "utils/stdtypes.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 { typedef enum {
AHCI_FIS_REGISTER_HOST_TO_DEVICE = 0x27, // host --> device AHCI_FIS_REGISTER_HOST_TO_DEVICE = 0x27, // host --> device
@ -105,6 +130,64 @@ typedef struct {
uint32_t reserved_3; uint32_t reserved_3;
} ahci_fis_dma_setup_T; } 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 #endif //NOXOS_AHCI_H

View File

@ -233,6 +233,7 @@ typedef struct {
typedef struct pci_device_T pci_device_T; typedef struct pci_device_T pci_device_T;
struct pci_device_T { struct pci_device_T {
pci_device_header_T* header; pci_device_header_T* header;
void* specific;
pci_device_T* prev; pci_device_T* prev;
pci_device_T* next; pci_device_T* next;
}; };

View File

@ -1,3 +1,74 @@
// This file is part of noxos and licensed under the MIT open source license // This file is part of noxos and licensed under the MIT open source license
#include "drivers/ahci.h" #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;
}
}

View File

@ -3,6 +3,7 @@
#include "drivers/pci.h" #include "drivers/pci.h"
#include "drivers/acpi/acpi.h" #include "drivers/acpi/acpi.h"
#include "drivers/acpi/mcfg.h" #include "drivers/acpi/mcfg.h"
#include "drivers/ahci.h"
#include "mm/page_map.h" #include "mm/page_map.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "utils/memory.h" #include "utils/memory.h"
@ -310,6 +311,20 @@ void pci_manager_add_device(pci_device_header_T* header) {
if (device->next != NULL) { if (device->next != NULL) {
device->next->prev = device; 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) { 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; 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); memory_free(device);
} }