aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao, Hui <hui.xiao@linux.intel.com>2011-12-07 22:25:48 -0500
committerLen Brown <len.brown@intel.com>2012-01-17 03:54:41 -0500
commitb4e008dc53a31cb4bf6a12d9dbaf1d5c6070a838 (patch)
tree32098721489d63bdd571bd31df07770b06744a14
parentfdea163d8c17ba08814142259a467ba3e899010d (diff)
ACPI, APEI, EINJ, Refine the fix of resource conflict
Current fix for resource conflict is to remove the address region <param1 & param2, ~param2+1> from trigger resource, which is highly relies on valid user input. This patch is trying to avoid such potential issues by fetching the exact address region from trigger action table entry. Signed-off-by: Xiao, Hui <hui.xiao@linux.intel.com> Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/apei/einj.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 4fdc8a3b4f6..6e6512e68a2 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -194,6 +194,26 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
194 return 0; 194 return 0;
195} 195}
196 196
197static struct acpi_generic_address *einj_get_trigger_parameter_region(
198 struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)
199{
200 int i;
201 struct acpi_whea_header *entry;
202
203 entry = (struct acpi_whea_header *)
204 ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
205 for (i = 0; i < trigger_tab->entry_count; i++) {
206 if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&
207 entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE &&
208 entry->register_region.space_id ==
209 ACPI_ADR_SPACE_SYSTEM_MEMORY &&
210 (entry->register_region.address & param2) == (param1 & param2))
211 return &entry->register_region;
212 entry++;
213 }
214
215 return NULL;
216}
197/* Execute instructions in trigger error action table */ 217/* Execute instructions in trigger error action table */
198static int __einj_error_trigger(u64 trigger_paddr, u32 type, 218static int __einj_error_trigger(u64 trigger_paddr, u32 type,
199 u64 param1, u64 param2) 219 u64 param1, u64 param2)
@@ -205,6 +225,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
205 struct resource *r; 225 struct resource *r;
206 u32 table_size; 226 u32 table_size;
207 int rc = -EIO; 227 int rc = -EIO;
228 struct acpi_generic_address *trigger_param_region = NULL;
208 229
209 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), 230 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
210 "APEI EINJ Trigger Table"); 231 "APEI EINJ Trigger Table");
@@ -266,12 +287,17 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
266 if (param_extension && (type & 0x0038) && param2) { 287 if (param_extension && (type & 0x0038) && param2) {
267 struct apei_resources addr_resources; 288 struct apei_resources addr_resources;
268 apei_resources_init(&addr_resources); 289 apei_resources_init(&addr_resources);
269 rc = apei_resources_add(&addr_resources, 290 trigger_param_region = einj_get_trigger_parameter_region(
270 param1 & param2, 291 trigger_tab, param1, param2);
271 ~param2 + 1, true); 292 if (trigger_param_region) {
272 if (rc) 293 rc = apei_resources_add(&addr_resources,
273 goto out_fini; 294 trigger_param_region->address,
274 rc = apei_resources_sub(&trigger_resources, &addr_resources); 295 trigger_param_region->bit_width/8, true);
296 if (rc)
297 goto out_fini;
298 rc = apei_resources_sub(&trigger_resources,
299 &addr_resources);
300 }
275 apei_resources_fini(&addr_resources); 301 apei_resources_fini(&addr_resources);
276 if (rc) 302 if (rc)
277 goto out_fini; 303 goto out_fini;