Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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