whereahci_controller_t sata_disk;
Code: Select all
struct ahci_controller {
uint8_t bus;
uint8_t device;
uint8_t function;
uint64_t abar;
bool initialized;
};
typedef struct ahci_controller ahci_controller_t;
Code: Select all
#define HBA_GHC_AHCI_ENABLE (1 << 31) // 0x80000000
#define HBA_PORT_CMD_ST (1 << 0) // 0x1
#define HBA_PORT_CMD_FRE (1 << 4) // 0x10
#define HBA_PORT_CMD_CR (1 << 15) // 0x8000
#define ATA_CMD_READ_DMA_EX 0x25
#define ATA_CMD_WRITE_DMA_EX 0x35
ahci_controller_t sata_disk;
void ahci_init() {
hba_mem *hba = (hba_mem*)(sata_disk.abar);
// Enable AHCI in GHC
hba->ghc |= HBA_GHC_AHCI_ENABLE;
while (!(hba->ghc & HBA_GHC_AHCI_ENABLE)); // Wait for enable
// Find active port
uint32_t pi = hba->pi;
for (int i = 0; i < 32; i++) {
if (pi & (1 << i)) {
struct hba_port *port = &hba->ports[i];
uint32_t ssts = port->ssts;
if ((ssts & 0xF) == 3) { // Device detected
ahci_port_init(port);
sata_disk.initialized = true;
return;
}
}
}
printf("AHCI: No active port found\n");
}
void ahci_port_init(struct hba_port *port) {
// Stop command engine
port->cmd &= ~HBA_PORT_CMD_ST;
while (port->cmd & HBA_PORT_CMD_CR);
// Allocate command list and FIS
// Assuming aligned allocation functions exist
void *cmd_list = (void *) kmalloc_a(1024, 1); // 32 entries * 32 bytes
void *fis = (void *) kmalloc_a(256, 1);
// Set command list and FIS base
port->clb = (uint32_t)(uintptr_t) vir_to_phys((uint64_t)cmd_list);
port->clbu = (uint32_t)((uintptr_t) vir_to_phys((uint64_t)cmd_list) >> 32);
port->fb = (uint32_t)(uintptr_t) vir_to_phys((uint64_t)fis);
port->fbu = (uint32_t)((uintptr_t) vir_to_phys((uint64_t)fis) >> 32);
// Enable FIS and start engine
port->cmd |= HBA_PORT_CMD_FRE;
port->cmd |= HBA_PORT_CMD_ST;
}
int ahci_read(uint64_t lba, uint32_t count, void *buffer) {
if (!sata_disk.initialized) return -1;
hba_mem *hba = (hba_mem*)sata_disk.abar;
struct hba_port *port = &hba->ports[0]; // Assuming port 0
// Prepare command header
volatile hba_cmd_header *cmdheader = (volatile hba_cmd_header *)(uintptr_t)port->clb;; // Access command list
cmdheader->cfl = sizeof(h2d_fis)/4; // Size in DWORDS
cmdheader->w = 0; // Read
cmdheader->prdtl = 1; // 1 PRDT entry
// Setup command table
hba_cmd_table *cmdtbl = (hba_cmd_table *) kheap_alloc(sizeof(hba_cmd_table));
memset(cmdtbl, 0, sizeof(hba_cmd_table));
h2d_fis *fis = (h2d_fis*) &cmdtbl->cfis;
fis->fis_type = 0x27; // H2D FIS
fis->pm_port = 0x80; // Command
fis->command = ATA_CMD_READ_DMA_EX;
fis->lba0 = lba;
fis->lba1 = lba >> 8;
fis->lba2 = lba >> 16;
fis->device = 0x40; // LBA mode
fis->lba3 = lba >> 24;
fis->lba4 = lba >> 32;
fis->lba5 = lba >> 40;
fis->countl = count & 0xFF;
fis->counth = (count >> 8) & 0xFF;
// Setup PRDT entry using hba_prdt_entry structure
cmdtbl->prdt[0].dba = (uint32_t)(uintptr_t)vir_to_phys((uint64_t)buffer);
cmdtbl->prdt[0].dbau = (uint32_t)(((uintptr_t)vir_to_phys((uint64_t)buffer)) >> 32);
cmdtbl->prdt[0].dbc = (count * 512) - 1; // 512 bytes per sector, minus one
cmdtbl->prdt[0].rsvd = 0;
cmdtbl->prdt[0].i = 1; // Interrupt on completion
// Issue command
port->ci = 1; // Use command slot 0
while (port->ci & 1); // Wait for completion
kheap_free((void *)cmdtbl, sizeof(hba_cmd_table));
return 0;
}
int ahci_write(uint64_t lba, uint32_t count, void *buffer) {
if (!sata_disk.initialized) return -1;
hba_mem *hba = (hba_mem*)sata_disk.abar;
hba_port_t *port = &hba->ports[0]; // Using port 0
// Initialize command header pointer from the port's command list base.
volatile hba_cmd_header *cmdheader = (volatile hba_cmd_header *)(uintptr_t)port->clb;
// Prepare command header for slot 0
cmdheader[0].cfl = sizeof(h2d_fis) / 4; // FIS length in DWORDS
cmdheader[0].w = 1; // Write operation
cmdheader[0].prdtl = 1; // One PRDT entry
// Allocate and clear a command table for this slot
hba_cmd_table *cmdtbl = (hba_cmd_table *) kmalloc_a(sizeof(hba_cmd_table), 1);
memset(cmdtbl, 0, sizeof(hba_cmd_table));
// Setup Host-to-Device FIS in the command table
h2d_fis *fis = (h2d_fis *)&cmdtbl->cfis;
fis->fis_type = 0x27; // H2D FIS
fis->pm_port = 0x80; // Command (bit 7 set)
fis->command = ATA_CMD_WRITE_DMA_EX;
fis->lba0 = lba;
fis->lba1 = lba >> 8;
fis->lba2 = lba >> 16;
fis->device = 0x40; // LBA mode
fis->lba3 = lba >> 24;
fis->lba4 = lba >> 32;
fis->lba5 = lba >> 40;
fis->countl = count & 0xFF;
fis->counth = (count >> 8) & 0xFF;
// Setup PRDT entry using hba_prdt_entry structure
cmdtbl->prdt[0].dba = (uint32_t)(uint64_t)vir_to_phys((uint64_t)buffer);
cmdtbl->prdt[0].dbau = (uint32_t)(vir_to_phys((uint64_t)buffer) >> 32);
cmdtbl->prdt[0].dbc = (count * 512) - 1; // (Transfer size in bytes) - 1
cmdtbl->prdt[0].rsvd = 0;
cmdtbl->prdt[0].i = 1; // Interrupt on completion
// Link the command table to the command header (slot 0)
uint64_t phys_cmdtbl = vir_to_phys((uint64_t)cmdtbl);
cmdheader[0].ctba = (uint32_t)phys_cmdtbl;
cmdheader[0].ctbau = (uint32_t)(phys_cmdtbl >> 32);
// Issue command by setting the command issue bit for slot 0
port->ci = 1; // Using command slot 0
// Wait for command to complete (consider adding a timeout)
while (port->ci & 1);
return 0;
}
Code: Select all
if (sata_disk.abar != 0) {
char *buffer = (char *) kmalloc_a(512, 1);
memset(buffer, 0, 512); // Clearing buffer
if (ahci_read(0, 1, (void *)buffer) == 0) {
printf("Disk Read Successful!\n");
// Check MBR signature (last 2 bytes of sector)
if (buffer[510] == 0x55 && buffer[511] == 0xAA) {
printf("Valid MBR Signature found!\n");
} else {
printf("No MBR found. Disk may be empty or unformatted.\n");
}
} else {
printf("AHCI Read Failed!\n");
}
char *write_buffer = (char *) kmalloc_a(512, 1);
memset(write_buffer, 'A', 512); // Fill buffer with 'A'
if (ahci_write(1, 1, write_buffer) == 0) {
printf("AHCI Write Successful at LBA 1!\n");
} else {
printf("AHCI Write Failed!\n");
}
char *read_buffer = (char *) kmalloc_a(512, 1);
memset(read_buffer, 0, 512);
if (ahci_read(1, 1, read_buffer) == 0) {
if (memcmp(write_buffer, read_buffer, 512) == 0) {
printf("Write Verification Successful! Data matches. %x\n", *write_buffer);
} else {
printf("Write Verification Failed! Data does not match.\n");
}
} else {
printf("Failed to read back written data.\n");
}
printf("Write_buffer[%d]: %x\n", 1, write_buffer[1]);
printf("Read_buffer[%d]: %x\n", 1, read_buffer[1]);
}
Code: Select all
Disk Read Successful!
No MBR found. Disk may be empty or unformatted.
AHCI Write Successful at LBA 1!
Write Verification Failed! Data does not match.
Write_buffer[1]: 0x41
Read_buffer[1]: 0x0
pci.c
pci.h
ahci.h
ahci.h