summaryrefslogtreecommitdiff
path: root/sys/dev/acpi
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-02-16 20:11:07 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-02-16 20:11:07 +0000
commit754f4fc24d729ee82c61d1ed0630fe5c288eb2a8 (patch)
tree14463a2e66c8e9a05b4cbcc2c029c012e0c65aed /sys/dev/acpi
parent51e3bbf4609ab0115efc65c0407631c19c44aaf7 (diff)
Be a litte bit more paranoid and validate the APIC table before committing
to APIC mode. tested by many ok marco@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r--sys/dev/acpi/acpimadt.c69
1 files changed, 68 insertions, 1 deletions
diff --git a/sys/dev/acpi/acpimadt.c b/sys/dev/acpi/acpimadt.c
index ca64cdea1d2..e0a8c9fd66b 100644
--- a/sys/dev/acpi/acpimadt.c
+++ b/sys/dev/acpi/acpimadt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpimadt.c,v 1.21 2008/09/15 19:25:36 kettenis Exp $ */
+/* $OpenBSD: acpimadt.c,v 1.22 2009/02/16 20:11:06 kettenis Exp $ */
/*
* Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org>
*
@@ -53,6 +53,7 @@ struct cfdriver acpimadt_cd = {
NULL, "acpimadt", DV_DULL
};
+int acpimadt_validate(struct acpi_madt *);
void acpimadt_cfg_intr(int, u_int32_t *);
int acpimadt_print(void *, const char *);
@@ -78,6 +79,66 @@ acpimadt_match(struct device *parent, void *match, void *aux)
return (1);
}
+int
+acpimadt_validate(struct acpi_madt *madt)
+{
+ caddr_t addr = (caddr_t)(madt + 1);
+
+ while (addr < (caddr_t)madt + madt->hdr.length) {
+ union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
+ u_int8_t length = entry->madt_lapic.length;
+
+ if (length < 2)
+ return (0);
+
+ if (addr + length > (caddr_t)madt + madt->hdr.length)
+ return (0);
+
+ switch (entry->madt_lapic.apic_type) {
+ case ACPI_MADT_LAPIC:
+ if (length != sizeof(entry->madt_lapic))
+ return (0);
+ break;
+ case ACPI_MADT_IOAPIC:
+ if (length != sizeof(entry->madt_ioapic))
+ return (0);
+ break;
+ case ACPI_MADT_OVERRIDE:
+ if (length != sizeof(entry->madt_override))
+ return (0);
+ break;
+ case ACPI_MADT_NMI:
+ if (length != sizeof(entry->madt_nmi))
+ return (0);
+ break;
+ case ACPI_MADT_LAPIC_NMI:
+ if (length != sizeof(entry->madt_lapic_nmi))
+ return (0);
+ break;
+ case ACPI_MADT_LAPIC_OVERRIDE:
+ if (length != sizeof(entry->madt_lapic_override))
+ return (0);
+ break;
+ case ACPI_MADT_IO_SAPIC:
+ if (length != sizeof(entry->madt_io_sapic))
+ return (0);
+ break;
+ case ACPI_MADT_LOCAL_SAPIC:
+ if (length != sizeof(entry->madt_local_sapic))
+ return (0);
+ break;
+ case ACPI_MADT_PLATFORM_INT:
+ if (length != sizeof(entry->madt_platform_int))
+ return (0);
+ break;
+ }
+
+ addr += length;
+ }
+
+ return (1);
+}
+
struct mp_bus acpimadt_busses[256];
struct mp_bus acpimadt_isa_bus;
@@ -131,6 +192,12 @@ acpimadt_attach(struct device *parent, struct device *self, void *aux)
int nlapic_nmis = 0;
int pin;
+ /* Do some sanity checks before committing to run in APIC mode. */
+ if (!acpimadt_validate(madt)) {
+ printf(": invalid, skipping\n");
+ return;
+ }
+
printf(" addr 0x%x", madt->local_apic_address);
if (madt->flags & ACPI_APIC_PCAT_COMPAT)
printf(": PC-AT compat");