acpi: fix crash in core ACPI code, triggered by CONFIG_ACPI_PCI_SLOT=y
[safe/jmp/linux-2.6] / drivers / acpi / utilities / utresrc.c
index 07a314c..c3e3e13 100644 (file)
@@ -1,11 +1,11 @@
 /*******************************************************************************
  *
- * Module Name: utresrc - Resource managment utilities
+ * Module Name: utresrc - Resource management utilities
  *
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2005, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <acpi/amlresrc.h>
 
 #define _COMPONENT          ACPI_UTILITIES
-ACPI_MODULE_NAME("utmisc")
+ACPI_MODULE_NAME("utresrc")
+#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+/*
+ * Strings used to decode resource descriptors.
+ * Used by both the disasssembler and the debugger resource dump routines
+ */
+const char *acpi_gbl_bm_decode[] = {
+       "NotBusMaster",
+       "BusMaster"
+};
+
+const char *acpi_gbl_config_decode[] = {
+       "0 - Good Configuration",
+       "1 - Acceptable Configuration",
+       "2 - Suboptimal Configuration",
+       "3 - ***Invalid Configuration***",
+};
+
+const char *acpi_gbl_consume_decode[] = {
+       "ResourceProducer",
+       "ResourceConsumer"
+};
+
+const char *acpi_gbl_dec_decode[] = {
+       "PosDecode",
+       "SubDecode"
+};
+
+const char *acpi_gbl_he_decode[] = {
+       "Level",
+       "Edge"
+};
+
+const char *acpi_gbl_io_decode[] = {
+       "Decode10",
+       "Decode16"
+};
+
+const char *acpi_gbl_ll_decode[] = {
+       "ActiveHigh",
+       "ActiveLow"
+};
+
+const char *acpi_gbl_max_decode[] = {
+       "MaxNotFixed",
+       "MaxFixed"
+};
+
+const char *acpi_gbl_mem_decode[] = {
+       "NonCacheable",
+       "Cacheable",
+       "WriteCombining",
+       "Prefetchable"
+};
+
+const char *acpi_gbl_min_decode[] = {
+       "MinNotFixed",
+       "MinFixed"
+};
+
+const char *acpi_gbl_mtp_decode[] = {
+       "AddressRangeMemory",
+       "AddressRangeReserved",
+       "AddressRangeACPI",
+       "AddressRangeNVS"
+};
+
+const char *acpi_gbl_rng_decode[] = {
+       "InvalidRanges",
+       "NonISAOnlyRanges",
+       "ISAOnlyRanges",
+       "EntireRange"
+};
+
+const char *acpi_gbl_rw_decode[] = {
+       "ReadOnly",
+       "ReadWrite"
+};
+
+const char *acpi_gbl_shr_decode[] = {
+       "Exclusive",
+       "Shared"
+};
+
+const char *acpi_gbl_siz_decode[] = {
+       "Transfer8",
+       "Transfer8_16",
+       "Transfer16",
+       "InvalidSize"
+};
+
+const char *acpi_gbl_trs_decode[] = {
+       "DenseTranslation",
+       "SparseTranslation"
+};
+
+const char *acpi_gbl_ttp_decode[] = {
+       "TypeStatic",
+       "TypeTranslation"
+};
+
+const char *acpi_gbl_typ_decode[] = {
+       "Compatibility",
+       "TypeA",
+       "TypeB",
+       "TypeF"
+};
+
+#endif
 
 /*
  * Base sizes of the raw AML resource descriptors, indexed by resource type.
@@ -131,6 +239,104 @@ static const u8 acpi_gbl_resource_types[] = {
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ut_walk_aml_resources
+ *
+ * PARAMETERS:  Aml             - Pointer to the raw AML resource template
+ *              aml_length      - Length of the entire template
+ *              user_function   - Called once for each descriptor found. If
+ *                                NULL, a pointer to the end_tag is returned
+ *              Context         - Passed to user_function
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
+ *              once for each resource found.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_walk_aml_resources(u8 * aml,
+                          acpi_size aml_length,
+                          acpi_walk_aml_callback user_function, void **context)
+{
+       acpi_status status;
+       u8 *end_aml;
+       u8 resource_index;
+       u32 length;
+       u32 offset = 0;
+
+       ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
+
+       /* The absolute minimum resource template is one end_tag descriptor */
+
+       if (aml_length < sizeof(struct aml_resource_end_tag)) {
+               return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+       }
+
+       /* Point to the end of the resource template buffer */
+
+       end_aml = aml + aml_length;
+
+       /* Walk the byte list, abort on any invalid descriptor type or length */
+
+       while (aml < end_aml) {
+
+               /* Validate the Resource Type and Resource Length */
+
+               status = acpi_ut_validate_resource(aml, &resource_index);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+
+               /* Get the length of this descriptor */
+
+               length = acpi_ut_get_descriptor_length(aml);
+
+               /* Invoke the user function */
+
+               if (user_function) {
+                       status =
+                           user_function(aml, length, offset, resource_index,
+                                         context);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+               }
+
+               /* An end_tag descriptor terminates this resource template */
+
+               if (acpi_ut_get_resource_type(aml) ==
+                   ACPI_RESOURCE_NAME_END_TAG) {
+                       /*
+                        * There must be at least one more byte in the buffer for
+                        * the 2nd byte of the end_tag
+                        */
+                       if ((aml + 1) >= end_aml) {
+                               return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+                       }
+
+                       /* Return the pointer to the end_tag if requested */
+
+                       if (!user_function) {
+                               *context = aml;
+                       }
+
+                       /* Normal exit */
+
+                       return_ACPI_STATUS(AE_OK);
+               }
+
+               aml += length;
+               offset += length;
+       }
+
+       /* Did not find an end_tag descriptor */
+
+       return (AE_AML_NO_RESOURCE_END_TAG);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ut_validate_resource
  *
  * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
@@ -157,13 +363,14 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index)
        /*
         * 1) Validate the resource_type field (Byte 0)
         */
-       resource_type = *((u8 *) aml);
+       resource_type = ACPI_GET8(aml);
 
        /*
         * Byte 0 contains the descriptor name (Resource Type)
         * Examine the large/small bit in the resource header
         */
        if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
+
                /* Verify the large resource type (name) against the max */
 
                if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
@@ -266,14 +473,15 @@ u8 acpi_ut_get_resource_type(void *aml)
         * Byte 0 contains the descriptor name (Resource Type)
         * Examine the large/small bit in the resource header
         */
-       if (*((u8 *) aml) & ACPI_RESOURCE_NAME_LARGE) {
+       if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
+
                /* Large Resource Type -- bits 6:0 contain the name */
 
-               return (*((u8 *) aml));
+               return (ACPI_GET8(aml));
        } else {
                /* Small Resource Type -- bits 6:3 contain the name */
 
-               return ((u8) (*((u8 *) aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
+               return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
        }
 }
 
@@ -301,15 +509,16 @@ u16 acpi_ut_get_resource_length(void *aml)
         * Byte 0 contains the descriptor name (Resource Type)
         * Examine the large/small bit in the resource header
         */
-       if (*((u8 *) aml) & ACPI_RESOURCE_NAME_LARGE) {
+       if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
+
                /* Large Resource type -- bytes 1-2 contain the 16-bit length */
 
-               ACPI_MOVE_16_TO_16(&resource_length, &((u8 *) aml)[1]);
+               ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
 
        } else {
                /* Small Resource type -- bits 2:0 of byte 0 contain the length */
 
-               resource_length = (u16) (*((u8 *) aml) &
+               resource_length = (u16) (ACPI_GET8(aml) &
                                         ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
        }
 
@@ -334,7 +543,7 @@ u8 acpi_ut_get_resource_header_length(void *aml)
 
        /* Examine the large/small bit in the resource header */
 
-       if (*((u8 *) aml) & ACPI_RESOURCE_NAME_LARGE) {
+       if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
                return (sizeof(struct aml_resource_large_header));
        } else {
                return (sizeof(struct aml_resource_small_header));
@@ -372,10 +581,12 @@ u32 acpi_ut_get_descriptor_length(void *aml)
  * FUNCTION:    acpi_ut_get_resource_end_tag
  *
  * PARAMETERS:  obj_desc        - The resource template buffer object
+ *              end_tag         - Where the pointer to the end_tag is returned
  *
- * RETURN:      Pointer to the end tag
+ * RETURN:      Status, pointer to the end tag
  *
  * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template
+ *              Note: allows a buffer length of zero.
  *
  ******************************************************************************/
 
@@ -384,45 +595,21 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc,
                             u8 ** end_tag)
 {
        acpi_status status;
-       u8 *aml;
-       u8 *end_aml;
-
-       ACPI_FUNCTION_TRACE("ut_get_resource_end_tag");
 
-       /* Get start and end pointers */
+       ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
 
-       aml = obj_desc->buffer.pointer;
-       end_aml = aml + obj_desc->buffer.length;
+       /* Allow a buffer length of zero */
 
-       /* Walk the resource template, one descriptor per iteration */
-
-       while (aml < end_aml) {
-               /* Validate the Resource Type and Resource Length */
-
-               status = acpi_ut_validate_resource(aml, NULL);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-
-               /* end_tag resource indicates the end of the resource template */
-
-               if (acpi_ut_get_resource_type(aml) ==
-                   ACPI_RESOURCE_NAME_END_TAG) {
-                       /* Return the pointer to the end_tag */
-
-                       *end_tag = aml;
-                       return_ACPI_STATUS(AE_OK);
-               }
-
-               /*
-                * Point to the next resource descriptor in the AML buffer. The
-                * descriptor length is guaranteed to be non-zero by resource
-                * validation above.
-                */
-               aml += acpi_ut_get_descriptor_length(aml);
+       if (!obj_desc->buffer.length) {
+               *end_tag = obj_desc->buffer.pointer;
+               return_ACPI_STATUS(AE_OK);
        }
 
-       /* Did not find an end_tag resource descriptor */
+       /* Validate the template and get a pointer to the end_tag */
+
+       status = acpi_ut_walk_aml_resources(obj_desc->buffer.pointer,
+                                           obj_desc->buffer.length, NULL,
+                                           (void **)end_tag);
 
-       return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+       return_ACPI_STATUS(status);
 }