Skip to content

Storage Drivers

NtinosTheGamer2324 edited this page Dec 11, 2025 · 1 revision

Storage Drivers

ModuOS supports multiple storage interfaces through a layered driver architecture.

Storage Stack

┌─────────────────────────────────────────┐
│      File Systems (FAT32/ISO9660)       │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│         vDrive Layer (Virtual Drives)   │
│         Unified interface for all       │
└────┬───────────────────────┬────────────┘
     │                       │
┌────▼──────────┐    ┌──────▼────────────┐
│   ATA/ATAPI   │    │    AHCI/SATA      │
│   (IDE/PATA)  │    │   (Modern SATA)   │
└────┬──────────┘    └──────┬────────────┘
     │                      │
     └──────────┬───────────┘
                │
┌───────────────▼─────────────────────────┐
│         Hardware Controllers            │
│    IDE Controller | AHCI Controller     │
└─────────────────────────────────────────┘

Virtual Drive (vDrive) Layer

File: src/drivers/Drive/vDrive.c

Purpose

Provides a unified interface for all storage devices regardless of underlying controller type.

vDrive Structure

#define VDRIVE_MAX_DRIVES 8
#define VDRIVE_MAX_PARTITIONS 4

typedef struct {
    uint8_t initialized;
    uint8_t type;              // 0=None, 1=ATA, 2=AHCI
    uint8_t exists;
    uint8_t controller_index;  // Index in ATA/AHCI driver
    char model[41];
    uint64_t size_sectors;
    
    // Partition table
    struct {
        uint8_t exists;
        uint8_t type;          // Partition type (0x0B=FAT32, etc.)
        uint32_t start_lba;
        uint32_t size_sectors;
    } partitions[VDRIVE_MAX_PARTITIONS];
} vdrive_t;

API

int vdrive_init(void);
int vdrive_get_count(void);
int vdrive_read_sector(int vdrive_id, uint32_t lba, void* buffer);
int vdrive_write_sector(int vdrive_id, uint32_t lba, const void* buffer);

ATA/ATAPI Driver

File: src/drivers/Drive/ATA/ata.c

Overview

ATA (AT Attachment) is the legacy IDE interface for hard drives. ATAPI (ATA Packet Interface) extends ATA for CD/DVD drives.

Hardware Channels

Primary Channel (0x1F0):
  - Master (drive 0)
  - Slave (drive 1)

Secondary Channel (0x170):
  - Master (drive 2)
  - Slave (drive 3)

ATA Registers

#define ATA_PRIMARY_BASE    0x1F0
#define ATA_PRIMARY_CTRL    0x3F6
#define ATA_SECONDARY_BASE  0x170
#define ATA_SECONDARY_CTRL  0x376

// Register offsets
#define REG_DATA     0    // Data port
#define REG_ERROR    1    // Error register
#define REG_SECCNT   2    // Sector count
#define REG_LBA_LO   3    // LBA low byte
#define REG_LBA_MID  4    // LBA mid byte
#define REG_LBA_HI   5    // LBA high byte
#define REG_DRIVE    6    // Drive select
#define REG_STATUS   7    // Status register
#define REG_COMMAND  7    // Command register

ATA Commands

#define ATA_CMD_IDENTIFY       0xEC  // Identify drive
#define ATA_CMD_IDENTIFY_PACKET 0xA1  // Identify ATAPI
#define ATA_CMD_READ_PIO       0x20  // Read sectors (PIO)
#define ATA_CMD_READ_PIO_EXT   0x24  // Read sectors (LBA48)
#define ATA_CMD_WRITE_PIO      0x30  // Write sectors
#define ATA_CMD_CACHE_FLUSH    0xE7  // Flush cache
#define ATA_CMD_PACKET         0xA0  // ATAPI packet command

Read Operation

int ata_read_sector_lba28(int drive_index, uint32_t lba, void* buffer) {
    // 1. Select drive and wait
    // 2. Send LBA and sector count
    // 3. Send READ command
    // 4. Wait for DRQ (data request)
    // 5. Read 256 words (512 bytes)
    
    uint16_t base = get_base_port(drive_index);
    uint8_t drive = get_drive_select(drive_index);
    
    // Wait for drive ready
    ata_wait_not_busy(base);
    
    // Select drive with LBA mode
    outb(base + REG_DRIVE, 0xE0 | (drive << 4) | ((lba >> 24) & 0x0F));
    
    // Send sector count and LBA
    outb(base + REG_SECCNT, 1);
    outb(base + REG_LBA_LO, lba & 0xFF);
    outb(base + REG_LBA_MID, (lba >> 8) & 0xFF);
    outb(base + REG_LBA_HI, (lba >> 16) & 0xFF);
    
    // Send read command
    outb(base + REG_COMMAND, ATA_CMD_READ_PIO);
    
    // Wait for data
    ata_wait_drq(base);
    
    // Read data
    uint16_t *buf = (uint16_t*)buffer;
    for (int i = 0; i < 256; i++) {
        buf[i] = inw(base + REG_DATA);
    }
    
    return 0;
}

AHCI/SATA Driver

File: src/drivers/Drive/SATA/AHCI.c

Overview

AHCI (Advanced Host Controller Interface) is the modern standard for SATA controllers.

Features:

  • Hot-plug support
  • Native Command Queuing (NCQ)
  • Port multiplier support
  • Higher performance than legacy ATA

AHCI Architecture

┌────────────────────────────────────┐
│        AHCI HBA (Host Adapter)     │
│  ┌──────┬──────┬──────┬──────┐    │
│  │Port 0│Port 1│Port 2│Port 3│    │
│  └──┬───┴──┬───┴──┬───┴──┬───┘    │
└─────┼──────┼──────┼──────┼─────────┘
      │      │      │      │
   [SATA] [SATA] [SATA] [SATA]
   Drive   Drive  Drive  Drive

AHCI Structures

HBA Memory Registers:

typedef struct {
    uint32_t cap;        // Host capabilities
    uint32_t ghc;        // Global host control
    uint32_t is;         // Interrupt status
    uint32_t pi;         // Ports implemented
    uint32_t vs;         // Version
    // ... more registers
    uint8_t  reserved[0xA0-0x2C];
    uint8_t  vendor[0x100-0xA0];
    ahci_port_t ports[32];  // Port registers
} ahci_hba_mem_t;

Port Registers:

typedef struct {
    uint32_t clb;        // Command list base address
    uint32_t clbu;       // Command list base address upper
    uint32_t fb;         // FIS base address
    uint32_t fbu;        // FIS base address upper
    uint32_t is;         // Interrupt status
    uint32_t ie;         // Interrupt enable
    uint32_t cmd;        // Command and status
    uint32_t reserved0;
    uint32_t tfd;        // Task file data
    uint32_t sig;        // Signature
    uint32_t ssts;       // SATA status
    uint32_t sctl;       // SATA control
    uint32_t serr;       // SATA error
    uint32_t sact;       // SATA active
    uint32_t ci;         // Command issue
    // ...
} ahci_port_t;

AHCI Initialization

int ahci_init(void) {
    // 1. Find AHCI controller via PCI
    pci_device_t *ahci_dev = pci_find_class(PCI_CLASS_STORAGE, 0x06);
    
    // 2. Enable bus mastering
    pci_enable_bus_mastering(ahci_dev);
    
    // 3. Map ABAR (AHCI Base Address Register)
    uint32_t abar = pci_read_bar(ahci_dev, 5);
    ahci_hba_mem_t *hba = (ahci_hba_mem_t*)abar;
    
    // 4. Enable AHCI mode
    hba->ghc |= AHCI_GHC_AHCI_ENABLE;
    
    // 5. Detect drives on each port
    uint32_t pi = hba->pi;
    for (int i = 0; i < 32; i++) {
        if (pi & (1 << i)) {
            ahci_probe_port(hba, i);
        }
    }
}

Read Operation

int ahci_read_sectors(int port, uint64_t lba, uint32_t count, void* buffer) {
    // 1. Allocate command slot
    // 2. Build FIS (Frame Information Structure)
    // 3. Set up PRDT (Physical Region Descriptor Table)
    // 4. Issue command
    // 5. Wait for completion
    // 6. Copy data from buffer
}

Partition Detection

File: src/drivers/Drive/vDrive.c

MBR Partition Table

typedef struct {
    uint8_t status;          // 0x80=bootable
    uint8_t first_chs[3];    // CHS address (legacy)
    uint8_t type;            // Partition type
    uint8_t last_chs[3];     // CHS address
    uint32_t start_lba;      // Starting LBA
    uint32_t size_sectors;   // Size in sectors
} __attribute__((packed)) mbr_partition_t;

Partition Types:

  • 0x0B: FAT32
  • 0x0C: FAT32 (LBA)
  • 0x07: NTFS
  • 0x83: Linux ext2/ext3/ext4
  • 0x05: Extended partition

Partition Scanning

void vdrive_scan_partitions(int vdrive_id) {
    uint8_t mbr[512];
    vdrive_read_sector(vdrive_id, 0, mbr);
    
    // Check MBR signature
    if (mbr[510] != 0x55 || mbr[511] != 0xAA) {
        return;  // Invalid MBR
    }
    
    mbr_partition_t *partitions = (mbr_partition_t*)&mbr[446];
    
    for (int i = 0; i < 4; i++) {
        if (partitions[i].type != 0) {
            // Valid partition
            vdrive[vdrive_id].partitions[i].exists = 1;
            vdrive[vdrive_id].partitions[i].type = partitions[i].type;
            vdrive[vdrive_id].partitions[i].start_lba = partitions[i].start_lba;
            vdrive[vdrive_id].partitions[i].size_sectors = partitions[i].size_sectors;
        }
    }
}

Driver Performance

PIO vs. DMA

PIO (Programmed I/O):

  • CPU reads/writes each word
  • Simple but slow
  • Used in ModuOS for ATA

DMA (Direct Memory Access):

  • Controller transfers data directly to RAM
  • CPU-free, higher performance
  • Planned for future AHCI implementation

Typical Performance

Interface Mode Speed
ATA PIO PIO Mode 4 ~16 MB/s
ATA DMA UDMA 133 ~133 MB/s
SATA I AHCI ~150 MB/s
SATA II AHCI ~300 MB/s
SATA III AHCI ~600 MB/s

Next Steps

Clone this wiki locally