linux/drivers/acpi/acpica/hwvalid.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: hwvalid - I/O request validation
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12
  13#define _COMPONENT          ACPI_HARDWARE
  14ACPI_MODULE_NAME("hwvalid")
  15
  16/* Local prototypes */
  17static acpi_status
  18acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width);
  19
  20/*
  21 * Protected I/O ports. Some ports are always illegal, and some are
  22 * conditionally illegal. This table must remain ordered by port address.
  23 *
  24 * The table is used to implement the Microsoft port access rules that
  25 * first appeared in Windows XP. Some ports are always illegal, and some
  26 * ports are only illegal if the BIOS calls _OSI with a win_XP string or
  27 * later (meaning that the BIOS itelf is post-XP.)
  28 *
  29 * This provides ACPICA with the desired port protections and
  30 * Microsoft compatibility.
  31 *
  32 * Description of port entries:
  33 *  DMA:   DMA controller
  34 *  PIC0:  Programmable Interrupt Controller (8259A)
  35 *  PIT1:  System Timer 1
  36 *  PIT2:  System Timer 2 failsafe
  37 *  RTC:   Real-time clock
  38 *  CMOS:  Extended CMOS
  39 *  DMA1:  DMA 1 page registers
  40 *  DMA1L: DMA 1 Ch 0 low page
  41 *  DMA2:  DMA 2 page registers
  42 *  DMA2L: DMA 2 low page refresh
  43 *  ARBC:  Arbitration control
  44 *  SETUP: Reserved system board setup
  45 *  POS:   POS channel select
  46 *  PIC1:  Cascaded PIC
  47 *  IDMA:  ISA DMA
  48 *  ELCR:  PIC edge/level registers
  49 *  PCI:   PCI configuration space
  50 */
  51static const struct acpi_port_info acpi_protected_ports[] = {
  52        {"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP},
  53        {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL},
  54        {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP},
  55        {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP},
  56        {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP},
  57        {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP},
  58        {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP},
  59        {"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP},
  60        {"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP},
  61        {"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP},
  62        {"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP},
  63        {"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP},
  64        {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP},
  65        {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL},
  66        {"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP},
  67        {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL},
  68        {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP}
  69};
  70
  71#define ACPI_PORT_INFO_ENTRIES      ACPI_ARRAY_LENGTH (acpi_protected_ports)
  72
  73/******************************************************************************
  74 *
  75 * FUNCTION:    acpi_hw_validate_io_request
  76 *
  77 * PARAMETERS:  Address             Address of I/O port/register
  78 *              bit_width           Number of bits (8,16,32)
  79 *
  80 * RETURN:      Status
  81 *
  82 * DESCRIPTION: Validates an I/O request (address/length). Certain ports are
  83 *              always illegal and some ports are only illegal depending on
  84 *              the requests the BIOS AML code makes to the predefined
  85 *              _OSI method.
  86 *
  87 ******************************************************************************/
  88
  89static acpi_status
  90acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
  91{
  92        u32 i;
  93        u32 byte_width;
  94        acpi_io_address last_address;
  95        const struct acpi_port_info *port_info;
  96
  97        ACPI_FUNCTION_TRACE(hw_validate_io_request);
  98
  99        /* Supported widths are 8/16/32 */
 100
 101        if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) {
 102                ACPI_ERROR((AE_INFO,
 103                            "Bad BitWidth parameter: %8.8X", bit_width));
 104                return_ACPI_STATUS(AE_BAD_PARAMETER);
 105        }
 106
 107        port_info = acpi_protected_ports;
 108        byte_width = ACPI_DIV_8(bit_width);
 109        last_address = address + byte_width - 1;
 110
 111        ACPI_DEBUG_PRINT((ACPI_DB_IO,
 112                          "Address %8.8X%8.8X LastAddress %8.8X%8.8X Length %X",
 113                          ACPI_FORMAT_UINT64(address),
 114                          ACPI_FORMAT_UINT64(last_address), byte_width));
 115
 116        /* Maximum 16-bit address in I/O space */
 117
 118        if (last_address > ACPI_UINT16_MAX) {
 119                ACPI_ERROR((AE_INFO,
 120                            "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X",
 121                            ACPI_FORMAT_UINT64(address), byte_width));
 122                return_ACPI_STATUS(AE_LIMIT);
 123        }
 124
 125        /* Exit if requested address is not within the protected port table */
 126
 127        if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) {
 128                return_ACPI_STATUS(AE_OK);
 129        }
 130
 131        /* Check request against the list of protected I/O ports */
 132
 133        for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, port_info++) {
 134                /*
 135                 * Check if the requested address range will write to a reserved
 136                 * port. There are four cases to consider:
 137                 *
 138                 * 1) Address range is contained completely in the port address range
 139                 * 2) Address range overlaps port range at the port range start
 140                 * 3) Address range overlaps port range at the port range end
 141                 * 4) Address range completely encompasses the port range
 142                 */
 143                if ((address <= port_info->end)
 144                    && (last_address >= port_info->start)) {
 145
 146                        /* Port illegality may depend on the _OSI calls made by the BIOS */
 147
 148                        if (acpi_gbl_osi_data >= port_info->osi_dependency) {
 149                                ACPI_DEBUG_PRINT((ACPI_DB_VALUES,
 150                                                  "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)\n",
 151                                                  ACPI_FORMAT_UINT64(address),
 152                                                  byte_width, port_info->name,
 153                                                  port_info->start,
 154                                                  port_info->end));
 155
 156                                return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
 157                        }
 158                }
 159
 160                /* Finished if address range ends before the end of this port */
 161
 162                if (last_address <= port_info->end) {
 163                        break;
 164                }
 165        }
 166
 167        return_ACPI_STATUS(AE_OK);
 168}
 169
 170/******************************************************************************
 171 *
 172 * FUNCTION:    acpi_hw_read_port
 173 *
 174 * PARAMETERS:  Address             Address of I/O port/register to read
 175 *              Value               Where value (data) is returned
 176 *              Width               Number of bits
 177 *
 178 * RETURN:      Status and value read from port
 179 *
 180 * DESCRIPTION: Read data from an I/O port or register. This is a front-end
 181 *              to acpi_os_read_port that performs validation on both the port
 182 *              address and the length.
 183 *
 184 *****************************************************************************/
 185
 186acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
 187{
 188        acpi_status status;
 189        u32 one_byte;
 190        u32 i;
 191
 192        /* Truncate address to 16 bits if requested */
 193
 194        if (acpi_gbl_truncate_io_addresses) {
 195                address &= ACPI_UINT16_MAX;
 196        }
 197
 198        /* Validate the entire request and perform the I/O */
 199
 200        status = acpi_hw_validate_io_request(address, width);
 201        if (ACPI_SUCCESS(status)) {
 202                status = acpi_os_read_port(address, value, width);
 203                return (status);
 204        }
 205
 206        if (status != AE_AML_ILLEGAL_ADDRESS) {
 207                return (status);
 208        }
 209
 210        /*
 211         * There has been a protection violation within the request. Fall
 212         * back to byte granularity port I/O and ignore the failing bytes.
 213         * This provides compatibility with other ACPI implementations.
 214         */
 215        for (i = 0, *value = 0; i < width; i += 8) {
 216
 217                /* Validate and read one byte */
 218
 219                if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
 220                        status = acpi_os_read_port(address, &one_byte, 8);
 221                        if (ACPI_FAILURE(status)) {
 222                                return (status);
 223                        }
 224
 225                        *value |= (one_byte << i);
 226                }
 227
 228                address++;
 229        }
 230
 231        return (AE_OK);
 232}
 233
 234/******************************************************************************
 235 *
 236 * FUNCTION:    acpi_hw_write_port
 237 *
 238 * PARAMETERS:  Address             Address of I/O port/register to write
 239 *              Value               Value to write
 240 *              Width               Number of bits
 241 *
 242 * RETURN:      Status
 243 *
 244 * DESCRIPTION: Write data to an I/O port or register. This is a front-end
 245 *              to acpi_os_write_port that performs validation on both the port
 246 *              address and the length.
 247 *
 248 *****************************************************************************/
 249
 250acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
 251{
 252        acpi_status status;
 253        u32 i;
 254
 255        /* Truncate address to 16 bits if requested */
 256
 257        if (acpi_gbl_truncate_io_addresses) {
 258                address &= ACPI_UINT16_MAX;
 259        }
 260
 261        /* Validate the entire request and perform the I/O */
 262
 263        status = acpi_hw_validate_io_request(address, width);
 264        if (ACPI_SUCCESS(status)) {
 265                status = acpi_os_write_port(address, value, width);
 266                return (status);
 267        }
 268
 269        if (status != AE_AML_ILLEGAL_ADDRESS) {
 270                return (status);
 271        }
 272
 273        /*
 274         * There has been a protection violation within the request. Fall
 275         * back to byte granularity port I/O and ignore the failing bytes.
 276         * This provides compatibility with other ACPI implementations.
 277         */
 278        for (i = 0; i < width; i += 8) {
 279
 280                /* Validate and write one byte */
 281
 282                if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
 283                        status =
 284                            acpi_os_write_port(address, (value >> i) & 0xFF, 8);
 285                        if (ACPI_FAILURE(status)) {
 286                                return (status);
 287                        }
 288                }
 289
 290                address++;
 291        }
 292
 293        return (AE_OK);
 294}
 295
 296/******************************************************************************
 297 *
 298 * FUNCTION:    acpi_hw_validate_io_block
 299 *
 300 * PARAMETERS:  Address             Address of I/O port/register blobk
 301 *              bit_width           Number of bits (8,16,32) in each register
 302 *              count               Number of registers in the block
 303 *
 304 * RETURN:      Status
 305 *
 306 * DESCRIPTION: Validates a block of I/O ports/registers.
 307 *
 308 ******************************************************************************/
 309
 310acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count)
 311{
 312        acpi_status status;
 313
 314        while (count--) {
 315                status = acpi_hw_validate_io_request((acpi_io_address)address,
 316                                                     bit_width);
 317                if (ACPI_FAILURE(status))
 318                        return_ACPI_STATUS(status);
 319
 320                address += ACPI_DIV_8(bit_width);
 321        }
 322
 323        return_ACPI_STATUS(AE_OK);
 324}
 325