Skip to content

Commit

Permalink
ported the address device command to the new xhci implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
FlareCoding committed Sep 19, 2024
1 parent cc10515 commit b0c957d
Show file tree
Hide file tree
Showing 9 changed files with 445 additions and 13 deletions.
Binary file modified efi/OVMF_VARS.fd
Binary file not shown.
81 changes: 81 additions & 0 deletions kernel/src/drivers/usb/xhci/xhci_device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "xhci_device.h"

uint16_t getInitialPacketSizeFromPortSpeed(uint8_t speed) {
// Calculate initial max packet size for the set device command
uint16_t initialMaxPacketSize = 0;
switch (speed) {
case XHCI_USB_SPEED_LOW_SPEED: initialMaxPacketSize = 8; break;

case XHCI_USB_SPEED_FULL_SPEED:
case XHCI_USB_SPEED_HIGH_SPEED: initialMaxPacketSize = 64; break;

case XHCI_USB_SPEED_SUPER_SPEED:
case XHCI_USB_SPEED_SUPER_SPEED_PLUS:
default: initialMaxPacketSize = 512; break;
}

return initialMaxPacketSize;
}

XhciDevice::XhciDevice(XhciHcContext* xhc) {
_allocInputContext(xhc);
}

XhciDevice::XhciDevice(XhciHcContext* xhc, uint8_t port) : port(port) {
_allocInputContext(xhc);
}

void XhciDevice::setupTransferRing() {
controlEpTransferRing = XhciTransferRing::allocate(slotId);
}

void XhciDevice::setupAddressDeviceCtx(uint8_t portSpeed) {
auto& inputControlCtx = inputContext32.virtualBase->controlContext;
auto& inputDeviceCtx = inputContext32.virtualBase->deviceContext;

// Setup the input control context
inputControlCtx.addFlags = (1 << 0) | (1 << 1);
inputControlCtx.dropFlags = 0;

// Setup the slot context
auto& slotContext = inputDeviceCtx.slotContext;
slotContext.contextEntries = 1;
slotContext.speed = portSpeed;
slotContext.rootHubPortNum = port;
slotContext.routeString = 0;
slotContext.interrupterTarget = 0;

// Setup the control endpoint context
auto& ctrlEpContext = inputDeviceCtx.controlEndpointContext;
ctrlEpContext.endpointState = XHCI_ENDPOINT_STATE_DISABLED;
ctrlEpContext.endpointType = XHCI_ENDPOINT_TYPE_CONTROL;
ctrlEpContext.interval = 0;
ctrlEpContext.errorCount = 3;
ctrlEpContext.maxPacketSize = getInitialPacketSizeFromPortSpeed(portSpeed);
ctrlEpContext.maxEsitPayloadLo = 0;
ctrlEpContext.maxEsitPayloadHi = 0;
ctrlEpContext.averageTrbLength = 8;
ctrlEpContext.transferRingDequeuePtr = controlEpTransferRing->getPhysicalBase();
ctrlEpContext.dcs = 1;
}

uint64_t XhciDevice::getInputContextPhysicalBase() {
// return inputContext64.physicalBase ? inputContext64.physicalBase : inputContext32.physicalBase;
return inputContext32.physicalBase;
}

void XhciDevice::_allocInputContext(XhciHcContext* xhc) {
if (xhc->has64ByteContextSize()) {
inputContext64 = xhciAllocDma<XhciInputContext64>(
sizeof(XhciInputContext64),
XHCI_INPUT_CONTROL_CONTEXT_ALIGNMENT,
XHCI_INPUT_CONTROL_CONTEXT_BOUNDARY
);
} else {
inputContext32 = xhciAllocDma<XhciInputContext32>(
sizeof(XhciInputContext32),
XHCI_INPUT_CONTROL_CONTEXT_ALIGNMENT,
XHCI_INPUT_CONTROL_CONTEXT_BOUNDARY
);
}
}
37 changes: 37 additions & 0 deletions kernel/src/drivers/usb/xhci/xhci_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef XHCI_DEVICE_H
#define XHCI_DEVICE_H

#include "xhci_device_ctx.h"
#include "xhci_ctx.h"

class XhciDevice {
public:
XhciDevice(XhciHcContext* xhc);
XhciDevice(XhciHcContext* xhc, uint8_t port);
~XhciDevice() = default;

void setupTransferRing();
void setupAddressDeviceCtx(uint8_t portSpeed);

uint64_t getInputContextPhysicalBase();

public:
uint8_t port;
uint8_t slotId;

// Pointer to the entry in DCBAA
XhciDma<XhciDeviceContext32> deviceContext32;
XhciDma<XhciDeviceContext64> deviceContext64;

// Input context buffer for configuring the device
XhciDma<XhciInputContext32> inputContext32;
XhciDma<XhciInputContext64> inputContext64;

// Control endpoint's transfer ring
kstl::SharedPtr<XhciTransferRing> controlEpTransferRing;

private:
void _allocInputContext(XhciHcContext* xhc);
};

#endif
32 changes: 24 additions & 8 deletions kernel/src/drivers/usb/xhci/xhci_device_ctx.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "xhci_device_ctx.h"
#include <kprint.h>

void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* ctx) {
size_t contextEntrySize = ctx->has64ByteContextSize() ? 64 : 32;
size_t dcbaaSize = contextEntrySize * (ctx->getMaxDeviceSlots() + 1);
void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* xhc) {
size_t contextEntrySize = xhc->has64ByteContextSize() ? 64 : 32;
size_t dcbaaSize = contextEntrySize * (xhc->getMaxDeviceSlots() + 1);

m_dcbaa = xhciAllocDma<uint64_t>(dcbaaSize, XHCI_DEVICE_CONTEXT_ALIGNMENT, XHCI_DEVICE_CONTEXT_BOUNDARY);

Expand All @@ -18,7 +18,7 @@ void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* ctx) {
*/

// Initialize scratchpad buffer array if needed
uint8_t scratchpadBuffers = ctx->getMaxScratchpadBuffers();
uint8_t scratchpadBuffers = xhc->getMaxScratchpadBuffers();
if (scratchpadBuffers > 0) {
// Array of uint64_t pointers
XhciDma<uint64_t> scratchpadArray = xhciAllocDma<uint64_t>(scratchpadBuffers * sizeof(uint64_t));
Expand All @@ -34,10 +34,26 @@ void XhciDeviceContextManager::allocateDcbaa(XhciHcContext* ctx) {
}

// Update the DCBAAP entry in operational registers
ctx->opRegs->dcbaap = m_dcbaa.physicalBase;
xhc->opRegs->dcbaap = m_dcbaa.physicalBase;
}

void* XhciDeviceContextManager::allocateDeviceContext(uint8_t slot) const {
(void)slot;
return nullptr;
void XhciDeviceContextManager::allocateDeviceContext(XhciHcContext* xhc, uint8_t slot) const {
// Allocate a memory block for the device context
if (xhc->has64ByteContextSize()) {
auto ctx = xhciAllocDma<XhciDeviceContext64>(
sizeof(XhciDeviceContext64),
XHCI_DEVICE_CONTEXT_ALIGNMENT,
XHCI_DEVICE_CONTEXT_BOUNDARY
);

m_dcbaa.virtualBase[slot] = ctx.physicalBase;
} else {
auto ctx = xhciAllocDma<XhciDeviceContext32>(
sizeof(XhciDeviceContext32),
XHCI_DEVICE_CONTEXT_ALIGNMENT,
XHCI_DEVICE_CONTEXT_BOUNDARY
);

m_dcbaa.virtualBase[slot] = ctx.physicalBase;
}
}
84 changes: 82 additions & 2 deletions kernel/src/drivers/usb/xhci/xhci_device_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,14 +485,94 @@ static_assert(sizeof(XhciDeviceContext32) == 1024, "Size mismatch for 32-byte De
using XhciDeviceContext64 = XhciDeviceContext<64>;
static_assert(sizeof(XhciDeviceContext64) == 2048, "Size mismatch for 64-byte Device Context.");

/*
// xHci Sped Section 6.2.5.1 Figure 6-6: Input Control Context (page 461)
The Input Control Context data structure defines which Device Context data
structures are affected by a command and the operations to be performed on
those contexts
*/
template <size_t Size>
struct XhciInputControlContext {
/*
Drop Context flags (D2 - D31). These single bit fields identify which Device Context data
structures should be disabled by command. If set to ‘1’, the respective Endpoint Context shall
be disabled. If cleared to ‘0’, the Endpoint Context is ignored.
*/
uint32_t dropFlags;

/*
Add Context flags (A0 - A31). These single bit fields identify which Device Context data
structures shall be evaluated and/or enabled by a command. If set to ‘1’, the respective Context
shall be evaluated. If cleared to ‘0’, the Context is ignored.
*/
uint32_t addFlags;

uint32_t rsvd0[5];

/*
Configuration Value. If CIC = ‘1’, CIE = ‘1’, and this Input Context is associated with a Configure
Endpoint Command, then this field contains the value of the Standard Configuration Descriptor
bConfigurationValue field associated with the command, otherwise the this field shall be
cleared to ‘0’.
*/
uint8_t configValue;

/*
Interface Number. If CIC = ‘1’, CIE = ‘1’, this Input Context is associated with a Configure
Endpoint Command, and the command was issued due to a SET_INTERFACE request, then this
field contains the value of the Standard Interface Descriptor bInterfaceNumber field associated
with the command, otherwise the this field shall be cleared to ‘0’.
*/
uint8_t interfaceNumber;

/*
Alternate Setting. If CIC = ‘1’, CIE = ‘1’, this Input Context is associated with a Configure
Endpoint Command, and the command was issued due to a SET_INTERFACE request, then this
field contains the value of the Standard Interface Descriptor bAlternateSetting field associated
with the command, otherwise the this field shall be cleared to ‘0’
*/
uint8_t alternateSetting;

// Reserved and zero'd
uint8_t rsvd1;

// Reserved fields depending on context size
uint32_t rsvd2[Size == 64 ? 8 : 0]; // 8 reserved for 64-byte context, none for 32-byte
} __attribute__((packed));

using XhciInputControlContext32 = XhciInputControlContext<32>;
static_assert(sizeof(XhciInputControlContext32) == 32, "Size mismatch for 32-byte Input Control Context.");

using XhciInputControlContext64 = XhciInputControlContext<64>;
static_assert(sizeof(XhciInputControlContext64) == 64, "Size mismatch for 64-byte Input Control Context.");

template <size_t Size>
struct XhciInputContext {
XhciInputControlContext<Size> controlContext;
XhciDeviceContext<Size> deviceContext;
};

using XhciInputContext32 = XhciInputContext<32>;
static_assert(sizeof(XhciInputContext32) == 1056, "Size mismatch for 32-byte Input Context.");

using XhciInputContext64 = XhciInputContext<64>;
static_assert(sizeof(XhciInputContext64) == 2112, "Size mismatch for 64-byte Input Context.");

class XhciDeviceContextManager {
public:
XhciDeviceContextManager() = default;
~XhciDeviceContextManager() = default;

void allocateDcbaa(XhciHcContext* ctx);
void allocateDcbaa(XhciHcContext* xhc);

// Returns a physical address
void allocateDeviceContext(XhciHcContext* xhc, uint8_t slot) const;

void* allocateDeviceContext(uint8_t slot) const;
template <size_t Size>
inline XhciDeviceContext<Size>* getDeviceContext(uint8_t slot) {
return reinterpret_cast<XhciDeviceContext<Size>*>(m_dcbaa.virtualBase[slot]);
}

private:
XhciDma<uint64_t> m_dcbaa;
Expand Down
Loading

0 comments on commit b0c957d

Please sign in to comment.