diff options
author | Lin Ming <ming.m.lin@intel.com> | 2009-04-16 03:18:16 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-04-24 00:25:55 -0400 |
commit | a65131e942e25c707a652fa4ec2cfcd8b63fec11 (patch) | |
tree | 78a3fdca9f37e1b3d88c6d0cd721b5bfa1477dbd /drivers | |
parent | 091069740304c979f957ceacec39c461d0192158 (diff) |
I/O port protection: update for windows compatibility.
For windows compatibility,
1) On a port protection violation, simply ignore the request and
do not return an exception (allow the control method to continue execution.)
2) If only part of the request overlaps a protected port,
read/write the individual ports that are not protected.
http://bugzilla.kernel.org/show_bug.cgi?id=13036
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/acpica/hwvalid.c | 85 |
1 files changed, 71 insertions, 14 deletions
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 7737afb157c3..9c8345754f6a 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c | |||
@@ -151,7 +151,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) | |||
151 | ACPI_ERROR((AE_INFO, | 151 | ACPI_ERROR((AE_INFO, |
152 | "Illegal I/O port address/length above 64K: 0x%p/%X", | 152 | "Illegal I/O port address/length above 64K: 0x%p/%X", |
153 | ACPI_CAST_PTR(void, address), byte_width)); | 153 | ACPI_CAST_PTR(void, address), byte_width)); |
154 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); | 154 | return_ACPI_STATUS(AE_LIMIT); |
155 | } | 155 | } |
156 | 156 | ||
157 | /* Exit if requested address is not within the protected port table */ | 157 | /* Exit if requested address is not within the protected port table */ |
@@ -178,11 +178,12 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) | |||
178 | /* Port illegality may depend on the _OSI calls made by the BIOS */ | 178 | /* Port illegality may depend on the _OSI calls made by the BIOS */ |
179 | 179 | ||
180 | if (acpi_gbl_osi_data >= port_info->osi_dependency) { | 180 | if (acpi_gbl_osi_data >= port_info->osi_dependency) { |
181 | ACPI_ERROR((AE_INFO, | 181 | ACPI_DEBUG_PRINT((ACPI_DB_IO, |
182 | "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", | 182 | "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", |
183 | ACPI_CAST_PTR(void, address), | 183 | ACPI_CAST_PTR(void, address), |
184 | byte_width, port_info->name, | 184 | byte_width, port_info->name, |
185 | port_info->start, port_info->end)); | 185 | port_info->start, |
186 | port_info->end)); | ||
186 | 187 | ||
187 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); | 188 | return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); |
188 | } | 189 | } |
@@ -206,7 +207,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) | |||
206 | * Value Where value is placed | 207 | * Value Where value is placed |
207 | * Width Number of bits | 208 | * Width Number of bits |
208 | * | 209 | * |
209 | * RETURN: Value read from port | 210 | * RETURN: Status and value read from port |
210 | * | 211 | * |
211 | * DESCRIPTION: Read data from an I/O port or register. This is a front-end | 212 | * DESCRIPTION: Read data from an I/O port or register. This is a front-end |
212 | * to acpi_os_read_port that performs validation on both the port | 213 | * to acpi_os_read_port that performs validation on both the port |
@@ -217,14 +218,43 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) | |||
217 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) | 218 | acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) |
218 | { | 219 | { |
219 | acpi_status status; | 220 | acpi_status status; |
221 | u32 one_byte; | ||
222 | u32 i; | ||
223 | |||
224 | /* Validate the entire request and perform the I/O */ | ||
220 | 225 | ||
221 | status = acpi_hw_validate_io_request(address, width); | 226 | status = acpi_hw_validate_io_request(address, width); |
222 | if (ACPI_FAILURE(status)) { | 227 | if (ACPI_SUCCESS(status)) { |
228 | status = acpi_os_read_port(address, value, width); | ||
223 | return status; | 229 | return status; |
224 | } | 230 | } |
225 | 231 | ||
226 | status = acpi_os_read_port(address, value, width); | 232 | if (status != AE_AML_ILLEGAL_ADDRESS) { |
227 | return status; | 233 | return status; |
234 | } | ||
235 | |||
236 | /* | ||
237 | * There has been a protection violation within the request. Fall | ||
238 | * back to byte granularity port I/O and ignore the failing bytes. | ||
239 | * This provides Windows compatibility. | ||
240 | */ | ||
241 | for (i = 0, *value = 0; i < width; i += 8) { | ||
242 | |||
243 | /* Validate and read one byte */ | ||
244 | |||
245 | if (acpi_hw_validate_io_request(address, 8) == AE_OK) { | ||
246 | status = acpi_os_read_port(address, &one_byte, 8); | ||
247 | if (ACPI_FAILURE(status)) { | ||
248 | return status; | ||
249 | } | ||
250 | |||
251 | *value |= (one_byte << i); | ||
252 | } | ||
253 | |||
254 | address++; | ||
255 | } | ||
256 | |||
257 | return AE_OK; | ||
228 | } | 258 | } |
229 | 259 | ||
230 | /****************************************************************************** | 260 | /****************************************************************************** |
@@ -235,7 +265,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) | |||
235 | * Value Value to write | 265 | * Value Value to write |
236 | * Width Number of bits | 266 | * Width Number of bits |
237 | * | 267 | * |
238 | * RETURN: None | 268 | * RETURN: Status |
239 | * | 269 | * |
240 | * DESCRIPTION: Write data to an I/O port or register. This is a front-end | 270 | * DESCRIPTION: Write data to an I/O port or register. This is a front-end |
241 | * to acpi_os_write_port that performs validation on both the port | 271 | * to acpi_os_write_port that performs validation on both the port |
@@ -246,12 +276,39 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) | |||
246 | acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) | 276 | acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) |
247 | { | 277 | { |
248 | acpi_status status; | 278 | acpi_status status; |
279 | u32 i; | ||
280 | |||
281 | /* Validate the entire request and perform the I/O */ | ||
249 | 282 | ||
250 | status = acpi_hw_validate_io_request(address, width); | 283 | status = acpi_hw_validate_io_request(address, width); |
251 | if (ACPI_FAILURE(status)) { | 284 | if (ACPI_SUCCESS(status)) { |
285 | status = acpi_os_write_port(address, value, width); | ||
252 | return status; | 286 | return status; |
253 | } | 287 | } |
254 | 288 | ||
255 | status = acpi_os_write_port(address, value, width); | 289 | if (status != AE_AML_ILLEGAL_ADDRESS) { |
256 | return status; | 290 | return status; |
291 | } | ||
292 | |||
293 | /* | ||
294 | * There has been a protection violation within the request. Fall | ||
295 | * back to byte granularity port I/O and ignore the failing bytes. | ||
296 | * This provides Windows compatibility. | ||
297 | */ | ||
298 | for (i = 0; i < width; i += 8) { | ||
299 | |||
300 | /* Validate and write one byte */ | ||
301 | |||
302 | if (acpi_hw_validate_io_request(address, 8) == AE_OK) { | ||
303 | status = | ||
304 | acpi_os_write_port(address, (value >> i) & 0xFF, 8); | ||
305 | if (ACPI_FAILURE(status)) { | ||
306 | return status; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | address++; | ||
311 | } | ||
312 | |||
313 | return AE_OK; | ||
257 | } | 314 | } |