[not working] basic achi driver
This commit is contained in:
parent
5303b1e59c
commit
eec6b437ad
4
Makefile
4
Makefile
|
@ -13,10 +13,10 @@ NASMFLAGS += -felf32
|
|||
BIN = sysroot/boot/hhhos.bin
|
||||
ISO = build/HhhOS.iso
|
||||
|
||||
DIRS = build build/boot build/std build/drivers build/drivers/terminal build/drivers/idt build/drivers/device build/drivers/keyboard build/drivers/pic
|
||||
DIRS = build build/boot build/std build/drivers build/drivers/terminal build/drivers/idt build/drivers/device build/drivers/keyboard build/drivers/pic build/drivers/ahci
|
||||
|
||||
OBJS = build/boot/boot.o build/boot/kernel.o build/std/string.o build/drivers/terminal/terminal.o build/drivers/idt/idt.o \
|
||||
build/drivers/idt/isr.o build/std/util.o build/drivers/device/device.o build/drivers/keyboard/keyboard.o build/drivers/pic/pic.o
|
||||
build/drivers/idt/isr.o build/std/util.o build/drivers/device/device.o build/drivers/keyboard/keyboard.o build/drivers/pic/pic.o build/drivers/ahci/ahci.o
|
||||
|
||||
ARCHDIR = arch/$(ARCH)/
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <drivers/keyboard/keyboard.h>
|
||||
#include <drivers/pic/pic.h>
|
||||
#include <drivers/device/device.h>
|
||||
#include <drivers/ahci/ahci.h>
|
||||
|
||||
/* Check if the compiler thinks you are targeting the wrong operating system. */
|
||||
#if defined(__linux__)
|
||||
|
@ -28,6 +29,9 @@ void kmain() {
|
|||
int keyboard_descriptor = keyboard_init();
|
||||
terminal_writestring("done, descriptor: ");
|
||||
terminal_writeline(itoa(keyboard_descriptor));
|
||||
|
||||
terminal_writestring("Preparing AHCI... ");
|
||||
ahci_init();
|
||||
|
||||
terminal_writestring("Are interrupts enabled? ");
|
||||
if (are_interrupts_enabled() == 1) {
|
||||
|
@ -42,8 +46,8 @@ void kmain() {
|
|||
terminal_writeline("no");
|
||||
}
|
||||
|
||||
terminal_writestring("kmain memory address: ");
|
||||
terminal_writeline(itoa(kmain));
|
||||
//terminal_writestring("kmain memory address: ");
|
||||
//terminal_writeline(itoa(kmain));
|
||||
|
||||
terminal_writeline("----------");
|
||||
|
||||
|
|
213
arch/i386/drivers/ahci/ahci.c
Normal file
213
arch/i386/drivers/ahci/ahci.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
#include <stdint.h>
|
||||
#include <drivers/ahci/ahci.h>
|
||||
#include <drivers/terminal/terminal.h>
|
||||
#include <std/util.h>
|
||||
#include <std/string.h>
|
||||
#include <std/inline.h>
|
||||
|
||||
// AHCI driver, source: https://wiki.osdev.org/AHCI
|
||||
|
||||
static void trace_ahci(const char* message, int i) {
|
||||
terminal_writestring(message);
|
||||
terminal_writeline(itoa(i));
|
||||
}
|
||||
|
||||
// Check device type
|
||||
static int check_type(HBA_PORT *port) {
|
||||
uint32_t ssts = port->ssts;
|
||||
|
||||
uint8_t ipm = (ssts >> 8) & 0x0F;
|
||||
uint8_t det = ssts & 0x0F;
|
||||
|
||||
if (det != HBA_PORT_DET_PRESENT) // Check drive status
|
||||
return AHCI_DEV_NULL;
|
||||
if (ipm != HBA_PORT_IPM_ACTIVE)
|
||||
return AHCI_DEV_NULL;
|
||||
|
||||
switch (port->sig)
|
||||
{
|
||||
case SATA_SIG_ATAPI:
|
||||
return AHCI_DEV_SATAPI;
|
||||
case SATA_SIG_SEMB:
|
||||
return AHCI_DEV_SEMB;
|
||||
case SATA_SIG_PM:
|
||||
return AHCI_DEV_PM;
|
||||
default:
|
||||
return AHCI_DEV_SATA;
|
||||
}
|
||||
}
|
||||
|
||||
void probe_port(HBA_MEM *abar) {
|
||||
// Search disk in implemented ports
|
||||
uint32_t pi = abar->pi;
|
||||
int i = 0;
|
||||
while (i<32)
|
||||
{
|
||||
if (pi & 1)
|
||||
{
|
||||
int dt = check_type(&abar->ports[i]);
|
||||
if (dt == AHCI_DEV_SATA)
|
||||
{
|
||||
trace_ahci("SATA drive found at port: ", i);
|
||||
}
|
||||
else if (dt == AHCI_DEV_SATAPI)
|
||||
{
|
||||
trace_ahci("SATAPI drive found at port: ", i);
|
||||
}
|
||||
else if (dt == AHCI_DEV_SEMB)
|
||||
{
|
||||
trace_ahci("SEMB drive found at port: ", i);
|
||||
}
|
||||
else if (dt == AHCI_DEV_PM)
|
||||
{
|
||||
trace_ahci("PM drive found at port: ", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
//trace_ahci("No drive found at port: ", i);
|
||||
}
|
||||
}
|
||||
|
||||
pi >>= 1;
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pci_config_read_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t address;
|
||||
uint32_t lbus = (uint32_t)bus;
|
||||
uint32_t lslot = (uint32_t)slot;
|
||||
uint32_t lfunc = (uint32_t)func;
|
||||
uint64_t tmp = 0;
|
||||
|
||||
/* create configuration address as per Figure 1 */
|
||||
address = (uint32_t)((lbus << 16) | (lslot << 11) |
|
||||
(lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000));
|
||||
|
||||
/* write out the address */
|
||||
outportl(0xCF8, address);
|
||||
/* read in the data */
|
||||
/* (offset & 2) * 8) = 0 will choose the first word of the 32 bits register */
|
||||
if (offset == 0x24)
|
||||
tmp = inportb(0xCFC) ;
|
||||
else
|
||||
tmp = (uint16_t)( (inportb(0xCFC) >> ((offset & 2) * 8) ) & 0xffff);
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
uint16_t get_vendor_id(uint8_t bus, uint8_t slot)
|
||||
{
|
||||
return pci_config_read_word(bus, slot, 0, 0);
|
||||
}
|
||||
|
||||
uint16_t get_device_id(uint8_t bus, uint8_t slot)
|
||||
{
|
||||
return pci_config_read_word(bus, slot, 0, 2);
|
||||
}
|
||||
|
||||
uint64_t check_device(uint8_t bus, uint8_t device) {
|
||||
//uint8_t function = 0;
|
||||
|
||||
uint16_t vendorID = get_vendor_id(bus, device);
|
||||
if(vendorID == 0xFFFF) return 0; // Device doesn't exist
|
||||
uint16_t deviceID = get_device_id(bus, device);
|
||||
|
||||
return pci_config_read_word(bus, device, 0, 0x24);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t check_all_buses(void)
|
||||
{
|
||||
uint16_t bus;
|
||||
uint8_t device;
|
||||
uint64_t bar5;
|
||||
|
||||
for(bus = 0; bus < 256; bus++)
|
||||
{
|
||||
for(device = 0; device < 32; device++)
|
||||
{
|
||||
bar5 = check_device(bus, device);
|
||||
if (bar5 == 0) return 0;
|
||||
probe_port((HBA_MEM*)bar5);
|
||||
return bar5;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Start command engine
|
||||
void start_cmd(HBA_PORT *port)
|
||||
{
|
||||
// Wait until CR (bit15) is cleared
|
||||
while (port->cmd & HBA_PxCMD_CR);
|
||||
|
||||
// Set FRE (bit4) and ST (bit0)
|
||||
port->cmd |= HBA_PxCMD_FRE;
|
||||
port->cmd |= HBA_PxCMD_ST;
|
||||
}
|
||||
|
||||
// Stop command engine
|
||||
void stop_cmd(HBA_PORT *port)
|
||||
{
|
||||
// Clear ST (bit0)
|
||||
port->cmd &= ~HBA_PxCMD_ST;
|
||||
|
||||
// Clear FRE (bit4)
|
||||
port->cmd &= ~HBA_PxCMD_FRE;
|
||||
|
||||
// Wait until FR (bit14), CR (bit15) are cleared
|
||||
while(1)
|
||||
{
|
||||
if (port->cmd & HBA_PxCMD_FR)
|
||||
continue;
|
||||
if (port->cmd & HBA_PxCMD_CR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void port_rebase(HBA_PORT *port, int portno)
|
||||
{
|
||||
stop_cmd(port); // Stop command engine
|
||||
|
||||
// Command list offset: 1K*portno
|
||||
// Command list entry size = 32
|
||||
// Command list entry maxim count = 32
|
||||
// Command list maxim size = 32*32 = 1K per port
|
||||
port->clb = AHCI_BASE + (portno<<10);
|
||||
port->clbu = 0;
|
||||
memset((void*)(port->clb), 0, 1024);
|
||||
|
||||
// FIS offset: 32K+256*portno
|
||||
// FIS entry size = 256 bytes per port
|
||||
port->fb = AHCI_BASE + (32<<10) + (portno<<8);
|
||||
port->fbu = 0;
|
||||
memset((void*)(port->fb), 0, 256);
|
||||
|
||||
// Command table offset: 40K + 8K*portno
|
||||
// Command table size = 256*32 = 8K per port
|
||||
HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)(port->clb);
|
||||
for (int i=0; i<32; i++)
|
||||
{
|
||||
cmdheader[i].prdtl = 8; // 8 prdt entries per command table
|
||||
// 256 bytes per command table, 64+16+48+16*8
|
||||
// Command table offset: 40K + 8K*portno + cmdheader_index*256
|
||||
cmdheader[i].ctba = AHCI_BASE + (40<<10) + (portno<<13) + (i<<8);
|
||||
cmdheader[i].ctbau = 0;
|
||||
memset((void*)cmdheader[i].ctba, 0, 256);
|
||||
}
|
||||
|
||||
start_cmd(port); // Start command engine
|
||||
}
|
||||
|
||||
void ahci_init(void) {
|
||||
uint64_t bar5 = check_all_buses();
|
||||
if (bar5 == 0) {
|
||||
terminal_writeline("Error: Could not find AHCI device");
|
||||
return;
|
||||
}
|
||||
|
||||
terminal_writestring("Found AHCI device at: ");
|
||||
terminal_writeline(itoa(bar5));
|
||||
}
|
354
include/drivers/ahci/ahci.h
Normal file
354
include/drivers/ahci/ahci.h
Normal file
|
@ -0,0 +1,354 @@
|
|||
#ifndef _AHCI_H
|
||||
#define _AHCI_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// AHCI driver, source: https://wiki.osdev.org/AHCI
|
||||
|
||||
// FIS = Frame Information Structure
|
||||
|
||||
// ---- FIS types ----
|
||||
// Following code defines different kinds of FIS specified in Serial ATA Revision 3.0.
|
||||
typedef enum {
|
||||
FIS_TYPE_REG_H2D = 0x27, // Register FIS - host to device
|
||||
FIS_TYPE_REG_D2H = 0x34, // Register FIS - device to host
|
||||
FIS_TYPE_DMA_ACT = 0x39, // DMA activate FIS - device to host
|
||||
FIS_TYPE_DMA_SETUP = 0x41, // DMA setup FIS - bidirectional
|
||||
FIS_TYPE_DATA = 0x46, // Data FIS - bidirectional
|
||||
FIS_TYPE_BIST = 0x58, // BIST activate FIS - bidirectional
|
||||
FIS_TYPE_PIO_SETUP = 0x5F, // PIO setup FIS - device to host
|
||||
FIS_TYPE_DEV_BITS = 0xA1, // Set device bits FIS - device to host
|
||||
} FIS_TYPE;
|
||||
|
||||
// ---- Various other FIS things (this struct was not found in OSDev wiki)
|
||||
typedef struct tagFIS_SET_DEVICE_BITS {
|
||||
uint8_t fis_type;
|
||||
uint8_t pmport:4;
|
||||
uint8_t rsvd:2;
|
||||
uint8_t i:1;
|
||||
uint8_t n:1;
|
||||
uint8_t statusl:3;
|
||||
uint8_t rsvd2:1;
|
||||
uint8_t statush:3;
|
||||
uint8_t rsvd3:1;
|
||||
uint8_t error;
|
||||
} FIS_DEV_BITS;
|
||||
|
||||
// ---- Register FIS - Host to Device ----
|
||||
typedef struct tagFIS_REG_H2D
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_REG_H2D
|
||||
|
||||
uint8_t pmport:4; // Port multiplier
|
||||
uint8_t rsv0:3; // Reserved
|
||||
uint8_t c:1; // 1: Command, 0: Control
|
||||
|
||||
uint8_t command; // Command register
|
||||
uint8_t featurel; // Feature register, 7:0
|
||||
|
||||
// DWORD 1
|
||||
uint8_t lba0; // LBA low register, 7:0
|
||||
uint8_t lba1; // LBA mid register, 15:8
|
||||
uint8_t lba2; // LBA high register, 23:16
|
||||
uint8_t device; // Device register
|
||||
|
||||
// DWORD 2
|
||||
uint8_t lba3; // LBA register, 31:24
|
||||
uint8_t lba4; // LBA register, 39:32
|
||||
uint8_t lba5; // LBA register, 47:40
|
||||
uint8_t featureh; // Feature register, 15:8
|
||||
|
||||
// DWORD 3
|
||||
uint8_t countl; // Count register, 7:0
|
||||
uint8_t counth; // Count register, 15:8
|
||||
uint8_t icc; // Isochronous command completion
|
||||
uint8_t control; // Control register
|
||||
|
||||
// DWORD 4
|
||||
uint8_t rsv1[4]; // Reserved
|
||||
} FIS_REG_H2D;
|
||||
|
||||
// ---- Register FIS – Device to Host ----
|
||||
// A device to host register FIS is used by the device to notify the host that some ATA register has changed. It contains the updated task files such as status, error and other registers.
|
||||
typedef struct tagFIS_REG_D2H
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_REG_D2H
|
||||
|
||||
uint8_t pmport:4; // Port multiplier
|
||||
uint8_t rsv0:2; // Reserved
|
||||
uint8_t i:1; // Interrupt bit
|
||||
uint8_t rsv1:1; // Reserved
|
||||
|
||||
uint8_t status; // Status register
|
||||
uint8_t error; // Error register
|
||||
|
||||
// DWORD 1
|
||||
uint8_t lba0; // LBA low register, 7:0
|
||||
uint8_t lba1; // LBA mid register, 15:8
|
||||
uint8_t lba2; // LBA high register, 23:16
|
||||
uint8_t device; // Device register
|
||||
|
||||
// DWORD 2
|
||||
uint8_t lba3; // LBA register, 31:24
|
||||
uint8_t lba4; // LBA register, 39:32
|
||||
uint8_t lba5; // LBA register, 47:40
|
||||
uint8_t rsv2; // Reserved
|
||||
|
||||
// DWORD 3
|
||||
uint8_t countl; // Count register, 7:0
|
||||
uint8_t counth; // Count register, 15:8
|
||||
uint8_t rsv3[2]; // Reserved
|
||||
|
||||
// DWORD 4
|
||||
uint8_t rsv4[4]; // Reserved
|
||||
} FIS_REG_D2H;
|
||||
|
||||
// ---- Data FIS – Bidirectional ----
|
||||
// This FIS is used by the host or device to send data payload. The data size can be varied.
|
||||
typedef struct tagFIS_DATA {
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_DATA
|
||||
|
||||
uint8_t pmport:4; // Port multiplier
|
||||
uint8_t rsv0:4; // Reserved
|
||||
|
||||
uint8_t rsv1[2]; // Reserved
|
||||
|
||||
// DWORD 1 ~ N
|
||||
uint32_t data[1]; // Payload
|
||||
} FIS_DATA;
|
||||
|
||||
// ---- PIO Setup – Device to Host ----
|
||||
// This FIS is used by the device to tell the host that it’s about to send or ready to receive a PIO data payload.
|
||||
typedef struct tagFIS_PIO_SETUP {
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_PIO_SETUP
|
||||
|
||||
uint8_t pmport:4; // Port multiplier
|
||||
uint8_t rsv0:1; // Reserved
|
||||
uint8_t d:1; // Data transfer direction, 1 - device to host
|
||||
uint8_t i:1; // Interrupt bit
|
||||
uint8_t rsv1:1;
|
||||
|
||||
uint8_t status; // Status register
|
||||
uint8_t error; // Error register
|
||||
|
||||
// DWORD 1
|
||||
uint8_t lba0; // LBA low register, 7:0
|
||||
uint8_t lba1; // LBA mid register, 15:8
|
||||
uint8_t lba2; // LBA high register, 23:16
|
||||
uint8_t device; // Device register
|
||||
|
||||
// DWORD 2
|
||||
uint8_t lba3; // LBA register, 31:24
|
||||
uint8_t lba4; // LBA register, 39:32
|
||||
uint8_t lba5; // LBA register, 47:40
|
||||
uint8_t rsv2; // Reserved
|
||||
|
||||
// DWORD 3
|
||||
uint8_t countl; // Count register, 7:0
|
||||
uint8_t counth; // Count register, 15:8
|
||||
uint8_t rsv3; // Reserved
|
||||
uint8_t e_status; // New value of status register
|
||||
|
||||
// DWORD 4
|
||||
uint16_t tc; // Transfer count
|
||||
uint8_t rsv4[2]; // Reserved
|
||||
} FIS_PIO_SETUP;
|
||||
|
||||
// ---- DMA Setup – Device to Host ----
|
||||
typedef struct tagFIS_DMA_SETUP {
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_DMA_SETUP
|
||||
|
||||
uint8_t pmport:4; // Port multiplier
|
||||
uint8_t rsv0:1; // Reserved
|
||||
uint8_t d:1; // Data transfer direction, 1 - device to host
|
||||
uint8_t i:1; // Interrupt bit
|
||||
uint8_t a:1; // Auto-activate. Specifies if DMA Activate FIS is needed
|
||||
|
||||
uint8_t rsved[2]; // Reserved
|
||||
|
||||
//DWORD 1&2
|
||||
|
||||
uint64_t DMAbufferID; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
|
||||
|
||||
//DWORD 3
|
||||
uint32_t rsvd; //More reserved
|
||||
|
||||
//DWORD 4
|
||||
uint32_t DMAbufOffset; //Byte offset into buffer. First 2 bits must be 0
|
||||
|
||||
//DWORD 5
|
||||
uint32_t TransferCount; //Number of bytes to transfer. Bit 0 must be 0
|
||||
|
||||
//DWORD 6
|
||||
uint32_t resvd; //Reserved
|
||||
|
||||
} FIS_DMA_SETUP;
|
||||
|
||||
|
||||
// ---- Memory structs (HBA memory registers) ----
|
||||
typedef volatile struct tagHBA_PORT {
|
||||
uint32_t clb; // 0x00, command list base address, 1K-byte aligned
|
||||
uint32_t clbu; // 0x04, command list base address upper 32 bits
|
||||
uint32_t fb; // 0x08, FIS base address, 256-byte aligned
|
||||
uint32_t fbu; // 0x0C, FIS base address upper 32 bits
|
||||
uint32_t is; // 0x10, interrupt status
|
||||
uint32_t ie; // 0x14, interrupt enable
|
||||
uint32_t cmd; // 0x18, command and status
|
||||
uint32_t rsv0; // 0x1C, Reserved
|
||||
uint32_t tfd; // 0x20, task file data
|
||||
uint32_t sig; // 0x24, signature
|
||||
uint32_t ssts; // 0x28, SATA status (SCR0:SStatus)
|
||||
uint32_t sctl; // 0x2C, SATA control (SCR2:SControl)
|
||||
uint32_t serr; // 0x30, SATA error (SCR1:SError)
|
||||
uint32_t sact; // 0x34, SATA active (SCR3:SActive)
|
||||
uint32_t ci; // 0x38, command issue
|
||||
uint32_t sntf; // 0x3C, SATA notification (SCR4:SNotification)
|
||||
uint32_t fbs; // 0x40, FIS-based switch control
|
||||
uint32_t rsv1[11]; // 0x44 ~ 0x6F, Reserved
|
||||
uint32_t vendor[4]; // 0x70 ~ 0x7F, vendor specific
|
||||
} HBA_PORT;
|
||||
|
||||
typedef volatile struct tagHBA_MEM {
|
||||
// 0x00 - 0x2B, Generic Host Control
|
||||
uint32_t cap; // 0x00, Host capability
|
||||
uint32_t ghc; // 0x04, Global host control
|
||||
uint32_t is; // 0x08, Interrupt status
|
||||
uint32_t pi; // 0x0C, Port implemented
|
||||
uint32_t vs; // 0x10, Version
|
||||
uint32_t ccc_ctl; // 0x14, Command completion coalescing control
|
||||
uint32_t ccc_pts; // 0x18, Command completion coalescing ports
|
||||
uint32_t em_loc; // 0x1C, Enclosure management location
|
||||
uint32_t em_ctl; // 0x20, Enclosure management control
|
||||
uint32_t cap2; // 0x24, Host capabilities extended
|
||||
uint32_t bohc; // 0x28, BIOS/OS handoff control and status
|
||||
|
||||
// 0x2C - 0x9F, Reserved
|
||||
uint8_t rsv[0xA0-0x2C];
|
||||
|
||||
// 0xA0 - 0xFF, Vendor specific registers
|
||||
uint8_t vendor[0x100-0xA0];
|
||||
|
||||
// 0x100 - 0x10FF, Port control registers
|
||||
HBA_PORT ports[1]; // 1 ~ 32
|
||||
} HBA_MEM;
|
||||
|
||||
// ---- Received FIS ----
|
||||
typedef volatile struct tagHBA_FIS {
|
||||
// 0x00
|
||||
FIS_DMA_SETUP dsfis; // DMA Setup FIS
|
||||
uint8_t pad0[4];
|
||||
|
||||
// 0x20
|
||||
FIS_PIO_SETUP psfis; // PIO Setup FIS
|
||||
uint8_t pad1[12];
|
||||
|
||||
// 0x40
|
||||
FIS_REG_D2H rfis; // Register – Device to Host FIS
|
||||
uint8_t pad2[4];
|
||||
|
||||
// 0x58
|
||||
FIS_DEV_BITS sdbfis; // Set Device Bit FIS
|
||||
|
||||
// 0x60
|
||||
uint8_t ufis[64];
|
||||
|
||||
// 0xA0
|
||||
uint8_t rsv[0x100-0xA0];
|
||||
} HBA_FIS;
|
||||
|
||||
// ---- Command List ----
|
||||
typedef struct tagHBA_CMD_HEADER {
|
||||
// DW0
|
||||
uint8_t cfl:5; // Command FIS length in DWORDS, 2 ~ 16
|
||||
uint8_t a:1; // ATAPI
|
||||
uint8_t w:1; // Write, 1: H2D, 0: D2H
|
||||
uint8_t p:1; // Prefetchable
|
||||
|
||||
uint8_t r:1; // Reset
|
||||
uint8_t b:1; // BIST
|
||||
uint8_t c:1; // Clear busy upon R_OK
|
||||
uint8_t rsv0:1; // Reserved
|
||||
uint8_t pmp:4; // Port multiplier port
|
||||
|
||||
uint16_t prdtl; // Physical region descriptor table length in entries
|
||||
|
||||
// DW1
|
||||
volatile
|
||||
uint32_t prdbc; // Physical region descriptor byte count transferred
|
||||
|
||||
// DW2, 3
|
||||
uint32_t ctba; // Command table descriptor base address
|
||||
uint32_t ctbau; // Command table descriptor base address upper 32 bits
|
||||
|
||||
// DW4 - 7
|
||||
uint32_t rsv1[4]; // Reserved
|
||||
} HBA_CMD_HEADER;
|
||||
|
||||
// ---- Command Table and Physical Region Descriptor Table ----
|
||||
typedef struct tagHBA_PRDT_ENTRY {
|
||||
uint32_t dba; // Data base address
|
||||
uint32_t dbau; // Data base address upper 32 bits
|
||||
uint32_t rsv0; // Reserved
|
||||
|
||||
// DW3
|
||||
uint32_t dbc:22; // Byte count, 4M max
|
||||
uint32_t rsv1:9; // Reserved
|
||||
uint32_t i:1; // Interrupt on completion
|
||||
} HBA_PRDT_ENTRY;
|
||||
|
||||
typedef struct tagHBA_CMD_TBL {
|
||||
// 0x00
|
||||
uint8_t cfis[64]; // Command FIS
|
||||
|
||||
// 0x40
|
||||
uint8_t acmd[16]; // ATAPI command, 12 or 16 bytes
|
||||
|
||||
// 0x50
|
||||
uint8_t rsv[48]; // Reserved
|
||||
|
||||
// 0x80
|
||||
HBA_PRDT_ENTRY prdt_entry[1]; // Physical region descriptor table entries, 0 ~ 65535
|
||||
} HBA_CMD_TBL;
|
||||
|
||||
// ---- Signatures and values ----
|
||||
|
||||
#define SATA_SIG_ATA 0x00000101 // SATA drive
|
||||
#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
|
||||
#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge
|
||||
#define SATA_SIG_PM 0x96690101 // Port multiplier
|
||||
|
||||
#define AHCI_DEV_NULL 0
|
||||
#define AHCI_DEV_SATA 1
|
||||
#define AHCI_DEV_SEMB 2
|
||||
#define AHCI_DEV_PM 3
|
||||
#define AHCI_DEV_SATAPI 4
|
||||
|
||||
#define HBA_PORT_IPM_ACTIVE 1
|
||||
#define HBA_PORT_DET_PRESENT 3
|
||||
|
||||
#define AHCI_BASE 0x400000 // 4M
|
||||
|
||||
#define HBA_PxCMD_ST 0x0001
|
||||
#define HBA_PxCMD_FRE 0x0010
|
||||
#define HBA_PxCMD_FR 0x4000
|
||||
#define HBA_PxCMD_CR 0x8000
|
||||
|
||||
#define ATA_DEV_BUSY 0x80
|
||||
#define ATA_DEV_DRQ 0x08
|
||||
|
||||
// ---- Functions ----
|
||||
|
||||
void ahci_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _AHCI_H */
|
Loading…
Reference in a new issue