diff options
author | Bob Moore <robert.moore@intel.com> | 2009-03-18 21:37:47 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 12:11:03 -0400 |
commit | 7f0719039085cc40114abce84cf29fe57da226f4 (patch) | |
tree | 8e210cd936bfb11fdc122b44d79100660b8ffb6a /drivers/acpi/acpica/hwvalid.c | |
parent | 20869dcfde204e1c21b642608d708d82472fee2b (diff) |
ACPICA: New: I/O port protection
Protect certain I/O ports from reads/writes. Provides MS
compatibility. New module, hwvalid.c
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/hwvalid.c')
-rw-r--r-- | drivers/acpi/acpica/hwvalid.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c new file mode 100644 index 000000000000..e0b562fbe7c1 --- /dev/null +++ b/drivers/acpi/acpica/hwvalid.c | |||
@@ -0,0 +1,240 @@ | |||
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 | static const struct acpi_port_info acpi_protected_ports[] = { | ||
68 | {"DMA1", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, | ||
69 | {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, | ||
70 | {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, | ||
71 | {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, | ||
72 | {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, | ||
73 | {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, | ||
74 | {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, | ||
75 | {"DMA1", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, | ||
76 | {"DMA2", 0x0089, 0x0089, ACPI_OSI_WIN_XP}, | ||
77 | {"DMA2", 0x008A, 0x008B, ACPI_OSI_WIN_XP}, | ||
78 | {"DMA2", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, | ||
79 | {"Arb", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, | ||
80 | {"Setup", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, | ||
81 | {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, | ||
82 | {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, | ||
83 | {"DMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, | ||
84 | {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, | ||
85 | {"PCI", 0x0CF8, 0x0D00, ACPI_OSI_WIN_XP} | ||
86 | }; | ||
87 | |||
88 | #define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (acpi_protected_ports) | ||
89 | |||
90 | /****************************************************************************** | ||
91 | * | ||
92 | * FUNCTION: acpi_hw_validate_io_request | ||
93 | * | ||
94 | * PARAMETERS: Address Address of I/O port/register | ||
95 | * bit_width Number of bits (8,16,32) | ||
96 | * | ||
97 | * RETURN: Status | ||
98 | * | ||
99 | * DESCRIPTION: Validates an I/O request (address/length). Certain ports are | ||
100 | * always illegal and some ports are only illegal depending on | ||
101 | * the requests the BIOS AML code makes to the predefined | ||
102 | * _OSI method. | ||
103 | * | ||
104 | ******************************************************************************/ | ||
105 | |||
106 | static acpi_status | ||
107 | acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) | ||
108 | { | ||
109 | u32 i; | ||
110 | u32 byte_width; | ||
111 | acpi_io_address last_address; | ||
112 | const struct acpi_port_info *port_info; | ||
113 | |||
114 | ACPI_FUNCTION_TRACE(hw_validate_io_request); | ||
115 | |||
116 | /* Supported widths are 8/16/32 */ | ||
117 | |||
118 | if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { | ||
119 | return AE_BAD_PARAMETER; | ||
120 | } | ||
121 | |||
122 | port_info = acpi_protected_ports; | ||
123 | byte_width = ACPI_DIV_8(bit_width); | ||
124 | last_address = address + byte_width - 1; | ||
125 | |||
126 | ACPI_DEBUG_PRINT((ACPI_DB_IO, "Address %p LastAddress %p Length %X", | ||
127 | ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, | ||
128 | last_address), | ||
129 | byte_width)); | ||
130 | |||
131 | /* Maximum 16-bit address in I/O space */ | ||
132 | |||
133 | if (last_address > ACPI_UINT16_MAX) { | ||
134 | ACPI_ERROR((AE_INFO, | ||
135 | "Illegal I/O port address/length above 64K: 0x%p/%X", | ||
136 | ACPI_CAST_PTR(void, address), byte_width)); | ||
137 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); | ||
138 | } | ||
139 | |||
140 | /* Exit if requested address is not within the protected port table */ | ||
141 | |||
142 | if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) { | ||
143 | return_ACPI_STATUS(AE_OK); | ||
144 | } | ||
145 | |||
146 | /* Check request against the list of protected I/O ports */ | ||
147 | |||
148 | for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, port_info++) { | ||
149 | /* | ||
150 | * Check if the requested address range will write to a reserved | ||
151 | * port. Four cases to consider: | ||
152 | * | ||
153 | * 1) Address range is contained completely in the port address range | ||
154 | * 2) Address range overlaps port range at the port range start | ||
155 | * 3) Address range overlaps port range at the port range end | ||
156 | * 4) Address range completely encompasses the port range | ||
157 | */ | ||
158 | if ((address <= port_info->end) | ||
159 | && (last_address >= port_info->start)) { | ||
160 | |||
161 | /* Port illegality may depend on the _OSI calls made by the BIOS */ | ||
162 | |||
163 | if (acpi_gbl_osi_data >= port_info->osi_dependency) { | ||
164 | ACPI_ERROR((AE_INFO, | ||
165 | "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", | ||
166 | ACPI_CAST_PTR(void, address), | ||
167 | byte_width, port_info->name, | ||
168 | port_info->start, port_info->end)); | ||
169 | |||
170 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /* Finished if address range ends before the end of this port */ | ||
175 | |||
176 | if (last_address <= port_info->end) { | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | return_ACPI_STATUS(AE_OK); | ||
182 | } | ||
183 | |||
184 | /****************************************************************************** | ||
185 | * | ||
186 | * FUNCTION: acpi_hw_read_port | ||
187 | * | ||
188 | * PARAMETERS: Address Address of I/O port/register to read | ||
189 | * Value Where value is placed | ||
190 | * Width Number of bits | ||
191 | * | ||
192 | * RETURN: Value read from port | ||
193 | * | ||
194 | * DESCRIPTION: Read data from an I/O port or register. This is a front-end | ||
195 | * to acpi_os_read_port that performs validation on both the port | ||
196 | * address and the length. | ||
197 | * | ||
198 | *****************************************************************************/ | ||
199 | |||
200 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) | ||
201 | { | ||
202 | acpi_status status; | ||
203 | |||
204 | status = acpi_hw_validate_io_request(address, width); | ||
205 | if (ACPI_FAILURE(status)) { | ||
206 | return status; | ||
207 | } | ||
208 | |||
209 | status = acpi_os_read_port(address, value, width); | ||
210 | return status; | ||
211 | } | ||
212 | |||
213 | /****************************************************************************** | ||
214 | * | ||
215 | * FUNCTION: acpi_hw_write_port | ||
216 | * | ||
217 | * PARAMETERS: Address Address of I/O port/register to write | ||
218 | * Value Value to write | ||
219 | * Width Number of bits | ||
220 | * | ||
221 | * RETURN: None | ||
222 | * | ||
223 | * DESCRIPTION: Write data to an I/O port or register. This is a front-end | ||
224 | * to acpi_os_write_port that performs validation on both the port | ||
225 | * address and the length. | ||
226 | * | ||
227 | *****************************************************************************/ | ||
228 | |||
229 | acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) | ||
230 | { | ||
231 | acpi_status status; | ||
232 | |||
233 | status = acpi_hw_validate_io_request(address, width); | ||
234 | if (ACPI_FAILURE(status)) { | ||
235 | return status; | ||
236 | } | ||
237 | |||
238 | status = acpi_os_write_port(address, value, width); | ||
239 | return status; | ||
240 | } | ||