Compare commits

...

5 Commits

12 changed files with 245 additions and 7 deletions

View File

@ -1,6 +1,7 @@
add_executable(voyageurs add_executable(voyageurs
keyboard/keyboard_driver.cpp keyboard/keyboard_driver.cpp
xhci/device_slot.cpp xhci/device_slot.cpp
xhci/endpoint.cpp
xhci/trb.cpp xhci/trb.cpp
xhci/trb_ring.cpp xhci/trb_ring.cpp
xhci/xhci_driver.cpp xhci/xhci_driver.cpp

View File

@ -21,7 +21,7 @@ class ReadControlCommand {
uint64_t value = RequestConstants<Output>::Value() << 16; uint64_t value = RequestConstants<Output>::Value() << 16;
// TODO: May need to be non-0 for string descriptors. // TODO: May need to be non-0 for string descriptors.
uint64_t index = (uint64_t)0 << 32; uint64_t index = (uint64_t)0 << 32;
uint64_t length = sizeof(Output) << 48; uint64_t length = (uint64_t)0x1000 << 48;
return { return {
.parameter = request_type | request | value | index | length, .parameter = request_type | request | value | index | length,
.status = 8, .status = 8,
@ -34,7 +34,7 @@ class ReadControlCommand {
XhciTrb DataTrb() { XhciTrb DataTrb() {
return { return {
.parameter = output_phys_, .parameter = output_phys_,
.status = sizeof(Output), .status = 0x1000,
.type_and_cycle = 1 | (1 << 5) | (3 << 10), .type_and_cycle = 1 | (1 << 5) | (3 << 10),
.control = 1, .control = 1,
}; };

View File

@ -34,3 +34,44 @@ class RequestConstants<DeviceDescriptor> {
static uint8_t Request() { return 0x6; }; static uint8_t Request() { return 0x6; };
static uint16_t Value() { return 0x100; }; static uint16_t Value() { return 0x100; };
}; };
struct ConfigurationDescriptor {
uint8_t length;
uint8_t type;
uint16_t total_length;
uint8_t num_interfaces;
uint8_t configuration_value;
uint8_t configuration_string_index;
uint8_t attributes;
uint8_t max_power;
} __attribute__((packed));
template <>
class RequestConstants<ConfigurationDescriptor> {
public:
static uint8_t RequestType() { return 0x80; }
static uint8_t Request() { return 0x6; }
// TODO: Consider getting other description indexes.
static uint16_t Value() { return 0x200; }
};
struct InterfaceDescriptor {
uint8_t length;
uint8_t type;
uint8_t interface_number;
uint8_t alternate_setting;
uint8_t num_endpoints;
uint8_t interface_class;
uint8_t interface_subclass;
uint8_t interface_protocol;
uint8_t interfact_string_index;
} __attribute__((packed));
struct EndpointDescriptor {
uint8_t length;
uint8_t type;
uint8_t endpoint_address;
uint8_t attributes;
uint16_t max_packet_size;
uint8_t interval;
} __attribute__((packed));

View File

@ -4,10 +4,13 @@
#include <mammoth/util/debug.h> #include <mammoth/util/debug.h>
#include "xhci/trb.h" #include "xhci/trb.h"
#include "xhci/xhci_driver.h"
void DeviceSlot::EnableAndInitializeDataStructures( void DeviceSlot::EnableAndInitializeDataStructures(
uint8_t slot_index, uint64_t* output_context, volatile uint32_t* doorbell) { XhciDriver* driver, uint8_t slot_index, uint64_t* output_context,
volatile uint32_t* doorbell) {
enabled_ = true; enabled_ = true;
xhci_driver_ = driver;
slot_index_ = slot_index; slot_index_ = slot_index;
doorbell_ = doorbell; doorbell_ = doorbell;
@ -42,6 +45,8 @@ XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port,
input_context_->endpoint_contexts[0].tr_dequeue_ptr = input_context_->endpoint_contexts[0].tr_dequeue_ptr =
control_endpoint_transfer_trb_->PhysicalAddress() | 0x1; control_endpoint_transfer_trb_->PhysicalAddress() | 0x1;
endpoints_ = glcr::Array<Endpoint>(32);
return ::CreateAddressDeviceCommand(context_phys_ + kInputSlotContextOffset, return ::CreateAddressDeviceCommand(context_phys_ + kInputSlotContextOffset,
slot_index_); slot_index_);
} }
@ -51,8 +56,19 @@ uint8_t DeviceSlot::State() {
} }
void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) { void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) {
if (endpoint_index >= 32) {
dbgln("ERROR: Received transfer for invalid endpoint {x}", endpoint_index);
return;
}
if (endpoint_index != 1) { if (endpoint_index != 1) {
crash("Transfer complete on non control endpoint", glcr::UNIMPLEMENTED); if (!endpoints_[endpoint_index].Enabled()) {
dbgln("ERROR: XHCI received transfer for disabled endpoint {x}",
endpoint_index);
return;
}
endpoints_[endpoint_index].TransferComplete(trb_phys);
return;
} }
if (!control_completion_sempahores_.Contains(trb_phys)) { if (!control_completion_sempahores_.Contains(trb_phys)) {
@ -63,3 +79,27 @@ void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) {
control_completion_sempahores_.at(trb_phys)->Signal(); control_completion_sempahores_.at(trb_phys)->Signal();
check(control_completion_sempahores_.Delete(trb_phys)); check(control_completion_sempahores_.Delete(trb_phys));
} }
mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand(uint8_t config_value) {
input_context_->input.add_contexts = (0x1 << 3) | 0x1;
input_context_->input.configuration_value = config_value;
// TODO: Maybe don't hardcode this.
input_context_->input.interface_number = 0;
input_context_->slot_context.route_speed_entries &= 0xFFFFFF;
// TODO: Don't hardcode this.
uint8_t max_endpoint = 0x3;
input_context_->slot_context.route_speed_entries |= (max_endpoint << 27);
// TODO: Dont' hardcode this.
endpoints_[3].Initialize(input_context_->endpoint_contexts + 2);
xhci_driver_->IssueCommand(CreateConfigureEndpointCommand(
context_phys_ + kInputSlotContextOffset, slot_index_));
return configure_device_semaphore_;
}
void DeviceSlot::SignalConfigureDeviceCompleted() {
configure_device_semaphore_.Signal();
}

View File

@ -8,22 +8,29 @@
#include <mammoth/util/memory_region.h> #include <mammoth/util/memory_region.h>
#include "xhci/control_command.h" #include "xhci/control_command.h"
#include "xhci/endpoint.h"
#include "xhci/trb_ring.h" #include "xhci/trb_ring.h"
#include "xhci/xhci.h" #include "xhci/xhci.h"
class XhciDriver;
class DeviceSlot { class DeviceSlot {
public: public:
DeviceSlot() = default; DeviceSlot() = default;
DeviceSlot(const DeviceSlot&) = delete; DeviceSlot(const DeviceSlot&) = delete;
DeviceSlot(DeviceSlot&&) = delete; DeviceSlot(DeviceSlot&&) = delete;
void EnableAndInitializeDataStructures(uint8_t slot_index_, void EnableAndInitializeDataStructures(XhciDriver* driver,
uint8_t slot_index_,
uint64_t* output_context, uint64_t* output_context,
volatile uint32_t* doorbell); volatile uint32_t* doorbell);
XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string, XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string,
uint16_t max_packet_size); uint16_t max_packet_size);
mmth::Semaphore IssueConfigureDeviceCommand(uint8_t config_value);
void SignalConfigureDeviceCompleted();
// Caller must keep the command in scope until it completes. // Caller must keep the command in scope until it completes.
template <typename T> template <typename T>
void ExecuteReadControlCommand(ReadControlCommand<T>& command); void ExecuteReadControlCommand(ReadControlCommand<T>& command);
@ -35,6 +42,7 @@ class DeviceSlot {
private: private:
bool enabled_ = false; bool enabled_ = false;
XhciDriver* xhci_driver_;
uint8_t slot_index_ = 0; uint8_t slot_index_ = 0;
volatile uint32_t* doorbell_ = nullptr; volatile uint32_t* doorbell_ = nullptr;
@ -49,6 +57,10 @@ class DeviceSlot {
glcr::UniquePtr<TrbRingWriter> control_endpoint_transfer_trb_; glcr::UniquePtr<TrbRingWriter> control_endpoint_transfer_trb_;
glcr::HashMap<uint64_t, glcr::SharedPtr<mmth::Semaphore>> glcr::HashMap<uint64_t, glcr::SharedPtr<mmth::Semaphore>>
control_completion_sempahores_; control_completion_sempahores_;
mmth::Semaphore configure_device_semaphore_;
glcr::Array<Endpoint> endpoints_;
}; };
template <typename T> template <typename T>

View File

@ -0,0 +1,37 @@
#include "xhci/endpoint.h"
#include <mammoth/util/debug.h>
void Endpoint::Initialize(XhciEndpointContext* context) {
enabled_ = true;
context_ = context;
trb_ring_ = glcr::MakeUnique<TrbRingWriter>();
recv_mem_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &recv_phys_);
context_->tr_dequeue_ptr = trb_ring_->PhysicalAddress() | 1;
context_->error_and_type = (0x3 << 1) | (0x7 << 3) | (0x8 << 16);
for (uint64_t i = 0; i < 10; i++) {
trb_ring_->EnqueueTrb({
.parameter = recv_phys_ + offset_,
.status = 8,
.type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10),
.control = 0,
});
offset_ += 8;
}
}
void Endpoint::TransferComplete(uint64_t trb_phys) {
uint64_t phys_offset =
(trb_phys - trb_ring_->PhysicalAddress()) / sizeof(XhciTrb);
dbgln("Data: {x}", *((uint64_t*)recv_mem_.vaddr() + phys_offset));
trb_ring_->EnqueueTrb({
.parameter = recv_phys_ + offset_,
.status = 8,
.type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10),
.control = 0,
});
offset_ += 8;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <glacier/memory/unique_ptr.h>
#include "xhci/trb_ring.h"
#include "xhci/xhci.h"
class Endpoint {
public:
Endpoint() {}
void Initialize(XhciEndpointContext* context);
bool Enabled() { return enabled_; }
void TransferComplete(uint64_t trb_phys);
private:
bool enabled_ = false;
XhciEndpointContext* context_ = nullptr;
glcr::UniquePtr<TrbRingWriter> trb_ring_;
uint64_t recv_phys_;
mmth::OwnedMemoryRegion recv_mem_;
uint64_t offset_ = 0;
};

View File

@ -49,6 +49,17 @@ XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id) {
}; };
} }
XhciTrb CreateConfigureEndpointCommand(uint64_t input_context,
uint8_t slot_id) {
return {
.parameter = input_context,
.status = 0,
.type_and_cycle =
(uint16_t)(TypeToInt(TrbType::ConfigureEndpoint) | kTrb_Cycle),
.control = (uint16_t)(slot_id << 8),
};
}
XhciTrb CreateNoOpCommandTrb() { XhciTrb CreateNoOpCommandTrb() {
return { return {
.parameter = 0, .parameter = 0,

View File

@ -18,6 +18,7 @@ enum class TrbType : uint8_t {
// Commands // Commands
EnableSlot = 9, EnableSlot = 9,
AddressDevice = 11, AddressDevice = 11,
ConfigureEndpoint = 12,
NoOpCommand = 23, NoOpCommand = 23,
// Events // Events
@ -32,4 +33,5 @@ XhciTrb CreateLinkTrb(uint64_t physical_address);
XhciTrb CreateEnableSlotTrb(); XhciTrb CreateEnableSlotTrb();
XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id); XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id);
XhciTrb CreateConfigureEndpointCommand(uint64_t input_context, uint8_t slot_id);
XhciTrb CreateNoOpCommandTrb(); XhciTrb CreateNoOpCommandTrb();

View File

@ -36,7 +36,7 @@ uint64_t TrbRingWriter::EnqueueTrb(const XhciTrb& trb) {
} }
trb_list_[ptr] = trb; trb_list_[ptr] = trb;
return phys_address_ + (ptr * sizeof(uint64_t)); return phys_address_ + (ptr * sizeof(XhciTrb));
} }
bool TrbRingReader::HasNext() { bool TrbRingReader::HasNext() {

View File

@ -31,6 +31,54 @@ void configure_device(void* void_device_slot) {
dbgln("Descriptor Type {x}, ({x})", descriptor->type, descriptor->usb_spec); dbgln("Descriptor Type {x}, ({x})", descriptor->type, descriptor->usb_spec);
dbgln("Device Class/Sub/Protocol: {x}/{x}/{x}", descriptor->device_class, dbgln("Device Class/Sub/Protocol: {x}/{x}/{x}", descriptor->device_class,
descriptor->device_subclass, descriptor->device_protocol); descriptor->device_subclass, descriptor->device_protocol);
dbgln("Num Configurations: {}", descriptor->num_configurations);
ReadControlCommand<ConfigurationDescriptor> config_command;
device_slot->ExecuteReadControlCommand(config_command);
ConfigurationDescriptor* config_descriptor = config_command.AwaitResult();
dbgln("Configuration Value: {x}", config_descriptor->configuration_value);
dbgln("Num Interfaces: {x}", config_descriptor->num_interfaces);
dbgln("Size: {x}, Total Length: {x}", config_descriptor->length,
config_descriptor->total_length);
uint64_t next_vaddr =
reinterpret_cast<uint64_t>(config_descriptor) + config_descriptor->length;
for (auto i = config_descriptor->num_interfaces; i > 0; i--) {
InterfaceDescriptor* interface =
reinterpret_cast<InterfaceDescriptor*>(next_vaddr);
dbgln("Interface: {x}", interface->interface_number);
dbgln("Interface Class/Sub/Protocol: {x}/{x}/{x}",
interface->interface_class, interface->interface_subclass,
interface->interface_protocol);
dbgln("Num Endpoints: {x}", interface->num_endpoints);
next_vaddr += interface->length;
for (auto j = interface->num_endpoints; j > 0; j--) {
EndpointDescriptor* endpoint =
reinterpret_cast<EndpointDescriptor*>(next_vaddr);
if (endpoint->type != 5) {
dbgln("Descriptor type {x}, skipping", endpoint->type);
j++;
next_vaddr += endpoint->length;
continue;
}
dbgln("Endpoint Addr: {x}", endpoint->endpoint_address);
dbgln("Endpoint Attr: {x}", endpoint->attributes);
next_vaddr += endpoint->length;
}
}
dbgln("---- Configuring with configuration: {x}",
config_descriptor->configuration_value);
device_slot
->IssueConfigureDeviceCommand(config_descriptor->configuration_value)
.Wait();
dbgln("Configured!");
} }
glcr::ErrorOr<glcr::UniquePtr<XhciDriver>> XhciDriver::InitiateDriver( glcr::ErrorOr<glcr::UniquePtr<XhciDriver>> XhciDriver::InitiateDriver(
@ -130,6 +178,11 @@ void XhciDriver::DumpDebugInfo() {
runtime_->interrupters[0].event_ring_segment_table_base_address); runtime_->interrupters[0].event_ring_segment_table_base_address);
} }
void XhciDriver::IssueCommand(const XhciTrb& command) {
command_ring_.EnqueueTrb(command);
doorbells_->doorbell[0] = 0;
}
XhciDriver::XhciDriver(mmth::OwnedMemoryRegion&& pci_space) XhciDriver::XhciDriver(mmth::OwnedMemoryRegion&& pci_space)
: pci_region_(glcr::Move(pci_space)) {} : pci_region_(glcr::Move(pci_space)) {}
@ -152,6 +205,8 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() {
runtime_ = reinterpret_cast<XhciRuntime*>(mmio_regions_.vaddr() + runtime_ = reinterpret_cast<XhciRuntime*>(mmio_regions_.vaddr() +
capabilities_->runtime_offset); capabilities_->runtime_offset);
dbgln("INTTTT: {x}", (uint64_t)runtime_->interrupters);
doorbells_ = reinterpret_cast<XhciDoorbells*>(mmio_regions_.vaddr() + doorbells_ = reinterpret_cast<XhciDoorbells*>(mmio_regions_.vaddr() +
capabilities_->doorbell_offset); capabilities_->doorbell_offset);
dbgln("Doorbells: {x}", (uint64_t)doorbells_); dbgln("Doorbells: {x}", (uint64_t)doorbells_);
@ -290,6 +345,11 @@ void XhciDriver::HandleCommandCompletion(
dbgln("State: {x}", devices_[slot - 1].State()); dbgln("State: {x}", devices_[slot - 1].State());
Thread(configure_device, &devices_[slot - 1]); Thread(configure_device, &devices_[slot - 1]);
break; break;
case TrbType::ConfigureEndpoint:
dbgln("Device COnfigured: {x}", slot);
dbgln("State: {x}", devices_[slot - 1].State());
devices_[slot - 1].SignalConfigureDeviceCompleted();
break;
case TrbType::NoOpCommand: case TrbType::NoOpCommand:
dbgln("No-op Command Completed"); dbgln("No-op Command Completed");
break; break;
@ -300,6 +360,11 @@ void XhciDriver::HandleCommandCompletion(
} }
void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) { void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) {
uint8_t status = transfer_event_trb.status >> 24;
if (status != 1 && status != 0xD) {
dbgln("Unexpected Status {x}", status);
return;
}
uint8_t slot_id = transfer_event_trb.control >> 8; uint8_t slot_id = transfer_event_trb.control >> 8;
uint8_t endpoint_id = transfer_event_trb.control & 0x1F; uint8_t endpoint_id = transfer_event_trb.control & 0x1F;
uint64_t trb_phys = transfer_event_trb.parameter; uint64_t trb_phys = transfer_event_trb.parameter;
@ -309,7 +374,7 @@ void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) {
void XhciDriver::InitializeSlot(uint8_t slot_index) { void XhciDriver::InitializeSlot(uint8_t slot_index) {
// TODO: Consider making this array one longer and ignore the first value. // TODO: Consider making this array one longer and ignore the first value.
devices_[slot_index - 1].EnableAndInitializeDataStructures( devices_[slot_index - 1].EnableAndInitializeDataStructures(
slot_index, &(device_context_base_array_[slot_index]), this, slot_index, &(device_context_base_array_[slot_index]),
&doorbells_->doorbell[slot_index]); &doorbells_->doorbell[slot_index]);
XhciPort* port = XhciPort* port =
reinterpret_cast<XhciPort*>(reinterpret_cast<uint64_t>(operational_) + reinterpret_cast<XhciPort*>(reinterpret_cast<uint64_t>(operational_) +

View File

@ -23,6 +23,8 @@ class XhciDriver {
void InterruptLoop(); void InterruptLoop();
void IssueCommand(const XhciTrb& command);
private: private:
// MMIO Structures. // MMIO Structures.
mmth::OwnedMemoryRegion pci_region_; mmth::OwnedMemoryRegion pci_region_;