Using Interrupt On Completion is not robust, because the interrupt flag
is also set if a short transfer is detected. So we need to poll the
Active flag in the transfer descriptors.
The XHCI device index and scratchpad buffers are mapped into high memory,
in order to conserve low memory. They need to be accessible in the virtual
address space to allow us to initialise them. After initialisation. only
the XHCI accesses them.
We also only need to access the data structures in the device private
workspace during initialisation, but keeping separate physical and virtual
addresses for these structures makes the code considerably more complex,
so for now, move these to low memory.
The old barrier implementation was very slow when running on a multi-socket
machine (pcmemtest issue 16).
The new implementation provides two options:
- when blocked, spin on a thread-local flag
- when blocked, execute a HLT instruction and wait for a NMI
The first option might be faster, but we need to measure it to find out. A
new boot command line option is provided to select between the two, with a
third setting that uses a mixture of the two.
We only map the first 4GB of physical address space, so if the ACPI tables
or local APIC are located above 4GB, or are overlaid when we remap something
else (e.g. the video frame buffer), we need to map them to somewhere we can
access. The ACPI tables are only used during startup, but the local APIC
will be needed when we are running tests if we are saving power by halting
idle CPU cores and using a NMI to wake them up.
This is needed for subsequent changes. If we do ever get presented with
a frame buffer larger than 8192x8192 pixels, we'll need to think again
about how to manage it.
Low/full speed USB devices attached directly to the root hub must be
rerouted to a companion controller. We can't rely on the BIOS to do
this for us. This requires us to initialise the EHCI device before
initialising any of its companions.
This also allows us to support keyboards attached via a high speed
hub on a system with EHCI plus companions.
When using a legacy BIOS, the memory regions used by the BIOS are well
defined. This is not the case when using a UEFI BIOS. So include the
stack area in the BSS so the loader knows how much memory to allocate,
and check we have space to relocate the program to either low or high
memory.
There are still some assumptions in the USB driver code that need to
be fixed.
This refactors the USB driver code into a more object-oriented design,
with usbkbd.c being the base class and ohci.c and xhci.c being subclasses.
This makes the code that performs USB device enumeration independent of
the host controller.
Mostly we write and read large chunks of data which will make it likely
that the data is no longer in the cache when we come to verify it. But
this is not always true, and in any case, we shouldn't rely on it.