// This file is part of noxos and licensed under the MIT open source license #ifndef NOXOS_AHCI_H #define NOXOS_AHCI_H #include "utils/stdtypes.h" #include "drivers/pci.h" #include "drivers/drive_manager.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_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, 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 AHCI_FIS_REGISTER_DEVICE_TO_HOST = 0x34, // host <-- device AHCI_FIS_DMA_ACTIVATE = 0x39, // host <-- device AHCI_FIS_DMA_SETUP = 0x41, // host <--> device AHCI_FIS_DATA = 0x46, // host <--> device AHCI_FIS_BIST = 0x58, // host <--> device AHCI_FIS_PIO_SETUP = 0x5F, // host <-- device AHCI_FIS_DEVICE_BITS = 0xA1 // host <-- device } 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; 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; } 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 } 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; } 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; } 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 { 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_controller_T ahci_controller_T; typedef struct { ahci_hba_port_T* hba_port; ahci_device_type_E type; ahci_controller_T* controller; uint8_t id; drive_T* drive; void* cmd_list_base; void* fis_base; void* command_tables [32]; } ahci_port_T; struct ahci_controller_T { ahci_port_T ports [32]; int num_ports; pci_device_T* pci_device; ahci_hba_memory_T* abar; }; 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_init_partitions_mbr (ahci_port_T* port); void ahci_port_init_partitions_gpt (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); 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]; #endif //NOXOS_AHCI_H