diff options
author | njl <njl@FreeBSD.org> | 2006-03-29 06:41:56 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2006-03-29 06:41:56 +0000 |
commit | 563f3ee2e41f5b4af287023ec2a02d3c231e5b2b (patch) | |
tree | 52acfb1cd3804dfbf7fa826dc74e1ea8f89f6c47 | |
parent | dbd623cfc1d31ef5647dbb7b3ea8267b93b51448 (diff) | |
download | FreeBSD-src-563f3ee2e41f5b4af287023ec2a02d3c231e5b2b.zip FreeBSD-src-563f3ee2e41f5b4af287023ec2a02d3c231e5b2b.tar.gz |
Add a blacklist for bad IO ports that AML should never touch. It seems
some systems were designed so that AML writes to various resources shared
with OS drivers, including the RTC, PIC, PCI, etc. These writes could
collide with writes by the OS and should never be performed. For now, we
print a message if such an access occurs, but do not block it. To block
the access, the tunable "debug.acpi.block_bad_io" can be set to 1. In the
future, we will flip the switch and this will become the default.
Information about this problem was found in Microsoft KB 283649. They
block IO accesses if the BIOS indicates via _OSI that it is Windows 2001
or higher. They always block accesses to the PIC, cascaded PIC, and ELCRs,
no matter how old the BIOS.
-rw-r--r-- | sys/dev/acpica/Osd/OsdHardware.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/sys/dev/acpica/Osd/OsdHardware.c b/sys/dev/acpica/Osd/OsdHardware.c index 0a1bb1a..4a61270 100644 --- a/sys/dev/acpica/Osd/OsdHardware.c +++ b/sys/dev/acpica/Osd/OsdHardware.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <contrib/dev/acpica/acpi.h> +#include <sys/kernel.h> #include <machine/bus.h> #include <machine/pci_cfgreg.h> #include <dev/pci/pcireg.h> @@ -62,9 +63,74 @@ __FBSDID("$FreeBSD$"); #define ACPI_BUS_HANDLE 0 #endif +/* + * Some BIOS vendors use AML to read/write directly to IO space. This + * can cause a problem if such accesses interfere with the OS's access to + * the same ports. Windows XP and newer systems block accesses to certain + * IO ports. We print a message or block accesses based on a tunable. + */ +static int illegal_bios_ports[] = { + 0x000, 0x00f, /* DMA controller 1 */ + 0x020, 0x021, /* PIC */ + 0x040, 0x043, /* Timer 1 */ + 0x048, 0x04b, /* Timer 2 failsafe */ + 0x070, 0x071, /* CMOS and RTC */ + 0x074, 0x076, /* Extended CMOS */ + 0x081, 0x083, /* DMA1 page registers */ + 0x087, 0x087, /* DMA1 ch0 low page */ + 0x089, 0x08b, /* DMA2 ch2 (0x89), ch3 low page (0x8a, 0x8b) */ + 0x08f, 0x091, /* DMA2 low page refresh (0x8f) */ + /* Arb ctrl port, card select feedback (0x90, 0x91) */ + 0x093, 0x094, /* System board setup */ + 0x096, 0x097, /* POS channel select */ + 0x0a0, 0x0a1, /* PIC (cascaded) */ + 0x0c0, 0x0df, /* ISA DMA */ + 0x4d0, 0x4d1, /* PIC ELCR (edge/level control) */ + 0xcf8, 0xcff, /* PCI config space. Microsoft adds 0xd00 also but + that seems incorrect. */ + -1, -1 +}; + +/* Block accesses to bad IO port addresses or just print a warning. */ +static int block_bad_io; +TUNABLE_INT("debug.acpi.block_bad_io", &block_bad_io); + +/* + * Look up bad ports in our table. Returns 0 if ok, 1 if marked bad but + * access is still allowed, or -1 to deny access. + */ +static int +acpi_os_check_port(UINT32 addr, UINT32 width) +{ + int error, *port; + + error = 0; + for (port = illegal_bios_ports; *port != -1; port += 2) { + if ((addr >= port[0] && addr <= port[1]) || + (addr < port[0] && addr + (width / 8) >= port[0])) { + if (block_bad_io) + error = -1; + else + error = 1; + break; + } + } + + return (error); +} + ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS InPort, UINT32 *Value, UINT32 Width) { + int error; + + error = acpi_os_check_port(InPort, Width); + if (error != 0) { + printf("acpi: bad read from port 0x%03x (%d)\n", InPort, Width); + if (error == -1) + return (AE_BAD_PARAMETER); + } + switch (Width) { case 8: *(u_int8_t *)Value = bus_space_read_1(ACPI_BUS_SPACE_IO, @@ -89,6 +155,16 @@ AcpiOsReadPort(ACPI_IO_ADDRESS InPort, UINT32 *Value, UINT32 Width) ACPI_STATUS AcpiOsWritePort(ACPI_IO_ADDRESS OutPort, UINT32 Value, UINT32 Width) { + int error; + + error = acpi_os_check_port(OutPort, Width); + if (error != 0) { + printf("acpi: bad write to port 0x%03x (%d), val %#x\n", OutPort, + Width, Value); + if (error == -1) + return (AE_BAD_PARAMETER); + } + switch (Width) { case 8: bus_space_write_1(ACPI_BUS_SPACE_IO, ACPI_BUS_HANDLE, OutPort, Value); |