diff --git a/src/kernel/service/serviceSyscalls.c b/src/kernel/service/serviceSyscalls.c index 288819d..b3a7456 100644 --- a/src/kernel/service/serviceSyscalls.c +++ b/src/kernel/service/serviceSyscalls.c @@ -73,8 +73,12 @@ void handleRequestSyscall(Syscall *call) { Service *service = call->service; Service *providerService = listGet(services, call->parameters[0]); + if (!providerService) + return; ServiceFunction *function = listGet(providerService->functions, call->parameters[1]); + if (!function) + return; scheduleFunction(function, call, call->parameters[2], call->parameters[3], service->nameHash, service->id); call->avoidReschedule = true; diff --git a/src/kernel/service/serviceSyscalls.c b/src/kernel/service/serviceSyscalls.c index 288819d..b3a7456 100644 --- a/src/kernel/service/serviceSyscalls.c +++ b/src/kernel/service/serviceSyscalls.c @@ -73,8 +73,12 @@ void handleRequestSyscall(Syscall *call) { Service *service = call->service; Service *providerService = listGet(services, call->parameters[0]); + if (!providerService) + return; ServiceFunction *function = listGet(providerService->functions, call->parameters[1]); + if (!function) + return; scheduleFunction(function, call, call->parameters[2], call->parameters[3], service->nameHash, service->id); call->avoidReschedule = true; diff --git a/src/kernel/util/list.c b/src/kernel/util/list.c index f427c1d..be6fd88 100644 --- a/src/kernel/util/list.c +++ b/src/kernel/util/list.c @@ -36,7 +36,11 @@ void *listGet(ListElement *list, uint32_t position) { for (uint32_t i = 0; i < position; i++) { + if (!list) + return NULL; list = list->next; } + if (!list) + return NULL; return list->data; } diff --git a/src/kernel/service/serviceSyscalls.c b/src/kernel/service/serviceSyscalls.c index 288819d..b3a7456 100644 --- a/src/kernel/service/serviceSyscalls.c +++ b/src/kernel/service/serviceSyscalls.c @@ -73,8 +73,12 @@ void handleRequestSyscall(Syscall *call) { Service *service = call->service; Service *providerService = listGet(services, call->parameters[0]); + if (!providerService) + return; ServiceFunction *function = listGet(providerService->functions, call->parameters[1]); + if (!function) + return; scheduleFunction(function, call, call->parameters[2], call->parameters[3], service->nameHash, service->id); call->avoidReschedule = true; diff --git a/src/kernel/util/list.c b/src/kernel/util/list.c index f427c1d..be6fd88 100644 --- a/src/kernel/util/list.c +++ b/src/kernel/util/list.c @@ -36,7 +36,11 @@ void *listGet(ListElement *list, uint32_t position) { for (uint32_t i = 0; i < position; i++) { + if (!list) + return NULL; list = list->next; } + if (!list) + return NULL; return list->data; } diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index 7a49026..31051c7 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -10,5 +10,5 @@ loadFromInitrd("lspci"); uint32_t id = loadFromInitrdUninitialized("shell"); requestName("ioManager", "setForeground", id, 0); - request(id, getFunction(id, "main"), 0, 0); + request(id, 0, 0, 0); } diff --git a/src/kernel/service/serviceSyscalls.c b/src/kernel/service/serviceSyscalls.c index 288819d..b3a7456 100644 --- a/src/kernel/service/serviceSyscalls.c +++ b/src/kernel/service/serviceSyscalls.c @@ -73,8 +73,12 @@ void handleRequestSyscall(Syscall *call) { Service *service = call->service; Service *providerService = listGet(services, call->parameters[0]); + if (!providerService) + return; ServiceFunction *function = listGet(providerService->functions, call->parameters[1]); + if (!function) + return; scheduleFunction(function, call, call->parameters[2], call->parameters[3], service->nameHash, service->id); call->avoidReschedule = true; diff --git a/src/kernel/util/list.c b/src/kernel/util/list.c index f427c1d..be6fd88 100644 --- a/src/kernel/util/list.c +++ b/src/kernel/util/list.c @@ -36,7 +36,11 @@ void *listGet(ListElement *list, uint32_t position) { for (uint32_t i = 0; i < position; i++) { + if (!list) + return NULL; list = list->next; } + if (!list) + return NULL; return list->data; } diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index 7a49026..31051c7 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -10,5 +10,5 @@ loadFromInitrd("lspci"); uint32_t id = loadFromInitrdUninitialized("shell"); requestName("ioManager", "setForeground", id, 0); - request(id, getFunction(id, "main"), 0, 0); + request(id, 0, 0, 0); } diff --git a/src/userland/usb/main.c b/src/userland/usb/main.c index dcc45f9..83868e0 100644 --- a/src/userland/usb/main.c +++ b/src/userland/usb/main.c @@ -3,11 +3,40 @@ #include "usb.h" +void xhci_command(XHCIController *controller, uint32_t p1, uint32_t p2, + uint32_t status, uint32_t control) { + control &= ~1; + control |= controller->commands.cycle; + + controller->commands.trbs[controller->commands.enqueue].dataLow = p1; + controller->commands.trbs[controller->commands.enqueue].dataHigh = p2; + controller->commands.trbs[controller->commands.enqueue].status = status; + controller->commands.trbs[controller->commands.enqueue].control = control; + + controller->commands.enqueue++; + if (controller->commands.enqueue == 63) { + controller->commands.trbs[controller->commands.enqueue].control ^= 1; + if (controller->commands.trbs[controller->commands.enqueue].control & + (1 << 1)) { + controller->commands.cycle ^= 1; + } + controller->commands.enqueue = 0; + } + controller->doorbells[0] = 0; +} + +void waitForKeyPress() { + printf("press a key to continue...\n"); + uint32_t ioManager = getService("ioManager"); + await(ioManager, getEvent(ioManager, "keyPress")); +} + #define REQUEST(functionName, service, function) \ uint32_t functionName(uint32_t data1, uint32_t data2) { \ static uint32_t serviceId = 0; \ if (!serviceId) { \ serviceId = getService(service); \ + serviceId = getService(service); \ } \ static uint32_t functionId = 0; \ if (!functionId) { \ @@ -18,309 +47,202 @@ REQUEST(getBaseAddress, "lspci", "getBaseAddress"); REQUEST(getDeviceClass, "lspci", "getDeviceClass"); - REQUEST(enableBusMaster, "lspci", "enableBusMaster"); REQUEST(getPCIInterrupt, "lspci", "getInterrupt"); -uint32_t getPortSpeed(XHCIPortRegister *port) { - return (port->statusControl > 5) & 0xF; -} - -char *getPortSpeedString(XHCIPortRegister *port) { - switch (getPortSpeed(port)) { - case 1: - return "Full Speed (USB 1.0)"; - case 2: - return "Low Speed (USB 1.0)"; - case 3: - return "Full Speed (USB 2.0)"; - case 4: - return "Super Speed (USB 3.0)"; - } - return "unknown speed"; -} - -void initializePort(XHCIController *controller, uint8_t index) { - XHCIPortRegister *port = &controller->ports[index]; - if (!(port->statusControl & 1)) { - // this port has nothing connected to it - return; - } - controller->deviceContexts[index] = malloc(sizeof(DeviceContext)); - controller->deviceContextArray->deviceContextPointer[index] = - U32(getPhysicalAddress(controller->deviceContexts[index])); - controller->inputContexts[index] = malloc(sizeof(XHCIInputContext)); - controller->slots[index] = malloc(sizeof(XHCISlot)); - for (uint32_t endpoint; endpoint < 31; endpoint++) { - XHCITransferRequestBlock *trbs = - malloc(256 * sizeof(XHCITransferRequestBlock)); - controller->trbs[index][endpoint] = trbs; - controller->slots[index]->endpoints[endpoint].trbs = trbs; - controller->slots[index]->endpoints[endpoint].cycleState = true; - controller->slots[index]->endpoints[endpoint].transferCount = 0; - controller->slots[index]->endpoints[endpoint].timeEvent = 0; - - XHCITransferRequestBlock *cycleTrb = &trbs[255]; - cycleTrb->dataLow = U32(getPhysicalAddress(trbs)); - cycleTrb->dataHigh = 0; - cycleTrb->type = 6; - cycleTrb->cycle = 1; - cycleTrb->interruptTarget = 0; - } - printf("port linkInfo: %x power: %x status: %x, speed: %s\n", - port->linkInfo, port->powerManagement, port->statusControl, - getPortSpeedString(port)); -} - -void resetController(XHCIController *controller) { - controller->operational->usbCommand &= ~(1); // stop controller - while (!(controller->operational->usbStatus & 1)) +void restartXHCIController(XHCIController *controller) { + printf("resetting controller...\n"); + controller->operational->command &= ~1; + while (!(controller->operational->status & (1 << 0))) syscall(-1, 0, 0, 0, 0); - controller->operational->usbCommand |= 2; // reset controller - while (controller->operational->usbStatus & 2) + controller->operational->command |= 1 << 1; + while ((controller->operational->command & (1 << 1))) + ; + while ((controller->operational->status & (1 << 11))) + ; +} + +XHCITRB *trbRingFetch(TrbRing *ring) { + while ((ring->trbs[ring->dequeue].control & 1) != ring->cycle) { syscall(-1, 0, 0, 0, 0); - printf("XHCI controller reset done\n"); + } + XHCITRB *result = &ring->trbs[ring->dequeue]; + ring->dequeue++; + if (ring->dequeue == 64) { + ring->dequeue = 0; + ring->cycle ^= -1; + } + return result; } -uint16_t findExtendedCapabilities(XHCICapabilities *capabilities) { - uint16_t extendedCapabilityOffset = - capabilities->capabilityParameters1 >> 16; - uint8_t id = 0; - while (extendedCapabilityOffset) { - id = *(uint8_t *)OFFSET(capabilities, extendedCapabilityOffset); - uint8_t offset = - *(uint8_t *)OFFSET(capabilities, extendedCapabilityOffset + 1); - if (!offset) { - extendedCapabilityOffset = 0; - } else { - extendedCapabilityOffset += offset << 2; +void setupTrbRing(TrbRing *ring, uint32_t size) { + ring->trbs = requestMemory(1, 0, 0); + ring->physical = getPhysicalAddress((void *)ring->trbs); + ring->cycle = true; + ring->enqueue = 0; + ring->dequeue = 0; + ring->size = size; + // define link to beginning + ring->trbs[ring->size - 1].dataLow = U32(ring->physical); + ring->trbs[ring->size - 1].control = 2 | (6 << 10); + + printf("TRB ring setup: %x (%x)\n", ring->trbs, ring->physical); +} + +void setupRuntime(XHCIController *controller) { + controller->runtime = OFFSET(controller->capabilities, + controller->capabilities->runtimeOffset); + controller->runtime->interrupters[0].enabled = true; + controller->runtime->interrupters[0].moderationCounter = 500; + controller->runtime->interrupters[0].eventRingSegmentTableSize = 1; + controller->runtime->interrupters[0].eventRingSegmentTableAddress[0] = + U32(controller->eventRingSegmentTablePhysical); + controller->runtime->interrupters[0].eventRingSegmentTableAddress[1] = 0; + controller->runtime->interrupters[0].eventRingDequeuePointer[0] = + U32(&controller->events.physical[controller->events.dequeue]) | + (1 << 3); + controller->runtime->interrupters[0].eventRingDequeuePointer[1] = 0; +} + +void setupEventRingSegmentTable(XHCIController *controller) { + // todo: research necessary alignment + controller->eventRingSegmentTable = requestMemory(1, 0, 0); + controller->eventRingSegmentTablePhysical = + getPhysicalAddress((void *)controller->eventRingSegmentTable); + + controller->eventRingSegmentTable[0].ringSegmentBaseAddress[0] = + U32(controller->events.physical); + controller->eventRingSegmentTable[0].ringSegmentSize = 64; +} + +void readExtendedCapabilities(XHCIController *controller) { + uintptr_t offset = (controller->capabilities->structuralParameters[0] >> 16) + << 2; + + volatile uint32_t *extendedCapabilities = + OFFSET(controller->capabilities, offset); + + while (1) { + uint32_t value = *extendedCapabilities; + + if ((value & 0xFF) == 2) { + uint8_t revisionMinor = extendedCapabilities[0] >> 16; + uint8_t revisionMajor = extendedCapabilities[0] >> 24; + + uint8_t portOffset = extendedCapabilities[2]; + uint8_t portCount = extendedCapabilities[2] >> 8; + + printf("protocol %i.%i %i port(s) starting from port %i\n", + revisionMajor, revisionMinor, portCount, portOffset); } + + if (value == 0xFFFFFFFF) + break; + if ((value & 0xFF00) == 0) + break; + extendedCapabilities = + (void *)((uintptr_t)extendedCapabilities + ((value & 0xFF00) >> 6)); } - return extendedCapabilityOffset; } -void deactivateXHCILegacy(XHCIController *controller) { - uint16_t extendedCapabilityOffset = - findExtendedCapabilities(controller->capabilities); - if (!extendedCapabilityOffset) { - printf("XHCI controller already owned by honey-OS\n"); - return; - } - printf("TODO: get XHCI controller ownership from the BIOS\n"); +void setupOperationalRegisters(XHCIController *controller) { + controller->deviceContextBaseAddressArray = (void *)requestMemory(1, 0, 0); + controller->operational->deviceContextBaseAddressArray[0] = + U32(getPhysicalAddress(controller->deviceContextBaseAddressArray)); + controller->operational->deviceContextBaseAddressArray[1] = 0; + + controller->operational->config = + (controller->operational->config & ~0xFF) | 32; + + controller->operational->commandRingControl[0] = + U32(controller->commands.physical) | 1; + controller->operational->commandRingControl[1] = 0; + controller->operational->config = + controller->capabilities->structuralParameters[0] & 0xFF; } -void createScratchpadBuffers(XHCIController *controller) { - controller->scratchpadBufferCount = - ((controller->capabilities->capabilityParameters2 >> 27) & 0x1F) | - ((controller->capabilities->capabilityParameters2 >> 16) & 0xE0); - if (controller->scratchpadBufferCount) { - printf("creatng scratchpad buffers\n"); - controller->scratchpadBuffers = - malloc(sizeof(uint64_t) * controller->scratchpadBufferCount); - uint64_t *physicalScratchpadBuffers = - malloc(sizeof(uint64_t) * controller->scratchpadBufferCount); - for (uint32_t i = 0; i < controller->scratchpadBufferCount; i++) { - controller->scratchpadBuffers[i] = malloc(4096); - physicalScratchpadBuffers[i] = - U32(getPhysicalAddress(controller->scratchpadBuffers[i])); +void setupScratchpadBuffers(XHCIController *controller) { + uint32_t hcs2 = controller->capabilities->structuralParameters[1]; + uint32_t scratchpadBufferCountHigh = (hcs2 >> 21) & 0x1f; + uint32_t scratchpadBufferCountLow = (hcs2 >> 27) & 0x1f; + uint32_t scratchpadBufferCount = + (scratchpadBufferCountHigh << 5) | scratchpadBufferCountLow; + + if (scratchpadBufferCount) { + printf("%i scratchpad buffers present\n", scratchpadBufferCount); + + uint64_t *scratchpadBuffer = (uint64_t *)requestMemory(1, 0, 0); + void *scratchpadPhysical = getPhysicalAddress(scratchpadBuffer); + for (unsigned int i = 0; i < scratchpadBufferCount; ++i) { + void *sb_phys = getPhysicalAddress(requestMemory(1, 0, 0)); + scratchpadBuffer[i] = U32(sb_phys); } - controller->deviceContextArray->scratchpadBufferBase = - U32(getPhysicalAddress(physicalScratchpadBuffers)); - } else { - printf("no scratchpad buffers implemented\n"); - controller->deviceContextArray->scratchpadBufferBase = 0; + controller->deviceContextBaseAddressArray[0] = U32(scratchpadPhysical); } } -void waitForKeyPress() { - printf("press a key to continue...\n"); - uint32_t ioManager = getService("ioManager"); - await(ioManager, getEvent(ioManager, "keyPress")); -} - -void usbInterrupt() { printf("usb interrupt detected!\n"); } - -void setupEvents(XHCIController *controller) { - printf("setting up events...\n"); - controller->eventSegmentSize = 32; - controller->eventSegmentNumber = 1; - controller->eventRing = - malloc(controller->eventSegmentSize * sizeof(XHCITransferRequestBlock)); - XHCIEventRingTableEntry *eventRingTableEntry = - malloc(sizeof(XHCIEventRingTableEntry)); - eventRingTableEntry->baseLow = - U32(getPhysicalAddress(controller->eventRing)); - eventRingTableEntry->baseHigh = 0; - eventRingTableEntry->ringSegmentSize = controller->eventSegmentSize; - - controller->runtime->interrupterRegisters[0].eventRingSize = - controller->eventSegmentSize; - controller->runtime->interrupterRegisters[0].eventRingDequeueLow = - U32(getPhysicalAddress(controller->eventRing)); - controller->runtime->interrupterRegisters[0].eventRingDequeueHigh = 0; - - controller->runtime->interrupterRegisters[0].eventRingBaseLow = - U32(getPhysicalAddress(eventRingTableEntry)); - controller->runtime->interrupterRegisters[0].eventRingBaseHigh = 0; - - controller->runtime->interrupterRegisters[0].moderationInterval = 4000; - controller->runtime->interrupterRegisters[0].moderationCounter = 0; - - controller->operational->usbCommand |= 1 << 2; - controller->runtime->interrupterRegisters[0].pending = 1; - controller->runtime->interrupterRegisters[0].enabled = 1; -} - -void advanceEnqueuePointer(XHCIController *controller) { - XHCITransferRequestBlock block = {}; - block.cycle = !controller->commandRingCycleState; - memcpy(controller->commandRingEnque, &block, sizeof(block)); -} - -XHCITransferRequestBlock *enqueueCommand(XHCIController *controller, - XHCITransferRequestBlock *block) { - block->cycle = controller->commandRingCycleState; - memcpy(controller->commandRingEnque, block, - sizeof(XHCITransferRequestBlock)); - XHCITransferRequestBlock *commandRing = controller->commandRingEnque; - controller->commandRingEnque++; - if (controller->commandRingEnque->type == 6) { - controller->commandRingEnque->cycle = controller->commandRingCycleState; - controller->commandRingEnque = controller->commandRing; - controller->commandRingCycleState = !controller->commandRingCycleState; - } - advanceEnqueuePointer(controller); - return commandRing; -} - -XHCITransferRequestBlock *enableSlot(XHCIController *controller, uint8_t port) { - XHCITransferRequestBlock block = {0}; - block.type = 9; - return enqueueCommand(controller, &block); -} - -void ringXHCIDoorbellAndWait(XHCIController *controller) { - controller->doorbells[0] = 0; -} - -void resetSlot(XHCIController *controller, uint8_t slotNumber) { - XHCIInputContext *context = controller->inputContexts[slotNumber - 1]; - context->A = 3; - context->D = ~context->A; - SlotContext *slot = &(context->deviceContext.slotContext); - if (slot) { - slot->routeString = 0; - slot->speed = 3; - slot->contextEntries = 1; - slot->rootHubPortNumber = slotNumber; - slot->interrupterTarget = 0; - slot->multiTT = 0; - slot->isHub = 0; - slot->deviceAddress = 0; - } - EndpointContext *endpoints = context->deviceContext.endpoints; - if (endpoints) { - endpoints[0].endpointState = 0; - endpoints[0].endpointType = 4; - endpoints[0].maxPacketSize = 8; - endpoints[0].maxBurstSize = 0; - endpoints[0].TRBDequePointerLow = - U32(getPhysicalAddress( - controller->slots[slotNumber - 1]->endpoints[0].trbs)) >> - 4; - endpoints[0].TRBDequePointerHigh = 0; - endpoints[0].maxPrimaryStreams = 0; - // endpoints[0].mult = 0; - endpoints[0].errorCount = 3; - endpoints[0].dequeueCycleState = 1; - endpoints[0].averageTRBLength = 8; - } -} - -void prepareControlTransfer(XHCIController *controller) { - for (uint8_t i = 0; i < 16; i++) { - controller->portSlotLinks[i].command = enableSlot(controller, i); - resetSlot(controller, i + 1); - XHCITransferRequestBlock block = {0}; - block.type = 4; - enqueueCommand(controller, &block); - } - ringXHCIDoorbellAndWait(controller); -} - -void printControllerStatus(XHCIController *controller) { - printf("status: halted: %i, host system error: %i, internal host " - "controller error: %i save/restore error: %i\n", - controller->operational->usbStatus & 1, - controller->operational->usbStatus >> 2 & 1, - controller->operational->usbStatus >> 12 & 1, - controller->operational->usbStatus >> 10 & 1); - printf("status: event: %i, portChange: %i, saveState: %i, restoreState: %i " - "not ready: %i\n", - controller->operational->usbStatus >> 3 & 1, - controller->operational->usbStatus >> 4 & 1, - controller->operational->usbStatus >> 8 & 1, - controller->operational->usbStatus >> 9 & 1, - controller->operational->usbStatus >> 11 & 1); -} - -void initializeUSB(uint32_t deviceId) { +XHCIController *initializeController(uint32_t deviceId) { XHCIController *controller = malloc(sizeof(XHCIController)); - controller->pciDeviceId = deviceId; - controller->commandRingCycleState = true; - enableBusMaster(controller->pciDeviceId, 0); - uint32_t baseAddress = getBaseAddress(deviceId, 0) & ~0xF; - controller->capabilities = requestMemory(1, NULL, PTR(baseAddress)); - controller->operational = OFFSET( - controller->capabilities, controller->capabilities->capabilitiesSize); - controller->runtime = + controller->pciDevice = deviceId; + + controller->capabilities = + requestMemory(4, 0, PTR(U32(getBaseAddress(deviceId, 0)) & ~0xF)); + controller->operational = OFFSET(controller->capabilities, - controller->capabilities->runtimeRegistersSpaceOffset); + controller->capabilities->capabilitiesLength & 0xFF); controller->doorbells = OFFSET(controller->capabilities, controller->capabilities->doorbellOffset); - resetController(controller); - deactivateXHCILegacy(controller); - if (!(controller->operational->usbStatus & 1)) { - return printf("controller is not halted, aborting...\n"); - } - syscall(-1, 0, 0, 0, 0); - controller->operational->deviceNotificationControl = 2; - controller->operational->configure |= 16; - controller->deviceContextArray = malloc(sizeof(DeviceContextArray)); - controller->operational->deviceContextArray = - (uint64_t)U32(getPhysicalAddress(controller->deviceContextArray)); - createScratchpadBuffers(controller); - controller->ports = OFFSET(controller->operational, 0x400); - for (uint32_t i = 0; i < 16; i++) { - initializePort(controller, i); - } - controller->commandRing = malloc(256 * sizeof(XHCITransferRequestBlock)); - controller->commandRingEnque = controller->commandRing; - controller->commandRing[255].dataLow = - U32(getPhysicalAddress(controller->commandRing)); - controller->commandRing[255].type = 6; - controller->commandRing[255].cycle = true; - controller->operational->commandRingControl = - U32(getPhysicalAddress(controller->commandRing)) | 1; - controller->operational->usbCommand |= 1; - controller->interrupt = getPCIInterrupt(controller->pciDeviceId, 0); - setupEvents(controller); - printf("irq pin : %i\n", controller->interrupt); - uint32_t pic = getService("pic"); - subscribeEvent(pic, getEvent(pic, "irq11"), (void *)usbInterrupt); - subscribeEvent(pic, getEvent(pic, "irq3"), (void *)usbInterrupt); + uint32_t slotInfo = controller->capabilities->structuralParameters[0]; + printf("%i available slots, %i available ports\n", slotInfo & 0xFF, + slotInfo >> 24); + return controller; +} + +static void initializeUSB(uint32_t deviceId) { + XHCIController *controller = initializeController(deviceId); + restartXHCIController(controller); + + setupTrbRing(&controller->commands, 256); + setupTrbRing(&controller->events, 256); + readExtendedCapabilities(controller); + setupOperationalRegisters(controller); + setupEventRingSegmentTable(controller); + setupRuntime(controller); + setupScratchpadBuffers(controller); + + controller->operational->command |= (1 << 0) | (1 << 2); waitForKeyPress(); - prepareControlTransfer(controller); + + if (controller->operational->status & (1 << 2)) + return printf("critical XHCI problem\n"); + + // just testing for now... + xhci_command(controller, 0, 0, 0, (9 << 10)); + xhci_command(controller, 0, 0, 0, (9 << 10)); + xhci_command(controller, 0, 0, 0, (9 << 10)); + xhci_command(controller, 0, 0, 0, (9 << 10)); + + while (1) { + XHCITRB *trb = trbRingFetch(&controller->events); + uint32_t type = (trb->control >> 10) & 0x3F; + + printf("event %i [%x %x %x %x] type: %i, slotId: %i\n", + controller->events.dequeue, trb->dataLow, trb->dataHigh, + trb->status, trb->control, type, trb->control >> 24); + + controller->runtime->interrupters[0].eventRingDequeuePointer[0] = + U32(&controller->events.physical[controller->events.dequeue]) | + (1 << 3); + } } int32_t main() { - uint32_t pciService = getService("lspci"); - uint32_t function = getFunction(pciService, "getDeviceClass"); uint32_t i = 0, class = 0; - while ((class = request(pciService, function, i, 0))) { + while ((class = getDeviceClass(i, 0))) { if (class == 0x0C0330) { - printf("found XHCI host controller at pci no. %i\n", i); + printf("found XHCI host controller at pci device no. %i\n", i); + enableBusMaster(i, 0); initializeUSB(i); } i++; diff --git a/src/kernel/service/serviceSyscalls.c b/src/kernel/service/serviceSyscalls.c index 288819d..b3a7456 100644 --- a/src/kernel/service/serviceSyscalls.c +++ b/src/kernel/service/serviceSyscalls.c @@ -73,8 +73,12 @@ void handleRequestSyscall(Syscall *call) { Service *service = call->service; Service *providerService = listGet(services, call->parameters[0]); + if (!providerService) + return; ServiceFunction *function = listGet(providerService->functions, call->parameters[1]); + if (!function) + return; scheduleFunction(function, call, call->parameters[2], call->parameters[3], service->nameHash, service->id); call->avoidReschedule = true; diff --git a/src/kernel/util/list.c b/src/kernel/util/list.c index f427c1d..be6fd88 100644 --- a/src/kernel/util/list.c +++ b/src/kernel/util/list.c @@ -36,7 +36,11 @@ void *listGet(ListElement *list, uint32_t position) { for (uint32_t i = 0; i < position; i++) { + if (!list) + return NULL; list = list->next; } + if (!list) + return NULL; return list->data; } diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index 7a49026..31051c7 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -10,5 +10,5 @@ loadFromInitrd("lspci"); uint32_t id = loadFromInitrdUninitialized("shell"); requestName("ioManager", "setForeground", id, 0); - request(id, getFunction(id, "main"), 0, 0); + request(id, 0, 0, 0); } diff --git a/src/userland/usb/main.c b/src/userland/usb/main.c index dcc45f9..83868e0 100644 --- a/src/userland/usb/main.c +++ b/src/userland/usb/main.c @@ -3,11 +3,40 @@ #include "usb.h" +void xhci_command(XHCIController *controller, uint32_t p1, uint32_t p2, + uint32_t status, uint32_t control) { + control &= ~1; + control |= controller->commands.cycle; + + controller->commands.trbs[controller->commands.enqueue].dataLow = p1; + controller->commands.trbs[controller->commands.enqueue].dataHigh = p2; + controller->commands.trbs[controller->commands.enqueue].status = status; + controller->commands.trbs[controller->commands.enqueue].control = control; + + controller->commands.enqueue++; + if (controller->commands.enqueue == 63) { + controller->commands.trbs[controller->commands.enqueue].control ^= 1; + if (controller->commands.trbs[controller->commands.enqueue].control & + (1 << 1)) { + controller->commands.cycle ^= 1; + } + controller->commands.enqueue = 0; + } + controller->doorbells[0] = 0; +} + +void waitForKeyPress() { + printf("press a key to continue...\n"); + uint32_t ioManager = getService("ioManager"); + await(ioManager, getEvent(ioManager, "keyPress")); +} + #define REQUEST(functionName, service, function) \ uint32_t functionName(uint32_t data1, uint32_t data2) { \ static uint32_t serviceId = 0; \ if (!serviceId) { \ serviceId = getService(service); \ + serviceId = getService(service); \ } \ static uint32_t functionId = 0; \ if (!functionId) { \ @@ -18,309 +47,202 @@ REQUEST(getBaseAddress, "lspci", "getBaseAddress"); REQUEST(getDeviceClass, "lspci", "getDeviceClass"); - REQUEST(enableBusMaster, "lspci", "enableBusMaster"); REQUEST(getPCIInterrupt, "lspci", "getInterrupt"); -uint32_t getPortSpeed(XHCIPortRegister *port) { - return (port->statusControl > 5) & 0xF; -} - -char *getPortSpeedString(XHCIPortRegister *port) { - switch (getPortSpeed(port)) { - case 1: - return "Full Speed (USB 1.0)"; - case 2: - return "Low Speed (USB 1.0)"; - case 3: - return "Full Speed (USB 2.0)"; - case 4: - return "Super Speed (USB 3.0)"; - } - return "unknown speed"; -} - -void initializePort(XHCIController *controller, uint8_t index) { - XHCIPortRegister *port = &controller->ports[index]; - if (!(port->statusControl & 1)) { - // this port has nothing connected to it - return; - } - controller->deviceContexts[index] = malloc(sizeof(DeviceContext)); - controller->deviceContextArray->deviceContextPointer[index] = - U32(getPhysicalAddress(controller->deviceContexts[index])); - controller->inputContexts[index] = malloc(sizeof(XHCIInputContext)); - controller->slots[index] = malloc(sizeof(XHCISlot)); - for (uint32_t endpoint; endpoint < 31; endpoint++) { - XHCITransferRequestBlock *trbs = - malloc(256 * sizeof(XHCITransferRequestBlock)); - controller->trbs[index][endpoint] = trbs; - controller->slots[index]->endpoints[endpoint].trbs = trbs; - controller->slots[index]->endpoints[endpoint].cycleState = true; - controller->slots[index]->endpoints[endpoint].transferCount = 0; - controller->slots[index]->endpoints[endpoint].timeEvent = 0; - - XHCITransferRequestBlock *cycleTrb = &trbs[255]; - cycleTrb->dataLow = U32(getPhysicalAddress(trbs)); - cycleTrb->dataHigh = 0; - cycleTrb->type = 6; - cycleTrb->cycle = 1; - cycleTrb->interruptTarget = 0; - } - printf("port linkInfo: %x power: %x status: %x, speed: %s\n", - port->linkInfo, port->powerManagement, port->statusControl, - getPortSpeedString(port)); -} - -void resetController(XHCIController *controller) { - controller->operational->usbCommand &= ~(1); // stop controller - while (!(controller->operational->usbStatus & 1)) +void restartXHCIController(XHCIController *controller) { + printf("resetting controller...\n"); + controller->operational->command &= ~1; + while (!(controller->operational->status & (1 << 0))) syscall(-1, 0, 0, 0, 0); - controller->operational->usbCommand |= 2; // reset controller - while (controller->operational->usbStatus & 2) + controller->operational->command |= 1 << 1; + while ((controller->operational->command & (1 << 1))) + ; + while ((controller->operational->status & (1 << 11))) + ; +} + +XHCITRB *trbRingFetch(TrbRing *ring) { + while ((ring->trbs[ring->dequeue].control & 1) != ring->cycle) { syscall(-1, 0, 0, 0, 0); - printf("XHCI controller reset done\n"); + } + XHCITRB *result = &ring->trbs[ring->dequeue]; + ring->dequeue++; + if (ring->dequeue == 64) { + ring->dequeue = 0; + ring->cycle ^= -1; + } + return result; } -uint16_t findExtendedCapabilities(XHCICapabilities *capabilities) { - uint16_t extendedCapabilityOffset = - capabilities->capabilityParameters1 >> 16; - uint8_t id = 0; - while (extendedCapabilityOffset) { - id = *(uint8_t *)OFFSET(capabilities, extendedCapabilityOffset); - uint8_t offset = - *(uint8_t *)OFFSET(capabilities, extendedCapabilityOffset + 1); - if (!offset) { - extendedCapabilityOffset = 0; - } else { - extendedCapabilityOffset += offset << 2; +void setupTrbRing(TrbRing *ring, uint32_t size) { + ring->trbs = requestMemory(1, 0, 0); + ring->physical = getPhysicalAddress((void *)ring->trbs); + ring->cycle = true; + ring->enqueue = 0; + ring->dequeue = 0; + ring->size = size; + // define link to beginning + ring->trbs[ring->size - 1].dataLow = U32(ring->physical); + ring->trbs[ring->size - 1].control = 2 | (6 << 10); + + printf("TRB ring setup: %x (%x)\n", ring->trbs, ring->physical); +} + +void setupRuntime(XHCIController *controller) { + controller->runtime = OFFSET(controller->capabilities, + controller->capabilities->runtimeOffset); + controller->runtime->interrupters[0].enabled = true; + controller->runtime->interrupters[0].moderationCounter = 500; + controller->runtime->interrupters[0].eventRingSegmentTableSize = 1; + controller->runtime->interrupters[0].eventRingSegmentTableAddress[0] = + U32(controller->eventRingSegmentTablePhysical); + controller->runtime->interrupters[0].eventRingSegmentTableAddress[1] = 0; + controller->runtime->interrupters[0].eventRingDequeuePointer[0] = + U32(&controller->events.physical[controller->events.dequeue]) | + (1 << 3); + controller->runtime->interrupters[0].eventRingDequeuePointer[1] = 0; +} + +void setupEventRingSegmentTable(XHCIController *controller) { + // todo: research necessary alignment + controller->eventRingSegmentTable = requestMemory(1, 0, 0); + controller->eventRingSegmentTablePhysical = + getPhysicalAddress((void *)controller->eventRingSegmentTable); + + controller->eventRingSegmentTable[0].ringSegmentBaseAddress[0] = + U32(controller->events.physical); + controller->eventRingSegmentTable[0].ringSegmentSize = 64; +} + +void readExtendedCapabilities(XHCIController *controller) { + uintptr_t offset = (controller->capabilities->structuralParameters[0] >> 16) + << 2; + + volatile uint32_t *extendedCapabilities = + OFFSET(controller->capabilities, offset); + + while (1) { + uint32_t value = *extendedCapabilities; + + if ((value & 0xFF) == 2) { + uint8_t revisionMinor = extendedCapabilities[0] >> 16; + uint8_t revisionMajor = extendedCapabilities[0] >> 24; + + uint8_t portOffset = extendedCapabilities[2]; + uint8_t portCount = extendedCapabilities[2] >> 8; + + printf("protocol %i.%i %i port(s) starting from port %i\n", + revisionMajor, revisionMinor, portCount, portOffset); } + + if (value == 0xFFFFFFFF) + break; + if ((value & 0xFF00) == 0) + break; + extendedCapabilities = + (void *)((uintptr_t)extendedCapabilities + ((value & 0xFF00) >> 6)); } - return extendedCapabilityOffset; } -void deactivateXHCILegacy(XHCIController *controller) { - uint16_t extendedCapabilityOffset = - findExtendedCapabilities(controller->capabilities); - if (!extendedCapabilityOffset) { - printf("XHCI controller already owned by honey-OS\n"); - return; - } - printf("TODO: get XHCI controller ownership from the BIOS\n"); +void setupOperationalRegisters(XHCIController *controller) { + controller->deviceContextBaseAddressArray = (void *)requestMemory(1, 0, 0); + controller->operational->deviceContextBaseAddressArray[0] = + U32(getPhysicalAddress(controller->deviceContextBaseAddressArray)); + controller->operational->deviceContextBaseAddressArray[1] = 0; + + controller->operational->config = + (controller->operational->config & ~0xFF) | 32; + + controller->operational->commandRingControl[0] = + U32(controller->commands.physical) | 1; + controller->operational->commandRingControl[1] = 0; + controller->operational->config = + controller->capabilities->structuralParameters[0] & 0xFF; } -void createScratchpadBuffers(XHCIController *controller) { - controller->scratchpadBufferCount = - ((controller->capabilities->capabilityParameters2 >> 27) & 0x1F) | - ((controller->capabilities->capabilityParameters2 >> 16) & 0xE0); - if (controller->scratchpadBufferCount) { - printf("creatng scratchpad buffers\n"); - controller->scratchpadBuffers = - malloc(sizeof(uint64_t) * controller->scratchpadBufferCount); - uint64_t *physicalScratchpadBuffers = - malloc(sizeof(uint64_t) * controller->scratchpadBufferCount); - for (uint32_t i = 0; i < controller->scratchpadBufferCount; i++) { - controller->scratchpadBuffers[i] = malloc(4096); - physicalScratchpadBuffers[i] = - U32(getPhysicalAddress(controller->scratchpadBuffers[i])); +void setupScratchpadBuffers(XHCIController *controller) { + uint32_t hcs2 = controller->capabilities->structuralParameters[1]; + uint32_t scratchpadBufferCountHigh = (hcs2 >> 21) & 0x1f; + uint32_t scratchpadBufferCountLow = (hcs2 >> 27) & 0x1f; + uint32_t scratchpadBufferCount = + (scratchpadBufferCountHigh << 5) | scratchpadBufferCountLow; + + if (scratchpadBufferCount) { + printf("%i scratchpad buffers present\n", scratchpadBufferCount); + + uint64_t *scratchpadBuffer = (uint64_t *)requestMemory(1, 0, 0); + void *scratchpadPhysical = getPhysicalAddress(scratchpadBuffer); + for (unsigned int i = 0; i < scratchpadBufferCount; ++i) { + void *sb_phys = getPhysicalAddress(requestMemory(1, 0, 0)); + scratchpadBuffer[i] = U32(sb_phys); } - controller->deviceContextArray->scratchpadBufferBase = - U32(getPhysicalAddress(physicalScratchpadBuffers)); - } else { - printf("no scratchpad buffers implemented\n"); - controller->deviceContextArray->scratchpadBufferBase = 0; + controller->deviceContextBaseAddressArray[0] = U32(scratchpadPhysical); } } -void waitForKeyPress() { - printf("press a key to continue...\n"); - uint32_t ioManager = getService("ioManager"); - await(ioManager, getEvent(ioManager, "keyPress")); -} - -void usbInterrupt() { printf("usb interrupt detected!\n"); } - -void setupEvents(XHCIController *controller) { - printf("setting up events...\n"); - controller->eventSegmentSize = 32; - controller->eventSegmentNumber = 1; - controller->eventRing = - malloc(controller->eventSegmentSize * sizeof(XHCITransferRequestBlock)); - XHCIEventRingTableEntry *eventRingTableEntry = - malloc(sizeof(XHCIEventRingTableEntry)); - eventRingTableEntry->baseLow = - U32(getPhysicalAddress(controller->eventRing)); - eventRingTableEntry->baseHigh = 0; - eventRingTableEntry->ringSegmentSize = controller->eventSegmentSize; - - controller->runtime->interrupterRegisters[0].eventRingSize = - controller->eventSegmentSize; - controller->runtime->interrupterRegisters[0].eventRingDequeueLow = - U32(getPhysicalAddress(controller->eventRing)); - controller->runtime->interrupterRegisters[0].eventRingDequeueHigh = 0; - - controller->runtime->interrupterRegisters[0].eventRingBaseLow = - U32(getPhysicalAddress(eventRingTableEntry)); - controller->runtime->interrupterRegisters[0].eventRingBaseHigh = 0; - - controller->runtime->interrupterRegisters[0].moderationInterval = 4000; - controller->runtime->interrupterRegisters[0].moderationCounter = 0; - - controller->operational->usbCommand |= 1 << 2; - controller->runtime->interrupterRegisters[0].pending = 1; - controller->runtime->interrupterRegisters[0].enabled = 1; -} - -void advanceEnqueuePointer(XHCIController *controller) { - XHCITransferRequestBlock block = {}; - block.cycle = !controller->commandRingCycleState; - memcpy(controller->commandRingEnque, &block, sizeof(block)); -} - -XHCITransferRequestBlock *enqueueCommand(XHCIController *controller, - XHCITransferRequestBlock *block) { - block->cycle = controller->commandRingCycleState; - memcpy(controller->commandRingEnque, block, - sizeof(XHCITransferRequestBlock)); - XHCITransferRequestBlock *commandRing = controller->commandRingEnque; - controller->commandRingEnque++; - if (controller->commandRingEnque->type == 6) { - controller->commandRingEnque->cycle = controller->commandRingCycleState; - controller->commandRingEnque = controller->commandRing; - controller->commandRingCycleState = !controller->commandRingCycleState; - } - advanceEnqueuePointer(controller); - return commandRing; -} - -XHCITransferRequestBlock *enableSlot(XHCIController *controller, uint8_t port) { - XHCITransferRequestBlock block = {0}; - block.type = 9; - return enqueueCommand(controller, &block); -} - -void ringXHCIDoorbellAndWait(XHCIController *controller) { - controller->doorbells[0] = 0; -} - -void resetSlot(XHCIController *controller, uint8_t slotNumber) { - XHCIInputContext *context = controller->inputContexts[slotNumber - 1]; - context->A = 3; - context->D = ~context->A; - SlotContext *slot = &(context->deviceContext.slotContext); - if (slot) { - slot->routeString = 0; - slot->speed = 3; - slot->contextEntries = 1; - slot->rootHubPortNumber = slotNumber; - slot->interrupterTarget = 0; - slot->multiTT = 0; - slot->isHub = 0; - slot->deviceAddress = 0; - } - EndpointContext *endpoints = context->deviceContext.endpoints; - if (endpoints) { - endpoints[0].endpointState = 0; - endpoints[0].endpointType = 4; - endpoints[0].maxPacketSize = 8; - endpoints[0].maxBurstSize = 0; - endpoints[0].TRBDequePointerLow = - U32(getPhysicalAddress( - controller->slots[slotNumber - 1]->endpoints[0].trbs)) >> - 4; - endpoints[0].TRBDequePointerHigh = 0; - endpoints[0].maxPrimaryStreams = 0; - // endpoints[0].mult = 0; - endpoints[0].errorCount = 3; - endpoints[0].dequeueCycleState = 1; - endpoints[0].averageTRBLength = 8; - } -} - -void prepareControlTransfer(XHCIController *controller) { - for (uint8_t i = 0; i < 16; i++) { - controller->portSlotLinks[i].command = enableSlot(controller, i); - resetSlot(controller, i + 1); - XHCITransferRequestBlock block = {0}; - block.type = 4; - enqueueCommand(controller, &block); - } - ringXHCIDoorbellAndWait(controller); -} - -void printControllerStatus(XHCIController *controller) { - printf("status: halted: %i, host system error: %i, internal host " - "controller error: %i save/restore error: %i\n", - controller->operational->usbStatus & 1, - controller->operational->usbStatus >> 2 & 1, - controller->operational->usbStatus >> 12 & 1, - controller->operational->usbStatus >> 10 & 1); - printf("status: event: %i, portChange: %i, saveState: %i, restoreState: %i " - "not ready: %i\n", - controller->operational->usbStatus >> 3 & 1, - controller->operational->usbStatus >> 4 & 1, - controller->operational->usbStatus >> 8 & 1, - controller->operational->usbStatus >> 9 & 1, - controller->operational->usbStatus >> 11 & 1); -} - -void initializeUSB(uint32_t deviceId) { +XHCIController *initializeController(uint32_t deviceId) { XHCIController *controller = malloc(sizeof(XHCIController)); - controller->pciDeviceId = deviceId; - controller->commandRingCycleState = true; - enableBusMaster(controller->pciDeviceId, 0); - uint32_t baseAddress = getBaseAddress(deviceId, 0) & ~0xF; - controller->capabilities = requestMemory(1, NULL, PTR(baseAddress)); - controller->operational = OFFSET( - controller->capabilities, controller->capabilities->capabilitiesSize); - controller->runtime = + controller->pciDevice = deviceId; + + controller->capabilities = + requestMemory(4, 0, PTR(U32(getBaseAddress(deviceId, 0)) & ~0xF)); + controller->operational = OFFSET(controller->capabilities, - controller->capabilities->runtimeRegistersSpaceOffset); + controller->capabilities->capabilitiesLength & 0xFF); controller->doorbells = OFFSET(controller->capabilities, controller->capabilities->doorbellOffset); - resetController(controller); - deactivateXHCILegacy(controller); - if (!(controller->operational->usbStatus & 1)) { - return printf("controller is not halted, aborting...\n"); - } - syscall(-1, 0, 0, 0, 0); - controller->operational->deviceNotificationControl = 2; - controller->operational->configure |= 16; - controller->deviceContextArray = malloc(sizeof(DeviceContextArray)); - controller->operational->deviceContextArray = - (uint64_t)U32(getPhysicalAddress(controller->deviceContextArray)); - createScratchpadBuffers(controller); - controller->ports = OFFSET(controller->operational, 0x400); - for (uint32_t i = 0; i < 16; i++) { - initializePort(controller, i); - } - controller->commandRing = malloc(256 * sizeof(XHCITransferRequestBlock)); - controller->commandRingEnque = controller->commandRing; - controller->commandRing[255].dataLow = - U32(getPhysicalAddress(controller->commandRing)); - controller->commandRing[255].type = 6; - controller->commandRing[255].cycle = true; - controller->operational->commandRingControl = - U32(getPhysicalAddress(controller->commandRing)) | 1; - controller->operational->usbCommand |= 1; - controller->interrupt = getPCIInterrupt(controller->pciDeviceId, 0); - setupEvents(controller); - printf("irq pin : %i\n", controller->interrupt); - uint32_t pic = getService("pic"); - subscribeEvent(pic, getEvent(pic, "irq11"), (void *)usbInterrupt); - subscribeEvent(pic, getEvent(pic, "irq3"), (void *)usbInterrupt); + uint32_t slotInfo = controller->capabilities->structuralParameters[0]; + printf("%i available slots, %i available ports\n", slotInfo & 0xFF, + slotInfo >> 24); + return controller; +} + +static void initializeUSB(uint32_t deviceId) { + XHCIController *controller = initializeController(deviceId); + restartXHCIController(controller); + + setupTrbRing(&controller->commands, 256); + setupTrbRing(&controller->events, 256); + readExtendedCapabilities(controller); + setupOperationalRegisters(controller); + setupEventRingSegmentTable(controller); + setupRuntime(controller); + setupScratchpadBuffers(controller); + + controller->operational->command |= (1 << 0) | (1 << 2); waitForKeyPress(); - prepareControlTransfer(controller); + + if (controller->operational->status & (1 << 2)) + return printf("critical XHCI problem\n"); + + // just testing for now... + xhci_command(controller, 0, 0, 0, (9 << 10)); + xhci_command(controller, 0, 0, 0, (9 << 10)); + xhci_command(controller, 0, 0, 0, (9 << 10)); + xhci_command(controller, 0, 0, 0, (9 << 10)); + + while (1) { + XHCITRB *trb = trbRingFetch(&controller->events); + uint32_t type = (trb->control >> 10) & 0x3F; + + printf("event %i [%x %x %x %x] type: %i, slotId: %i\n", + controller->events.dequeue, trb->dataLow, trb->dataHigh, + trb->status, trb->control, type, trb->control >> 24); + + controller->runtime->interrupters[0].eventRingDequeuePointer[0] = + U32(&controller->events.physical[controller->events.dequeue]) | + (1 << 3); + } } int32_t main() { - uint32_t pciService = getService("lspci"); - uint32_t function = getFunction(pciService, "getDeviceClass"); uint32_t i = 0, class = 0; - while ((class = request(pciService, function, i, 0))) { + while ((class = getDeviceClass(i, 0))) { if (class == 0x0C0330) { - printf("found XHCI host controller at pci no. %i\n", i); + printf("found XHCI host controller at pci device no. %i\n", i); + enableBusMaster(i, 0); initializeUSB(i); } i++; diff --git a/src/userland/usb/usb.h b/src/userland/usb/usb.h index e82202d..f7550c8 100644 --- a/src/userland/usb/usb.h +++ b/src/userland/usb/usb.h @@ -3,208 +3,85 @@ #include -#define OFFSET(ptr, off) (((void *)ptr) + off) +#define OFFSET(ptr, off) (((void *)(ptr)) + (off)) -typedef struct { - uint8_t capabilitiesSize; +typedef volatile struct { + uint8_t capabilitiesLength; uint8_t reserved; uint16_t interfaceVersion; uint32_t structuralParameters[3]; - uint32_t capabilityParameters1; + uint32_t capabilityParameter1; uint32_t doorbellOffset; - uint32_t runtimeRegistersSpaceOffset; - uint32_t capabilityParameters2; -} XHCICapabilities; + uint32_t runtimeOffset; + uint32_t capabilityParameter2; +} __attribute__((packed)) XHCICapabilities; -typedef struct { - uint32_t usbCommand, usbStatus; - uint64_t pageSize; - uint32_t deviceNotificationControl, commandRingControl; - uint64_t deviceContextArray; - uint32_t configure; -} XHCIOperationalRegisters; +typedef volatile struct { + uint32_t status; + uint32_t pm_status; + uint32_t link_info; + uint32_t lpm_control; +} __attribute__((packed)) XHCIPort; -typedef struct { - uint32_t routeString : 20; - uint32_t speed : 4; - uint32_t reserved : 1; - uint32_t multiTT : 1; - uint32_t isHub : 1; - uint32_t contextEntries : 5; +typedef volatile struct { + uint32_t command; + uint32_t status; + uint32_t pageSize; + uint32_t reserved[2]; + uint32_t op_dnctrl; + uint32_t commandRingControl[2]; + uint32_t reserved1[4]; + uint32_t deviceContextBaseAddressArray[2]; + uint32_t config; + uint8_t reserved2[964]; + XHCIPort ports[256]; +} __attribute__((packed)) XHCIOperational; - uint32_t maxExitLatency : 16; - uint32_t rootHubPortNumber : 8; - uint32_t portCount : 8; // only if this is a hub - - uint32_t parentHubSlot : 8; - uint32_t parentPortNumber : 8; - uint32_t TTThinkTime : 2; - uint32_t reserved1 : 4; - uint32_t interrupterTarget : 10; - - uint32_t deviceAddress : 8; - uint32_t reserved2 : 20; - uint32_t slotState : 4; - - uint32_t reserved3[4]; -} SlotContext; - -typedef struct { - uint32_t endpointState : 3; - uint32_t reserved : 5; - uint32_t maximumBurstCount : 2; - uint32_t maxPrimaryStreams : 5; - uint32_t linearStreamArray : 1; - uint32_t interval : 8; - uint32_t maxEndpointServiceTime : 8; - - uint32_t reserved1 : 1; - uint32_t errorCount : 2; - uint32_t endpointType : 3; - uint32_t reserved2 : 1; - uint32_t hostInitiateDisable : 1; - uint32_t maxBurstSize : 8; - uint32_t maxPacketSize : 16; - - uint32_t dequeueCycleState : 1; - uint32_t reserved3 : 3; - uint32_t TRBDequePointerLow : 28; - uint32_t TRBDequePointerHigh; - - uint32_t averageTRBLength : 16; - uint32_t maxServiceTimeIntervalPayloadLow : 16; - - uint32_t reserved4[3]; -} EndpointContext; - -typedef struct { - SlotContext slotContext; - EndpointContext endpoints[31]; -} DeviceContext; - -typedef struct { - uint32_t D; // drop contextFlags - uint32_t A; // add context flags - uint32_t reserved[5]; - uint8_t configValue; - uint8_t interfaceNumber; - uint8_t alternateSetting; - uint8_t reserved1; - DeviceContext deviceContext; -} XHCIInputContext; - -typedef struct { - uint64_t scratchpadBufferBase; - uint64_t deviceContextPointer[16]; -} DeviceContextArray; - -typedef struct { - uint32_t statusControl, powerManagement, linkInfo, reserved; -} XHCIPortRegister; - -typedef struct { +typedef volatile struct { uint32_t dataLow; uint32_t dataHigh; + uint32_t status; + uint32_t control; +} __attribute__((packed)) XHCITRB; - uint32_t dataSize : 17; - uint32_t transferSize : 5; - uint32_t interruptTarget : 10; - - uint32_t cycle : 1; - uint32_t ent : 1; - uint32_t interruptOnShortPacket : 1; - uint32_t noSnoop : 1; - uint32_t chainBit : 1; - uint32_t interruptOnCompletion : 1; - uint32_t immediateData : 1; - uint32_t reserved : 2; - uint32_t blockEventInterrupt : 1; - uint32_t type : 6; - uint32_t reserved1 : 16; -} XHCITransferRequestBlock; - -typedef struct { - uint32_t timeTransfer; - uint32_t timeEvent; - uint8_t epState; - bool pendingTransfer; - uint8_t transferError; - - bool cycleState; - - uint32_t transferCount; - - XHCITransferRequestBlock *trbs; -} XHCIEndpoint; - -typedef struct { - XHCIEndpoint endpoints[31]; - uint8_t slotState; -} XHCISlot; - -typedef struct { - uint32_t baseLow; - uint32_t baseHigh; - uint32_t ringSegmentSize : 16; - uint32_t reserved : 16; - uint32_t reserved1; -} XHCIEventRingTableEntry; - -typedef struct { - uint32_t pending : 1; - uint32_t enabled : 1; - uint32_t reserved : 30; - - uint16_t moderationInterval; - uint16_t moderationCounter; - - uint16_t eventRingSize; - uint16_t reserved1; - +typedef volatile struct { + uint32_t pending : 1, enabled : 1, reserved : 30; + uint32_t moderationCounter : 16, moderationInterval : 16; + uint32_t eventRingSegmentTableSize; // MAX 16 bit uint32_t reserved2; + uint32_t eventRingSegmentTableAddress[2]; + uint32_t eventRingDequeuePointer[2]; +} __attribute__((packed)) XHCIInterrupter; - uint32_t eventRingBaseLow; - uint32_t eventRingBaseHigh; +typedef volatile struct { + uint8_t microframeIndex; + uint8_t reserved[0x20 - 1]; + XHCIInterrupter interrupters[1023]; +} __attribute__((packed)) XHCIRuntime; - uint32_t eventRingDequeueLow; - uint32_t eventRingDequeueHigh; -} XHCIInterrupterRegisterSet; +typedef volatile struct { + uint32_t ringSegmentBaseAddress[2]; + uint16_t ringSegmentSize, reserved; + uint32_t reserved1; +} __attribute__((packed)) XHCIEventRingSegmentTableEntry; typedef struct { - uint32_t microframeIndex : 14; - uint32_t reserved : 18; - uint32_t reserved1[7]; - XHCIInterrupterRegisterSet interrupterRegisters[128]; -} XHCIRuntimeRegisters; + XHCITRB *trbs, *physical; + uint32_t size, enqueue, dequeue; + bool cycle; +} TrbRing; typedef struct { - uint8_t slotNumber; - XHCITransferRequestBlock *command; -} PortSlotLink; - -typedef struct { - uint32_t pciDeviceId; XHCICapabilities *capabilities; - XHCIOperationalRegisters *operational; - DeviceContextArray *deviceContextArray; - void **scratchpadBuffers; - uint32_t scratchpadBufferCount; - XHCIPortRegister *ports; - DeviceContext *deviceContexts[16]; - XHCIInputContext *inputContexts[16]; - XHCISlot *slots[16]; - XHCITransferRequestBlock *trbs[16][32]; - XHCITransferRequestBlock *commandRing; - XHCITransferRequestBlock *commandRingEnque; - bool commandRingCycleState; + XHCIOperational *operational; + XHCIRuntime *runtime; + TrbRing commands; + TrbRing events; + uint32_t pciDevice; volatile uint32_t *doorbells; - uint32_t interrupt; - uint32_t eventSegmentSize; - uint32_t eventSegmentCounter; - uint32_t eventSegmentNumber; - XHCITransferRequestBlock *eventRing; - XHCIRuntimeRegisters *runtime; - PortSlotLink portSlotLinks[10]; + XHCIEventRingSegmentTableEntry *eventRingSegmentTable, + *eventRingSegmentTablePhysical; + uint64_t *deviceContextBaseAddressArray; } XHCIController; #endif