10d02842fSSascha Wildner /****************************************************************************** 20d02842fSSascha Wildner * 30d02842fSSascha Wildner * Module Name: hwvalid - I/O request validation 40d02842fSSascha Wildner * 50d02842fSSascha Wildner *****************************************************************************/ 60d02842fSSascha Wildner 70d02842fSSascha Wildner /* 8fe7b5cb4SSascha Wildner * Copyright (C) 2000 - 2015, Intel Corp. 90d02842fSSascha Wildner * All rights reserved. 100d02842fSSascha Wildner * 110d02842fSSascha Wildner * Redistribution and use in source and binary forms, with or without 120d02842fSSascha Wildner * modification, are permitted provided that the following conditions 130d02842fSSascha Wildner * are met: 140d02842fSSascha Wildner * 1. Redistributions of source code must retain the above copyright 150d02842fSSascha Wildner * notice, this list of conditions, and the following disclaimer, 160d02842fSSascha Wildner * without modification. 170d02842fSSascha Wildner * 2. Redistributions in binary form must reproduce at minimum a disclaimer 180d02842fSSascha Wildner * substantially similar to the "NO WARRANTY" disclaimer below 190d02842fSSascha Wildner * ("Disclaimer") and any redistribution must be conditioned upon 200d02842fSSascha Wildner * including a substantially similar Disclaimer requirement for further 210d02842fSSascha Wildner * binary redistribution. 220d02842fSSascha Wildner * 3. Neither the names of the above-listed copyright holders nor the names 230d02842fSSascha Wildner * of any contributors may be used to endorse or promote products derived 240d02842fSSascha Wildner * from this software without specific prior written permission. 250d02842fSSascha Wildner * 260d02842fSSascha Wildner * Alternatively, this software may be distributed under the terms of the 270d02842fSSascha Wildner * GNU General Public License ("GPL") version 2 as published by the Free 280d02842fSSascha Wildner * Software Foundation. 290d02842fSSascha Wildner * 300d02842fSSascha Wildner * NO WARRANTY 310d02842fSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 320d02842fSSascha Wildner * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 330d02842fSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 340d02842fSSascha Wildner * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 350d02842fSSascha Wildner * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 360d02842fSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 370d02842fSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 380d02842fSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 390d02842fSSascha Wildner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 400d02842fSSascha Wildner * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 410d02842fSSascha Wildner * POSSIBILITY OF SUCH DAMAGES. 420d02842fSSascha Wildner */ 430d02842fSSascha Wildner 440d02842fSSascha Wildner #include "acpi.h" 450d02842fSSascha Wildner #include "accommon.h" 460d02842fSSascha Wildner 470d02842fSSascha Wildner #define _COMPONENT ACPI_HARDWARE 480d02842fSSascha Wildner ACPI_MODULE_NAME ("hwvalid") 490d02842fSSascha Wildner 500d02842fSSascha Wildner /* Local prototypes */ 510d02842fSSascha Wildner 520d02842fSSascha Wildner static ACPI_STATUS 530d02842fSSascha Wildner AcpiHwValidateIoRequest ( 540d02842fSSascha Wildner ACPI_IO_ADDRESS Address, 550d02842fSSascha Wildner UINT32 BitWidth); 560d02842fSSascha Wildner 570d02842fSSascha Wildner 580d02842fSSascha Wildner /* 590d02842fSSascha Wildner * Protected I/O ports. Some ports are always illegal, and some are 600d02842fSSascha Wildner * conditionally illegal. This table must remain ordered by port address. 610d02842fSSascha Wildner * 620d02842fSSascha Wildner * The table is used to implement the Microsoft port access rules that 630d02842fSSascha Wildner * first appeared in Windows XP. Some ports are always illegal, and some 640d02842fSSascha Wildner * ports are only illegal if the BIOS calls _OSI with a WinXP string or 650d02842fSSascha Wildner * later (meaning that the BIOS itelf is post-XP.) 660d02842fSSascha Wildner * 670d02842fSSascha Wildner * This provides ACPICA with the desired port protections and 680d02842fSSascha Wildner * Microsoft compatibility. 690d02842fSSascha Wildner * 700d02842fSSascha Wildner * Description of port entries: 710d02842fSSascha Wildner * DMA: DMA controller 720d02842fSSascha Wildner * PIC0: Programmable Interrupt Controller (8259A) 730d02842fSSascha Wildner * PIT1: System Timer 1 740d02842fSSascha Wildner * PIT2: System Timer 2 failsafe 750d02842fSSascha Wildner * RTC: Real-time clock 760d02842fSSascha Wildner * CMOS: Extended CMOS 770d02842fSSascha Wildner * DMA1: DMA 1 page registers 780d02842fSSascha Wildner * DMA1L: DMA 1 Ch 0 low page 790d02842fSSascha Wildner * DMA2: DMA 2 page registers 800d02842fSSascha Wildner * DMA2L: DMA 2 low page refresh 810d02842fSSascha Wildner * ARBC: Arbitration control 820d02842fSSascha Wildner * SETUP: Reserved system board setup 830d02842fSSascha Wildner * POS: POS channel select 840d02842fSSascha Wildner * PIC1: Cascaded PIC 850d02842fSSascha Wildner * IDMA: ISA DMA 860d02842fSSascha Wildner * ELCR: PIC edge/level registers 870d02842fSSascha Wildner * PCI: PCI configuration space 880d02842fSSascha Wildner */ 890d02842fSSascha Wildner static const ACPI_PORT_INFO AcpiProtectedPorts[] = 900d02842fSSascha Wildner { 910d02842fSSascha Wildner {"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, 920d02842fSSascha Wildner {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, 930d02842fSSascha Wildner {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, 940d02842fSSascha Wildner {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, 950d02842fSSascha Wildner {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, 960d02842fSSascha Wildner {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, 970d02842fSSascha Wildner {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, 980d02842fSSascha Wildner {"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, 990d02842fSSascha Wildner {"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP}, 1000d02842fSSascha Wildner {"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, 1010d02842fSSascha Wildner {"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, 1020d02842fSSascha Wildner {"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, 1030d02842fSSascha Wildner {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, 1040d02842fSSascha Wildner {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, 1050d02842fSSascha Wildner {"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, 1060d02842fSSascha Wildner {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, 1070d02842fSSascha Wildner {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} 1080d02842fSSascha Wildner }; 1090d02842fSSascha Wildner 1100d02842fSSascha Wildner #define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (AcpiProtectedPorts) 1110d02842fSSascha Wildner 1120d02842fSSascha Wildner 1130d02842fSSascha Wildner /****************************************************************************** 1140d02842fSSascha Wildner * 1150d02842fSSascha Wildner * FUNCTION: AcpiHwValidateIoRequest 1160d02842fSSascha Wildner * 1170d02842fSSascha Wildner * PARAMETERS: Address Address of I/O port/register 1180d02842fSSascha Wildner * BitWidth Number of bits (8,16,32) 1190d02842fSSascha Wildner * 1200d02842fSSascha Wildner * RETURN: Status 1210d02842fSSascha Wildner * 1220d02842fSSascha Wildner * DESCRIPTION: Validates an I/O request (address/length). Certain ports are 1230d02842fSSascha Wildner * always illegal and some ports are only illegal depending on 1240d02842fSSascha Wildner * the requests the BIOS AML code makes to the predefined 1250d02842fSSascha Wildner * _OSI method. 1260d02842fSSascha Wildner * 1270d02842fSSascha Wildner ******************************************************************************/ 1280d02842fSSascha Wildner 1290d02842fSSascha Wildner static ACPI_STATUS 1300d02842fSSascha Wildner AcpiHwValidateIoRequest ( 1310d02842fSSascha Wildner ACPI_IO_ADDRESS Address, 1320d02842fSSascha Wildner UINT32 BitWidth) 1330d02842fSSascha Wildner { 1340d02842fSSascha Wildner UINT32 i; 1350d02842fSSascha Wildner UINT32 ByteWidth; 1360d02842fSSascha Wildner ACPI_IO_ADDRESS LastAddress; 1370d02842fSSascha Wildner const ACPI_PORT_INFO *PortInfo; 1380d02842fSSascha Wildner 1390d02842fSSascha Wildner 1400d02842fSSascha Wildner ACPI_FUNCTION_TRACE (HwValidateIoRequest); 1410d02842fSSascha Wildner 1420d02842fSSascha Wildner 1430d02842fSSascha Wildner /* Supported widths are 8/16/32 */ 1440d02842fSSascha Wildner 1450d02842fSSascha Wildner if ((BitWidth != 8) && 1460d02842fSSascha Wildner (BitWidth != 16) && 1470d02842fSSascha Wildner (BitWidth != 32)) 1480d02842fSSascha Wildner { 1490d02842fSSascha Wildner ACPI_ERROR ((AE_INFO, 1500d02842fSSascha Wildner "Bad BitWidth parameter: %8.8X", BitWidth)); 1510d02842fSSascha Wildner return (AE_BAD_PARAMETER); 1520d02842fSSascha Wildner } 1530d02842fSSascha Wildner 1540d02842fSSascha Wildner PortInfo = AcpiProtectedPorts; 1550d02842fSSascha Wildner ByteWidth = ACPI_DIV_8 (BitWidth); 1560d02842fSSascha Wildner LastAddress = Address + ByteWidth - 1; 1570d02842fSSascha Wildner 158*5943f66cSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Address %8.8X%8.8X LastAddress %8.8X%8.8X Length %X", 159*5943f66cSSascha Wildner ACPI_FORMAT_UINT64 (Address), ACPI_FORMAT_UINT64 (LastAddress), 1600d02842fSSascha Wildner ByteWidth)); 1610d02842fSSascha Wildner 1620d02842fSSascha Wildner /* Maximum 16-bit address in I/O space */ 1630d02842fSSascha Wildner 1640d02842fSSascha Wildner if (LastAddress > ACPI_UINT16_MAX) 1650d02842fSSascha Wildner { 1660d02842fSSascha Wildner ACPI_ERROR ((AE_INFO, 167*5943f66cSSascha Wildner "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", 168*5943f66cSSascha Wildner ACPI_FORMAT_UINT64 (Address), ByteWidth)); 1690d02842fSSascha Wildner return_ACPI_STATUS (AE_LIMIT); 1700d02842fSSascha Wildner } 1710d02842fSSascha Wildner 1720d02842fSSascha Wildner /* Exit if requested address is not within the protected port table */ 1730d02842fSSascha Wildner 1740d02842fSSascha Wildner if (Address > AcpiProtectedPorts[ACPI_PORT_INFO_ENTRIES - 1].End) 1750d02842fSSascha Wildner { 1760d02842fSSascha Wildner return_ACPI_STATUS (AE_OK); 1770d02842fSSascha Wildner } 1780d02842fSSascha Wildner 1790d02842fSSascha Wildner /* Check request against the list of protected I/O ports */ 1800d02842fSSascha Wildner 1810d02842fSSascha Wildner for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, PortInfo++) 1820d02842fSSascha Wildner { 1830d02842fSSascha Wildner /* 1840d02842fSSascha Wildner * Check if the requested address range will write to a reserved 1850d02842fSSascha Wildner * port. Four cases to consider: 1860d02842fSSascha Wildner * 1870d02842fSSascha Wildner * 1) Address range is contained completely in the port address range 1880d02842fSSascha Wildner * 2) Address range overlaps port range at the port range start 1890d02842fSSascha Wildner * 3) Address range overlaps port range at the port range end 1900d02842fSSascha Wildner * 4) Address range completely encompasses the port range 1910d02842fSSascha Wildner */ 1920d02842fSSascha Wildner if ((Address <= PortInfo->End) && (LastAddress >= PortInfo->Start)) 1930d02842fSSascha Wildner { 1940d02842fSSascha Wildner /* Port illegality may depend on the _OSI calls made by the BIOS */ 1950d02842fSSascha Wildner 1960d02842fSSascha Wildner if (AcpiGbl_OsiData >= PortInfo->OsiDependency) 1970d02842fSSascha Wildner { 1980d02842fSSascha Wildner ACPI_DEBUG_PRINT ((ACPI_DB_IO, 199*5943f66cSSascha Wildner "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)", 200*5943f66cSSascha Wildner ACPI_FORMAT_UINT64 (Address), ByteWidth, PortInfo->Name, 2010d02842fSSascha Wildner PortInfo->Start, PortInfo->End)); 2020d02842fSSascha Wildner 2030d02842fSSascha Wildner return_ACPI_STATUS (AE_AML_ILLEGAL_ADDRESS); 2040d02842fSSascha Wildner } 2050d02842fSSascha Wildner } 2060d02842fSSascha Wildner 2070d02842fSSascha Wildner /* Finished if address range ends before the end of this port */ 2080d02842fSSascha Wildner 2090d02842fSSascha Wildner if (LastAddress <= PortInfo->End) 2100d02842fSSascha Wildner { 2110d02842fSSascha Wildner break; 2120d02842fSSascha Wildner } 2130d02842fSSascha Wildner } 2140d02842fSSascha Wildner 2150d02842fSSascha Wildner return_ACPI_STATUS (AE_OK); 2160d02842fSSascha Wildner } 2170d02842fSSascha Wildner 2180d02842fSSascha Wildner 2190d02842fSSascha Wildner /****************************************************************************** 2200d02842fSSascha Wildner * 2210d02842fSSascha Wildner * FUNCTION: AcpiHwReadPort 2220d02842fSSascha Wildner * 2230d02842fSSascha Wildner * PARAMETERS: Address Address of I/O port/register to read 2240d02842fSSascha Wildner * Value Where value is placed 2250d02842fSSascha Wildner * Width Number of bits 2260d02842fSSascha Wildner * 2270d02842fSSascha Wildner * RETURN: Status and value read from port 2280d02842fSSascha Wildner * 2290d02842fSSascha Wildner * DESCRIPTION: Read data from an I/O port or register. This is a front-end 2300d02842fSSascha Wildner * to AcpiOsReadPort that performs validation on both the port 2310d02842fSSascha Wildner * address and the length. 2320d02842fSSascha Wildner * 2330d02842fSSascha Wildner *****************************************************************************/ 2340d02842fSSascha Wildner 2350d02842fSSascha Wildner ACPI_STATUS 2360d02842fSSascha Wildner AcpiHwReadPort ( 2370d02842fSSascha Wildner ACPI_IO_ADDRESS Address, 2380d02842fSSascha Wildner UINT32 *Value, 2390d02842fSSascha Wildner UINT32 Width) 2400d02842fSSascha Wildner { 2410d02842fSSascha Wildner ACPI_STATUS Status; 2420d02842fSSascha Wildner UINT32 OneByte; 2430d02842fSSascha Wildner UINT32 i; 2440d02842fSSascha Wildner 2450d02842fSSascha Wildner 2460d02842fSSascha Wildner /* Truncate address to 16 bits if requested */ 2470d02842fSSascha Wildner 2480d02842fSSascha Wildner if (AcpiGbl_TruncateIoAddresses) 2490d02842fSSascha Wildner { 2500d02842fSSascha Wildner Address &= ACPI_UINT16_MAX; 2510d02842fSSascha Wildner } 2520d02842fSSascha Wildner 2530d02842fSSascha Wildner /* Validate the entire request and perform the I/O */ 2540d02842fSSascha Wildner 2550d02842fSSascha Wildner Status = AcpiHwValidateIoRequest (Address, Width); 2560d02842fSSascha Wildner if (ACPI_SUCCESS (Status)) 2570d02842fSSascha Wildner { 2580d02842fSSascha Wildner Status = AcpiOsReadPort (Address, Value, Width); 2590d02842fSSascha Wildner return (Status); 2600d02842fSSascha Wildner } 2610d02842fSSascha Wildner 2620d02842fSSascha Wildner if (Status != AE_AML_ILLEGAL_ADDRESS) 2630d02842fSSascha Wildner { 2640d02842fSSascha Wildner return (Status); 2650d02842fSSascha Wildner } 2660d02842fSSascha Wildner 2670d02842fSSascha Wildner /* 2680d02842fSSascha Wildner * There has been a protection violation within the request. Fall 2690d02842fSSascha Wildner * back to byte granularity port I/O and ignore the failing bytes. 2700d02842fSSascha Wildner * This provides Windows compatibility. 2710d02842fSSascha Wildner */ 2720d02842fSSascha Wildner for (i = 0, *Value = 0; i < Width; i += 8) 2730d02842fSSascha Wildner { 2740d02842fSSascha Wildner /* Validate and read one byte */ 2750d02842fSSascha Wildner 2760d02842fSSascha Wildner if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) 2770d02842fSSascha Wildner { 2780d02842fSSascha Wildner Status = AcpiOsReadPort (Address, &OneByte, 8); 2790d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 2800d02842fSSascha Wildner { 2810d02842fSSascha Wildner return (Status); 2820d02842fSSascha Wildner } 2830d02842fSSascha Wildner 2840d02842fSSascha Wildner *Value |= (OneByte << i); 2850d02842fSSascha Wildner } 2860d02842fSSascha Wildner 2870d02842fSSascha Wildner Address++; 2880d02842fSSascha Wildner } 2890d02842fSSascha Wildner 2900d02842fSSascha Wildner return (AE_OK); 2910d02842fSSascha Wildner } 2920d02842fSSascha Wildner 2930d02842fSSascha Wildner 2940d02842fSSascha Wildner /****************************************************************************** 2950d02842fSSascha Wildner * 2960d02842fSSascha Wildner * FUNCTION: AcpiHwWritePort 2970d02842fSSascha Wildner * 2980d02842fSSascha Wildner * PARAMETERS: Address Address of I/O port/register to write 2990d02842fSSascha Wildner * Value Value to write 3000d02842fSSascha Wildner * Width Number of bits 3010d02842fSSascha Wildner * 3020d02842fSSascha Wildner * RETURN: Status 3030d02842fSSascha Wildner * 3040d02842fSSascha Wildner * DESCRIPTION: Write data to an I/O port or register. This is a front-end 3050d02842fSSascha Wildner * to AcpiOsWritePort that performs validation on both the port 3060d02842fSSascha Wildner * address and the length. 3070d02842fSSascha Wildner * 3080d02842fSSascha Wildner *****************************************************************************/ 3090d02842fSSascha Wildner 3100d02842fSSascha Wildner ACPI_STATUS 3110d02842fSSascha Wildner AcpiHwWritePort ( 3120d02842fSSascha Wildner ACPI_IO_ADDRESS Address, 3130d02842fSSascha Wildner UINT32 Value, 3140d02842fSSascha Wildner UINT32 Width) 3150d02842fSSascha Wildner { 3160d02842fSSascha Wildner ACPI_STATUS Status; 3170d02842fSSascha Wildner UINT32 i; 3180d02842fSSascha Wildner 3190d02842fSSascha Wildner 3200d02842fSSascha Wildner /* Truncate address to 16 bits if requested */ 3210d02842fSSascha Wildner 3220d02842fSSascha Wildner if (AcpiGbl_TruncateIoAddresses) 3230d02842fSSascha Wildner { 3240d02842fSSascha Wildner Address &= ACPI_UINT16_MAX; 3250d02842fSSascha Wildner } 3260d02842fSSascha Wildner 3270d02842fSSascha Wildner /* Validate the entire request and perform the I/O */ 3280d02842fSSascha Wildner 3290d02842fSSascha Wildner Status = AcpiHwValidateIoRequest (Address, Width); 3300d02842fSSascha Wildner if (ACPI_SUCCESS (Status)) 3310d02842fSSascha Wildner { 3320d02842fSSascha Wildner Status = AcpiOsWritePort (Address, Value, Width); 3330d02842fSSascha Wildner return (Status); 3340d02842fSSascha Wildner } 3350d02842fSSascha Wildner 3360d02842fSSascha Wildner if (Status != AE_AML_ILLEGAL_ADDRESS) 3370d02842fSSascha Wildner { 3380d02842fSSascha Wildner return (Status); 3390d02842fSSascha Wildner } 3400d02842fSSascha Wildner 3410d02842fSSascha Wildner /* 3420d02842fSSascha Wildner * There has been a protection violation within the request. Fall 3430d02842fSSascha Wildner * back to byte granularity port I/O and ignore the failing bytes. 3440d02842fSSascha Wildner * This provides Windows compatibility. 3450d02842fSSascha Wildner */ 3460d02842fSSascha Wildner for (i = 0; i < Width; i += 8) 3470d02842fSSascha Wildner { 3480d02842fSSascha Wildner /* Validate and write one byte */ 3490d02842fSSascha Wildner 3500d02842fSSascha Wildner if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) 3510d02842fSSascha Wildner { 3520d02842fSSascha Wildner Status = AcpiOsWritePort (Address, (Value >> i) & 0xFF, 8); 3530d02842fSSascha Wildner if (ACPI_FAILURE (Status)) 3540d02842fSSascha Wildner { 3550d02842fSSascha Wildner return (Status); 3560d02842fSSascha Wildner } 3570d02842fSSascha Wildner } 3580d02842fSSascha Wildner 3590d02842fSSascha Wildner Address++; 3600d02842fSSascha Wildner } 3610d02842fSSascha Wildner 3620d02842fSSascha Wildner return (AE_OK); 3630d02842fSSascha Wildner } 364