On Fri, Dec 9, 2011 at 3:01 AM, Lin Ming <ming.m.lin@xxxxxxxxx> wrote: > Hi Luca, > > We have investigated this issue more and think that it's better to move > the resource validation code into ACPICA core. > > Here is the new patch. > > The major changes include: > - Remove acpi_os_validate_address/acpi_os_invalidate_address from osl.c. > They are reimplemented in ACPICA core: > acpi_ut_add_address_range/acpi_ut_remove_address_range. > > - Add new interface for drivers to check resource conflict: > acpi_check_address_range > > Could you help to test it? Sure, works fine: Tested-by: Luca Tettamanti <kronos.it@xxxxxxxxx> > > Thanks, > Lin Ming > --- > drivers/acpi/acpica/Makefile | 2 +- > drivers/acpi/acpica/acconfig.h | 4 + > drivers/acpi/acpica/acglobal.h | 2 + > drivers/acpi/acpica/aclocal.h | 9 ++ > drivers/acpi/acpica/acutils.h | 18 +++ > drivers/acpi/acpica/dsargs.c | 7 + > drivers/acpi/acpica/utaddress.c | 295 +++++++++++++++++++++++++++++++++++++++ > drivers/acpi/acpica/utdelete.c | 13 +- > drivers/acpi/acpica/utglobal.c | 6 + > drivers/acpi/acpica/utinit.c | 1 + > drivers/acpi/acpica/utxface.c | 38 +++++ > drivers/acpi/osl.c | 202 ++------------------------- > include/acpi/acpixf.h | 5 + > 13 files changed, 406 insertions(+), 196 deletions(-) > > diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile > index 301bd2d..855785b 100644 > --- a/drivers/acpi/acpica/Makefile > +++ b/drivers/acpi/acpica/Makefile > @@ -45,4 +45,4 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o > acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ > utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ > utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \ > - utosi.o utxferror.o utdecode.o > + utosi.o utxferror.o utdecode.o utaddress.o > diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h > index f895a24..4dbd010 100644 > --- a/drivers/acpi/acpica/acconfig.h > +++ b/drivers/acpi/acpica/acconfig.h > @@ -123,6 +123,10 @@ > > #define ACPI_MAX_SLEEP 2000 /* Two seconds */ > > +/* Address Range lists are per-space_id (Memory and I/O only) */ > + > +#define ACPI_ADDRESS_RANGE_MAX 2 > + > /****************************************************************************** > * > * ACPI Specification constants (Do not change unless the specification changes) > diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h > index 76dc02f..b7e7fbd 100644 > --- a/drivers/acpi/acpica/acglobal.h > +++ b/drivers/acpi/acpica/acglobal.h > @@ -295,6 +295,8 @@ ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; > ACPI_EXTERN u8 acpi_gbl_events_initialized; > ACPI_EXTERN u8 acpi_gbl_osi_data; > ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces; > +ACPI_EXTERN struct acpi_address_range > + *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]; > > #ifndef DEFINE_ACPI_GLOBALS > > diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h > index 5552125..44a2164 100644 > --- a/drivers/acpi/acpica/aclocal.h > +++ b/drivers/acpi/acpica/aclocal.h > @@ -625,6 +625,15 @@ union acpi_generic_state { > > typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state); > > +/* Address Range info block */ > + > +struct acpi_address_range { > + struct acpi_address_range *next; > + struct acpi_namespace_node *region_node; > + acpi_physical_address start_address; > + acpi_physical_address end_address; > +}; > + > /***************************************************************************** > * > * Parser typedefs and structs > diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h > index 99c140d..dfea11d 100644 > --- a/drivers/acpi/acpica/acutils.h > +++ b/drivers/acpi/acpica/acutils.h > @@ -579,6 +579,24 @@ acpi_ut_create_list(char *list_name, > #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ > > /* > + * utaddress - address range check > + */ > +acpi_status > +acpi_ut_add_address_range(acpi_adr_space_type space_id, > + acpi_physical_address address, > + u32 length, struct acpi_namespace_node *region_node); > + > +void > +acpi_ut_remove_address_range(acpi_adr_space_type space_id, > + struct acpi_namespace_node *region_node); > + > +u32 > +acpi_ut_check_address_range(acpi_adr_space_type space_id, > + acpi_physical_address address, u32 length, u8 warn); > + > +void acpi_ut_delete_address_lists(void); > + > +/* > * utxferror - various error/warning output functions > */ > void ACPI_INTERNAL_VAR_XFACE > diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c > index 8c7b997..0e62474 100644 > --- a/drivers/acpi/acpica/dsargs.c > +++ b/drivers/acpi/acpica/dsargs.c > @@ -387,5 +387,12 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) > status = acpi_ds_execute_arguments(node, node->parent, > extra_desc->extra.aml_length, > extra_desc->extra.aml_start); > + if (ACPI_FAILURE(status)) { > + return_ACPI_STATUS(status); > + } > + > + status = acpi_ut_add_address_range(obj_desc->region.space_id, > + obj_desc->region.address, > + obj_desc->region.length, node); > return_ACPI_STATUS(status); > } > diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c > new file mode 100644 > index 0000000..6ef7649 > --- /dev/null > +++ b/drivers/acpi/acpica/utaddress.c > @@ -0,0 +1,295 @@ > +/****************************************************************************** > + * > + * Module Name: utaddress - op_region address range check > + * > + *****************************************************************************/ > + > +/* > + * Copyright (C) 2000 - 2011, Intel Corp. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions, and the following disclaimer, > + * without modification. > + * 2. Redistributions in binary form must reproduce at minimum a disclaimer > + * substantially similar to the "NO WARRANTY" disclaimer below > + * ("Disclaimer") and any redistribution must be conditioned upon > + * including a substantially similar Disclaimer requirement for further > + * binary redistribution. > + * 3. Neither the names of the above-listed copyright holders nor the names > + * of any contributors may be used to endorse or promote products derived > + * from this software without specific prior written permission. > + * > + * Alternatively, this software may be distributed under the terms of the > + * GNU General Public License ("GPL") version 2 as published by the Free > + * Software Foundation. > + * > + * NO WARRANTY > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING > + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > + * POSSIBILITY OF SUCH DAMAGES. > + */ > + > +#include <acpi/acpi.h> > +#include "accommon.h" > +#include "acnamesp.h" > + > +#define _COMPONENT ACPI_UTILITIES > +ACPI_MODULE_NAME("utaddress") > + > +/******************************************************************************* > + * > + * FUNCTION: acpi_ut_add_address_range > + * > + * PARAMETERS: space_id - Address space ID > + * Address - op_region start address > + * Length - op_region length > + * region_node - op_region namespace node > + * > + * RETURN: Status > + * > + * DESCRIPTION: Add the Operation Region address range to the global list. > + * The only supported Space IDs are Memory and I/O. Called when > + * the op_region address/length operands are fully evaluated. > + * > + * MUTEX: Locks the namespace > + * > + * NOTE: Because this interface is only called when an op_region argument > + * list is evaluated, there cannot be any duplicate region_nodes. > + * Duplicate Address/Length values are allowed, however, so that multiple > + * address conflicts can be detected. > + * > + ******************************************************************************/ > +acpi_status > +acpi_ut_add_address_range(acpi_adr_space_type space_id, > + acpi_physical_address address, > + u32 length, struct acpi_namespace_node *region_node) > +{ > + struct acpi_address_range *range_info; > + acpi_status status; > + > + ACPI_FUNCTION_TRACE(ut_add_address_range); > + > + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && > + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { > + return_ACPI_STATUS(AE_OK); > + } > + > + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); > + if (ACPI_FAILURE(status)) { > + return_ACPI_STATUS(status); > + } > + > + /* Allocate/init a new info block, add it to the appropriate list */ > + > + range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range)); > + if (!range_info) { > + status = AE_NO_MEMORY; > + goto exit; > + } > + > + range_info->start_address = address; > + range_info->end_address = (address + length - 1); > + range_info->region_node = region_node; > + > + range_info->next = acpi_gbl_address_range_list[space_id]; > + acpi_gbl_address_range_list[space_id] = range_info; > + > + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, > + "\nAdded [%4.4s] address range: 0x%p-0x%p\n", > + acpi_ut_get_node_name(range_info->region_node), > + ACPI_CAST_PTR(void, address), > + ACPI_CAST_PTR(void, range_info->end_address))); > + > + exit: > + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); > + return_ACPI_STATUS(status); > +} > + > +/******************************************************************************* > + * > + * FUNCTION: acpi_ut_remove_address_range > + * > + * PARAMETERS: space_id - Address space ID > + * region_node - op_region namespace node > + * > + * RETURN: None > + * > + * DESCRIPTION: Remove the Operation Region from the global list. The only > + * supported Space IDs are Memory and I/O. Called when an > + * op_region is deleted. > + * > + * MUTEX: Assumes the namespace is locked > + * > + ******************************************************************************/ > + > +void > +acpi_ut_remove_address_range(acpi_adr_space_type space_id, > + struct acpi_namespace_node *region_node) > +{ > + struct acpi_address_range *range_info; > + struct acpi_address_range *prev; > + > + ACPI_FUNCTION_TRACE(ut_remove_address_range); > + > + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && > + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { > + return_VOID; > + } > + > + /* Get the appropriate list head and check the list */ > + > + range_info = prev = acpi_gbl_address_range_list[space_id]; > + while (range_info) { > + if (range_info->region_node == region_node) { > + if (range_info == prev) { /* Found at list head */ > + acpi_gbl_address_range_list[space_id] = > + range_info->next; > + } else { > + prev->next = range_info->next; > + } > + > + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, > + "\nRemoved [%4.4s] address range: 0x%p-0x%p\n", > + acpi_ut_get_node_name(range_info-> > + region_node), > + ACPI_CAST_PTR(void, > + range_info-> > + start_address), > + ACPI_CAST_PTR(void, > + range_info-> > + end_address))); > + > + ACPI_FREE(range_info); > + return_VOID; > + } > + > + prev = range_info; > + range_info = range_info->next; > + } > + > + return_VOID; > +} > + > +/******************************************************************************* > + * > + * FUNCTION: acpi_ut_check_address_range > + * > + * PARAMETERS: space_id - Address space ID > + * Address - Start address > + * Length - Length of address range > + * Warn - TRUE if warning on overlap desired > + * > + * RETURN: Count of the number of conflicts detected. Zero is always > + * returned for Space IDs other than Memory or I/O. > + * > + * DESCRIPTION: Check if the input address range overlaps any of the > + * ASL operation region address ranges. The only supported > + * Space IDs are Memory and I/O. > + * > + * MUTEX: Assumes the namespace is locked. > + * > + ******************************************************************************/ > + > +u32 > +acpi_ut_check_address_range(acpi_adr_space_type space_id, > + acpi_physical_address address, u32 length, u8 warn) > +{ > + struct acpi_address_range *range_info; > + acpi_physical_address end_address; > + char *pathname; > + u32 overlap_count = 0; > + > + ACPI_FUNCTION_TRACE(ut_check_address_range); > + > + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && > + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { > + return_UINT32(0); > + } > + > + range_info = acpi_gbl_address_range_list[space_id]; > + end_address = address + length - 1; > + > + /* Check entire list for all possible conflicts */ > + > + while (range_info) { > + /* > + * Check if the requested Address/Length overlaps this address_range. > + * Four cases to consider: > + * > + * 1) Input address/length is contained completely in the address range > + * 2) Input address/length overlaps range at the range start > + * 3) Input address/length overlaps range at the range end > + * 4) Input address/length completely encompasses the range > + */ > + if ((address <= range_info->end_address) && > + (end_address >= range_info->start_address)) { > + > + /* Found an address range overlap */ > + > + overlap_count++; > + if (warn) { /* Optional warning message */ > + pathname = > + acpi_ns_get_external_pathname(range_info-> > + region_node); > + > + ACPI_WARNING((AE_INFO, > + "0x%p-0x%p %s conflicts with Region %s %d", > + ACPI_CAST_PTR(void, address), > + ACPI_CAST_PTR(void, end_address), > + acpi_ut_get_region_name(space_id), > + pathname, overlap_count)); > + ACPI_FREE(pathname); > + } > + } > + > + range_info = range_info->next; > + } > + > + return_UINT32(overlap_count); > +} > + > +/******************************************************************************* > + * > + * FUNCTION: acpi_ut_delete_address_lists > + * > + * PARAMETERS: None > + * > + * RETURN: None > + * > + * DESCRIPTION: Delete all global address range lists (called during > + * subsystem shutdown). > + * > + ******************************************************************************/ > + > +void acpi_ut_delete_address_lists(void) > +{ > + struct acpi_address_range *next; > + struct acpi_address_range *range_info; > + int i; > + > + /* Delete all elements in all address range lists */ > + > + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { > + next = acpi_gbl_address_range_list[i]; > + > + while (next) { > + range_info = next; > + next = range_info->next; > + ACPI_FREE(range_info); > + } > + > + acpi_gbl_address_range_list[i] = NULL; > + } > +} > diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c > index 31f5a78..93ec06b 100644 > --- a/drivers/acpi/acpica/utdelete.c > +++ b/drivers/acpi/acpica/utdelete.c > @@ -215,11 +215,14 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) > ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, > "***** Region %p\n", object)); > > - /* Invalidate the region address/length via the host OS */ > - > - acpi_os_invalidate_address(object->region.space_id, > - object->region.address, > - (acpi_size) object->region.length); > + /* > + * Update address_range list. However, only permanent regions > + * are installed in this list. (Not created within a method) > + */ > + if (!(object->region.node->flags & ANOBJ_TEMPORARY)) { > + acpi_ut_remove_address_range(object->region.space_id, > + object->region.node); > + } > > second_desc = acpi_ns_get_secondary_object(object); > if (second_desc) { > diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c > index ffba0a3..3cf758b 100644 > --- a/drivers/acpi/acpica/utglobal.c > +++ b/drivers/acpi/acpica/utglobal.c > @@ -264,6 +264,12 @@ acpi_status acpi_ut_init_globals(void) > return_ACPI_STATUS(status); > } > > + /* Address Range lists */ > + > + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { > + acpi_gbl_address_range_list[i] = NULL; > + } > + > /* Mutex locked flags */ > > for (i = 0; i < ACPI_NUM_MUTEX; i++) { > diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c > index 191b682..cab61a0 100644 > --- a/drivers/acpi/acpica/utinit.c > +++ b/drivers/acpi/acpica/utinit.c > @@ -92,6 +92,7 @@ static void acpi_ut_terminate(void) > gpe_xrupt_info = next_gpe_xrupt_info; > } > > + acpi_ut_delete_address_lists(); > return_VOID; > } > > diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c > index 420ebfe..15cbdde 100644 > --- a/drivers/acpi/acpica/utxface.c > +++ b/drivers/acpi/acpica/utxface.c > @@ -48,6 +48,7 @@ > #include "acnamesp.h" > #include "acdebug.h" > #include "actables.h" > +#include "acinterp.h" > > #define _COMPONENT ACPI_UTILITIES > ACPI_MODULE_NAME("utxface") > @@ -640,4 +641,41 @@ acpi_status acpi_install_interface_handler(acpi_interface_handler handler) > } > > ACPI_EXPORT_SYMBOL(acpi_install_interface_handler) > + > +/***************************************************************************** > + * > + * FUNCTION: acpi_check_address_range > + * > + * PARAMETERS: space_id - Address space ID > + * Address - Start address > + * Length - Length > + * Warn - TRUE if warning on overlap desired > + * > + * RETURN: Count of the number of conflicts detected. > + * > + * DESCRIPTION: Check if the input address range overlaps any of the > + * ASL operation region address ranges. > + * > + ****************************************************************************/ > +u32 > +acpi_check_address_range(acpi_adr_space_type space_id, > + acpi_physical_address address, > + acpi_size length, u8 warn) > +{ > + u32 overlaps; > + acpi_status status; > + > + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); > + if (ACPI_FAILURE(status)) { > + return (0); > + } > + > + overlaps = acpi_ut_check_address_range(space_id, address, > + (u32)length, warn); > + > + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); > + return (overlaps); > +} > + > +ACPI_EXPORT_SYMBOL(acpi_check_address_range) > #endif /* !ACPI_ASL_COMPILER */ > diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c > index f31c5c5..3e57fbd 100644 > --- a/drivers/acpi/osl.c > +++ b/drivers/acpi/osl.c > @@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq; > struct workqueue_struct *kacpi_hotplug_wq; > EXPORT_SYMBOL(kacpi_hotplug_wq); > > -struct acpi_res_list { > - resource_size_t start; > - resource_size_t end; > - acpi_adr_space_type resource_type; /* IO port, System memory, ...*/ > - char name[5]; /* only can have a length of 4 chars, make use of this > - one instead of res->name, no need to kalloc then */ > - struct list_head resource_list; > - int count; > -}; > - > -static LIST_HEAD(resource_list_head); > -static DEFINE_SPINLOCK(acpi_res_lock); > - > /* > * This list of permanent mappings is for memory that may be accessed from > * interrupt context, where we can't do the ioremap(). > @@ -1278,44 +1265,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); > * drivers */ > int acpi_check_resource_conflict(const struct resource *res) > { > - struct acpi_res_list *res_list_elem; > - int ioport = 0, clash = 0; > + acpi_adr_space_type space_id; > + acpi_size length; > + u8 warn = 0; > + int clash = 0; > > if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) > return 0; > if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) > return 0; > > - ioport = res->flags & IORESOURCE_IO; > - > - spin_lock(&acpi_res_lock); > - list_for_each_entry(res_list_elem, &resource_list_head, > - resource_list) { > - if (ioport && (res_list_elem->resource_type > - != ACPI_ADR_SPACE_SYSTEM_IO)) > - continue; > - if (!ioport && (res_list_elem->resource_type > - != ACPI_ADR_SPACE_SYSTEM_MEMORY)) > - continue; > + if (res->flags & IORESOURCE_IO) > + space_id = ACPI_ADR_SPACE_SYSTEM_IO; > + else > + space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; > > - if (res->end < res_list_elem->start > - || res_list_elem->end < res->start) > - continue; > - clash = 1; > - break; > - } > - spin_unlock(&acpi_res_lock); > + length = res->end - res->start + 1; > + if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) > + warn = 1; > + clash = acpi_check_address_range(space_id, res->start, length, warn); > > if (clash) { > if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { > - printk(KERN_WARNING "ACPI: resource %s %pR" > - " conflicts with ACPI region %s " > - "[%s 0x%zx-0x%zx]\n", > - res->name, res, res_list_elem->name, > - (res_list_elem->resource_type == > - ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", > - (size_t) res_list_elem->start, > - (size_t) res_list_elem->end); > if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) > printk(KERN_NOTICE "ACPI: This conflict may" > " cause random problems and system" > @@ -1467,155 +1438,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) > kmem_cache_free(cache, object); > return (AE_OK); > } > - > -static inline int acpi_res_list_add(struct acpi_res_list *res) > -{ > - struct acpi_res_list *res_list_elem; > - > - list_for_each_entry(res_list_elem, &resource_list_head, > - resource_list) { > - > - if (res->resource_type == res_list_elem->resource_type && > - res->start == res_list_elem->start && > - res->end == res_list_elem->end) { > - > - /* > - * The Region(addr,len) already exist in the list, > - * just increase the count > - */ > - > - res_list_elem->count++; > - return 0; > - } > - } > - > - res->count = 1; > - list_add(&res->resource_list, &resource_list_head); > - return 1; > -} > - > -static inline void acpi_res_list_del(struct acpi_res_list *res) > -{ > - struct acpi_res_list *res_list_elem; > - > - list_for_each_entry(res_list_elem, &resource_list_head, > - resource_list) { > - > - if (res->resource_type == res_list_elem->resource_type && > - res->start == res_list_elem->start && > - res->end == res_list_elem->end) { > - > - /* > - * If the res count is decreased to 0, > - * remove and free it > - */ > - > - if (--res_list_elem->count == 0) { > - list_del(&res_list_elem->resource_list); > - kfree(res_list_elem); > - } > - return; > - } > - } > -} > - > -acpi_status > -acpi_os_invalidate_address( > - u8 space_id, > - acpi_physical_address address, > - acpi_size length) > -{ > - struct acpi_res_list res; > - > - switch (space_id) { > - case ACPI_ADR_SPACE_SYSTEM_IO: > - case ACPI_ADR_SPACE_SYSTEM_MEMORY: > - /* Only interference checks against SystemIO and SystemMemory > - are needed */ > - res.start = address; > - res.end = address + length - 1; > - res.resource_type = space_id; > - spin_lock(&acpi_res_lock); > - acpi_res_list_del(&res); > - spin_unlock(&acpi_res_lock); > - break; > - case ACPI_ADR_SPACE_PCI_CONFIG: > - case ACPI_ADR_SPACE_EC: > - case ACPI_ADR_SPACE_SMBUS: > - case ACPI_ADR_SPACE_CMOS: > - case ACPI_ADR_SPACE_PCI_BAR_TARGET: > - case ACPI_ADR_SPACE_DATA_TABLE: > - case ACPI_ADR_SPACE_FIXED_HARDWARE: > - break; > - } > - return AE_OK; > -} > - > -/****************************************************************************** > - * > - * FUNCTION: acpi_os_validate_address > - * > - * PARAMETERS: space_id - ACPI space ID > - * address - Physical address > - * length - Address length > - * > - * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, > - * should return AE_AML_ILLEGAL_ADDRESS. > - * > - * DESCRIPTION: Validate a system address via the host OS. Used to validate > - * the addresses accessed by AML operation regions. > - * > - *****************************************************************************/ > - > -acpi_status > -acpi_os_validate_address ( > - u8 space_id, > - acpi_physical_address address, > - acpi_size length, > - char *name) > -{ > - struct acpi_res_list *res; > - int added; > - if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) > - return AE_OK; > - > - switch (space_id) { > - case ACPI_ADR_SPACE_SYSTEM_IO: > - case ACPI_ADR_SPACE_SYSTEM_MEMORY: > - /* Only interference checks against SystemIO and SystemMemory > - are needed */ > - res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL); > - if (!res) > - return AE_OK; > - /* ACPI names are fixed to 4 bytes, still better use strlcpy */ > - strlcpy(res->name, name, 5); > - res->start = address; > - res->end = address + length - 1; > - res->resource_type = space_id; > - spin_lock(&acpi_res_lock); > - added = acpi_res_list_add(res); > - spin_unlock(&acpi_res_lock); > - pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " > - "name: %s\n", added ? "Added" : "Already exist", > - (space_id == ACPI_ADR_SPACE_SYSTEM_IO) > - ? "SystemIO" : "System Memory", > - (unsigned long long)res->start, > - (unsigned long long)res->end, > - res->name); > - if (!added) > - kfree(res); > - break; > - case ACPI_ADR_SPACE_PCI_CONFIG: > - case ACPI_ADR_SPACE_EC: > - case ACPI_ADR_SPACE_SMBUS: > - case ACPI_ADR_SPACE_CMOS: > - case ACPI_ADR_SPACE_PCI_BAR_TARGET: > - case ACPI_ADR_SPACE_DATA_TABLE: > - case ACPI_ADR_SPACE_FIXED_HARDWARE: > - break; > - } > - return AE_OK; > -} > #endif > > acpi_status __init acpi_os_initialize(void) > diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h > index f554a93..7d7df17 100644 > --- a/include/acpi/acpixf.h > +++ b/include/acpi/acpixf.h > @@ -111,6 +111,11 @@ acpi_status acpi_install_interface(acpi_string interface_name); > > acpi_status acpi_remove_interface(acpi_string interface_name); > > +u32 > +acpi_check_address_range(acpi_adr_space_type space_id, > + acpi_physical_address address, > + acpi_size length, u8 warn); > + > /* > * ACPI Memory management > */ > > >> >> > diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c >> > index 8c7b997..42163d8 100644 >> > --- a/drivers/acpi/acpica/dsargs.c >> > +++ b/drivers/acpi/acpica/dsargs.c >> > @@ -387,5 +387,29 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) >> > status = acpi_ds_execute_arguments(node, node->parent, >> > extra_desc->extra.aml_length, >> > extra_desc->extra.aml_start); >> > + if (ACPI_FAILURE(status)) { >> > + return_ACPI_STATUS(status); >> > + } >> > + >> > + /* Validate the region address/length via the host OS */ >> > + >> > + status = acpi_os_validate_address(obj_desc->region.space_id, >> > + obj_desc->region.address, >> > + (acpi_size) obj_desc->region.length, >> > + acpi_ut_get_node_name(node)); >> > + >> > + if (ACPI_FAILURE(status)) { >> > + /* >> > + * Invalid address/length. We will emit an error message and mark >> > + * the region as invalid, so that it will cause an additional error if >> > + * it is ever used. Then return AE_OK. >> > + */ >> > + ACPI_EXCEPTION((AE_INFO, status, >> > + "During address validation of OpRegion [%4.4s]", >> > + node->name.ascii)); >> > + obj_desc->common.flags |= AOPOBJ_INVALID; >> > + status = AE_OK; >> > + } >> > + >> > return_ACPI_STATUS(status); >> > } >> ��.n��������+%������w��{.n�����{�����ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f