Skip to content

Commit

Permalink
[metal] Reprogram PIT 0 (system timer) before enabling IRQ 0
Browse files Browse the repository at this point in the history
  • Loading branch information
tkchia committed Sep 21, 2023
1 parent cee68a8 commit 5ddbb79
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 9 deletions.
14 changes: 11 additions & 3 deletions libc/irq/acpi-fadt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 5 additions & 3 deletions libc/irq/acpi-xsdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
10 changes: 8 additions & 2 deletions libc/irq/acpi.internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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()) { \
Expand Down
21 changes: 20 additions & 1 deletion libc/irq/irq-8259.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down
15 changes: 15 additions & 0 deletions libc/runtime/pc.internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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┐
Expand Down

0 comments on commit 5ddbb79

Please sign in to comment.