diff options
Diffstat (limited to 'drivers/acpi/acpica/hwvalid.c')
-rw-r--r-- | drivers/acpi/acpica/hwvalid.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c new file mode 100644 index 000000000000..bd3c937b0ac0 --- /dev/null +++ b/drivers/acpi/acpica/hwvalid.c | |||
@@ -0,0 +1,258 @@ | |||
1 | |||
2 | /****************************************************************************** | ||
3 | * | ||
4 | * Module Name: hwvalid - I/O request validation | ||
5 | * | ||
6 | *****************************************************************************/ | ||
7 | |||
8 | /* | ||
9 | * Copyright (C) 2000 - 2009, Intel Corp. | ||
10 | * All rights reserved. | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions | ||
14 | * are met: | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions, and the following disclaimer, | ||
17 | * without modification. | ||
18 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
19 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
20 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
21 | * including a substantially similar Disclaimer requirement for further | ||
22 | * binary redistribution. | ||
23 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
24 | * of any contributors may be used to endorse or promote products derived | ||
25 | * from this software without specific prior written permission. | ||
26 | * | ||
27 | * Alternatively, this software may be distributed under the terms of the | ||
28 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
29 | * Software Foundation. | ||
30 | * | ||
31 | * NO WARRANTY | ||
32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
33 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
35 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
36 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
37 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
38 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
39 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
40 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
41 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
42 | * POSSIBILITY OF SUCH DAMAGES. | ||
43 | */ | ||
44 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include "accommon.h" | ||
47 | |||
48 | #define _COMPONENT ACPI_HARDWARE | ||
49 | ACPI_MODULE_NAME("hwvalid") | ||
50 | |||
51 | /* Local prototypes */ | ||
52 | static acpi_status | ||
53 | acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width); | ||
54 | |||
55 | /* | ||
56 | * Protected I/O ports. Some ports are always illegal, and some are | ||
57 | * conditionally illegal. This table must remain ordered by port address. | ||
58 | * | ||
59 | * The table is used to implement the Microsoft port access rules that | ||
60 | * first appeared in Windows XP. Some ports are always illegal, and some | ||
61 | * ports are only illegal if the BIOS calls _OSI with a win_xP string or | ||
62 | * later (meaning that the BIOS itelf is post-XP.) | ||
63 | * | ||
64 | * This provides ACPICA with the desired port protections and | ||
65 | * Microsoft compatibility. | ||
66 | * | ||
67 | * Description of port entries: | ||
68 | * DMA: DMA controller | ||
69 | * PIC0: Programmable Interrupt Controller (8259_a) | ||
70 | * PIT1: System Timer 1 | ||
71 | * PIT2: System Timer 2 failsafe | ||
72 | * RTC: Real-time clock | ||
73 | * CMOS: Extended CMOS | ||
74 | * DMA1: DMA 1 page registers | ||
75 | * DMA1L: DMA 1 Ch 0 low page | ||
76 | * DMA2: DMA 2 page registers | ||
77 | * DMA2L: DMA 2 low page refresh | ||
78 | * ARBC: Arbitration control | ||
79 | * SETUP: Reserved system board setup | ||
80 | * POS: POS channel select | ||
81 | * PIC1: Cascaded PIC | ||
82 | * IDMA: ISA DMA | ||
83 | * ELCR: PIC edge/level registers | ||
84 | * PCI: PCI configuration space | ||
85 | */ | ||
86 | static const struct acpi_port_info acpi_protected_ports[] = { | ||
87 | {"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, | ||
88 | {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, | ||
89 | {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, | ||
90 | {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, | ||
91 | {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, | ||
92 | {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, | ||
93 | {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, | ||
94 | {"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, | ||
95 | {"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP}, | ||
96 | {"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, | ||
97 | {"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, | ||
98 | {"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, | ||
99 | {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, | ||
100 | {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, | ||
101 | {"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, | ||
102 | {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, | ||
103 | {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} | ||
104 | }; | ||
105 | |||
106 | #define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (acpi_protected_ports) | ||
107 | |||
108 | /****************************************************************************** | ||
109 | * | ||
110 | * FUNCTION: acpi_hw_validate_io_request | ||
111 | * | ||
112 | * PARAMETERS: Address Address of I/O port/register | ||
113 | * bit_width Number of bits (8,16,32) | ||
114 | * | ||
115 | * RETURN: Status | ||
116 | * | ||
117 | * DESCRIPTION: Validates an I/O request (address/length). Certain ports are | ||
118 | * always illegal and some ports are only illegal depending on | ||
119 | * the requests the BIOS AML code makes to the predefined | ||
120 | * _OSI method. | ||
121 | * | ||
122 | ******************************************************************************/ | ||
123 | |||
124 | static acpi_status | ||
125 | acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) | ||
126 | { | ||
127 | u32 i; | ||
128 | u32 byte_width; | ||
129 | acpi_io_address last_address; | ||
130 | const struct acpi_port_info *port_info; | ||
131 | |||
132 | ACPI_FUNCTION_TRACE(hw_validate_io_request); | ||
133 | |||
134 | /* Supported widths are 8/16/32 */ | ||
135 | |||
136 | if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { | ||
137 | return AE_BAD_PARAMETER; | ||
138 | } | ||
139 | |||
140 | port_info = acpi_protected_ports; | ||
141 | byte_width = ACPI_DIV_8(bit_width); | ||
142 | last_address = address + byte_width - 1; | ||
143 | |||
144 | ACPI_DEBUG_PRINT((ACPI_DB_IO, "Address %p LastAddress %p Length %X", | ||
145 | ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, | ||
146 | last_address), | ||
147 | byte_width)); | ||
148 | |||
149 | /* Maximum 16-bit address in I/O space */ | ||
150 | |||
151 | if (last_address > ACPI_UINT16_MAX) { | ||
152 | ACPI_ERROR((AE_INFO, | ||
153 | "Illegal I/O port address/length above 64K: 0x%p/%X", | ||
154 | ACPI_CAST_PTR(void, address), byte_width)); | ||
155 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); | ||
156 | } | ||
157 | |||
158 | /* Exit if requested address is not within the protected port table */ | ||
159 | |||
160 | if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) { | ||
161 | return_ACPI_STATUS(AE_OK); | ||
162 | } | ||
163 | |||
164 | /* Check request against the list of protected I/O ports */ | ||
165 | |||
166 | for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, port_info++) { | ||
167 | /* | ||
168 | * Check if the requested address range will write to a reserved | ||
169 | * port. Four cases to consider: | ||
170 | * | ||
171 | * 1) Address range is contained completely in the port address range | ||
172 | * 2) Address range overlaps port range at the port range start | ||
173 | * 3) Address range overlaps port range at the port range end | ||
174 | * 4) Address range completely encompasses the port range | ||
175 | */ | ||
176 | if ((address <= port_info->end) | ||
177 | && (last_address >= port_info->start)) { | ||
178 | |||
179 | /* Port illegality may depend on the _OSI calls made by the BIOS */ | ||
180 | |||
181 | if (acpi_gbl_osi_data >= port_info->osi_dependency) { | ||
182 | ACPI_ERROR((AE_INFO, | ||
183 | "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", | ||
184 | ACPI_CAST_PTR(void, address), | ||
185 | byte_width, port_info->name, | ||
186 | port_info->start, port_info->end)); | ||
187 | |||
188 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* Finished if address range ends before the end of this port */ | ||
193 | |||
194 | if (last_address <= port_info->end) { | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | return_ACPI_STATUS(AE_OK); | ||
200 | } | ||
201 | |||
202 | /****************************************************************************** | ||
203 | * | ||
204 | * FUNCTION: acpi_hw_read_port | ||
205 | * | ||
206 | * PARAMETERS: Address Address of I/O port/register to read | ||
207 | * Value Where value is placed | ||
208 | * Width Number of bits | ||
209 | * | ||
210 | * RETURN: Value read from port | ||
211 | * | ||
212 | * DESCRIPTION: Read data from an I/O port or register. This is a front-end | ||
213 | * to acpi_os_read_port that performs validation on both the port | ||
214 | * address and the length. | ||
215 | * | ||
216 | *****************************************************************************/ | ||
217 | |||
218 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) | ||
219 | { | ||
220 | acpi_status status; | ||
221 | |||
222 | status = acpi_hw_validate_io_request(address, width); | ||
223 | if (ACPI_FAILURE(status)) { | ||
224 | return status; | ||
225 | } | ||
226 | |||
227 | status = acpi_os_read_port(address, value, width); | ||
228 | return status; | ||
229 | } | ||
230 | |||
231 | /****************************************************************************** | ||
232 | * | ||
233 | * FUNCTION: acpi_hw_write_port | ||
234 | * | ||
235 | * PARAMETERS: Address Address of I/O port/register to write | ||
236 | * Value Value to write | ||
237 | * Width Number of bits | ||
238 | * | ||
239 | * RETURN: None | ||
240 | * | ||
241 | * DESCRIPTION: Write data to an I/O port or register. This is a front-end | ||
242 | * to acpi_os_write_port that performs validation on both the port | ||
243 | * address and the length. | ||
244 | * | ||
245 | *****************************************************************************/ | ||
246 | |||
247 | acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) | ||
248 | { | ||
249 | acpi_status status; | ||
250 | |||
251 | status = acpi_hw_validate_io_request(address, width); | ||
252 | if (ACPI_FAILURE(status)) { | ||
253 | return status; | ||
254 | } | ||
255 | |||
256 | status = acpi_os_write_port(address, value, width); | ||
257 | return status; | ||
258 | } | ||