[metal] Reprogram PIT 0 (system timer) before enabling IRQ 0

This commit is contained in:
tkchia 2023-09-21 21:17:44 +00:00
parent d0f247f182
commit 915fda840d
5 changed files with 59 additions and 9 deletions

View file

@ -493,14 +493,22 @@ textstartup void _AcpiFadtInit(void) {
return; return;
} }
length = fadt->Header.Length; 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, Dsdt) == 40);
_Static_assert(offsetof(AcpiTableFadt, BootFlags) == 109); _Static_assert(offsetof(AcpiTableFadt, BootFlags) == 109);
_Static_assert(offsetof(AcpiTableFadt, XDsdt) == 140); _Static_assert(offsetof(AcpiTableFadt, XDsdt) == 140);
if (length >= offsetof(AcpiTableFadt, BootFlags) + sizeof(fadt->BootFlags)) if (length >= offsetof(AcpiTableFadt, BootFlags) + sizeof(fadt->BootFlags))
{ {
_AcpiBootFlags = flags = fadt->BootFlags; flags = fadt->BootFlags;
ACPI_INFO("FADT: boot flags %#x", (unsigned)flags); 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) && if (length >= offsetof(AcpiTableFadt, XDsdt) + sizeof(fadt->XDsdt) &&
fadt->XDsdt) { fadt->XDsdt) {

View file

@ -193,13 +193,14 @@ textstartup void _AcpiXsdtInit(void) {
ACPI_INFO("no RSDP found"); ACPI_INFO("no RSDP found");
return; return;
} }
ACPI_INFO("RSDP @ %p", rsdp); ACPI_INFO("RSDP OEM %.6!s @ %p", rsdp->OemId, rsdp);
if (rsdp->Revision <= 1 || if (rsdp->Revision <= 1 ||
rsdp->Length < offsetof(AcpiTableRsdp, Reserved) || rsdp->Length < offsetof(AcpiTableRsdp, Reserved) ||
!rsdp->XsdtPhysicalAddress) { !rsdp->XsdtPhysicalAddress) {
const AcpiTableRsdt *rsdt = _AcpiMapTable(rsdp->RsdtPhysicalAddress); const AcpiTableRsdt *rsdt = _AcpiMapTable(rsdp->RsdtPhysicalAddress);
nents = (rsdt->Header.Length - sizeof(rsdt->Header)) / sizeof(uint32_t); 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 *)); ents = _AcpiOsAllocate(nents * sizeof(AcpiTableHeader *));
if (ents) { if (ents) {
for (i = 0; i < nents; ++i) { for (i = 0; i < nents; ++i) {
@ -209,7 +210,8 @@ textstartup void _AcpiXsdtInit(void) {
} else { } else {
const AcpiTableXsdt *xsdt = _AcpiMapTable(rsdp->XsdtPhysicalAddress); const AcpiTableXsdt *xsdt = _AcpiMapTable(rsdp->XsdtPhysicalAddress);
nents = (xsdt->Header.Length - sizeof(xsdt->Header)) / sizeof(uint64_t); 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 *)); ents = _AcpiOsAllocate(nents * sizeof(AcpiTableHeader *));
if (ents) { if (ents) {
for (i = 0; i < nents; ++i) { for (i = 0; i < nents; ++i) {

View file

@ -348,8 +348,8 @@ _AcpiCompressHid(const uint8_t *__hid, size_t __len) {
__c = __hid[6]; __c = __hid[6];
if (__c < '0' || __c > 'F' || (__c > '9' && __c < 'A')) return 0; if (__c < '0' || __c > 'F' || (__c > '9' && __c < 'A')) return 0;
__d3 = __c <= '9' ? __c - '0' : __c - 'A' + 0xA; __d3 = __c <= '9' ? __c - '0' : __c - 'A' + 0xA;
__evalu = (uint32_t)__a0 << 26 | (uint32_t)__a1 << 21 | (uint32_t)__a2 << 16 | __evalu = (uint32_t)__a0 << 26 | (uint32_t)__a1 << 21 | (uint32_t)__a2 << 16
__d0 << 12 | __d1 << 8 | __d2 << 4 | __d3; | __d0 << 12 | __d1 << 8 | __d2 << 4 | __d3;
return bswap_32(__evalu); return bswap_32(__evalu);
} }
@ -382,6 +382,12 @@ forceinline bool _AcpiDecompressHid(uintmax_t __hid,
return true; 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, ...) \ #define ACPI_INFO(FMT, ...) \
do { \ do { \
if (!IsTiny()) { \ if (!IsTiny()) { \

View file

@ -34,7 +34,24 @@
#ifdef __x86_64__ #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)(); if (_weaken(_ApicDisableAll)) _weaken(_ApicDisableAll)();
ACPI_INFO("starting 8259 IRQs"); ACPI_INFO("starting 8259 IRQs");
outb(PIC1_CMD, PIC_INIT | PIC_IC4); /* ICW1 */ outb(PIC1_CMD, PIC_INIT | PIC_IC4); /* ICW1 */
@ -51,12 +68,14 @@ textstartup void _Irq8259Init(void) {
/* Send EOIs for good measure. */ /* Send EOIs for good measure. */
outb(PIC1_CMD, PIC_EOI); outb(PIC1_CMD, PIC_EOI);
outb(PIC2_CMD, PIC_EOI); outb(PIC2_CMD, PIC_EOI);
/* Reprogram PIT 0. */
enable(); enable();
} }
textstartup void _IrqHwInit(void) { textstartup void _IrqHwInit(void) {
if (!_weaken(_AcpiMadtFlags) || if (!_weaken(_AcpiMadtFlags) ||
(_AcpiMadtFlags & kAcpiMadtPcAtCompat) != 0) { (_AcpiMadtFlags & kAcpiMadtPcAtCompat) != 0) {
_Pit0Init();
_Irq8259Init(); _Irq8259Init();
} else { } else {
/* TODO */ /* TODO */

View file

@ -147,6 +147,21 @@
#define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */ #define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */
#define PIC_READ_ISR 0x0b /* OCW3 irq service 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 /* Long Mode Paging
@see Intel Manual V.3A §4.1 §4.5 @see Intel Manual V.3A §4.1 §4.5
IsValid (ignored on CR3) V IsValid (ignored on CR3) V