diff --git a/kernel/device/idedrv.h b/kernel/device/idedrv.h index af93659..7587e58 100644 --- a/kernel/device/idedrv.h +++ b/kernel/device/idedrv.h @@ -7,7 +7,6 @@ #include #include #include -#include #define IDE_PROBE_AVAIL (1 << 0) #define IDE_PROBE_LBA48 (1 << 1) diff --git a/kernel/device/pci.c b/kernel/device/pci.c index 52acef8..5c9fe56 100644 --- a/kernel/device/pci.c +++ b/kernel/device/pci.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -12,6 +13,7 @@ static const struct pci_driver_info pci_driver_infos[] = { {.class = 0x01, .subclass = 0x01, .init = &pci_ide_init}, + {.class = 0x0C, .subclass = 0x03, .init = &pci_xhci_init}, }; static spin_lock_t pci_lock = SPIN_LOCK_INIT; @@ -279,7 +281,9 @@ static void pci_discovery_cb (struct proc* proc, struct reschedule_ctx* rctx, for (size_t driver = 0; driver < lengthof (pci_driver_infos); driver++) { if (pci_driver_infos[driver].class == pci_info.class && pci_driver_infos[driver].subclass == pci_info.subclass) { - pci_driver_infos[driver].init (proc, rctx, pci_info); + if (!pci_driver_infos[driver].init (proc, rctx, pci_info)) { + DEBUG ("Init failed. Skipping this device!\n"); + } } } } diff --git a/kernel/device/pci_xhci.c b/kernel/device/pci_xhci.c new file mode 100644 index 0000000..2bea411 --- /dev/null +++ b/kernel/device/pci_xhci.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int xhci_counter = 0; + +bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF); + + /* not an XHCI controller */ + if (progif != 0x30) { + return true; + } + + uint16_t pci_cmd = pci_read16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND); + + uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2)); + + if (pci_cmd != new_cmd) { + pci_write16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND, new_cmd); + } + + uintptr_t xhci_phys = 0; + + uint32_t bar0 = pci_read32 (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR0); + + if ((bar0 & PCI_BAR_MEM64)) { + uint32_t bar1 = pci_read32 (pci_info.bus, pci_info.slot, pci_info.func, PCI_BAR1); + xhci_phys = ((uint64_t)bar1 << 32) | (bar0 & ~0xF); + DEBUG ("XHCI phys base addr=%p (64 bit)\n", xhci_phys); + } else { + xhci_phys = (bar0 & ~0xF); + DEBUG ("XHCI phys base addr=%p (32 bit)\n", xhci_phys); + } + + if (xhci_phys == 0) { + DEBUG ("WARNING xhci_phys is NULL!\n"); + return false; + } + + uintptr_t xhci_base = xhci_phys + (uintptr_t)hhdm->offset; + + /* 2 pages should cover the mmio space */ + mm_map_kernel_page (xhci_phys, xhci_base, MM_PG_RW | MM_PG_PRESENT); + mm_map_kernel_page (xhci_phys + PAGE_SIZE, xhci_base + PAGE_SIZE, MM_PG_RW | MM_PG_PRESENT); + + char key[32]; + snprintf (key, sizeof (key), "xhci%d", xhci_counter++); + + struct xhci_init init = {.xhci_mmio_base = xhci_base}; + + device_op_func_t ops[] = {0}; + + struct device* xhci = + device_create (key, ops, lengthof (ops), &xhci_init, &xhci_fini, &init, proc, rctx); + + return true; +} diff --git a/kernel/device/pci_xhci.h b/kernel/device/pci_xhci.h new file mode 100644 index 0000000..06fd91e --- /dev/null +++ b/kernel/device/pci_xhci.h @@ -0,0 +1,11 @@ +#ifndef _KERNEL_DEVICE_PCI_XHCI_H +#define _KERNEL_DEVICE_PCI_XHCI_H + +#include +#include +#include +#include + +bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info); + +#endif // _KERNEL_DEVICE_PCI_XHCI_H diff --git a/kernel/device/src.mk b/kernel/device/src.mk index 662f8f0..fd6d565 100644 --- a/kernel/device/src.mk +++ b/kernel/device/src.mk @@ -17,11 +17,15 @@ ifeq ($(platform),amd64) device/idedrv.c \ device/pci.c \ device/pci_defs.c \ - device/pci_ide.c + device/pci_ide.c \ + device/pci_xhci.c \ + device/xhci.c o += device/ps2_kb.o \ device/idedrv.o \ device/pci.o \ device/pci_defs.o \ - device/pci_ide.o + device/pci_ide.o \ + device/pci_xhci.o \ + device/xhci.o endif diff --git a/kernel/device/xhci.c b/kernel/device/xhci.c new file mode 100644 index 0000000..101fc27 --- /dev/null +++ b/kernel/device/xhci.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* clang-format off */ + +/* capability registers */ +#define XHCI_CAPLENGTH 0x00 +#define XHCI_RSVD 0x01 +#define XHCI_HCIVERSION 0x02 +#define XHCI_HCSPARAMS1 0x04 +#define XHCI_HCSPARAMS2 0x08 +#define XHCI_HCSPARAMS3 0x0C +#define XHCI_HCCPARAMS1 0x10 +#define XHCI_DBOFF 0x14 +#define XHCI_RTSOFF 0x18 +#define XHCI_HCCPARAMS2 0x1C + +/* operational registers */ +#define XHCI_USBCMD 0x00 +#define XHCI_USBSTS 0x04 +#define XHCI_PAGESIZE 0x08 +#define XHCI_DNCTRL 0x14 +#define XHCI_CRCR 0x18 +#define XHCI_DCBAAP 0x30 +#define XHCI_CONFIG 0x38 + +/* port registers */ +#define XHCI_PORTSC 0x00 +#define XHCI_PORTPMSC 0x04 +#define XHCI_PORTLI 0x08 + +/* runtime registers */ +#define XHCI_MFINDEX 0x00 +/* + IRQ sets (0x20) */ +#define XHCI_IMAN 0x00 +#define XHCI_IMOD 0x04 +#define XHCI_ERSTSZ 0x08 +#define XHCI_ERSTBA 0x10 +#define XHCI_ERDP 0x18 + +/* clang-format on */ + +static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) { + *(volatile uint8_t*)(base + reg) = value; +} + +static void xhci_write16 (uintptr_t base, uint32_t reg, uint16_t value) { + *(volatile uint16_t*)(base + reg) = value; +} + +static void xhci_write32 (uintptr_t base, uint32_t reg, uint32_t value) { + *(volatile uint32_t*)(base + reg) = value; +} + +static uint8_t xhci_read8 (uintptr_t base, uint32_t reg) { + return *(volatile uint8_t*)(base + reg); +} + +static uint16_t xhci_read16 (uintptr_t base, uint32_t reg) { + return *(volatile uint16_t*)(base + reg); +} + +static uint32_t xhci_read32 (uintptr_t base, uint32_t reg) { + return *(volatile uint32_t*)(base + reg); +} + +DEFINE_DEVICE_INIT (xhci_init) { + struct xhci* xhci = malloc (sizeof (*xhci)); + + if (xhci == NULL) + return false; + + struct xhci_init* init = arg; + + memset (xhci, 0, sizeof (*xhci)); + xhci->device = device; + xhci->xhci_mmio_base = init->xhci_mmio_base; + + device->udata = xhci; + + uint8_t cap_length = xhci_read8 (xhci->xhci_mmio_base, XHCI_CAPLENGTH); + + xhci->xhci_oper_base = xhci->xhci_mmio_base + cap_length; + + uint32_t rtsoff = xhci_read32 (xhci->xhci_mmio_base, XHCI_RTSOFF); + xhci->xhci_runtime_base = xhci->xhci_mmio_base + rtsoff; + + uint32_t dboff = xhci_read32 (xhci->xhci_mmio_base, XHCI_DBOFF); + xhci->xhci_doorbell_base = xhci->xhci_mmio_base + dboff; + + return true; +} + +DEFINE_DEVICE_FINI (xhci_fini) { + struct xhci* xhci = device->udata; + + free (xhci); +} diff --git a/kernel/device/xhci.h b/kernel/device/xhci.h new file mode 100644 index 0000000..e4092d0 --- /dev/null +++ b/kernel/device/xhci.h @@ -0,0 +1,27 @@ +#ifndef _KERNEL_DEVICE_XHCI_H +#define _KERNEL_DEVICE_XHCI_H + +#include +#include +#include +#include +#include +#include + +struct xhci_init { + uintptr_t xhci_mmio_base; +}; + +struct xhci { + struct device* device; + uintptr_t xhci_mmio_base; + uintptr_t xhci_oper_base; + uintptr_t xhci_runtime_base; + uintptr_t xhci_doorbell_base; +}; + +DEFINE_DEVICE_INIT (xhci_init); + +DEFINE_DEVICE_FINI (xhci_fini); + +#endif // _KERNEL_DEVICE_XHCI_H