summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/Osd
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2006-03-29 06:41:56 +0000
committernjl <njl@FreeBSD.org>2006-03-29 06:41:56 +0000
commit563f3ee2e41f5b4af287023ec2a02d3c231e5b2b (patch)
tree52acfb1cd3804dfbf7fa826dc74e1ea8f89f6c47 /sys/dev/acpica/Osd
parentdbd623cfc1d31ef5647dbb7b3ea8267b93b51448 (diff)
downloadFreeBSD-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.
Diffstat (limited to 'sys/dev/acpica/Osd')
-rw-r--r--sys/dev/acpica/Osd/OsdHardware.c76
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);
OpenPOWER on IntegriCloud