feat: aarch64 port - Raspberry Pi 4/400 SD boot (SDHCI, ext2 root + first-boot grow), USB hubs, PCI INTx routing, SMP, DMA fences

This commit is contained in:
daniel committed 2026-10-25 13:48:26 +01:00
1 parent 8c09ccef66
commit 808e1d66fd
66 files changed
+3690 -196

No files matched your search

+130
View File
@@ -14,11 +14,16 @@
#include <Drivers/USB/Xhci.hpp>
#include <Drivers/Storage/Ahci.hpp>
#include <Drivers/Storage/Nvme.hpp>
#include <Drivers/Storage/Sdhci.hpp>
#include <Drivers/Storage/Gpt.hpp>
#include <Drivers/Audio/IntelHda.hpp>
#include <Graphics/Framebuffer.hpp>
#include <Net/Net.hpp>
#include <Terminal/Terminal.hpp>
#include <ACPI/AcpiDevices.hpp>
#include <Boot/Boot.hpp>
#include <ACPI/AML/AmlInterpreter.hpp>
#include <ACPI/AML/AmlResource.hpp>
namespace Drivers {
@@ -89,6 +94,10 @@ namespace Drivers {
return Storage::Nvme::Probe(dev);
}
static bool ProbeSdhci(const Pci::PciDevice& dev) {
return Storage::Sdhci::Probe(dev);
}
static bool ProbeIntelHda(const Pci::PciDevice& dev) {
return Audio::IntelHda::Probe(dev);
}
@@ -189,6 +198,18 @@ namespace Drivers {
// also reports 0x01, but it exposes an I/O-space BAR0:
// ReadBar0 returns 0 for I/O BARs and Probe rejects it
// cleanly, so matching it here is harmless.
// SD host controller (standard interface) - class 0x08/0x05
{
"SDHCI",
0,
0x08, // ClassCode (Base system peripheral)
0x05, // SubClass (SD host controller)
0xFF,
nullptr,
0,
Pci::ProbePhase::Normal,
ProbeSdhci,
},
{
"IntelHDA",
0x8086, // VendorId (Intel)
@@ -227,8 +248,117 @@ namespace Drivers {
Graphics::DgpuPower::PowerDownUnused();
}
// A device's _DMA (or its parent's) bounds the addresses it can reach.
// DMA buffers come from anywhere in RAM, so RAM past the bound is a
// configuration error: on the Raspberry Pi 4 the firmware's "Limit RAM
// to 3 GB" setting must stay on.
static void WarnIfRamBeyondDma(const char* devicePath) {
char path[160];
int len = 0;
while (devicePath[len] != '\0' && len < 120) { path[len] = devicePath[len]; len++; }
Hal::AML::ResourceList dma;
bool found = false;
for (int attempt = 0; attempt < 2 && !found; attempt++) {
const char suffix[] = "._DMA";
for (int i = 0; i < (int)sizeof(suffix); i++) path[len + i] = suffix[i];
Hal::AML::Object obj;
if (Hal::AML::GetInterpreter().EvaluateObject(path, obj) &&
obj.Type == Hal::AML::ObjectType::Buffer &&
Hal::AML::ParseResourceTemplate(obj.Buffer.Data, obj.Buffer.Length, dma)) {
found = true;
break;
}
// Retry on the parent device.
while (len > 0 && path[len - 1] != '.') len--;
if (len == 0) return;
len--;
}
uint64_t dmaBase = 0, dmaLength = 0;
if (!found || !dma.GetMemory(dmaBase, dmaLength) || dmaLength == 0) return;
uint64_t dmaEnd = dmaBase + dmaLength;
const auto& map = montauk::boot::Info().memoryMap;
for (uint64_t i = 0; i < map.count; i++) {
const auto& r = map.regions[i];
if (r.kind == montauk::boot::MemoryKind::Usable && r.base + r.length > dmaEnd) {
Kt::KernelLogStream(Kt::WARNING, "Drivers") << devicePath << " can only reach RAM below 0x"
<< base::hex << dmaEnd << ", but there is RAM up to 0x" << (r.base + r.length)
<< ": its DMA may fail (Raspberry Pi 4: keep 'Limit RAM to 3 GB' enabled)";
return;
}
}
}
// An xHCI controller ACPI describes as a platform device (PNP0D10)
// instead of a PCI function: the Raspberry Pi 4/400's VL805 under UEFI
// firmware in ACPI mode, where firmware has set up the non-ECAM PCIe
// behind it. Its DMA is non-coherent unless _CCA says otherwise.
static void ProbePlatformXhci() {
if (USB::Xhci::IsInitialized()) return;
Hal::AcpiDevices::DeviceInfo info{};
if (!Hal::AcpiDevices::FindDeviceByHid("PNP0D10", info) &&
!Hal::AcpiDevices::FindDeviceByHid("PNP0D15", info)) {
return;
}
Hal::AML::ResourceList resources;
uint64_t base = 0, length = 0;
if (!Hal::AcpiDevices::EvaluateCrs(info.NodeIndex, resources) ||
!resources.GetMemory(base, length) || base == 0) {
Kt::KernelLogStream(Kt::WARNING, "Drivers") << "xHCI " << info.Path
<< ": no register block in _CRS";
return;
}
uint32_t gsi = 0;
bool level = true, activeLow = false;
if (auto* irq = resources.FindFirst(Hal::AML::ResourceType::ExtendedIrq)) {
gsi = irq->ExtendedIrq.Interrupt;
level = (irq->ExtendedIrq.Flags & 1) == 0;
activeLow = (irq->ExtendedIrq.Flags & 2) != 0;
}
bool coherent = false;
Hal::AML::Object cca;
if (Hal::AML::GetInterpreter().EvaluateChild(info.NodeIndex, "_CCA", nullptr, 0, cca) &&
cca.Type == Hal::AML::ObjectType::Integer) {
coherent = cca.Integer != 0;
}
Kt::KernelLogStream(Kt::INFO, "Drivers") << "xHCI platform device " << info.Path
<< " at 0x" << base::hex << base << ", GSI " << base::dec << (uint64_t)gsi
<< (coherent ? ", coherent DMA" : ", non-coherent DMA");
WarnIfRamBeyondDma(info.Path);
USB::Xhci::ProbePlatform(base, length, gsi, level, activeLow, coherent);
}
// SD host controllers ACPI describes directly: the Raspberry Pi 4's
// EMMC2 (BRCME88C, the SD card slot) or a standard PNP0D40.
static void ProbePlatformSdhci() {
if (Storage::Sdhci::IsInitialized()) return;
Hal::AcpiDevices::DeviceInfo info{};
if (!Hal::AcpiDevices::FindDeviceByHid("BRCME88C", info) &&
!Hal::AcpiDevices::FindDeviceByHid("PNP0D40", info)) {
return;
}
Hal::AML::ResourceList resources;
uint64_t base = 0, length = 0;
if (!Hal::AcpiDevices::EvaluateCrs(info.NodeIndex, resources) ||
!resources.GetMemory(base, length) || base == 0) {
return;
}
Storage::Sdhci::ProbePlatform(base, info.Path);
}
void ProbeNormal() {
Pci::ProbeAll(g_driverTable, g_driverTableCount, Pci::ProbePhase::Normal);
ProbePlatformXhci();
ProbePlatformSdhci();
}
void InitializeNetwork() {