From 915fda840d08db2f3783abe80d499619499691ad Mon Sep 17 00:00:00 2001 From: tkchia Date: Thu, 21 Sep 2023 21:17:44 +0000 Subject: [PATCH] [metal] Reprogram PIT 0 (system timer) before enabling IRQ 0 --- libc/irq/acpi-fadt.c | 14 +++++++++++--- libc/irq/acpi-xsdt.c | 8 +++++--- libc/irq/acpi.internal.h | 10 ++++++++-- libc/irq/irq-8259.c | 21 ++++++++++++++++++++- libc/runtime/pc.internal.h | 15 +++++++++++++++ 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/libc/irq/acpi-fadt.c b/libc/irq/acpi-fadt.c index 9248994a7..92d5327a1 100644 --- a/libc/irq/acpi-fadt.c +++ b/libc/irq/acpi-fadt.c @@ -493,14 +493,22 @@ textstartup void _AcpiFadtInit(void) { return; } length = fadt->Header.Length; - ACPI_INFO("FADT @ %p,+%#zx", fadt, length); + ACPI_INFO("FADT %.8!s @ %p,+%#zx", fadt->Header.OemTableId, fadt, length); _Static_assert(offsetof(AcpiTableFadt, Dsdt) == 40); _Static_assert(offsetof(AcpiTableFadt, BootFlags) == 109); _Static_assert(offsetof(AcpiTableFadt, XDsdt) == 140); if (length >= offsetof(AcpiTableFadt, BootFlags) + sizeof(fadt->BootFlags)) { - _AcpiBootFlags = flags = fadt->BootFlags; - ACPI_INFO("FADT: boot flags %#x", (unsigned)flags); + flags = fadt->BootFlags; + if (READ64LE(fadt->Header.OemTableId) == READ64LE("BXPC ")) { + /* Work around incomplete AML tables under QEMU. */ + ACPI_WARN("FADT: boot flags %#x -> %#x (QEMU workaround)", + (unsigned)flags, (unsigned)(flags | kAcpiFadtLegacyDevices)); + flags |= kAcpiFadtLegacyDevices; + } else { + ACPI_INFO("FADT: boot flags %#x", (unsigned)flags); + } + _AcpiBootFlags = flags; } if (length >= offsetof(AcpiTableFadt, XDsdt) + sizeof(fadt->XDsdt) && fadt->XDsdt) { diff --git a/libc/irq/acpi-xsdt.c b/libc/irq/acpi-xsdt.c index 835cb66f7..46236f811 100644 --- a/libc/irq/acpi-xsdt.c +++ b/libc/irq/acpi-xsdt.c @@ -193,13 +193,14 @@ textstartup void _AcpiXsdtInit(void) { ACPI_INFO("no RSDP found"); return; } - ACPI_INFO("RSDP @ %p", rsdp); + ACPI_INFO("RSDP OEM %.6!s @ %p", rsdp->OemId, rsdp); if (rsdp->Revision <= 1 || rsdp->Length < offsetof(AcpiTableRsdp, Reserved) || !rsdp->XsdtPhysicalAddress) { const AcpiTableRsdt *rsdt = _AcpiMapTable(rsdp->RsdtPhysicalAddress); nents = (rsdt->Header.Length - sizeof(rsdt->Header)) / sizeof(uint32_t); - ACPI_INFO("RSDT @ %p, %#zx entries", rsdt, nents); + ACPI_INFO("RSDT %.8!s @ %p, %#zx entries", rsdt->Header.OemTableId, rsdt, + nents); ents = _AcpiOsAllocate(nents * sizeof(AcpiTableHeader *)); if (ents) { for (i = 0; i < nents; ++i) { @@ -209,7 +210,8 @@ textstartup void _AcpiXsdtInit(void) { } else { const AcpiTableXsdt *xsdt = _AcpiMapTable(rsdp->XsdtPhysicalAddress); nents = (xsdt->Header.Length - sizeof(xsdt->Header)) / sizeof(uint64_t); - ACPI_INFO("XSDT @ %p, %#zx entries", xsdt, nents); + ACPI_INFO("XSDT %.8!s @ %p, %#zx entries", xsdt->Header.OemTableId, xsdt, + nents); ents = _AcpiOsAllocate(nents * sizeof(AcpiTableHeader *)); if (ents) { for (i = 0; i < nents; ++i) { diff --git a/libc/irq/acpi.internal.h b/libc/irq/acpi.internal.h index 22dd16b67..caf62c144 100644 --- a/libc/irq/acpi.internal.h +++ b/libc/irq/acpi.internal.h @@ -348,8 +348,8 @@ _AcpiCompressHid(const uint8_t *__hid, size_t __len) { __c = __hid[6]; if (__c < '0' || __c > 'F' || (__c > '9' && __c < 'A')) return 0; __d3 = __c <= '9' ? __c - '0' : __c - 'A' + 0xA; - __evalu = (uint32_t)__a0 << 26 | (uint32_t)__a1 << 21 | (uint32_t)__a2 << 16 | - __d0 << 12 | __d1 << 8 | __d2 << 4 | __d3; + __evalu = (uint32_t)__a0 << 26 | (uint32_t)__a1 << 21 | (uint32_t)__a2 << 16 + | __d0 << 12 | __d1 << 8 | __d2 << 4 | __d3; return bswap_32(__evalu); } @@ -382,6 +382,12 @@ forceinline bool _AcpiDecompressHid(uintmax_t __hid, return true; } +forceinline AcpiDeviceHid _AcpiMakePnpHid(uint16_t __pnp_id) { + uint32_t __evalu = (uint32_t)16 << 26 | (uint32_t)14 << 21 | + (uint32_t)16 << 16 | __pnp_id; + return bswap_32(__evalu); +} + #define ACPI_INFO(FMT, ...) \ do { \ if (!IsTiny()) { \ diff --git a/libc/irq/irq-8259.c b/libc/irq/irq-8259.c index 6e0a231a1..a12c96546 100644 --- a/libc/irq/irq-8259.c +++ b/libc/irq/irq-8259.c @@ -34,7 +34,24 @@ #ifdef __x86_64__ -textstartup void _Irq8259Init(void) { +textstartup static const AcpiDefDevice *_AcpiFindDevice(AcpiDeviceHid hid) { + const AcpiDefDevice *dev = _AcpiDefDevices; + while (dev && dev->hid != hid) dev = dev->next; + return dev; +} + +textstartup static void _Pit0Init(void) { + if (!(_AcpiBootFlags & kAcpiFadtLegacyDevices) && + !_AcpiFindDevice(_AcpiMakePnpHid(0x0100))) { + ACPI_FATAL("no 8254 PIT"); + } + ACPI_INFO("resetting 8254 PIT"); + outb(PIT_CMD, PIT_SC0 | PIT_RW | PIT_SQW); + outb(PIT0_DATA, 0x00); + outb(PIT0_DATA, 0x00); +} + +textstartup static void _Irq8259Init(void) { if (_weaken(_ApicDisableAll)) _weaken(_ApicDisableAll)(); ACPI_INFO("starting 8259 IRQs"); outb(PIC1_CMD, PIC_INIT | PIC_IC4); /* ICW1 */ @@ -51,12 +68,14 @@ textstartup void _Irq8259Init(void) { /* Send EOIs for good measure. */ outb(PIC1_CMD, PIC_EOI); outb(PIC2_CMD, PIC_EOI); + /* Reprogram PIT 0. */ enable(); } textstartup void _IrqHwInit(void) { if (!_weaken(_AcpiMadtFlags) || (_AcpiMadtFlags & kAcpiMadtPcAtCompat) != 0) { + _Pit0Init(); _Irq8259Init(); } else { /* TODO */ diff --git a/libc/runtime/pc.internal.h b/libc/runtime/pc.internal.h index 3f77d1240..f666cf022 100644 --- a/libc/runtime/pc.internal.h +++ b/libc/runtime/pc.internal.h @@ -147,6 +147,21 @@ #define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */ #define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */ +/* + * @see Intel Corporation. 82C54 CHMOS Programmable Interval Timer. 1994. + * Intel order number 23124-006. + */ +#define PIT 0x40 /* IO base address for PIT */ +#define PIT0_DATA (PIT + 0) +#define PIT1_DATA (PIT + 1) +#define PIT2_DATA (PIT + 2) +#define PIT_CMD (PIT + 3) +#define PIT_SC0 0x00 /* select counter 0 */ +#define PIT_SC1 0x00 /* select counter 1 */ +#define PIT_SC2 0x00 /* select counter 2 */ +#define PIT_RW 0x30 /* read/write operation */ +#define PIT_SQW 0x06 /* square wave mode */ + /* Long Mode Paging @see Intel Manual V.3A §4.1 §4.5 IsValid (ignored on CR3) V┐