Add basic xHCI driver and USB devices enumeration

This commit is contained in:
2026-08-07 21:11:08 +03:00
parent a2128de3e2
commit 4813725cf3
12 changed files with 721 additions and 117 deletions
+15 -38
View File
@@ -1,10 +1,10 @@
#include "src/kernel/nvme.h"
#include "src/kernel/log.h"
#include "src/kernel/memory.h"
#include "src/kernel/panic.h"
#include "src/kernel/pci.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#define SECTOR_SIZE 512
@@ -41,8 +41,8 @@ typedef volatile struct __attribute__((packed)) {
#define NVME_REGS_ASQS_R(r) BITS_R(r->aqa, 11, 0)
#define NVME_REGS_ASQS_W(r, v) BITS_W(r->aqa, 11, 0, v)
static nvme_regs_t *regs = (nvme_regs_t *)(KERNEL_VIRTUAL_BASE + MEMORY_SIZE);
static volatile uint32_t *db_regs = (uint32_t *)(KERNEL_VIRTUAL_BASE + MEMORY_SIZE + 0x1000); // TODO Get stride from caps.
static nvme_regs_t *regs = (nvme_regs_t *)KERNEL_VIRTUAL_NVME;
static volatile uint32_t *db_regs = (uint32_t *)(KERNEL_VIRTUAL_NVME + 0x1000); // TODO Get stride from caps.
#define QUEUE_DEPTH 2
@@ -140,7 +140,7 @@ static void io_exec_sync(nvme_sqe_t *cmd) {
memory_copy(cmd, sizeof(nvme_sqe_t), &io_sq[io_sq_tail]);
TRACE_LN("Advancing submission doorbell...");
db_regs[2] = io_sq_tail = (io_sq_tail + 1) % QUEUE_DEPTH; // TODO Get offset from caps.
db_regs[2] = io_sq_tail = (io_sq_tail + 1) % QUEUE_DEPTH;
TRACE_LN("Waiting for completion...");
nvme_cqe_t *cmp = &io_cq[io_cq_head];
@@ -165,46 +165,23 @@ static void io_exec_sync(nvme_sqe_t *cmd) {
}
void nvme_init() {
LOG_LN("Searching for suitable device...");
uint8_t found = 0;
for (uint16_t bus = 0; bus < PCI_MAX_BUSES && !found; bus++) {
for (uint8_t device = 0; device < PCI_MAX_DEVICES && !found; device++) {
for (uint8_t function = 0; function < PCI_MAX_FUNCTIONS && !found; function++) {
uint32_t id = pci_read((uint8_t)bus, device, function, PCI_OFFSET_DEVICE_VENDOR);
if (PCI_DEVICE(id) == PCI_DEVICE_EMPTY) {
continue;
}
uint32_t class = pci_read((uint8_t)bus, device, function, PCI_OFFSET_CLASS_REVISION);
if (PCI_CLASS(class) != NVME_PCI_CLASS || PCI_CLASS_SUB(class) != NVME_PCI_SUBCLASS) {
continue;
}
TRACE_LN("Searching for suitable device...");
pci_bdf_t bdf = pci_find_by_class(NVME_PCI_CLASS, NVME_PCI_SUBCLASS, NUL);
ASSERT(bdf, "nvme_init: No suitable devices found.");
LOG_LN("Found device, %hx:%hx.", PCI_VENDOR(id), PCI_DEVICE(id));
uint64_t bar = pci_bar((uint8_t)bus, device, function);
LOG_LN("Mapping device to memory, phys %lx <-> virt %lx...", bar, regs);
for (uint8_t i = 0; i < 4; i++) {
memory_page_map((void *)KERNEL_VIRTUAL_PML4, (void *)((uint8_t *)regs + i * PAGE_SIZE), (void *)((uint8_t *)bar + i * PAGE_SIZE),
PAGE_WRITABLE | PAGE_PCD | PAGE_USER);
}
found = 1;
}
}
}
ASSERT(found, "nvme_init: No suitable devices found.");
TRACE_LN("Mapping device to virtual memory...");
pci_map(bdf, regs, 4);
ASSERT(NVME_REGS_NVME_CS_SUPPORTED(regs), "nvme_init: NVM command set not supported.");
ASSERT(QUEUE_DEPTH <= NVME_REGS_MQES(regs), "nvme_init: Command queues are too big.")
LOG_LN("Disabling device...");
TRACE_LN("Disabling device...");
regs->cc = 0;
TRACE_VAL_F(regs->cc, "%lx");
while (NVME_REGS_RDY(regs))
;
TRACE_VAL_F(regs->cc, "%lx");
LOG_LN("Configuring device...");
TRACE_LN("Configuring device...");
NVME_REGS_ASQS_W(regs, QUEUE_DEPTH - 1);
regs->asq = (uint64_t)(VIRT_TO_PHYS(admin_sq));
NVME_REGS_ACQS_W(regs, QUEUE_DEPTH - 1);
@@ -213,7 +190,7 @@ void nvme_init() {
TRACE_VAL_F(regs->acq, "%lx");
TRACE_VAL_F(regs->aqa, "%lx");
LOG_LN("Enabling device...");
TRACE_LN("Enabling device...");
NVME_REGS_IOCQES_W(regs, 4);
NVME_REGS_IOSQES_W(regs, 6);
NVME_REGS_CSS_W(regs, 0);
@@ -223,7 +200,7 @@ void nvme_init() {
;
TRACE_VAL_F(regs->cc, "%lx");
LOG_LN("Creating I/O completion queue...");
TRACE_LN("Creating I/O completion queue...");
nvme_sqe_t create_io_cq = {
.opc = 0x05,
.prp1 = (uint64_t)VIRT_TO_PHYS(io_cq),
@@ -232,7 +209,7 @@ void nvme_init() {
};
admin_exec_sync(&create_io_cq);
LOG_LN("Creating I/O submission queue...");
TRACE_LN("Creating I/O submission queue...");
nvme_sqe_t create_io_sq = {
.opc = 0x01,
.prp1 = (uint64_t)VIRT_TO_PHYS(io_sq),
@@ -241,7 +218,7 @@ void nvme_init() {
};
admin_exec_sync(&create_io_sq);
LOG_LN("Done.");
TRACE_LN("Done.");
}
void nvme_read_sectors(uint32_t index, uint8_t count, void *to) {