Branch data Line data Source code
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 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : :
13 : : #define _COMPONENT ACPI_HARDWARE
14 : : ACPI_MODULE_NAME("hwvalid")
15 : :
16 : : /* Local prototypes */
17 : : static acpi_status
18 : : acpi_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 : : */
51 : : static 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 : :
89 : : static acpi_status
90 : 189 : acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
91 : : {
92 : 189 : u32 i;
93 : 189 : u32 byte_width;
94 : 189 : acpi_io_address last_address;
95 : 189 : const struct acpi_port_info *port_info;
96 : :
97 : 189 : ACPI_FUNCTION_TRACE(hw_validate_io_request);
98 : :
99 : : /* Supported widths are 8/16/32 */
100 : :
101 [ + + - + ]: 189 : if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) {
102 : 0 : ACPI_ERROR((AE_INFO,
103 : : "Bad BitWidth parameter: %8.8X", bit_width));
104 : 0 : return_ACPI_STATUS(AE_BAD_PARAMETER);
105 : : }
106 : :
107 : 189 : port_info = acpi_protected_ports;
108 : 189 : byte_width = ACPI_DIV_8(bit_width);
109 : 189 : 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 : 189 : ACPI_FORMAT_UINT64(last_address), byte_width));
115 : :
116 : : /* Maximum 16-bit address in I/O space */
117 : :
118 [ - + ]: 189 : if (last_address > ACPI_UINT16_MAX) {
119 : 0 : 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 : 0 : return_ACPI_STATUS(AE_LIMIT);
123 : : }
124 : :
125 : : /* Exit if requested address is not within the protected port table */
126 : :
127 [ + + ]: 189 : 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 [ + - ]: 1524 : 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 [ + + ]: 1524 : if ((address <= port_info->end)
144 [ - + ]: 90 : && (last_address >= port_info->start)) {
145 : :
146 : : /* Port illegality may depend on the _OSI calls made by the BIOS */
147 : :
148 [ # # ]: 0 : 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 [ + + ]: 1524 : 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 : :
186 : 114 : acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
187 : : {
188 : 114 : acpi_status status;
189 : 114 : u32 one_byte;
190 : 114 : u32 i;
191 : :
192 : : /* Truncate address to 16 bits if requested */
193 : :
194 [ - + ]: 114 : if (acpi_gbl_truncate_io_addresses) {
195 : 0 : address &= ACPI_UINT16_MAX;
196 : : }
197 : :
198 : : /* Validate the entire request and perform the I/O */
199 : :
200 : 114 : status = acpi_hw_validate_io_request(address, width);
201 [ + - ]: 114 : if (ACPI_SUCCESS(status)) {
202 : 114 : status = acpi_os_read_port(address, value, width);
203 : 114 : return (status);
204 : : }
205 : :
206 [ # # ]: 0 : 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 [ # # ]: 0 : for (i = 0, *value = 0; i < width; i += 8) {
216 : :
217 : : /* Validate and read one byte */
218 : :
219 [ # # ]: 0 : if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
220 : 0 : status = acpi_os_read_port(address, &one_byte, 8);
221 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
222 : 0 : return (status);
223 : : }
224 : :
225 : 0 : *value |= (one_byte << i);
226 : : }
227 : :
228 : 0 : 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 : :
250 : 75 : acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
251 : : {
252 : 75 : acpi_status status;
253 : 75 : u32 i;
254 : :
255 : : /* Truncate address to 16 bits if requested */
256 : :
257 [ - + ]: 75 : if (acpi_gbl_truncate_io_addresses) {
258 : 0 : address &= ACPI_UINT16_MAX;
259 : : }
260 : :
261 : : /* Validate the entire request and perform the I/O */
262 : :
263 : 75 : status = acpi_hw_validate_io_request(address, width);
264 [ + - ]: 75 : if (ACPI_SUCCESS(status)) {
265 : 75 : status = acpi_os_write_port(address, value, width);
266 : 75 : return (status);
267 : : }
268 : :
269 [ # # ]: 0 : 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 [ # # ]: 0 : for (i = 0; i < width; i += 8) {
279 : :
280 : : /* Validate and write one byte */
281 : :
282 [ # # ]: 0 : if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
283 : 0 : status =
284 : 0 : acpi_os_write_port(address, (value >> i) & 0xFF, 8);
285 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
286 : 0 : return (status);
287 : : }
288 : : }
289 : :
290 : 0 : address++;
291 : : }
292 : :
293 : : return (AE_OK);
294 : : }
|