feature (AHCI): implemented port initialization
This commit is contained in:
parent
caacc16f35
commit
20112833d5
|
@ -6,19 +6,24 @@
|
||||||
#include "utils/stdtypes.h"
|
#include "utils/stdtypes.h"
|
||||||
#include "drivers/pci.h"
|
#include "drivers/pci.h"
|
||||||
|
|
||||||
#define SATA_SIG_ATA 0x00000101
|
#define SATA_SIG_ATA 0x00000101
|
||||||
#define SATA_SIG_ATAPI 0xEB140101
|
#define SATA_SIG_ATAPI 0xEB140101
|
||||||
#define SATA_SIG_SEMB 0xC33C0101
|
#define SATA_SIG_SEMB 0xC33C0101
|
||||||
#define SATA_SIG_PORT_MULTIPLIER 0x96690101
|
#define SATA_SIG_PORT_MULTIPLIER 0x96690101
|
||||||
|
|
||||||
#define ATA_DEVICE_BUSY 0x80
|
#define ATA_DEVICE_BUSY 0x80
|
||||||
#define ATA_DEVICE_DRQ 0x08
|
#define ATA_DEVICE_DRQ 0x08
|
||||||
#define ATA_CMD_READ_DMA_EX 0x25
|
#define ATA_CMD_READ_DMA_EX 0x25
|
||||||
#define ATA_CMD_WRITE_DMA_EX 0x35
|
#define ATA_CMD_WRITE_DMA_EX 0x35
|
||||||
|
|
||||||
#define HBA_PX_IS_TFES (1 << 30)
|
#define HBA_PX_IS_TFES (1 << 30)
|
||||||
#define HBA_PORT_DEVICE_PRESENT 0x03
|
#define HBA_PX_COMMAND_CMD_LIST_RUNNING 0x8000
|
||||||
#define HBA_PORT_IPM_ACTIVE 0x01
|
#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 {
|
typedef enum {
|
||||||
AHCI_DEVICE_NONE,
|
AHCI_DEVICE_NONE,
|
||||||
|
@ -169,11 +174,33 @@ typedef struct {
|
||||||
ahci_hba_port_T ports [1];
|
ahci_hba_port_T ports [1];
|
||||||
} ahci_hba_memory_T;
|
} 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 {
|
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* fis_base;
|
||||||
|
void* command_tables [32];
|
||||||
} ahci_port_T;
|
} ahci_port_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -185,7 +212,10 @@ 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_configure (ahci_port_T* port);
|
void ahci_port_init (ahci_port_T* port);
|
||||||
|
void ahci_port_destruct (ahci_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);
|
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];
|
extern string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM];
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "utils/memory.h"
|
#include "utils/memory.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include "mm/page_map.h"
|
#include "mm/page_map.h"
|
||||||
|
#include "mm/page_frame.h"
|
||||||
|
|
||||||
string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM] = {
|
string_t g_ahci_device_type_strings[AHCI_DEVICE_TYPE_END_OF_ENUM] = {
|
||||||
"None",
|
"None",
|
||||||
|
@ -46,18 +47,75 @@ ahci_controller_T* ahci_controller_alloc(pci_device_T* pci_device) {
|
||||||
log(LOG_INFO, "AHCI devices:");
|
log(LOG_INFO, "AHCI devices:");
|
||||||
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_configure(&controller->ports[i]);
|
ahci_port_init(&controller->ports[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ahci_controller_destruct(ahci_controller_T* controller) {
|
void ahci_controller_destruct(ahci_controller_T* controller) {
|
||||||
|
for (int i = 0; i < controller->num_ports; i++) {
|
||||||
|
ahci_port_destruct(&controller->ports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
page_map_unmap_memory(g_kernel_page_map, controller->abar);
|
||||||
|
|
||||||
memory_free(controller);
|
memory_free(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ahci_port_configure(ahci_port_T* port) {
|
void ahci_port_init(ahci_port_T* port) {
|
||||||
|
ahci_port_command_stop(port);
|
||||||
|
|
||||||
|
port->cmd_list_base = pframe_request();
|
||||||
|
port->fis_base = pframe_request();
|
||||||
|
port->hba_port->command_list_base = (uint32_t)(uint64_t)port->cmd_list_base;
|
||||||
|
port->hba_port->command_list_base_upper = (uint32_t)((uint64_t)port->cmd_list_base >> 32);
|
||||||
|
port->hba_port->fis_base_address = (uint32_t)(uint64_t)port->fis_base;
|
||||||
|
port->hba_port->fis_base_address_upper = (uint32_t)((uint64_t)port->fis_base >> 32);
|
||||||
|
memory_set(port->cmd_list_base, 0, 0x400);
|
||||||
|
memory_set(port->fis_base, 0, 0x100);
|
||||||
|
|
||||||
|
ahci_hba_command_T* command_header = (ahci_hba_command_T*)port->cmd_list_base;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 32; i++) {
|
||||||
|
port->command_tables[i] = pframe_request();
|
||||||
|
|
||||||
|
uint64_t address = (uint64_t)port->command_tables[i] + (i << 8);
|
||||||
|
command_header[i].prdt_length = 8;
|
||||||
|
command_header[i].command_table_base_address = (uint32_t)address;
|
||||||
|
command_header[i].command_table_base_address_upper = (uint32_t)(address >> 32);
|
||||||
|
|
||||||
|
memory_set((void*)address, 0, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
ahci_port_command_start(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ahci_port_destruct(ahci_port_T* port) {
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 32; i++) {
|
||||||
|
pframe_free(port->command_tables[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pframe_free(port->fis_base);
|
||||||
|
pframe_free(port->cmd_list_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
while ((port->hba_port->command_status & HBA_PX_COMMAND_CMD_LIST_RUNNING) &&
|
||||||
|
(port->hba_port->command_status & HBA_PX_COMMAND_FIS_RECV_RUNNING)) {
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ahci_port_command_start(ahci_port_T* port) {
|
||||||
|
while (port->hba_port->command_status & HBA_PX_COMMAND_CMD_LIST_RUNNING) asm("hlt");
|
||||||
|
|
||||||
|
port->hba_port->command_status |= HBA_PX_COMMAND_FIS_RECV_ENABLE;
|
||||||
|
port->hba_port->command_status |= HBA_PX_COMMAND_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
ahci_device_type_E ahci_port_get_type(ahci_hba_port_T* port) {
|
ahci_device_type_E ahci_port_get_type(ahci_hba_port_T* port) {
|
||||||
|
|
Loading…
Reference in New Issue