Commit a65131e9 authored by Lin Ming's avatar Lin Ming Committed by Len Brown

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=13036Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 09106974
...@@ -151,7 +151,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) ...@@ -151,7 +151,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"Illegal I/O port address/length above 64K: 0x%p/%X", "Illegal I/O port address/length above 64K: 0x%p/%X",
ACPI_CAST_PTR(void, address), byte_width)); ACPI_CAST_PTR(void, address), byte_width));
return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); return_ACPI_STATUS(AE_LIMIT);
} }
/* Exit if requested address is not within the protected port table */ /* 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,11 +178,12 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
/* Port illegality may depend on the _OSI calls made by the BIOS */ /* Port illegality may depend on the _OSI calls made by the BIOS */
if (acpi_gbl_osi_data >= port_info->osi_dependency) { if (acpi_gbl_osi_data >= port_info->osi_dependency) {
ACPI_ERROR((AE_INFO, ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)",
ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, address),
byte_width, port_info->name, byte_width, port_info->name,
port_info->start, port_info->end)); port_info->start,
port_info->end));
return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS);
} }
...@@ -206,7 +207,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) ...@@ -206,7 +207,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
* Value Where value is placed * Value Where value is placed
* Width Number of bits * Width Number of bits
* *
* RETURN: Value read from port * RETURN: Status and value read from port
* *
* DESCRIPTION: Read data from an I/O port or register. This is a front-end * DESCRIPTION: Read data from an I/O port or register. This is a front-end
* to acpi_os_read_port that performs validation on both the port * 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,14 +218,43 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width)
acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
{ {
acpi_status status; acpi_status status;
u32 one_byte;
u32 i;
/* Validate the entire request and perform the I/O */
status = acpi_hw_validate_io_request(address, width); status = acpi_hw_validate_io_request(address, width);
if (ACPI_FAILURE(status)) { if (ACPI_SUCCESS(status)) {
status = acpi_os_read_port(address, value, width);
return status; return status;
} }
status = acpi_os_read_port(address, value, width); if (status != AE_AML_ILLEGAL_ADDRESS) {
return status; return status;
}
/*
* There has been a protection violation within the request. Fall
* back to byte granularity port I/O and ignore the failing bytes.
* This provides Windows compatibility.
*/
for (i = 0, *value = 0; i < width; i += 8) {
/* Validate and read one byte */
if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
status = acpi_os_read_port(address, &one_byte, 8);
if (ACPI_FAILURE(status)) {
return status;
}
*value |= (one_byte << i);
}
address++;
}
return AE_OK;
} }
/****************************************************************************** /******************************************************************************
...@@ -235,7 +265,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width) ...@@ -235,7 +265,7 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
* Value Value to write * Value Value to write
* Width Number of bits * Width Number of bits
* *
* RETURN: None * RETURN: Status
* *
* DESCRIPTION: Write data to an I/O port or register. This is a front-end * DESCRIPTION: Write data to an I/O port or register. This is a front-end
* to acpi_os_write_port that performs validation on both the port * 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,12 +276,39 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width) acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
{ {
acpi_status status; acpi_status status;
u32 i;
/* Validate the entire request and perform the I/O */
status = acpi_hw_validate_io_request(address, width); status = acpi_hw_validate_io_request(address, width);
if (ACPI_FAILURE(status)) { if (ACPI_SUCCESS(status)) {
status = acpi_os_write_port(address, value, width);
return status; return status;
} }
status = acpi_os_write_port(address, value, width); if (status != AE_AML_ILLEGAL_ADDRESS) {
return status; return status;
}
/*
* There has been a protection violation within the request. Fall
* back to byte granularity port I/O and ignore the failing bytes.
* This provides Windows compatibility.
*/
for (i = 0; i < width; i += 8) {
/* Validate and write one byte */
if (acpi_hw_validate_io_request(address, 8) == AE_OK) {
status =
acpi_os_write_port(address, (value >> i) & 0xFF, 8);
if (ACPI_FAILURE(status)) {
return status;
}
}
address++;
}
return AE_OK;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment