1 /******************************************************************************
   2  *
   3  * Module Name: tbxfload - Table load/unload external interfaces
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, Intel Corp.
   9  * All rights reserved.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  * 1. Redistributions of source code must retain the above copyright
  15  *    notice, this list of conditions, and the following disclaimer,
  16  *    without modification.
  17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18  *    substantially similar to the "NO WARRANTY" disclaimer below
  19  *    ("Disclaimer") and any redistribution must be conditioned upon
  20  *    including a substantially similar Disclaimer requirement for further
  21  *    binary redistribution.
  22  * 3. Neither the names of the above-listed copyright holders nor the names
  23  *    of any contributors may be used to endorse or promote products derived
  24  *    from this software without specific prior written permission.
  25  *
  26  * Alternatively, this software may be distributed under the terms of the
  27  * GNU General Public License ("GPL") version 2 as published by the Free
  28  * Software Foundation.
  29  *
  30  * NO WARRANTY
  31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41  * POSSIBILITY OF SUCH DAMAGES.
  42  */
  43 
  44 #define __TBXFLOAD_C__
  45 #define EXPORT_ACPI_INTERFACES
  46 
  47 #include "acpi.h"
  48 #include "accommon.h"
  49 #include "acnamesp.h"
  50 #include "actables.h"
  51 
  52 #define _COMPONENT          ACPI_TABLES
  53         ACPI_MODULE_NAME    ("tbxfload")
  54 
  55 /* Local prototypes */
  56 
  57 static ACPI_STATUS
  58 AcpiTbLoadNamespace (
  59     void);
  60 
  61 
  62 /*******************************************************************************
  63  *
  64  * FUNCTION:    AcpiLoadTables
  65  *
  66  * PARAMETERS:  None
  67  *
  68  * RETURN:      Status
  69  *
  70  * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
  71  *
  72  ******************************************************************************/
  73 
  74 ACPI_STATUS
  75 AcpiLoadTables (
  76     void)
  77 {
  78     ACPI_STATUS             Status;
  79 
  80 
  81     ACPI_FUNCTION_TRACE (AcpiLoadTables);
  82 
  83 
  84     /* Load the namespace from the tables */
  85 
  86     Status = AcpiTbLoadNamespace ();
  87     if (ACPI_FAILURE (Status))
  88     {
  89         ACPI_EXCEPTION ((AE_INFO, Status,
  90             "While loading namespace from ACPI tables"));
  91     }
  92 
  93     return_ACPI_STATUS (Status);
  94 }
  95 
  96 ACPI_EXPORT_SYMBOL_INIT (AcpiLoadTables)
  97 
  98 
  99 /*******************************************************************************
 100  *
 101  * FUNCTION:    AcpiTbLoadNamespace
 102  *
 103  * PARAMETERS:  None
 104  *
 105  * RETURN:      Status
 106  *
 107  * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
 108  *              the RSDT/XSDT.
 109  *
 110  ******************************************************************************/
 111 
 112 static ACPI_STATUS
 113 AcpiTbLoadNamespace (
 114     void)
 115 {
 116     ACPI_STATUS             Status;
 117     UINT32                  i;
 118     ACPI_TABLE_HEADER       *NewDsdt;
 119 
 120 
 121     ACPI_FUNCTION_TRACE (TbLoadNamespace);
 122 
 123 
 124     (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
 125 
 126     /*
 127      * Load the namespace. The DSDT is required, but any SSDT and
 128      * PSDT tables are optional. Verify the DSDT.
 129      */
 130     if (!AcpiGbl_RootTableList.CurrentTableCount ||
 131         !ACPI_COMPARE_NAME (
 132             &(AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Signature),
 133             ACPI_SIG_DSDT) ||
 134          ACPI_FAILURE (AcpiTbVerifyTable (
 135             &AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT])))
 136     {
 137         Status = AE_NO_ACPI_TABLES;
 138         goto UnlockAndExit;
 139     }
 140 
 141     /*
 142      * Save the DSDT pointer for simple access. This is the mapped memory
 143      * address. We must take care here because the address of the .Tables
 144      * array can change dynamically as tables are loaded at run-time. Note:
 145      * .Pointer field is not validated until after call to AcpiTbVerifyTable.
 146      */
 147     AcpiGbl_DSDT = AcpiGbl_RootTableList.Tables[ACPI_TABLE_INDEX_DSDT].Pointer;
 148 
 149     /*
 150      * Optionally copy the entire DSDT to local memory (instead of simply
 151      * mapping it.) There are some BIOSs that corrupt or replace the original
 152      * DSDT, creating the need for this option. Default is FALSE, do not copy
 153      * the DSDT.
 154      */
 155     if (AcpiGbl_CopyDsdtLocally)
 156     {
 157         NewDsdt = AcpiTbCopyDsdt (ACPI_TABLE_INDEX_DSDT);
 158         if (NewDsdt)
 159         {
 160             AcpiGbl_DSDT = NewDsdt;
 161         }
 162     }
 163 
 164     /*
 165      * Save the original DSDT header for detection of table corruption
 166      * and/or replacement of the DSDT from outside the OS.
 167      */
 168     ACPI_MEMCPY (&AcpiGbl_OriginalDsdtHeader, AcpiGbl_DSDT,
 169         sizeof (ACPI_TABLE_HEADER));
 170 
 171     (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
 172 
 173     /* Load and parse tables */
 174 
 175     Status = AcpiNsLoadTable (ACPI_TABLE_INDEX_DSDT, AcpiGbl_RootNode);
 176     if (ACPI_FAILURE (Status))
 177     {
 178         return_ACPI_STATUS (Status);
 179     }
 180 
 181     /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */
 182 
 183     (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
 184     for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i)
 185     {
 186         if ((!ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
 187                     ACPI_SIG_SSDT) &&
 188              !ACPI_COMPARE_NAME (&(AcpiGbl_RootTableList.Tables[i].Signature),
 189                     ACPI_SIG_PSDT)) ||
 190              ACPI_FAILURE (AcpiTbVerifyTable (
 191                 &AcpiGbl_RootTableList.Tables[i])))
 192         {
 193             continue;
 194         }
 195 
 196         /*
 197          * Optionally do not load any SSDTs from the RSDT/XSDT. This can
 198          * be useful for debugging ACPI problems on some machines.
 199          */
 200         if (AcpiGbl_DisableSsdtTableLoad)
 201         {
 202             ACPI_INFO ((AE_INFO, "Ignoring %4.4s at %p",
 203                 AcpiGbl_RootTableList.Tables[i].Signature.Ascii,
 204                 ACPI_CAST_PTR (void, AcpiGbl_RootTableList.Tables[i].Address)));
 205             continue;
 206         }
 207 
 208         /* Ignore errors while loading tables, get as many as possible */
 209 
 210         (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
 211         (void) AcpiNsLoadTable (i, AcpiGbl_RootNode);
 212         (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
 213     }
 214 
 215     ACPI_INFO ((AE_INFO, "All ACPI Tables successfully acquired"));
 216 
 217 UnlockAndExit:
 218     (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
 219     return_ACPI_STATUS (Status);
 220 }
 221 
 222 
 223 /*******************************************************************************
 224  *
 225  * FUNCTION:    AcpiLoadTable
 226  *
 227  * PARAMETERS:  Table               - Pointer to a buffer containing the ACPI
 228  *                                    table to be loaded.
 229  *
 230  * RETURN:      Status
 231  *
 232  * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must
 233  *              be a valid ACPI table with a valid ACPI table header.
 234  *              Note1: Mainly intended to support hotplug addition of SSDTs.
 235  *              Note2: Does not copy the incoming table. User is responsible
 236  *              to ensure that the table is not deleted or unmapped.
 237  *
 238  ******************************************************************************/
 239 
 240 ACPI_STATUS
 241 AcpiLoadTable (
 242     ACPI_TABLE_HEADER       *Table)
 243 {
 244     ACPI_STATUS             Status;
 245     ACPI_TABLE_DESC         TableDesc;
 246     UINT32                  TableIndex;
 247 
 248 
 249     ACPI_FUNCTION_TRACE (AcpiLoadTable);
 250 
 251 
 252     /* Parameter validation */
 253 
 254     if (!Table)
 255     {
 256         return_ACPI_STATUS (AE_BAD_PARAMETER);
 257     }
 258 
 259     /* Init local table descriptor */
 260 
 261     ACPI_MEMSET (&TableDesc, 0, sizeof (ACPI_TABLE_DESC));
 262     TableDesc.Address = ACPI_PTR_TO_PHYSADDR (Table);
 263     TableDesc.Pointer = Table;
 264     TableDesc.Length = Table->Length;
 265     TableDesc.Flags = ACPI_TABLE_ORIGIN_UNKNOWN;
 266 
 267     /* Must acquire the interpreter lock during this operation */
 268 
 269     Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
 270     if (ACPI_FAILURE (Status))
 271     {
 272         return_ACPI_STATUS (Status);
 273     }
 274 
 275     /* Install the table and load it into the namespace */
 276 
 277     ACPI_INFO ((AE_INFO, "Host-directed Dynamic ACPI Table Load:"));
 278     Status = AcpiTbAddTable (&TableDesc, &TableIndex);
 279     if (ACPI_FAILURE (Status))
 280     {
 281         goto UnlockAndExit;
 282     }
 283 
 284     Status = AcpiNsLoadTable (TableIndex, AcpiGbl_RootNode);
 285 
 286     /* Invoke table handler if present */
 287 
 288     if (AcpiGbl_TableHandler)
 289     {
 290         (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table,
 291                     AcpiGbl_TableHandlerContext);
 292     }
 293 
 294 UnlockAndExit:
 295     (void) AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
 296     return_ACPI_STATUS (Status);
 297 }
 298 
 299 ACPI_EXPORT_SYMBOL (AcpiLoadTable)
 300 
 301 
 302 /*******************************************************************************
 303  *
 304  * FUNCTION:    AcpiUnloadParentTable
 305  *
 306  * PARAMETERS:  Object              - Handle to any namespace object owned by
 307  *                                    the table to be unloaded
 308  *
 309  * RETURN:      Status
 310  *
 311  * DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads
 312  *              the table and deletes all namespace objects associated with
 313  *              that table. Unloading of the DSDT is not allowed.
 314  *              Note: Mainly intended to support hotplug removal of SSDTs.
 315  *
 316  ******************************************************************************/
 317 
 318 ACPI_STATUS
 319 AcpiUnloadParentTable (
 320     ACPI_HANDLE             Object)
 321 {
 322     ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Object);
 323     ACPI_STATUS             Status = AE_NOT_EXIST;
 324     ACPI_OWNER_ID           OwnerId;
 325     UINT32                  i;
 326 
 327 
 328     ACPI_FUNCTION_TRACE (AcpiUnloadParentTable);
 329 
 330 
 331     /* Parameter validation */
 332 
 333     if (!Object)
 334     {
 335         return_ACPI_STATUS (AE_BAD_PARAMETER);
 336     }
 337 
 338     /*
 339      * The node OwnerId is currently the same as the parent table ID.
 340      * However, this could change in the future.
 341      */
 342     OwnerId = Node->OwnerId;
 343     if (!OwnerId)
 344     {
 345         /* OwnerId==0 means DSDT is the owner. DSDT cannot be unloaded */
 346 
 347         return_ACPI_STATUS (AE_TYPE);
 348     }
 349 
 350     /* Must acquire the interpreter lock during this operation */
 351 
 352     Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
 353     if (ACPI_FAILURE (Status))
 354     {
 355         return_ACPI_STATUS (Status);
 356     }
 357 
 358     /* Find the table in the global table list */
 359 
 360     for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
 361     {
 362         if (OwnerId != AcpiGbl_RootTableList.Tables[i].OwnerId)
 363         {
 364             continue;
 365         }
 366 
 367         /*
 368          * Allow unload of SSDT and OEMx tables only. Do not allow unload
 369          * of the DSDT. No other types of tables should get here, since
 370          * only these types can contain AML and thus are the only types
 371          * that can create namespace objects.
 372          */
 373         if (ACPI_COMPARE_NAME (
 374             AcpiGbl_RootTableList.Tables[i].Signature.Ascii,
 375             ACPI_SIG_DSDT))
 376         {
 377             Status = AE_TYPE;
 378             break;
 379         }
 380 
 381         /* Ensure the table is actually loaded */
 382 
 383         if (!AcpiTbIsTableLoaded (i))
 384         {
 385             Status = AE_NOT_EXIST;
 386             break;
 387         }
 388 
 389         /* Invoke table handler if present */
 390 
 391         if (AcpiGbl_TableHandler)
 392         {
 393             (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD,
 394                         AcpiGbl_RootTableList.Tables[i].Pointer,
 395                         AcpiGbl_TableHandlerContext);
 396         }
 397 
 398         /*
 399          * Delete all namespace objects owned by this table. Note that
 400          * these objects can appear anywhere in the namespace by virtue
 401          * of the AML "Scope" operator. Thus, we need to track ownership
 402          * by an ID, not simply a position within the hierarchy.
 403          */
 404         Status = AcpiTbDeleteNamespaceByOwner (i);
 405         if (ACPI_FAILURE (Status))
 406         {
 407             break;
 408         }
 409 
 410         Status = AcpiTbReleaseOwnerId (i);
 411         AcpiTbSetTableLoadedFlag (i, FALSE);
 412         break;
 413     }
 414 
 415     (void) AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
 416     return_ACPI_STATUS (Status);
 417 }
 418 
 419 ACPI_EXPORT_SYMBOL (AcpiUnloadParentTable)