boredos_mirror/docs/architecture/storage/ahci_drivers.md

3 KiB

AHCI Storage Driver

BoredOS implements an Advanced Host Controller Interface (AHCI) driver to interface with Serial ATA (SATA) mass storage devices. The driver is located in src/dev/ahci.c and allows the OS to read and write sectors directly to physical hard drives or solid-state drives using DMA (Direct Memory Access).

1. Discovery and Initialization

The AHCI initialization process (ahci_init) starts by querying the PCI subsystem:

  1. It searches for a PCI device with Class 0x01 (Mass Storage) and Subclass 0x06 (SATA).
  2. It calls pci_enable_bus_mastering and pci_enable_mmio to ensure the controller can perform DMA and its registers are accessible.
  3. It retrieves the ABAR (AHCI Base Address Register) from PCI BAR5.
  4. The ABAR points to the HBA_MEM structure (Host Bus Adapter Memory Registers). The kernel iterates through the pi (Ports Implemented) bitmask to find active SATA ports.

2. Port Configuration

For every active SATA port found, the driver must allocate memory structures that the hardware will use to process commands:

  1. Command List Base (clb): A 1KB memory region holding 32 Command Headers.
  2. FIS Base (fb): A 256-byte memory region where the HBA writes incoming Frame Information Structures (FIS) from the drive.
  3. Command Tables (ctba): A larger memory region allocated for each Command Header, containing the actual SATA command bytes and the scatter/gather lists (PRDT).

Note: All AHCI data structures must be allocated in physically contiguous memory and properly aligned (e.g., 1KB or 256-byte boundaries) because the HBA reads them directly from physical RAM via DMA.

3. Physical Region Descriptor Tables (PRDT)

When reading or writing data, BoredOS must tell the AHCI controller where in RAM the data should be stored or fetched. This is done using PRDT entries.

Each HBA_PRDT_ENTRY specifies:

  • A physical Data Base Address (dba).
  • A Byte Count (dbc), limited to a maximum of 4MB per entry.

If a read/write request spans multiple fragmented pages or exceeds 4MB, the driver constructs multiple PRDT entries within the Command Table to form a scatter/gather list. The AHCI hardware seamlessly processes these entries as a single contiguous disk operation.

4. Reading and Writing Sectors

To execute a command (e.g., ahci_read_sectors or ahci_write_sectors):

  1. The driver finds a free slot in the Command List.
  2. It populates the Command Header, setting the cfl (Command FIS Length) and w (Write) bit.
  3. It builds a Host-to-Device Register FIS (FIS_REG_H2D) in the Command Table, issuing the ATA_CMD_READ_DMA_EX or ATA_CMD_WRITE_DMA_EX command and specifying the starting LBA (Logical Block Address) and sector count.
  4. It sets up the PRDT entries pointing to the physical memory of the provided buffer.
  5. It sets the corresponding bit in the Port's Command Issue register (ci).
  6. The driver then polls the ci register (or waits for an interrupt) until the bit clears, indicating the hardware has completed the DMA transfer.