Skip to content

Commit

Permalink
Added AHCI disk reading. (partial)
Browse files Browse the repository at this point in the history
  • Loading branch information
pradosh-arduino committed Jan 15, 2025
1 parent e50401d commit 16e2acf
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
29 changes: 29 additions & 0 deletions source/includes/ahci.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,33 @@
#define semb_disk 0xC33C0101
#define port_multiplier 0x96690101

#define SECTOR_SIZE 512

// Structure to represent an AHCI command header
typedef struct {
uint32_t cfl; // Command FIS length
uint8_t cfis[64]; // Command FIS
uint32_t prdtl; // Physical Region Descriptor Table Length
uint32_t prdt; // Physical Region Descriptor Table
uint32_t reserved[4];
uint32_t ciss; // Command and Status
uint32_t iss; // Interrupt Status
uint32_t sact; // Start/Activate
uint32_t ci; // Command Issue
uint32_t dsts; // Data Strobe
uint32_t serr; // Serialization Error
uint32_t intm; // Interrupt Mask
uint32_t cmd; // Command
uint32_t fis; // FIS register
uint32_t ctl; // Control register
} __attribute__((packed)) ahci_command_header_t;

// Structure to represent a Physical Region Descriptor
typedef struct {
uint32_t dba; // Device Base Address
uint32_t dbc; // Data Base Count
} __attribute__((packed)) prdt_entry_t;

typedef volatile struct {
int32 clb; // Command List Base Address, 1K-byte aligned
int32 clbu; // Command List Base Address Upper 32 Bits
Expand Down Expand Up @@ -60,6 +87,8 @@ typedef volatile struct {
ahci_port ports[32]; // Port control registers
} ahci_controller;

extern ahci_controller* global_ahci_ctrl;

/**
* @brief Probes and detects all the AHCI Devices
*
Expand Down
60 changes: 60 additions & 0 deletions source/includes/disk/gpt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#ifndef __GPT_H
#define __GPT_H
#include <stdint.h>
#include <stddef.h>
#include <mbr.h>

#define GPT_EFI_PMBR_SECTOR 0
#define GPT_EFI_PART_HEADER_SECTOR 1
#define GPT_PARTITION_ENTRIES_SECTOR 2
#define GPT_PART_ATTRIB_FIRMWARE 0b1
#define GPT_PART_ATTRIB_USED_BY_OS 0b10
#define GPT_ENTRIES_SIZE (512*31)/sizeof(GPT_PartitionEntry)

#if defined(__cplusplus)
extern "C" {
#endif

extern uint8_t GPT_EFI_SIGNATURE[]; // it's just "EFI PART"

struct GPT_PartTableHeader{
uint8_t Signature[8]; // MUST BE "EFI PART"
uint32_t Revision;
uint32_t HeaderSize;
uint32_t CRC32_Checksum;
uint32_t Reserved0;
uint64_t ThisHdrLBA;
uint64_t AlternateHdrLBA;
uint64_t FirstUsableGptEntryBlock;
uint64_t LastUsableGptEntryBlock;
uint8_t GUID[16];
uint64_t StartLBA_GUID_Entries;
uint32_t NumEntries;
uint32_t PartitionEntrySize; // In bytes!
uint32_t CRC32_PartitionEntries;
uint8_t Reserved1[512-0x5C]; // Should be zeroed
} __attribute__((packed)) ;

struct GPT_PartitionEntry{
uint8_t PartitionTypeGUID[16]; // 0 == unused entry
uint8_t UniqueGUID[16];
uint64_t StartLBA;
uint64_t EndLBA;
uint8_t Attributes;
uint8_t PartitionName[72];
} __attribute__((packed)) ;

struct GPT_START{
MBR PMBR; // Protected MBR
GPT_PartTableHeader PartitionTableHeader;
} __attribute__((packed)) ;

struct GPT_END{
GPT_PartTableHeader PartitionTableHeaderMirror; // Has to be same as at the start
} __attribute__((packed)) ;

#if defined(__cplusplus)
} // extern "C"
#endif

#endif
48 changes: 48 additions & 0 deletions source/includes/disk/mbr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
*
* Master Boot Record (partition table)
*
*/
#ifndef __MBR_H
#define __MBR_H
#include <stdint.h>
#include <stddef.h>

#define MBR_PART_BOOTABLE 0x80
#define MBR_VALID_MBR 0xaa55

#if defined( __cplusplus )
extern "C" {
#endif

struct MBR_Partition{
uint8_t Attributes;

uint8_t StartHead;
uint8_t StartSector : 6;
uint16_t StartCylinder : 10;

uint8_t SystemID;

uint8_t EndHead;
uint8_t EndSector : 6;
uint16_t EndCylinder : 10;

uint32_t LBA_Start;
uint32_t SectorCount;
} __attribute__((packed)) ;

struct MBR{
uint8_t Bootloader[440];
uint32_t UniqueDiskID;
uint16_t Reserved0;
MBR_Partition Partitions[4];
uint16_t ValidationSignature;
} __attribute__((packed)) ;


#if defined( __cplusplus )
}
#endif

#endif
66 changes: 66 additions & 0 deletions source/kernel/C/ahci.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@
*
*/
#include <ahci.h>
#include <stdbool.h>

ahci_controller* global_ahci_ctrl = null;

void detect_ahci_devices(ahci_controller* ahci_ctrl) {
global_ahci_ctrl = ahci_ctrl;

for (int i = 0; i < 32; i++)
{
ahci_port* port = &ahci_ctrl->ports[i];
Expand All @@ -28,6 +33,15 @@ void detect_ahci_devices(ahci_controller* ahci_ctrl) {
int32 sig = port->sig;
if (sig == sata_disk) {
printf("SATA Disk detected at port %d", i);
uint8_t sector_buffer[SECTOR_SIZE * 5]; // Buffer to store 5 sectors

if (read_sectors(0, 5, sector_buffer) != 0) {
error("sector reading failed!", __FILE__);
}

for(int x = 0; x < SECTOR_SIZE * 5; x++){
// debug_printf("%u", sector_buffer[x]);
}
} else if (sig == satapi_disk) {
printf("SATAPI Disk detected at port %d", i);
} else if (sig == semb_disk) {
Expand All @@ -41,3 +55,55 @@ void detect_ahci_devices(ahci_controller* ahci_ctrl) {
}
}
}

ahci_command_header_t* get_free_command_header() {
// Iterate through command headers to find a free one
for (int i = 0; i < 32; i++) {
if (!(global_ahci_ctrl->ports[0].ci & 1)) {
info("FOUND FREE CMD HEADER!", __FILE__);
return &global_ahci_ctrl->ports[0].cmd;
}
}
// No free command headers available
return NULL;
}

// Function to allocate memory for PRDT entries
prdt_entry_t* allocate_prdt(size_t num_entries) {
// Allocate memory for the desired number of PRDT entries
return (prdt_entry_t*)malloc(num_entries * sizeof(prdt_entry_t));
}

int read_sectors(uint32_t lba, uint32_t sector_count, void* buffer) {
// 1. Get AHCI command header and PRDT
ahci_command_header_t* cmd_header = get_free_command_header();
prdt_entry_t* prdt = allocate_prdt(1);

// 2. Fill command FIS
cmd_header->cfis[0] = 0x27; // ATA command: Read
cmd_header->cfis[2] = lba & 0xFF;
cmd_header->cfis[3] = (lba >> 8) & 0xFF;
cmd_header->cfis[4] = (lba >> 16) & 0xFF;
cmd_header->cfis[5] = (lba >> 24) & 0xFF;
cmd_header->cfis[7] = sector_count & 0xFF;
cmd_header->cfis[8] = (sector_count >> 8) & 0xFF;

// 3. Fill PRDT
prdt[0].dba = (uint32_t)buffer; // Address of the buffer to store data
prdt[0].dbc = sector_count * SECTOR_SIZE - 1; // Number of bytes to transfer

// 4. Set up command header
cmd_header->prdtl = sizeof(prdt_entry_t); // Size of PRDT
cmd_header->prdt = (uint32_t)prdt;

// 5. Issue the command
cmd_header->ci = 1; // Issue command

// 6. Wait for command completion
// - Check command header->iss for completion status
// - Handle potential errors (e.g., check serr register)

// 7. Read data from the buffer

return 0; // Command successful
}

0 comments on commit 16e2acf

Please sign in to comment.