1 /****************************************************************************** 2 * 3 * Module Name: hwvalid - I/O request validation 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #define __HWVALID_C__ 45 46 #include "acpi.h" 47 #include "accommon.h" 48 49 #define _COMPONENT ACPI_HARDWARE 50 ACPI_MODULE_NAME ("hwvalid") 51 52 /* Local prototypes */ 53 54 static ACPI_STATUS 55 AcpiHwValidateIoRequest ( 56 ACPI_IO_ADDRESS Address, 57 UINT32 BitWidth); 58 59 60 /* 61 * Protected I/O ports. Some ports are always illegal, and some are 62 * conditionally illegal. This table must remain ordered by port address. 63 * 64 * The table is used to implement the Microsoft port access rules that 65 * first appeared in Windows XP. Some ports are always illegal, and some 66 * ports are only illegal if the BIOS calls _OSI with a WinXP string or 67 * later (meaning that the BIOS itelf is post-XP.) 68 * 69 * This provides ACPICA with the desired port protections and 70 * Microsoft compatibility. 71 * 72 * Description of port entries: 73 * DMA: DMA controller 74 * PIC0: Programmable Interrupt Controller (8259A) 75 * PIT1: System Timer 1 76 * PIT2: System Timer 2 failsafe 77 * RTC: Real-time clock 78 * CMOS: Extended CMOS 79 * DMA1: DMA 1 page registers 80 * DMA1L: DMA 1 Ch 0 low page 81 * DMA2: DMA 2 page registers 82 * DMA2L: DMA 2 low page refresh 83 * ARBC: Arbitration control 84 * SETUP: Reserved system board setup 85 * POS: POS channel select 86 * PIC1: Cascaded PIC 87 * IDMA: ISA DMA 88 * ELCR: PIC edge/level registers 89 * PCI: PCI configuration space 90 */ 91 static const ACPI_PORT_INFO AcpiProtectedPorts[] = 92 { 93 {"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, 94 {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, 95 {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, 96 {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, 97 {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, 98 {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, 99 {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, 100 {"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, 101 {"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP}, 102 {"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, 103 {"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, 104 {"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, 105 {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, 106 {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, 107 {"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, 108 {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, 109 {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} 110 }; 111 112 #define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (AcpiProtectedPorts) 113 114 115 /****************************************************************************** 116 * 117 * FUNCTION: AcpiHwValidateIoRequest 118 * 119 * PARAMETERS: Address Address of I/O port/register 120 * BitWidth Number of bits (8,16,32) 121 * 122 * RETURN: Status 123 * 124 * DESCRIPTION: Validates an I/O request (address/length). Certain ports are 125 * always illegal and some ports are only illegal depending on 126 * the requests the BIOS AML code makes to the predefined 127 * _OSI method. 128 * 129 ******************************************************************************/ 130 131 static ACPI_STATUS 132 AcpiHwValidateIoRequest ( 133 ACPI_IO_ADDRESS Address, 134 UINT32 BitWidth) 135 { 136 UINT32 i; 137 UINT32 ByteWidth; 138 ACPI_IO_ADDRESS LastAddress; 139 const ACPI_PORT_INFO *PortInfo; 140 141 142 ACPI_FUNCTION_TRACE (HwValidateIoRequest); 143 144 145 /* Supported widths are 8/16/32 */ 146 147 if ((BitWidth != 8) && 148 (BitWidth != 16) && 149 (BitWidth != 32)) 150 { 151 ACPI_ERROR ((AE_INFO, 152 "Bad BitWidth parameter: %8.8X", BitWidth)); 153 return (AE_BAD_PARAMETER); 154 } 155 156 PortInfo = AcpiProtectedPorts; 157 ByteWidth = ACPI_DIV_8 (BitWidth); 158 LastAddress = Address + ByteWidth - 1; 159 160 ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Address %p LastAddress %p Length %X", 161 ACPI_CAST_PTR (void, Address), ACPI_CAST_PTR (void, LastAddress), 162 ByteWidth)); 163 164 /* Maximum 16-bit address in I/O space */ 165 166 if (LastAddress > ACPI_UINT16_MAX) 167 { 168 ACPI_ERROR ((AE_INFO, 169 "Illegal I/O port address/length above 64K: %p/0x%X", 170 ACPI_CAST_PTR (void, Address), ByteWidth)); 171 return_ACPI_STATUS (AE_LIMIT); 172 } 173 174 /* Exit if requested address is not within the protected port table */ 175 176 if (Address > AcpiProtectedPorts[ACPI_PORT_INFO_ENTRIES - 1].End) 177 { 178 return_ACPI_STATUS (AE_OK); 179 } 180 181 /* Check request against the list of protected I/O ports */ 182 183 for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, PortInfo++) 184 { 185 /* 186 * Check if the requested address range will write to a reserved 187 * port. Four cases to consider: 188 * 189 * 1) Address range is contained completely in the port address range 190 * 2) Address range overlaps port range at the port range start 191 * 3) Address range overlaps port range at the port range end 192 * 4) Address range completely encompasses the port range 193 */ 194 if ((Address <= PortInfo->End) && (LastAddress >= PortInfo->Start)) 195 { 196 /* Port illegality may depend on the _OSI calls made by the BIOS */ 197 198 if (AcpiGbl_OsiData >= PortInfo->OsiDependency) 199 { 200 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 201 "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", 202 ACPI_CAST_PTR (void, Address), ByteWidth, PortInfo->Name, 203 PortInfo->Start, PortInfo->End)); 204 205 return_ACPI_STATUS (AE_AML_ILLEGAL_ADDRESS); 206 } 207 } 208 209 /* Finished if address range ends before the end of this port */ 210 211 if (LastAddress <= PortInfo->End) 212 { 213 break; 214 } 215 } 216 217 return_ACPI_STATUS (AE_OK); 218 } 219 220 221 /****************************************************************************** 222 * 223 * FUNCTION: AcpiHwReadPort 224 * 225 * PARAMETERS: Address Address of I/O port/register to read 226 * Value Where value is placed 227 * Width Number of bits 228 * 229 * RETURN: Status and value read from port 230 * 231 * DESCRIPTION: Read data from an I/O port or register. This is a front-end 232 * to AcpiOsReadPort that performs validation on both the port 233 * address and the length. 234 * 235 *****************************************************************************/ 236 237 ACPI_STATUS 238 AcpiHwReadPort ( 239 ACPI_IO_ADDRESS Address, 240 UINT32 *Value, 241 UINT32 Width) 242 { 243 ACPI_STATUS Status; 244 UINT32 OneByte; 245 UINT32 i; 246 247 248 /* Truncate address to 16 bits if requested */ 249 250 if (AcpiGbl_TruncateIoAddresses) 251 { 252 Address &= ACPI_UINT16_MAX; 253 } 254 255 /* Validate the entire request and perform the I/O */ 256 257 Status = AcpiHwValidateIoRequest (Address, Width); 258 if (ACPI_SUCCESS (Status)) 259 { 260 Status = AcpiOsReadPort (Address, Value, Width); 261 return (Status); 262 } 263 264 if (Status != AE_AML_ILLEGAL_ADDRESS) 265 { 266 return (Status); 267 } 268 269 /* 270 * There has been a protection violation within the request. Fall 271 * back to byte granularity port I/O and ignore the failing bytes. 272 * This provides Windows compatibility. 273 */ 274 for (i = 0, *Value = 0; i < Width; i += 8) 275 { 276 /* Validate and read one byte */ 277 278 if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) 279 { 280 Status = AcpiOsReadPort (Address, &OneByte, 8); 281 if (ACPI_FAILURE (Status)) 282 { 283 return (Status); 284 } 285 286 *Value |= (OneByte << i); 287 } 288 289 Address++; 290 } 291 292 return (AE_OK); 293 } 294 295 296 /****************************************************************************** 297 * 298 * FUNCTION: AcpiHwWritePort 299 * 300 * PARAMETERS: Address Address of I/O port/register to write 301 * Value Value to write 302 * Width Number of bits 303 * 304 * RETURN: Status 305 * 306 * DESCRIPTION: Write data to an I/O port or register. This is a front-end 307 * to AcpiOsWritePort that performs validation on both the port 308 * address and the length. 309 * 310 *****************************************************************************/ 311 312 ACPI_STATUS 313 AcpiHwWritePort ( 314 ACPI_IO_ADDRESS Address, 315 UINT32 Value, 316 UINT32 Width) 317 { 318 ACPI_STATUS Status; 319 UINT32 i; 320 321 322 /* Truncate address to 16 bits if requested */ 323 324 if (AcpiGbl_TruncateIoAddresses) 325 { 326 Address &= ACPI_UINT16_MAX; 327 } 328 329 /* Validate the entire request and perform the I/O */ 330 331 Status = AcpiHwValidateIoRequest (Address, Width); 332 if (ACPI_SUCCESS (Status)) 333 { 334 Status = AcpiOsWritePort (Address, Value, Width); 335 return (Status); 336 } 337 338 if (Status != AE_AML_ILLEGAL_ADDRESS) 339 { 340 return (Status); 341 } 342 343 /* 344 * There has been a protection violation within the request. Fall 345 * back to byte granularity port I/O and ignore the failing bytes. 346 * This provides Windows compatibility. 347 */ 348 for (i = 0; i < Width; i += 8) 349 { 350 /* Validate and write one byte */ 351 352 if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) 353 { 354 Status = AcpiOsWritePort (Address, (Value >> i) & 0xFF, 8); 355 if (ACPI_FAILURE (Status)) 356 { 357 return (Status); 358 } 359 } 360 361 Address++; 362 } 363 364 return (AE_OK); 365 }