Add AHCI SATA device enumeration + SATA device IDENTIFY
This commit is contained in:
@@ -5,3 +5,4 @@ doc/latex
|
||||
bochsrc.txt
|
||||
config
|
||||
test.img
|
||||
eth_*
|
||||
|
||||
@@ -36,6 +36,7 @@ OBJS+=$(O)/sys/amd64/hw/rs232.o \
|
||||
$(O)/sys/amd64/hw/pci/pci.o \
|
||||
$(O)/sys/amd64/hw/pci/ide.o \
|
||||
$(O)/sys/amd64/hw/pci/ahci.o \
|
||||
$(O)/sys/amd64/hw/ide/ahci.o \
|
||||
$(O)/sys/amd64/hw/pci/pcidb.o \
|
||||
$(ACPICA_OBJS) \
|
||||
$(O)/sys/amd64/acpi_osl_mem.o \
|
||||
@@ -82,4 +83,5 @@ DIRS+=$(O)/sys/amd64/image/boot/grub \
|
||||
$(O)/sys/amd64/sys \
|
||||
$(O)/sys/amd64/mm \
|
||||
$(O)/sys/amd64/hw/pci \
|
||||
$(O)/sys/amd64/hw/ide \
|
||||
$(ACPICA_OBJD)
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
#define AHCI_PORT_SSTS_DET_OK 0x3
|
||||
#define AHCI_PORT_SSTS_IPM_ACTIVE 0x1
|
||||
#define AHCI_PORT_SIG_SATA 0x00000101
|
||||
#define AHCI_PORT_SIG_SATAPI 0xEB140101
|
||||
|
||||
#define AHCI_PORT_CMD_ST (1 << 0)
|
||||
#define AHCI_PORT_CMD_FRE (1 << 4)
|
||||
#define AHCI_PORT_CMD_FR (1 << 14)
|
||||
#define AHCI_PORT_CMD_CR (1 << 15)
|
||||
|
||||
enum ahci_fis_type {
|
||||
FIS_REG_H2D = 0x27,
|
||||
FIS_REG_D2H = 0x34,
|
||||
FIS_DMA_ACT = 0x39,
|
||||
FIS_DMA_SETUP = 0x41,
|
||||
FIS_DATA = 0x46,
|
||||
FIS_BIST = 0x58,
|
||||
FIS_PIO_SETUP = 0x5F,
|
||||
FIS_DEV_BITS = 0xA1
|
||||
};
|
||||
|
||||
struct ahci_registers {
|
||||
// Generic host control
|
||||
uint32_t cap; // 0x00
|
||||
uint32_t ghc; // 0x04
|
||||
uint32_t is; // 0x08
|
||||
uint32_t pi; // 0x0C
|
||||
uint32_t vs; // 0x10
|
||||
uint32_t ccc_ctl; // 0x14
|
||||
uint32_t ccc_ports; // 0x18
|
||||
uint32_t em_loc; // 0x1C
|
||||
uint32_t em_ctl; // 0x20
|
||||
uint32_t cap2; // 0x24
|
||||
uint32_t bohc; // 0x28
|
||||
// Reserved
|
||||
uint32_t __res0[13];
|
||||
// Reserved for NVMHCI
|
||||
// Also vendor specific settings
|
||||
uint32_t __res1[40];
|
||||
|
||||
// Port control registers
|
||||
struct ahci_port_registers {
|
||||
uint32_t p_clb;
|
||||
uint32_t p_clbu;
|
||||
uint32_t p_fb;
|
||||
uint32_t p_fbu;
|
||||
uint32_t p_is;
|
||||
uint32_t p_ie;
|
||||
uint32_t p_cmd;
|
||||
uint32_t __res0;
|
||||
uint32_t p_tfd;
|
||||
uint32_t p_sig;
|
||||
uint32_t p_ssts;
|
||||
uint32_t p_sctl;
|
||||
uint32_t p_serr;
|
||||
uint32_t p_sact;
|
||||
uint32_t p_ci;
|
||||
uint32_t p_sntf;
|
||||
uint32_t p_fbs;
|
||||
uint32_t p_devslp;
|
||||
uint32_t __res1[14];
|
||||
} __attribute__((packed)) ports[32];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ahci_fis_reg_h2d {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
uint8_t cmd;
|
||||
uint8_t feature_low;
|
||||
|
||||
uint8_t lba0;
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t dev;
|
||||
|
||||
uint8_t lba3;
|
||||
uint8_t lba4;
|
||||
uint8_t lba5;
|
||||
uint8_t feature_high;
|
||||
|
||||
uint8_t countl;
|
||||
uint8_t counth;
|
||||
uint8_t icc;
|
||||
uint8_t control;
|
||||
|
||||
uint8_t __res0[4];
|
||||
};
|
||||
|
||||
struct ahci_fis_reg_d2h {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
uint8_t status;
|
||||
uint8_t error;
|
||||
|
||||
uint8_t lba0;
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t dev;
|
||||
|
||||
uint8_t lba3;
|
||||
uint8_t lba4;
|
||||
uint8_t lba5;
|
||||
uint8_t __res0;
|
||||
|
||||
uint8_t countl;
|
||||
uint8_t counth;
|
||||
|
||||
uint8_t __res1[6];
|
||||
};
|
||||
|
||||
struct ahci_fis_dma_setup {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
uint8_t __res0[2];
|
||||
uint64_t dma_buffer_id;
|
||||
uint32_t __res1;
|
||||
uint32_t dma_buffer_offset;
|
||||
uint32_t transfer_count;
|
||||
uint32_t __res2;
|
||||
};
|
||||
|
||||
struct ahci_fis_pio_setup {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
uint8_t status;
|
||||
uint8_t error;
|
||||
|
||||
uint8_t lba0;
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t device;
|
||||
|
||||
uint8_t lba3;
|
||||
uint8_t lba4;
|
||||
uint8_t lba5;
|
||||
uint8_t __res0;
|
||||
|
||||
uint8_t countl;
|
||||
uint8_t counth;
|
||||
uint8_t __res1;
|
||||
uint8_t e_status;
|
||||
|
||||
uint16_t tc;
|
||||
uint8_t __res2[2];
|
||||
};
|
||||
|
||||
struct ahci_fis_data {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
|
||||
uint8_t __res0[2];
|
||||
|
||||
uint32_t data[];
|
||||
};
|
||||
|
||||
struct ahci_recv_fis {
|
||||
union {
|
||||
// DMA setup FIS
|
||||
struct ahci_fis_dma_setup dsfis;
|
||||
char __block0[0x20];
|
||||
};
|
||||
union {
|
||||
// PIO setup FIS
|
||||
struct ahci_fis_pio_setup psfis;
|
||||
char __block1[0x20];
|
||||
};
|
||||
union {
|
||||
// Register FIS
|
||||
struct ahci_fis_reg_d2h rfis;
|
||||
char __block2[0x18];
|
||||
};
|
||||
union {
|
||||
// Set device bits FIS
|
||||
char __block3[0x2];
|
||||
};
|
||||
union {
|
||||
// Unknown FIS
|
||||
char __block4[0x40];
|
||||
};
|
||||
};
|
||||
|
||||
struct ahci_command_header {
|
||||
// Bits:
|
||||
// 0..4 Command length in dwords
|
||||
// 5 ATAPI
|
||||
uint16_t attr;
|
||||
uint16_t prdtl;
|
||||
volatile uint32_t prdbc;
|
||||
uint32_t ctba;
|
||||
uint32_t ctbau;
|
||||
uint32_t __res0[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ahci_prdt_entry {
|
||||
uint32_t dba;
|
||||
uint32_t dbau;
|
||||
uint32_t __res0;
|
||||
// Bits:
|
||||
// 0 1
|
||||
// 1..21 Data byte count
|
||||
// 22..30 Reserved
|
||||
// 31 Interrupt
|
||||
uint32_t dbc;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ahci_command_table_entry {
|
||||
union {
|
||||
struct ahci_fis_reg_h2d fis_reg_h2d;
|
||||
uint8_t __cmd_fis[64];
|
||||
} __attribute__((packed));
|
||||
uint8_t acmd[16];
|
||||
uint8_t __res0[48];
|
||||
struct ahci_prdt_entry prdt[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define AHCI_PORT_CMD_LIST(p) (struct ahci_command_header *) MM_VIRTUALIZE(((uintptr_t) (p)->p_clbu << 32) | ((p)->p_clb))
|
||||
#define AHCI_CMD_TABLE_ENTRY(l, i) (struct ahci_command_table_entry *) MM_VIRTUALIZE(((uintptr_t) (l)[i].ctbau << 32) | ((l)[i].ctba))
|
||||
|
||||
void ahci_port_start(struct ahci_port_registers *port);
|
||||
void ahci_port_stop(struct ahci_port_registers *port);
|
||||
|
||||
void ahci_port_init(uint8_t n, struct ahci_port_registers *port);
|
||||
|
||||
void ahci_init(struct ahci_registers *regs);
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
|
||||
#define ATA_SR_BUSY (1 << 7)
|
||||
#define ATA_SR_DRQ (1 << 3)
|
||||
|
||||
#define ATA_IDENT_DEVICE_TYPE 0x00
|
||||
#define ATA_IDENT_CYLINDERS 0x02
|
||||
#define ATA_IDENT_HEADS 0x06
|
||||
#define ATA_IDENT_SECTORS 0x0C
|
||||
#define ATA_IDENT_SERIAL 0x14
|
||||
#define ATA_IDENT_MODEL 0x36
|
||||
#define ATA_IDENT_CAPS 0x62
|
||||
#define ATA_IDENT_MAX_LBA 0x78
|
||||
#define ATA_IDENT_CMD_SETS 0xA4
|
||||
#define ATA_IDENT_MAX_LBAEXT 0xC8
|
||||
@@ -1,4 +1,11 @@
|
||||
#pragma once
|
||||
#include "pci.h"
|
||||
#include "sys/amd64/hw/ide/ahci.h"
|
||||
|
||||
struct pci_ahci {
|
||||
pci_addr_t addr;
|
||||
uint32_t abar_phys;
|
||||
struct ahci_registers *volatile regs;
|
||||
};
|
||||
|
||||
void pci_ahci_init(pci_addr_t addr);
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
#include "sys/amd64/hw/ide/ahci.h"
|
||||
#include "sys/amd64/hw/ide/ata.h"
|
||||
#include "sys/amd64/mm/phys.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
// Memory required for a port:
|
||||
// 1024 - command list (32 * sizeof(ahci_command_header))
|
||||
// 256 - received FIS
|
||||
// 8192 - command table (32 * sizeof(ahci_command_table_entry))
|
||||
// So we need at least 3 pages for all the stuff (buffers not included)
|
||||
|
||||
static int ahci_alloc_cmd(struct ahci_port_registers *port) {
|
||||
uint32_t slots = (port->p_sact | port->p_ci);
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (!(slots & (1 << i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ahci_sata_port_identify(struct ahci_port_registers *port) {
|
||||
port->p_is = -1;
|
||||
|
||||
int cmd = ahci_alloc_cmd(port);
|
||||
_assert(cmd != -1);
|
||||
|
||||
// Command list
|
||||
struct ahci_command_header *cmd_list = AHCI_PORT_CMD_LIST(port);
|
||||
struct ahci_command_header *cmd_header = &cmd_list[cmd];
|
||||
// Command table entry for the slot
|
||||
struct ahci_command_table_entry *cmd_table = AHCI_CMD_TABLE_ENTRY(cmd_list, cmd);
|
||||
|
||||
// One PRDT entry
|
||||
char ident_buf[1024] = {0};
|
||||
uintptr_t ident_buf_phys = ((uintptr_t) ident_buf) - 0xFFFFFF0000000000;
|
||||
|
||||
cmd_header->attr = (sizeof(struct ahci_fis_reg_h2d) / 4);
|
||||
cmd_header->prdtl = 1;
|
||||
|
||||
memset(cmd_table, 0, sizeof(struct ahci_command_table_entry) + sizeof(struct ahci_prdt_entry));
|
||||
cmd_table->prdt[0].dba = ident_buf_phys & 0xFFFFFFFF;
|
||||
cmd_table->prdt[0].dbau = ident_buf_phys >> 32;
|
||||
cmd_table->prdt[0].dbc = 1 | ((sizeof(ident_buf) - 1) << 1);
|
||||
|
||||
struct ahci_fis_reg_h2d *fis_reg_h2d = &cmd_table->fis_reg_h2d;
|
||||
memset(fis_reg_h2d, 0, sizeof(struct ahci_fis_reg_h2d));
|
||||
fis_reg_h2d->type = FIS_REG_H2D;
|
||||
fis_reg_h2d->cmd = ATA_CMD_IDENTIFY;
|
||||
fis_reg_h2d->cmd_port = 1 << 7;
|
||||
|
||||
uint32_t spin = 0;
|
||||
while ((port->p_tfd & (ATA_SR_BUSY | ATA_SR_DRQ)) && spin < 1000000) {
|
||||
++spin;
|
||||
}
|
||||
if (spin == 1000000) {
|
||||
panic("SATA port hang\n");
|
||||
}
|
||||
|
||||
port->p_ci |= 1 << cmd;
|
||||
|
||||
while (1) {
|
||||
if (!(port->p_ci & (1 << cmd))) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (port->p_is & (1 << 30) /* AHCI_PORT_IS_TFES */) {
|
||||
panic("Port task file error\n");
|
||||
}
|
||||
}
|
||||
|
||||
kdebug("Drive identification:\n");
|
||||
|
||||
char model_str[41] = {0};
|
||||
uint32_t cmd_sets = *(uint32_t *) (ident_buf + ATA_IDENT_CMD_SETS);
|
||||
uint32_t disk_size = 0;
|
||||
for (size_t i = 0; i < 40; i += 2) {
|
||||
model_str[i] = ident_buf[ATA_IDENT_MODEL + i + 1];
|
||||
model_str[i + 1] = ident_buf[ATA_IDENT_MODEL + i];
|
||||
}
|
||||
|
||||
if (cmd_sets & (1 << 26)) {
|
||||
disk_size = *((uint32_t *) (ident_buf + ATA_IDENT_MAX_LBAEXT));
|
||||
} else {
|
||||
disk_size = *((uint32_t *) (ident_buf + ATA_IDENT_MAX_LBA));
|
||||
}
|
||||
|
||||
kdebug("Model: %s\n", model_str);
|
||||
kdebug("Size: %S\n", disk_size * 512);
|
||||
}
|
||||
|
||||
static void ahci_sata_port_init(struct ahci_port_registers *port) {
|
||||
ahci_port_stop(port);
|
||||
|
||||
uintptr_t page0 = amd64_phys_alloc_page();
|
||||
_assert(page0 != MM_NADDR);
|
||||
kdebug("Command list/recv FIS: %p\n", page0);
|
||||
|
||||
memset((void *) MM_VIRTUALIZE(page0), 0, 4096);
|
||||
|
||||
port->p_clb = page0 & 0xFFFFFFFF;
|
||||
port->p_clbu = page0 >> 32;
|
||||
|
||||
port->p_fb = (page0 + 0x400) & 0xFFFFFFFF;
|
||||
port->p_fbu = (page0 + 0x400) >> 32;
|
||||
|
||||
// 8K
|
||||
uintptr_t page1 = amd64_phys_alloc_contiguous(2);
|
||||
_assert(page1 != MM_NADDR);
|
||||
memset((void *) MM_VIRTUALIZE(page1), 0, 8192);
|
||||
|
||||
struct ahci_command_header *cmd_list = (struct ahci_command_header *) MM_VIRTUALIZE(page0);
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
uintptr_t addr = page1 + i * 256;
|
||||
|
||||
cmd_list[i].prdtl = 8;
|
||||
cmd_list[i].ctba = addr & 0xFFFFFFFF;
|
||||
cmd_list[i].ctbau = addr >> 32;
|
||||
}
|
||||
|
||||
ahci_port_start(port);
|
||||
|
||||
// TODO: add the device somewhere to kernel as /dev/sdX
|
||||
// guess I should implement device management eventually
|
||||
}
|
||||
|
||||
// Setup a SATA port
|
||||
void ahci_port_init(uint8_t n, struct ahci_port_registers *port) {
|
||||
switch (port->p_sig) {
|
||||
case AHCI_PORT_SIG_SATA:
|
||||
ahci_sata_port_init(port);
|
||||
ahci_sata_port_identify(port);
|
||||
break;
|
||||
default:
|
||||
kdebug("Skipping unknown drive type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ahci_port_stop(struct ahci_port_registers *port) {
|
||||
port->p_cmd &= ~(AHCI_PORT_CMD_ST | AHCI_PORT_CMD_FRE);
|
||||
|
||||
while (port->p_cmd & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_FR));
|
||||
}
|
||||
|
||||
void ahci_port_start(struct ahci_port_registers *port) {
|
||||
while (port->p_cmd & AHCI_PORT_CMD_CR);
|
||||
|
||||
port->p_cmd |= AHCI_PORT_CMD_FRE | AHCI_PORT_CMD_ST;
|
||||
}
|
||||
|
||||
void ahci_init(struct ahci_registers *regs) {
|
||||
// Read AHCI version
|
||||
kdebug("Initializing AHCI controller version %d.%d\n", regs->vs >> 16, regs->vs & 0xFFFF);
|
||||
|
||||
uint32_t pi = regs->pi;
|
||||
|
||||
// Find available ports
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
uint32_t bit = 1 << i;
|
||||
|
||||
if (pi & bit) {
|
||||
struct ahci_port_registers *port = ®s->ports[i];
|
||||
uint32_t ssts = port->p_ssts;
|
||||
|
||||
uint8_t ipm = (ssts >> 8) & 0x0F;
|
||||
uint8_t spd = (ssts >> 4) & 0x0F;
|
||||
uint8_t det = ssts & 0x0F;
|
||||
|
||||
if (ipm != AHCI_PORT_SSTS_IPM_ACTIVE || spd == 0 || det != AHCI_PORT_SSTS_DET_OK) {
|
||||
// For one of the reasons the device is not available at this port
|
||||
continue;
|
||||
}
|
||||
|
||||
ahci_port_init(i, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-154
@@ -1,131 +1,15 @@
|
||||
#include "sys/amd64/hw/pci/pci.h"
|
||||
#include "sys/amd64/hw/pci/ahci.h"
|
||||
#include "sys/amd64/hw/ide/ahci.h"
|
||||
#include "sys/amd64/hw/ide/ata.h"
|
||||
#include "sys/amd64/mm/phys.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
#define AHCI_PORT_SSTS_DET_OK 0x3
|
||||
#define AHCI_PORT_SSTS_IPM_ACTIVE 0x1
|
||||
#define AHCI_PORT_SIG_SATA 0x00000101
|
||||
#define AHCI_PORT_SIG_SATAPI 0xEB140101
|
||||
|
||||
enum ahci_fis_type {
|
||||
FIS_REG_H2D = 0x27,
|
||||
FIS_REG_D2H = 0x34,
|
||||
FIS_DMA_ACT = 0x39,
|
||||
FIS_DMA_SETUP = 0x41,
|
||||
FIS_DATA = 0x46,
|
||||
FIS_BIST = 0x58,
|
||||
FIS_PIO_SETUP = 0x5F,
|
||||
FIS_DEV_BITS = 0xA1
|
||||
};
|
||||
|
||||
struct ahci_registers {
|
||||
// Generic host control
|
||||
uint32_t cap; // 0x00
|
||||
uint32_t ghc; // 0x04
|
||||
uint32_t is; // 0x08
|
||||
uint32_t pi; // 0x0C
|
||||
uint32_t vs; // 0x10
|
||||
uint32_t ccc_ctl; // 0x14
|
||||
uint32_t ccc_ports; // 0x18
|
||||
uint32_t em_loc; // 0x1C
|
||||
uint32_t em_ctl; // 0x20
|
||||
uint32_t cap2; // 0x24
|
||||
uint32_t bohc; // 0x28
|
||||
// Reserved
|
||||
uint32_t __res0[13];
|
||||
// Reserved for NVMHCI
|
||||
// Also vendor specific settings
|
||||
uint32_t __res1[40];
|
||||
|
||||
// Port control registers
|
||||
struct ahci_port_registers {
|
||||
uint32_t p_clb;
|
||||
uint32_t p_clbu;
|
||||
uint32_t p_fb;
|
||||
uint32_t p_fbu;
|
||||
uint32_t p_is;
|
||||
uint32_t p_ie;
|
||||
uint32_t p_cmd;
|
||||
uint32_t __res0;
|
||||
uint32_t p_tfd;
|
||||
uint32_t p_sig;
|
||||
uint32_t p_ssts;
|
||||
uint32_t p_sctl;
|
||||
uint32_t p_serr;
|
||||
uint32_t p_sact;
|
||||
uint32_t p_ci;
|
||||
uint32_t p_sntf;
|
||||
uint32_t p_fbs;
|
||||
uint32_t p_devslp;
|
||||
uint32_t __res1[14];
|
||||
} __attribute__((packed)) ports[32];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ahci_fis_reg_h2d {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
uint8_t cmd;
|
||||
uint8_t feature_low;
|
||||
|
||||
uint8_t lba0;
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t dev;
|
||||
|
||||
uint8_t lba3;
|
||||
uint8_t lba4;
|
||||
uint8_t lba5;
|
||||
uint8_t feature_high;
|
||||
|
||||
uint8_t countl;
|
||||
uint8_t counth;
|
||||
uint8_t icc;
|
||||
uint8_t control;
|
||||
|
||||
uint8_t __res0[4];
|
||||
};
|
||||
|
||||
struct ahci_fis_reg_d2h {
|
||||
uint8_t type;
|
||||
uint8_t cmd_port;
|
||||
uint8_t status;
|
||||
uint8_t error;
|
||||
|
||||
uint8_t lba0;
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t dev;
|
||||
|
||||
uint8_t lba3;
|
||||
uint8_t lba4;
|
||||
uint8_t lba5;
|
||||
uint8_t __res0;
|
||||
|
||||
uint8_t countl;
|
||||
uint8_t counth;
|
||||
|
||||
uint8_t __res1[6];
|
||||
};
|
||||
|
||||
struct pci_ahci {
|
||||
pci_addr_t addr;
|
||||
uint32_t abar_phys;
|
||||
struct ahci_registers *volatile regs;
|
||||
};
|
||||
|
||||
// Only one controller is supported now
|
||||
static struct pci_ahci ahci;
|
||||
|
||||
// Setup a SATA port
|
||||
static void pci_ahci_sata_add(uint8_t n, struct ahci_port_registers *port) {
|
||||
kdebug("SATA port %d\n", n);
|
||||
}
|
||||
|
||||
// SATAPI port
|
||||
static void pci_ahci_satapi_add(uint8_t n, struct ahci_port_registers *port) {
|
||||
kdebug("SATAPI port %d\n", n);
|
||||
}
|
||||
|
||||
void pci_ahci_init(pci_addr_t addr) {
|
||||
kdebug("Initializing AHCI controller at " PCI_FMTADDR "\n", PCI_VAADDR(addr));
|
||||
|
||||
@@ -135,36 +19,5 @@ void pci_ahci_init(pci_addr_t addr) {
|
||||
|
||||
kdebug("AHCI registers: %p\n", ahci.regs);
|
||||
|
||||
// Read AHCI version
|
||||
kdebug("AHCI controller version %d.%d\n", ahci.regs->vs >> 16, ahci.regs->vs & 0xFFFF);
|
||||
|
||||
uint32_t pi = ahci.regs->pi;
|
||||
|
||||
// Find available ports
|
||||
for (size_t i = 0; i < 32; ++i) {
|
||||
uint32_t bit = 1 << i;
|
||||
|
||||
if (pi & bit) {
|
||||
struct ahci_port_registers *port = &ahci.regs->ports[i];
|
||||
uint32_t ssts = port->p_ssts;
|
||||
|
||||
uint8_t ipm = (ssts >> 8) & 0x0F;
|
||||
uint8_t spd = (ssts >> 4) & 0x0F;
|
||||
uint8_t det = ssts & 0x0F;
|
||||
|
||||
if (ipm != AHCI_PORT_SSTS_IPM_ACTIVE || spd == 0 || det != AHCI_PORT_SSTS_DET_OK) {
|
||||
// For one of the reasons the device is not available at this port
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (port->p_sig) {
|
||||
case AHCI_PORT_SIG_SATA:
|
||||
pci_ahci_sata_add(i, port);
|
||||
break;
|
||||
case AHCI_PORT_SIG_SATAPI:
|
||||
pci_ahci_satapi_add(i, port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ahci_init(ahci.regs);
|
||||
}
|
||||
|
||||
+42
@@ -1,5 +1,6 @@
|
||||
#include "sys/string.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/ctype.h"
|
||||
#include "sys/attr.h"
|
||||
#include "sys/spin.h"
|
||||
#include <stdint.h>
|
||||
@@ -297,3 +298,44 @@ void debugfv(int level, const char *fmt, va_list args) {
|
||||
spin_release_irqrestore(&debug_spin, &irq);
|
||||
}
|
||||
|
||||
void debug_dump(int level, const void *block, size_t count) {
|
||||
size_t n_lines = (count + 15) / 16;
|
||||
const char *bytes = block;
|
||||
|
||||
for (size_t l = 0; l < n_lines; ++l) {
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
if (i * 2 + l * 16 < count) {
|
||||
uint16_t word = *(const uint16_t *) (bytes + i * 2 + l * 16);
|
||||
|
||||
debugc(level, s_debug_xs_set1[(word >> 4) & 0xF]);
|
||||
debugc(level, s_debug_xs_set1[word & 0xF]);
|
||||
|
||||
debugc(level, s_debug_xs_set1[word >> 12]);
|
||||
debugc(level, s_debug_xs_set1[(word >> 8) & 0xF]);
|
||||
} else {
|
||||
debugc(level, ' ');
|
||||
debugc(level, ' ');
|
||||
debugc(level, ' ');
|
||||
debugc(level, ' ');
|
||||
}
|
||||
debugc(level, ' ');
|
||||
}
|
||||
|
||||
debugc(level, '|');
|
||||
debugc(level, ' ');
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
if (i + l * 16 < count) {
|
||||
char c = bytes[i + l * 16];
|
||||
|
||||
if (isprint(c)) {
|
||||
debugc(level, c);
|
||||
} else if (c != 0) {
|
||||
debugc(level, ' ');
|
||||
} else {
|
||||
debugc(level, '.');
|
||||
}
|
||||
}
|
||||
}
|
||||
debugc(level, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user