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
+2
View File
@@ -86,7 +86,9 @@ kernel_sources = files([
'src/kernel/syscall.c',
'src/kernel/timer.c',
'src/kernel/tss.c',
'src/kernel/usb.c',
'src/kernel/vga.c',
'src/kernel/xhci.c',
])
kernel_elf = executable(
+14
View File
@@ -14,8 +14,10 @@
#include "src/kernel/syscall.h"
#include "src/kernel/timer.h"
#include "src/kernel/tss.h"
#include "src/kernel/usb.h"
#include "src/kernel/util.h"
#include "src/kernel/vga.h"
#include "src/kernel/xhci.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/syscall.h"
@@ -26,6 +28,15 @@ __attribute__((interrupt)) void isr_divide_by_zero(__attribute__((unused)) struc
;
}
__attribute__((interrupt)) void isr_invalid_opcode(struct interrupt_frame *frame) {
char msg[80];
string_format("INVALID OPCODE: ip=%x cs=%x flags=%x sp=%x", 80, msg, frame->ip, frame->cs, frame->flags, frame->sp);
vga_set_string(VGA_HEIGHT - 1, 0, msg, 0x4F);
while (1)
;
}
__attribute__((interrupt)) void isr_page_fault(__attribute__((unused)) struct interrupt_frame *frame, uint64_t error_code) {
uint64_t cr2;
__asm__ volatile("mov %%cr2, %0" : "=r"(cr2));
@@ -57,6 +68,7 @@ void kernel_main() {
idt_init();
outb(0x21, inb(0x21) | 0x01); // mask out timer interrupt
idt_set_entry(0, isr_divide_by_zero, 0x8E);
idt_set_entry(0x06, isr_invalid_opcode, 0x8E);
idt_set_entry_ec(0x0E, isr_page_fault, 0x8E);
idt_set_entry(0x0D, isr_general_violation, 0x8E);
idt_set_entry(46, isr_ata_primary, 0x8E);
@@ -65,6 +77,8 @@ void kernel_main() {
syscall_init();
pci_init();
nvme_init();
xhci_init();
usb_init();
process_t *kernel = memory_allocate(sizeof(process_t));
kernel->pml4 = (uint64_t *)KERNEL_VIRTUAL_PML4;
+19 -15
View File
@@ -6,37 +6,41 @@
extern stream_t *kernel_log;
#define LOG(fmt, ...) \
#define PRINT(stream, fmt, ...) \
do { \
uint64_t _size = string_length(fmt) * 10; \
char *_string = memory_allocate(_size); \
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \
kernel_log->write(kernel_log, _string, _size); \
stream->write(stream, _string, _size); \
memory_free(_string); \
} while (0)
#define PRINT_LN(stream, fmt, ...) \
do { \
uint64_t _size = string_length(fmt) * 10; \
char *_string = memory_allocate(_size); \
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \
stream->write(stream, __func__, string_length(__func__)); \
stream->write(stream, ": ", 2); \
stream->write(stream, _string, _size); \
stream->write(stream, "\n", 1); \
memory_free(_string); \
} while (0)
#define LOG(fmt, ...) PRINT(kernel_log, fmt, ##__VA_ARGS__)
#define TRACE(fmt, ...)
#define LOG_LN(fmt, ...) \
do { \
uint64_t _size = string_length(fmt) * 10; \
char *_string = memory_allocate(_size); \
_size = string_format(fmt, _size, _string, ##__VA_ARGS__); \
kernel_log->write(kernel_log, __func__, string_length(__func__)); \
kernel_log->write(kernel_log, ": ", 2); \
kernel_log->write(kernel_log, _string, _size); \
kernel_log->write(kernel_log, "\n", 1); \
memory_free(_string); \
} while (0)
#define LOG_LN(fmt, ...) PRINT_LN(kernel_log, fmt, ##__VA_ARGS__)
#define LOG_VAL(v) LOG_LN(#v "=%x")
#define LOG_VAL_F(v, f) LOG_LN(#v "=" f)
#define LOG_VAL_F(v, f) LOG_LN(#v "=" f, v)
#define TRACE_LN(fmt, ...)
#define TRACE_VAL(v) TRACE_LN(#v "=%lx")
#define TRACE_VAL_F(v, f) TRACE_LN(#v "=" f)
#define TRACE_VAL_F(v, f) TRACE_LN(#v "=" f, v)
void log_init(stream_t *log);
+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) {
+94 -38
View File
@@ -1,55 +1,111 @@
#include "src/kernel/pci.h"
#include "src/kernel/log.h"
#include "src/kernel/panic.h"
#include "src/kernel/memory.h"
#include "src/kernel/util.h"
#include "src/lib/layout.h"
#include "src/lib/util.h"
#define PCI_MAX_BUSES 256
#define PCI_MAX_DEVICES 32
#define PCI_MAX_FUNCTIONS 8
#define PCI_PORT_ADDRESS 0xCF8
#define PCI_PORT_DATA 0xCFC
void pci_init() {
LOG_LN("Scanning devices...");
for (uint16_t bus = 0; bus < PCI_MAX_BUSES; bus++) {
for (uint8_t device = 0; device < PCI_MAX_DEVICES; device++) {
for (uint8_t function = 0; function < PCI_MAX_FUNCTIONS; 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);
LOG_LN("%hx:%hx class=%hhx subclass=%hhx, iface=%hhx.", PCI_VENDOR(id), PCI_DEVICE(id), PCI_CLASS(class), PCI_CLASS_SUB(class),
PCI_CLASS_IFACE(class));
}
}
}
LOG_LN("Done.");
}
#define PCI_BDF(b, d, f) (pci_bdf_t)(((b) << 8) | ((d) << 3) | (f))
#define PCI_B(bdf) (((bdf) >> 8) & 0xFF)
#define PCI_D(bdf) (((bdf) >> 3) & 0x1F)
#define PCI_F(bdf) ((bdf) & 0x07)
uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) {
// ASSERT(bus < PCI_MAX_BUSES, "pci_read: Malformed address.");
ASSERT(device < PCI_MAX_DEVICES, "pci_read: Malformed address.");
ASSERT(function < PCI_MAX_FUNCTIONS, "pci_read: Malformed address.");
outl(PCI_PORT_ADDRESS,
((uint32_t)1 << 31) | ((uint32_t)bus << 16) | ((uint32_t)device << 11) | ((uint32_t)function << 8) | (offset & 0xFC));
#define PCI_OFFSET_DEVICE_VENDOR 0x00
#define PCI_OFFSET_STATUS_COMMAND 0x04
#define PCI_OFFSET_CLASS_REVISION 0x08
#define PCI_OFFSET_BAR_0 0x10
#define PCI_OFFSET_BAR_1 0x14
#define PCI_VENDOR(i) BITS_R(i, 15, 0)
#define PCI_DEVICE(i) BITS_R(i, 31, 16)
#define PCI_DEVICE_EMPTY 0xFFFF
#define PCI_CLASS(c) BITS_R(c, 31, 24)
#define PCI_SUBCLASS(c) BITS_R(c, 23, 16)
#define PCI_INTERFACE(c) BITS_R(c, 15, 8)
#define PCI_COMMAND_MEMORY_SPACE 0x02
#define PCI_COMMAND_BUS_MASTER 0x04
static uint32_t pci_read(pci_bdf_t bdf, uint8_t offset) {
outl(PCI_PORT_ADDRESS, ((uint32_t)1 << 31) | ((uint32_t)bdf << 8) | (offset & 0xFC));
return inl(PCI_PORT_DATA);
}
void pci_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) {
// ASSERT(bus < PCI_MAX_BUSES, "pci_write: Malformed address.");
ASSERT(device < PCI_MAX_DEVICES, "pci_write: Malformed address.");
ASSERT(function < PCI_MAX_FUNCTIONS, "pci_write: Malformed address.");
outl(PCI_PORT_ADDRESS,
((uint32_t)1 << 31) | ((uint32_t)bus << 16) | ((uint32_t)device << 11) | ((uint32_t)function << 8) | (offset & 0xFC));
static void pci_write(pci_bdf_t bdf, uint8_t offset, uint32_t value) {
outl(PCI_PORT_ADDRESS, ((uint32_t)1 << 31) | ((uint32_t)bdf << 8) | (offset & 0xFC));
outl(PCI_PORT_DATA, value);
}
uint64_t pci_bar(uint8_t bus, uint8_t device, uint8_t function) {
// ASSERT(bus < PCI_MAX_BUSES, "pci_bar: Malformed address.");
ASSERT(device < PCI_MAX_DEVICES, "pci_bar: Malformed address.");
ASSERT(function < PCI_MAX_FUNCTIONS, "pci_bar: Malformed address.");
void pci_init() {
LOG_LN("Scanning devices...");
pci_enumerate(kernel_log);
LOG_LN("Done.");
}
pci_write(bus, device, function, PCI_OFFSET_STATUS_COMMAND,
pci_read(bus, device, function, PCI_OFFSET_STATUS_COMMAND) | PCI_COMMAND_MEMORY_SPACE | PCI_COMMAND_BUS_MASTER);
void pci_enumerate(stream_t *out) {
for (uint16_t b = 0; b < PCI_MAX_BUSES; b++) {
for (uint8_t d = 0; d < PCI_MAX_DEVICES; d++) {
for (uint8_t f = 0; f < PCI_MAX_FUNCTIONS; f++) {
uint32_t id = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_DEVICE_VENDOR);
if (PCI_DEVICE(id) == PCI_DEVICE_EMPTY) {
continue;
}
uint32_t class = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_CLASS_REVISION);
PRINT_LN(out, "%hx:%hx class=%hhx subclass=%hhx iface=%hhx.", PCI_VENDOR(id), PCI_DEVICE(id), PCI_CLASS(class),
PCI_SUBCLASS(class), PCI_INTERFACE(class));
}
}
}
}
return ((uint64_t)pci_read(bus, device, function, PCI_OFFSET_BAR_1) << 32) |
(pci_read(bus, device, function, PCI_OFFSET_BAR_0) & 0xFFFFFFF0);
pci_bdf_t pci_find_by_class(uint8_t class, uint8_t subclass, uint8_t iface) {
for (uint16_t b = 0; b < PCI_MAX_BUSES; b++) {
for (uint8_t d = 0; d < PCI_MAX_DEVICES; d++) {
for (uint8_t f = 0; PCI_MAX_FUNCTIONS; f++) {
uint32_t id = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_DEVICE_VENDOR);
if (PCI_DEVICE(id) == PCI_DEVICE_EMPTY) {
continue;
}
uint32_t csi = pci_read(PCI_BDF(b, d, f), PCI_OFFSET_CLASS_REVISION);
if ((class != NUL && PCI_CLASS(csi) != class) || (subclass != NUL && PCI_SUBCLASS(csi) != subclass) ||
(iface != NUL && PCI_INTERFACE(csi) != iface)) {
continue;
}
return PCI_BDF(b, d, f);
}
}
}
return NUL;
}
void pci_map(pci_bdf_t bdf, volatile void *virt, uint8_t pages) {
pci_write(bdf, PCI_OFFSET_STATUS_COMMAND, pci_read(bdf, PCI_OFFSET_STATUS_COMMAND) | PCI_COMMAND_MEMORY_SPACE | PCI_COMMAND_BUS_MASTER);
uint64_t bar = ((uint64_t)pci_read(bdf, PCI_OFFSET_BAR_1) << 32) | (pci_read(bdf, PCI_OFFSET_BAR_0) & 0xFFFFFFF0);
LOG_LN("Mapping BAR to memory, phys %lx <-> virt %lx...", bar, virt);
for (uint8_t i = 0; i < pages; i++) {
memory_page_map((void *)KERNEL_VIRTUAL_PML4, (void *)((uint8_t *)virt + i * PAGE_SIZE), (void *)((uint8_t *)bar + i * PAGE_SIZE),
PAGE_WRITABLE | PAGE_PCD | PAGE_USER);
}
}
void pci_unmap(pci_bdf_t bdf, volatile void *virt, uint8_t pages) {
LOG_LN("Unmapping BAR from memory, virt %lx...", virt);
for (uint8_t i = 0; i < pages; i++) {
memory_page_unmap((void *)KERNEL_VIRTUAL_PML4, (void *)((uint8_t *)virt + i * PAGE_SIZE));
}
pci_write(bdf, PCI_OFFSET_STATUS_COMMAND,
pci_read(bdf, PCI_OFFSET_STATUS_COMMAND) & ~(uint32_t)(PCI_COMMAND_MEMORY_SPACE | PCI_COMMAND_BUS_MASTER));
}
+7 -26
View File
@@ -1,34 +1,15 @@
#pragma once
#include <stdint.h>
#include "src/lib/util.h"
#include "src/kernel/stream.h"
#define PCI_MAX_BUSES 256
#define PCI_MAX_DEVICES 32
#define PCI_MAX_FUNCTIONS 8
#define PCI_OFFSET_DEVICE_VENDOR 0x00
#define PCI_OFFSET_STATUS_COMMAND 0x04
#define PCI_OFFSET_CLASS_REVISION 0x08
#define PCI_OFFSET_BAR_0 0x10
#define PCI_OFFSET_BAR_1 0x14
#define PCI_VENDOR(i) BITS_R(i, 15, 0)
#define PCI_DEVICE(i) BITS_R(i, 31, 16)
#define PCI_DEVICE_EMPTY 0xFFFF
#define PCI_CLASS(c) BITS_R(c, 31, 24)
#define PCI_CLASS_SUB(c) BITS_R(c, 23, 16)
#define PCI_CLASS_IFACE(c) BITS_R(c, 15, 8)
#define PCI_COMMAND_MEMORY_SPACE 0x02
#define PCI_COMMAND_BUS_MASTER 0x04
typedef uint16_t pci_bdf_t;
void pci_init();
uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset);
void pci_enumerate(stream_t *out);
void pci_write(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value);
pci_bdf_t pci_find_by_class(uint8_t class, uint8_t subclass, uint8_t iface);
uint64_t pci_bar(uint8_t bus, uint8_t device, uint8_t function);
void pci_map(pci_bdf_t bdf, volatile void *virt, uint8_t pages);
void pci_unmap(pci_bdf_t bdf, volatile void *virt, uint8_t pages);
+44
View File
@@ -0,0 +1,44 @@
#include "src/kernel/usb.h"
#include "src/kernel/log.h"
#include "src/kernel/stream.h"
#include "src/kernel/xhci.h"
typedef struct __attribute__((packed)) {
uint8_t length;
uint8_t descriptor_type; // 0x01 for device descriptor
uint16_t usb_version; // BCD, e.g. 0x0200 for USB 2.0
uint8_t device_class;
uint8_t device_subclass;
uint8_t device_protocol;
uint8_t max_packet_size; // for ep0
uint16_t vendor_id;
uint16_t product_id;
uint16_t device_version;
uint8_t manufacturer_str;
uint8_t product_str;
uint8_t serial_str;
uint8_t num_configurations;
} usb_device_descriptor_t;
static usb_device_descriptor_t device_descriptor __attribute__((aligned(64)));
void usb_init() {
LOG_LN("Enumerating devices...");
usb_enumerate(kernel_log);
LOG_LN("Done.");
}
void usb_enumerate(stream_t *out) {
for (uint8_t i = 0; i < xhci_port_count(); i++) {
if (!xhci_port_connected(i)) {
continue;
}
xhci_slot_t slot = xhci_attach(i);
xhci_control_transfer(slot, 0x0012000001000680ULL, &device_descriptor, sizeof(usb_device_descriptor_t));
PRINT_LN(out, "%hx:%hx class=%hx subclass=%hx protocol=%hx", device_descriptor.vendor_id, device_descriptor.product_id,
device_descriptor.device_class, device_descriptor.device_subclass, device_descriptor.device_protocol);
}
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include "src/kernel/stream.h"
#include <stdint.h>
void usb_init();
void usb_enumerate(stream_t *out);
+490
View File
@@ -0,0 +1,490 @@
#include "src/kernel/xhci.h"
#include "src/kernel/log.h"
#include "src/kernel/panic.h"
#include "src/kernel/pci.h"
#include "src/kernel/stream.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#define XHCI_PCI_CLASS 0x0C
#define XHCI_PCI_SUBCLASS 0x03
#define XHCI_PCI_INTERFACE 0x30
typedef volatile struct __attribute__((packed)) {
uint8_t caplength;
uint8_t reserved;
uint16_t hciversion;
uint32_t hcsparams1;
uint32_t hcsparams2;
uint32_t hcsparams3;
uint32_t hccparams1;
uint32_t dboff;
uint32_t rtsoff;
uint32_t hccparams2;
} xhci_cap_regs_t;
#define XHCI_CAP_REGS_MAX_SLOTS(c) BITS_R((c)->hcsparams1, 7, 0)
#define XHCI_CAP_REGS_MAX_INTRS(c) BITS_R((c)->hcsparams1, 18, 8)
#define XHCI_CAP_REGS_MAX_PORTS(c) BITS_R((c)->hcsparams1, 31, 24)
#define XHCI_CAP_REGS_MAX_ERSTS(c) BITS_R((c)->hcsparams2, 7, 4)
typedef volatile struct __attribute__((packed)) {
uint32_t usbcmd;
uint32_t usbsts;
uint32_t pagesize;
uint32_t reserved[2];
uint32_t dnctrl;
uint64_t crcr;
uint32_t reserved2[4];
uint64_t dcbaap;
uint32_t config;
} xhci_op_regs_t;
#define XHCI_OP_REGS_RS_R(o) BITS_R((o)->usbcmd, 0, 0)
#define XHCI_OP_REGS_RS_W(o, v) BITS_W((o)->usbcmd, 0, 0, v)
#define XHCI_OP_REGS_HCRST_R(o) BITS_R((o)->usbcmd, 1, 1)
#define XHCI_OP_REGS_HCRST_W(o, v) BITS_W((o)->usbcmd, 1, 1, v)
#define XHCI_OP_REGS_HCH(o) BITS_R((o)->usbsts, 0, 0)
#define XHCI_OP_REGS_HSE(o) BITS_R((o)->usbsts, 2, 2)
#define XHCI_OP_REGS_EINT_R(o) BITS_R((o)->usbsts, 3, 3)
#define XHCI_OP_REGS_EINT_W(o, v) BITS_W((o)->usbsts, 3, 3, v)
#define XHCI_OP_REGS_CNR(o) BITS_R((o)->usbsts, 11, 11)
#define XHCI_OP_REGS_HCE(o) BITS_R((o)->usbsts, 12, 12)
#define XHCI_OP_REGS_RCS(o) BITS_R((o)->crcr, 0, 0)
#define XHCI_OP_REGS_CRR(o) BITS_R((o)->crcr, 3, 3)
#define XHCI_OP_REGS_CRP(o) BITS_R((o)->crcr, 63, 6)
#define XHCI_OP_REGS_MAX_SLOTS_EN_R(o) BITS_R((o)->config, 7, 0)
#define XHCI_OP_REGS_MAX_SLOTS_EN_W(o, v) BITS_W((o)->config, 7, 0, v)
typedef volatile struct __attribute__((packed)) {
uint32_t portsc;
uint32_t portpmsc;
uint32_t portli;
uint32_t porthlpmc;
} xhci_port_regs_t;
#define XHCI_PORT_REGS_CCS(p) BITS_R((p)->portsc, 0, 0)
#define XHCI_PORT_REGS_PED(p) BITS_R((p)->portsc, 1, 1)
#define XHCI_PORT_REGS_PR_R(p) BITS_R((p)->portsc, 4, 4)
#define XHCI_PORT_REGS_PR_W(p, v) BITS_W((p)->portsc, 4, 4, v)
#define XHCI_PORT_REGS_PP(p) BITS_R((p)->portsc, 9, 9)
#define XHCI_PORT_REGS_PS(p) BITS_R((p)->portsc, 13, 10)
typedef volatile struct __attribute__((packed)) {
uint32_t iman;
uint32_t imod;
uint32_t erstsz;
uint32_t reserved;
uint64_t erstba;
uint64_t erdp;
} xhci_intr_regs_t;
static xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)KERNEL_VIRTUAL_XHCI;
static xhci_op_regs_t *op_regs;
static xhci_port_regs_t *port_regs;
static xhci_intr_regs_t *intr_regs;
typedef volatile uint32_t xhci_db_regs;
#define XHCI_DB_REGS_TASK_ID(d) BITS_R((d), 31, 16)
#define XHCI_DB_REGS_TARGET(d) BITS_R((d), 7, 0)
static xhci_db_regs *db_regs;
#define MAX_SLOTS 32
static void *dcbaa[MAX_SLOTS + 1] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) {
uint64_t base;
uint32_t size;
uint32_t reserved;
} xchi_erst_entry_t;
typedef struct __attribute__((packed)) {
uint64_t parameter;
uint32_t status;
uint32_t control;
} xhci_trb_t;
#define XHCI_TRB_CYCLE_R(t) BITS_R((t)->control, 0, 0)
#define XHCI_TRB_CYCLE_W(t, v) BITS_W((t)->control, 0, 0, v)
#define XHCI_TRB_TOGGLE_CYCLE_R(t) BITS_R((t)->control, 1, 1)
#define XHCI_TRB_TOGGLE_CYCLE_W(t, v) BITS_W((t)->control, 1, 1, v)
#define XHCI_TRB_TRB_TYPE_R(t) BITS_R((t)->control, 15, 10)
#define XHCI_TRB_TRB_TYPE_W(t, v) BITS_W((t)->control, 15, 10, v)
#define XHCI_TRB_SLOT_TYPE_R(t) BITS_R((t)->control, 20, 16)
#define XHCI_TRB_SLOT_TYPE_W(t, v) BITS_W((t)->control, 20, 16, v)
#define XHCI_TRB_COMPLETION_CODE(t) BITS_R((t)->status, 31, 24)
#define XHCI_TRB_SLOT_ID_R(t) BITS_R((t)->control, 31, 24)
#define XHCI_TRB_SLOT_ID_W(t, v) BITS_W((t)->control, 31, 24, v)
#define XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE 2
#define XHCI_TRB_TYPE_TRANSFER_DATA_STAGE 3
#define XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE 4
#define XHCI_TRB_TYPE_LINK 6
#define XHCI_TRB_TYPE_COMMAND_ENABLE_SLOT 9
#define XHCI_TRB_TYPE_COMMAND_DISABLE_SLOT 10
#define XHCI_TRB_TYPE_COMMAND_ADDRESS_DEVICE 11
#define XHCI_TRB_TYPE_COMMAND_NOOP 23
#define XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION 32
#define XHCI_TRB_TYPE_EVENT_COMMAND_COMPLETION 33
#define XHCI_TRB_TYPE_EVENT_PORT_STATUS_CHANGE 34
static xchi_erst_entry_t erst[1] __attribute__((aligned(PAGE_SIZE)));
#define RING_LENGTH 32
static uint8_t cr_cycle = 1;
static uint8_t cr_i = 0;
static xhci_trb_t cr[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
static uint8_t er_cycle = 1;
static uint8_t er_i = 0;
static xhci_trb_t er[RING_LENGTH] __attribute__((aligned(PAGE_SIZE)));
typedef struct __attribute__((packed)) {
uint32_t drop_flags;
uint32_t add_flags;
uint32_t reserved[6];
} xhci_input_control_ctx_t;
typedef struct __attribute__((packed)) {
uint32_t dw0;
uint32_t dw1;
uint32_t dw2;
uint32_t dw3;
uint32_t reserved[4];
} xhci_slot_ctx_t;
#define XHCI_SLOT_CTX_SPEED_R(s) BITS_R((s)->dw0, 23, 20)
#define XHCI_SLOT_CTX_SPEED_W(s, v) BITS_W((s)->dw0, 23, 20, v)
#define XHCI_SLOT_CTX_CTX_ENTRIES_R(s) BITS_R((s)->dw0, 31, 27)
#define XHCI_SLOT_CTX_CTX_ENTRIES_W(s, v) BITS_W((s)->dw0, 31, 27, v)
#define XHCI_SLOT_CTX_ROOT_HUB_PORT_R(s) BITS_R((s)->dw1, 23, 16)
#define XHCI_SLOT_CTX_ROOT_HUB_PORT_W(s, v) BITS_W((s)->dw1, 23, 16, v)
typedef struct __attribute__((packed)) {
uint32_t dw0;
uint32_t dw1;
uint64_t dequeue;
uint32_t dw4;
uint32_t reserved[3];
} xhci_ep_ctx_t;
#define USB_EP_CTX_EP_TYPE_R(e) BITS_R((e)->dw1, 5, 3)
#define USB_EP_CTX_EP_TYPE_W(e, v) BITS_W((e)->dw1, 5, 3, v)
#define USB_EP_CTX_MAX_PACKET_SIZE_R(e) BITS_R((e)->dw1, 31, 16)
#define USB_EP_CTX_MAX_PACKET_SIZE_W(e, v) BITS_W((e)->dw1, 31, 16, v)
typedef struct __attribute__((packed)) {
xhci_input_control_ctx_t control;
xhci_slot_ctx_t slot;
xhci_ep_ctx_t ep[31];
} xhci_input_ctx_t;
static xhci_input_ctx_t input_ctx __attribute__((aligned(64)));
typedef struct __attribute__((packed)) {
xhci_slot_ctx_t slot;
xhci_ep_ctx_t endpoints[31];
} xchi_device_ctx_t;
static xchi_device_ctx_t device_ctx __attribute__((aligned(64)));
static uint8_t tr_attached_slot = 0;
static uint8_t tr_cycle = 1;
static uint8_t tr_i = 0;
static xhci_trb_t tr[RING_LENGTH + 1] __attribute__((aligned(PAGE_SIZE)));
static const xhci_trb_t *command_exec_sync(const xhci_trb_t *cmd) {
LOG_LN("Queueing command TRB...");
LOG_VAL_F(cmd->parameter, "%lx");
LOG_VAL_F(cmd->status, "%x");
LOG_VAL_F(cmd->control, "%x");
xhci_trb_t *cre = &cr[cr_i];
memory_copy(cmd, sizeof(xhci_trb_t), cre);
XHCI_TRB_CYCLE_W(cre, cr_cycle);
cr_i = (cr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W((&cr[RING_LENGTH]), cr_cycle);
cr_cycle ^= (cr_i == 0);
LOG_LN("Ringing command doorbell...");
LOG_VAL_F(op_regs->usbsts, "%x");
db_regs[0] = 0;
LOG_VAL_F(op_regs->usbsts, "%x");
LOG_LN("Waiting for completion...");
while (1) {
xhci_trb_t *cmp = &er[er_i];
while (XHCI_TRB_CYCLE_R(cmp) != er_cycle)
;
er_i = (er_i + 1) % RING_LENGTH;
intr_regs->erdp = (uint64_t)(VIRT_TO_PHYS(&er[er_i]));
er_cycle ^= (er_i == 0);
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_COMMAND_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(cre)) {
LOG_LN("Received irrelevant event, skipping...");
} else {
LOG_LN("Received command completion event...");
LOG_VAL_F(cmp->parameter, "%lx");
LOG_VAL_F(cmp->status, "%x");
LOG_VAL_F(cmp->control, "%x");
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "command_exec_sync: Command failed.");
return cmp;
}
}
}
void xhci_init() {
TRACE_LN("Searching for suitable controller...");
pci_bdf_t bdf = pci_find_by_class(XHCI_PCI_CLASS, XHCI_PCI_SUBCLASS, XHCI_PCI_INTERFACE);
ASSERT(bdf, "xhci_init: No suitable controllers found.");
TRACE_LN("Mapping controller to virtual memory...");
pci_map(bdf, cap_regs, 4);
op_regs = (xhci_op_regs_t *)((uint8_t *)cap_regs + cap_regs->caplength);
port_regs = (xhci_port_regs_t *)((uint8_t *)cap_regs + cap_regs->caplength + 0x400);
intr_regs = (xhci_intr_regs_t *)((uint8_t *)cap_regs + cap_regs->rtsoff + 0x20);
db_regs = (uint32_t *)((uint8_t *)cap_regs + cap_regs->dboff);
TRACE_VAL_F(cap_regs->caplength, "%hhx");
TRACE_VAL_F(cap_regs->hciversion, "%hx");
TRACE_VAL_F(cap_regs->hcsparams1, "%x");
TRACE_VAL_F(cap_regs->hcsparams2, "%x");
TRACE_VAL_F(cap_regs->hcsparams3, "%x");
TRACE_VAL_F(cap_regs->hccparams1, "%x");
TRACE_VAL_F(cap_regs->dboff, "%x");
TRACE_VAL_F(cap_regs->rtsoff, "%x");
TRACE_VAL_F(cap_regs->hccparams2, "%x");
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
TRACE_VAL_F(op_regs->pagesize, "%x");
TRACE_VAL_F(op_regs->dnctrl, "%x");
TRACE_VAL_F(op_regs->crcr, "%lx");
TRACE_VAL_F(op_regs->dcbaap, "%lx");
TRACE_VAL_F(op_regs->config, "%x");
TRACE_LN("Stopping controller...");
XHCI_OP_REGS_RS_W(op_regs, 0);
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (!XHCI_OP_REGS_HCH(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
TRACE_LN("Resetting controller...");
XHCI_OP_REGS_EINT_W(op_regs, 0);
XHCI_OP_REGS_HCRST_W(op_regs, 1);
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_HCRST_R(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_CNR(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
TRACE_LN("Setting up command ring...");
xhci_trb_t *wrapper = &cr[RING_LENGTH];
wrapper->parameter = (uint64_t)VIRT_TO_PHYS(cr);
wrapper->status = 0;
XHCI_TRB_TRB_TYPE_W(wrapper, XHCI_TRB_TYPE_LINK);
XHCI_TRB_TOGGLE_CYCLE_W(wrapper, 1);
XHCI_TRB_CYCLE_W(wrapper, cr_cycle);
TRACE_LN("Configuring controller...");
XHCI_OP_REGS_MAX_SLOTS_EN_W(op_regs, MAX_SLOTS);
op_regs->dcbaap = (uint64_t)VIRT_TO_PHYS(dcbaa);
op_regs->crcr = (uint64_t)VIRT_TO_PHYS(cr) | cr_cycle;
erst[0].size = RING_LENGTH;
erst[0].base = (uint64_t)VIRT_TO_PHYS(er);
intr_regs->erstsz = sizeof(erst) / sizeof(xchi_erst_entry_t);
intr_regs->erstba = (uint64_t)VIRT_TO_PHYS(erst);
intr_regs->erdp = erst[0].base;
TRACE_VAL_F(op_regs->config, "%x");
TRACE_VAL_F(op_regs->dcbaap, "%lx");
TRACE_VAL_F(op_regs->crcr, "%lx");
TRACE_VAL_F(intr_regs->erstba, "%lx");
TRACE_VAL_F(intr_regs->erstsz, "%x");
TRACE_VAL_F(intr_regs->erdp, "%lx");
TRACE_VAL_F(erst[0].size, "%hx");
TRACE_VAL_F(erst[0].base, "%lx");
TRACE_LN("Starting controller...");
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
XHCI_OP_REGS_RS_W(op_regs, 1);
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
while (XHCI_OP_REGS_HCH(op_regs))
;
TRACE_VAL_F(op_regs->usbcmd, "%x");
TRACE_VAL_F(op_regs->usbsts, "%x");
LOG_LN("Enumerating ports...");
xhci_enumerate(kernel_log);
LOG_LN("Done.");
}
void xhci_enumerate(stream_t *out) {
for (uint8_t i = 0; i < XHCI_CAP_REGS_MAX_PORTS(cap_regs); i++) {
PRINT_LN(out, "port=%d CCS=%d PED=%d PP=%d PS=%d", i, XHCI_PORT_REGS_CCS(&port_regs[i]), XHCI_PORT_REGS_PED(&port_regs[i]),
XHCI_PORT_REGS_PP(&port_regs[i]), XHCI_PORT_REGS_PS(&port_regs[i]));
}
}
uint8_t xhci_port_count() {
return XHCI_CAP_REGS_MAX_PORTS(cap_regs);
}
uint8_t xhci_port_connected(uint8_t port) {
return XHCI_PORT_REGS_CCS(&port_regs[port]);
}
xhci_slot_t xhci_attach(uint8_t port) {
ASSERT(!tr_attached_slot, "xhci_attach: Can only attach one port at a time.")
ASSERT(XHCI_PORT_REGS_CCS(&port_regs[port]), "xhci_attach: Port is not connected.");
memory_set(0, sizeof(tr), tr);
tr_i = 0;
tr_cycle = 1;
LOG_LN("Resetting device...");
port_regs[port].portsc = 1 << 4;
while (XHCI_PORT_REGS_PR_R(&port_regs[port]))
;
while (!XHCI_PORT_REGS_PED(&port_regs[port]))
;
TRACE_VAL_F(XHCI_PORT_REGS_PED(&port_regs[port]), "%hhx");
LOG_LN("Enabling a slot...");
xhci_trb_t cmd_es;
memory_set(0, sizeof(xhci_trb_t), &cmd_es);
XHCI_TRB_TRB_TYPE_W(&cmd_es, XHCI_TRB_TYPE_COMMAND_ENABLE_SLOT);
xhci_slot_t slot = XHCI_TRB_SLOT_ID_R(command_exec_sync(&cmd_es));
LOG_LN("Addressing device...");
memory_set(0, sizeof(input_ctx), &input_ctx);
input_ctx.control.add_flags = 0b11;
XHCI_SLOT_CTX_CTX_ENTRIES_W(&input_ctx.slot, 1);
XHCI_SLOT_CTX_ROOT_HUB_PORT_W(&input_ctx.slot, port + 1);
XHCI_SLOT_CTX_SPEED_W(&input_ctx.slot, XHCI_PORT_REGS_PS((&port_regs[port])));
USB_EP_CTX_EP_TYPE_W(&input_ctx.ep[0], 4);
USB_EP_CTX_MAX_PACKET_SIZE_W(&input_ctx.ep[0], 64);
input_ctx.ep[0].dequeue = (uint64_t)VIRT_TO_PHYS(tr) | tr_cycle;
dcbaa[slot] = VIRT_TO_PHYS(&device_ctx);
xhci_trb_t cmd_ad;
memory_set(0, sizeof(xhci_trb_t), &cmd_ad);
cmd_ad.parameter = (uint64_t)VIRT_TO_PHYS(&input_ctx);
XHCI_TRB_TRB_TYPE_W(&cmd_ad, XHCI_TRB_TYPE_COMMAND_ADDRESS_DEVICE);
XHCI_TRB_SLOT_ID_W(&cmd_ad, slot);
command_exec_sync(&cmd_ad);
tr_attached_slot = slot;
return slot;
}
uint64_t xhci_control_transfer(xhci_slot_t slot, uint64_t setup, void *data, uint16_t length) {
ASSERT(tr_attached_slot == slot, "xhci_control_transfer: Can only attach one port at a time.");
LOG_LN("Queueing transfer TRBs...");
tr[tr_i].parameter = setup;
tr[tr_i].status = sizeof(setup);
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_SETUP_STAGE);
BITS_W(tr[tr_i].control, 17, 16, 3);
BITS_W(tr[tr_i].control, 6, 6, 1);
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
LOG_VAL_F(tr[tr_i].parameter, "%lx");
LOG_VAL_F(tr[tr_i].status, "%x");
LOG_VAL_F(tr[tr_i].control, "%x");
tr_i = (tr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
tr_cycle ^= (tr_i == 0);
tr[tr_i].parameter = (uint64_t)VIRT_TO_PHYS(data);
tr[tr_i].status = length;
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_DATA_STAGE);
BITS_W(tr[tr_i].control, 16, 16, 1);
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
LOG_VAL_F(tr[tr_i].parameter, "%lx");
LOG_VAL_F(tr[tr_i].status, "%x");
LOG_VAL_F(tr[tr_i].control, "%x");
tr_i = (tr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
tr_cycle ^= (tr_i == 0);
xhci_trb_t *tre = &tr[tr_i];
XHCI_TRB_TRB_TYPE_W(&tr[tr_i], XHCI_TRB_TYPE_TRANSFER_STATUS_STAGE);
BITS_W(tr[tr_i].control, 16, 16, 0);
BITS_W(tr[tr_i].control, 5, 5, 1);
XHCI_TRB_CYCLE_W(&tr[tr_i], tr_cycle);
tr_i = (tr_i + 1) % RING_LENGTH;
XHCI_TRB_CYCLE_W(&tr[RING_LENGTH], tr_cycle);
tr_cycle ^= (tr_i == 0);
LOG_LN("Ringing slot doorbell...");
db_regs[tr_attached_slot] = 1;
LOG_LN("Waiting for completion...");
while (1) {
xhci_trb_t *cmp = &er[er_i];
while (XHCI_TRB_CYCLE_R(cmp) != er_cycle)
;
er_i = (er_i + 1) % RING_LENGTH;
intr_regs->erdp = (uint64_t)(VIRT_TO_PHYS(&er[er_i]));
er_cycle ^= (er_i == 0);
if (XHCI_TRB_TRB_TYPE_R(cmp) != XHCI_TRB_TYPE_EVENT_TRANSFER_COMPLETION || (void *)cmp->parameter != VIRT_TO_PHYS(tre)) {
LOG_LN("Received irrelevant event, skipping...");
} else {
LOG_LN("Received transfer completion event...");
LOG_VAL_F(cmp->parameter, "%lx");
LOG_VAL_F(cmp->status, "%x");
LOG_VAL_F(cmp->control, "%x");
ASSERT(XHCI_TRB_COMPLETION_CODE(cmp) == 1, "xhci_control_transfer: Transfer failed.");
return length - (cmp->status & 0xFFFFFF);
}
}
}
void xhci_detach(xhci_slot_t slot) {
ASSERT(tr_attached_slot == slot, "xhci_detach: Slot not attached.");
xhci_trb_t cmd_ds;
memory_set(0, sizeof(xhci_trb_t), &cmd_ds);
XHCI_TRB_TRB_TYPE_W(&cmd_ds, XHCI_TRB_TYPE_COMMAND_DISABLE_SLOT);
XHCI_TRB_SLOT_ID_W(&cmd_ds, slot);
command_exec_sync(&cmd_ds);
dcbaa[slot] = 0;
tr_attached_slot = 0;
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include "src/kernel/stream.h"
#include <stdint.h>
typedef uint8_t xhci_slot_t;
void xhci_init(); // Assuming one and only one xHCI controller.
void xhci_enumerate(stream_t *out);
uint8_t xhci_port_count();
uint8_t xhci_port_connected(uint8_t port);
xhci_slot_t xhci_attach(uint8_t port);
uint64_t xhci_control_transfer(xhci_slot_t slot, uint64_t setup, void *data, uint16_t length);
void xhci_detach(xhci_slot_t slot);
+5
View File
@@ -11,12 +11,17 @@
#define PHYS_TO_VIRT(phys) ((void *)((uint64_t)(phys) + KERNEL_VIRTUAL_BASE))
#define VIRT_TO_PHYS(virt) ((void *)((uint64_t)(virt) - KERNEL_VIRTUAL_BASE))
#define NVME_PAGE_COUNT 4
#define USB_PAGE_COUNT 4
#define KERNEL_VIRTUAL_PML4 (KERNEL_VIRTUAL_BASE + 0x10000)
#define KERNEL_VIRTUAL_CODE (KERNEL_VIRTUAL_PML4 + 0x10000)
#define KERNEL_VIRTUAL_HEAP (KERNEL_VIRTUAL_CODE + 0x100000)
#define KERNEL_VIRTUAL_UNUSED (KERNEL_VIRTUAL_HEAP + HEAP_SIZE)
#define KERNEL_VIRTUAL_STACK (KERNEL_VIRTUAL_BASE + 0xF00000 - PAGE_SIZE)
#define KERNEL_VIRTUAL_STACK_TOP (KERNEL_VIRTUAL_STACK + PAGE_SIZE)
#define KERNEL_VIRTUAL_NVME (KERNEL_VIRTUAL_BASE + MEMORY_SIZE)
#define KERNEL_VIRTUAL_XHCI (KERNEL_VIRTUAL_NVME + NVME_PAGE_COUNT * PAGE_SIZE)
#define USER_VIRTUAL_BASE 0x0000000000000000ULL
#define USER_VIRTUAL_CODE (USER_VIRTUAL_BASE + 0x400000)
+3
View File
@@ -11,5 +11,8 @@ qemu-system-x86_64 \
-monitor stdio \
-drive file=build/os.img,format=raw,if=none,id=nvme0 \
-device nvme,drive=nvme0,serial=foo \
-device qemu-xhci,id=xhci,msi=off,msix=off \
-device usb-kbd,bus=xhci.0 \
-no-reboot \
-trace "*xhci*" \
-d int