summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksa Vuckovic <aleksa@vuckovic.cc>2023-06-07 01:23:03 +0200
committerAleksa Vuckovic <aleksa@vuckovic.cc>2023-06-07 01:23:03 +0200
commit90e2de72ef2688986c206fd08605aec81b5890d6 (patch)
tree0a72bf0b2f2a564f3fc18314e6ea1cbe524eb28f
parentf5826164936359560ef5b88b97fc953065eb7794 (diff)
sata & ahciHEADmaster
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/include/ahci.h143
-rw-r--r--kernel/include/pci.h21
-rw-r--r--kernel/include/sata.h167
-rw-r--r--kernel/src/devices/pci.c67
-rw-r--r--kernel/src/devices/sata.c73
-rw-r--r--kernel/src/main.c2
7 files changed, 442 insertions, 32 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index b168ee0..3726508 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -26,6 +26,7 @@ OBJS = \
src/devices/keyboard.o \
src/devices/pci_info.o \
src/devices/pci.o \
+ src/devices/sata.o \
src/devices/serial.o \
src/devices/timer.o \
src/fs/ext2.o \
diff --git a/kernel/include/ahci.h b/kernel/include/ahci.h
new file mode 100644
index 0000000..2758c37
--- /dev/null
+++ b/kernel/include/ahci.h
@@ -0,0 +1,143 @@
+#ifndef AHCI_H
+#define AHCI_H
+
+#include <types.h>
+#include <sata.h>
+
+#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
+
+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;
+
+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
+ uint16_t sdbfis; // Set Device Bit FIS
+
+ // 0x60
+ uint8_t ufis[64];
+
+ // 0xA0
+ uint8_t rsv[0x100 - 0xA0];
+} HBA_FIS;
+
+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;
+
+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;
+
+#endif
diff --git a/kernel/include/pci.h b/kernel/include/pci.h
index 779d75a..d9475ff 100644
--- a/kernel/include/pci.h
+++ b/kernel/include/pci.h
@@ -2,8 +2,9 @@
#define PCI_H
#include <types.h>
+#include <libk/list.h>
-struct pci_dev {
+struct pci_dev_t {
uint16_t vendor_id;
uint16_t device_id;
uint16_t command;
@@ -17,6 +18,22 @@ struct pci_dev {
uint8_t header_type;
uint8_t bist;
};
-typedef struct pci_dev pci_dev;
+typedef struct pci_dev_t pci_dev_t;
+
+struct pci_dev0_t {
+ pci_dev_t pci_dev;
+ uint32_t bar[6];
+};
+typedef struct pci_dev0_t pci_dev0_t;
+
+struct pci_dev_list_t {
+ pci_dev0_t *dev;
+ list_t list;
+};
+typedef struct pci_dev_list_t pci_dev_list_t;
+
+extern pci_dev_list_t pci_dev_list;
+
+void pci_print_all(void);
#endif
diff --git a/kernel/include/sata.h b/kernel/include/sata.h
new file mode 100644
index 0000000..3705218
--- /dev/null
+++ b/kernel/include/sata.h
@@ -0,0 +1,167 @@
+#ifndef SATA_H
+#define SATA_H
+
+#include <types.h>
+
+#define ATA_CMD_IDENTIFY 0xEC
+
+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;
+
+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;
+
+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;
+
+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;
+
+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;
+
+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;
+
+void ahci(void);
+
+#endif
diff --git a/kernel/src/devices/pci.c b/kernel/src/devices/pci.c
index 9862dee..ea6c80e 100644
--- a/kernel/src/devices/pci.c
+++ b/kernel/src/devices/pci.c
@@ -9,7 +9,9 @@
#include <pci.h>
#include <pci_info.h>
-inline void pci_print_dev(pci_dev *pci_func)
+pci_dev_list_t pci_dev_list;
+
+inline void pci_print_dev(pci_dev_t *pci_func)
{
const char *vendor_str = get_vendor(pci_func->vendor_id);
const char *class_str = get_class(pci_func->class_);
@@ -54,18 +56,20 @@ void enumerate_function(uint64_t dev_addr, uint64_t function)
uint64_t func_addr = dev_addr + (function << 12);
map_addr(func_addr, func_addr, FLAG_PRESENT);
- pci_dev *pci_func = (pci_dev *)kalloc(sizeof(pci_dev));
- memcpy(pci_func, (uint64_t *)func_addr, sizeof(pci_dev));
+ pci_dev0_t *pci_func = (pci_dev0_t *)kalloc(sizeof(pci_dev0_t));
+ memcpy(pci_func, (uint64_t *)func_addr, sizeof(pci_dev0_t));
- if (pci_func->device_id == 0)
- goto error;
- if (pci_func->device_id == 0xFFFF)
- goto error;
+ int id = pci_func->pci_dev.device_id;
+ if (id == 0 || id == 0xFFFF) {
+ kfree(pci_func);
+ return;
+ }
- pci_print_dev(pci_func);
+ pci_dev_list_t *dev_list = kalloc(sizeof(pci_dev_list_t));
+ dev_list->dev = pci_func;
-error:
- kfree(pci_func);
+ add_to_list(&dev_list->list, &pci_dev_list.list,
+ pci_dev_list.list.next);
}
void enumerate_device(uint64_t bus_addr, uint64_t device)
@@ -73,21 +77,18 @@ void enumerate_device(uint64_t bus_addr, uint64_t device)
uint64_t dev_addr = bus_addr + (device << 15);
map_addr(dev_addr, dev_addr, FLAG_PRESENT);
- pci_dev *pci_device = (pci_dev *)kalloc(sizeof(pci_dev));
- memcpy(pci_device, (uint64_t *)bus_addr, sizeof(pci_dev));
+ pci_dev_t *pci_device = (pci_dev_t *)kalloc(sizeof(pci_dev_t));
+ memcpy(pci_device, (uint64_t *)bus_addr, sizeof(pci_dev_t));
- if (pci_device->device_id == 0)
- goto error;
- if (pci_device->device_id == 0xFFFF)
- goto error;
+ if (pci_device->device_id == 0 || pci_device->device_id == 0xFFFF) {
+ kfree(pci_device);
+ return;
+ }
size_t func;
for (func = 0; func < 8; func++) {
enumerate_function(dev_addr, func);
}
-
-error:
- kfree(pci_device);
}
void enumerate_bus(uint64_t base_addr, uint64_t bus)
@@ -95,31 +96,39 @@ void enumerate_bus(uint64_t base_addr, uint64_t bus)
uint64_t bus_addr = base_addr + (bus << 20);
map_addr(bus_addr, bus_addr, FLAG_PRESENT);
- pci_dev *pci_device = (pci_dev *)kalloc(sizeof(pci_dev));
- memcpy(pci_device, (uint64_t *)bus_addr, sizeof(pci_dev));
+ pci_dev_t *pci_device = (pci_dev_t *)kalloc(sizeof(pci_dev_t));
+ memcpy(pci_device, (uint64_t *)bus_addr, sizeof(pci_dev_t));
- if (pci_device->device_id == 0)
- goto error;
- if (pci_device->device_id == 0xFFFF)
- goto error;
+ if (pci_device->device_id == 0 || pci_device->device_id == 0xFFFF) {
+ kfree(pci_device);
+ return;
+ }
size_t dev;
for (dev = 0; dev < 32; dev++) {
enumerate_device(bus_addr, dev);
}
-
-error:
- kfree(pci_device);
}
void enumerate_cfg_space(config_space_mcfgt *cfg_space)
{
+ INIT_LIST(pci_dev_list.list);
+
size_t i;
for (i = cfg_space->start_bus; i < cfg_space->end_bus; i++) {
enumerate_bus(cfg_space->base_addr, i);
}
}
+void pci_print_all()
+{
+ pci_dev_list_t *curr;
+ list_for_each_entry(curr, (&pci_dev_list.list), list) {
+ pci_print_dev(&curr->dev->pci_dev);
+ }
+ printf("\n");
+}
+
void read_mcfgt()
{
uint64_t *mcfgt_addr = find_sys_table_addr("MCFG");
@@ -145,9 +154,7 @@ void read_mcfgt()
for (i = 0; i < len; i++) {
memcpy(cfg_space, (uint64_t *)mcfgt_cfg_addr,
sizeof(config_space_mcfgt));
- /* printf("addr: 0x%x, group: %d, start: %d, stop: %d\n", cfg_space->base_addr, cfg_space->pci_seg_group, cfg_space->start_bus, cfg_space->end_bus); */
enumerate_cfg_space(cfg_space);
}
- printf("\n");
kfree(cfg_space);
}
diff --git a/kernel/src/devices/sata.c b/kernel/src/devices/sata.c
new file mode 100644
index 0000000..d091941
--- /dev/null
+++ b/kernel/src/devices/sata.c
@@ -0,0 +1,73 @@
+#include <sata.h>
+#include <libk/string.h>
+#include <libk/stdio.h>
+#include <heap.h>
+#include <paging.h>
+#include <pci.h>
+#include <ahci.h>
+
+// 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) {
+ printf("SATA drive found at port %d\n", i);
+ } else if (dt == AHCI_DEV_SATAPI) {
+ printf("SATAPI drive found at port %d\n", i);
+ } else if (dt == AHCI_DEV_SEMB) {
+ printf("SEMB drive found at port %d\n", i);
+ } else if (dt == AHCI_DEV_PM) {
+ printf("PM drive found at port %d\n", i);
+ }
+ }
+
+ pi >>= 1;
+ i++;
+ }
+}
+
+void ahci()
+{
+ pci_dev_list_t *pos;
+ list_for_each_entry(pos, (&pci_dev_list.list), list) {
+ pci_dev_t *dev = &pos->dev->pci_dev;
+ if (dev->class_ != 0x1 || dev->subclass != 0x6)
+ continue;
+
+ HBA_MEM *abar = (HBA_MEM *)(uint64_t)pos->dev->bar[5];
+ printf("AHCI: %x\n", abar);
+ map_addr((uint64_t)abar, (uint64_t)abar,
+ FLAG_PRESENT | FLAG_WRITABLE | FLAG_HUGE);
+
+ probe_port(abar);
+ }
+}
diff --git a/kernel/src/main.c b/kernel/src/main.c
index ceba990..465c4b3 100644
--- a/kernel/src/main.c
+++ b/kernel/src/main.c
@@ -26,6 +26,7 @@
#include <scheduler.h>
#include <process.h>
#include <mcfg.h>
+#include <sata.h>
int kernel_main(mb2_tag_header *multiboot_bootinfo, uint32_t multiboot_magic);
int kernel_main(mb2_tag_header *multiboot_bootinfo, uint32_t multiboot_magic)
@@ -52,6 +53,7 @@ int kernel_main(mb2_tag_header *multiboot_bootinfo, uint32_t multiboot_magic)
enable_interrupts();
init_userspace();
read_mcfgt();
+ ahci();
init_scheduler();