tbinstal.c revision 217365
1/******************************************************************************
2 *
3 * Module Name: tbinstal - ACPI table installation and removal
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, 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
45#define __TBINSTAL_C__
46
47#include <contrib/dev/acpica/include/acpi.h>
48#include <contrib/dev/acpica/include/accommon.h>
49#include <contrib/dev/acpica/include/acnamesp.h>
50#include <contrib/dev/acpica/include/actables.h>
51
52
53#define _COMPONENT          ACPI_TABLES
54        ACPI_MODULE_NAME    ("tbinstal")
55
56
57/******************************************************************************
58 *
59 * FUNCTION:    AcpiTbVerifyTable
60 *
61 * PARAMETERS:  TableDesc           - table
62 *
63 * RETURN:      Status
64 *
65 * DESCRIPTION: this function is called to verify and map table
66 *
67 *****************************************************************************/
68
69ACPI_STATUS
70AcpiTbVerifyTable (
71    ACPI_TABLE_DESC         *TableDesc)
72{
73    ACPI_STATUS             Status = AE_OK;
74
75
76    ACPI_FUNCTION_TRACE (TbVerifyTable);
77
78
79    /* Map the table if necessary */
80
81    if (!TableDesc->Pointer)
82    {
83        if ((TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK) ==
84            ACPI_TABLE_ORIGIN_MAPPED)
85        {
86            TableDesc->Pointer = AcpiOsMapMemory (
87                TableDesc->Address, TableDesc->Length);
88        }
89
90        if (!TableDesc->Pointer)
91        {
92            return_ACPI_STATUS (AE_NO_MEMORY);
93        }
94    }
95
96    /* FACS is the odd table, has no standard ACPI header and no checksum */
97
98    if (!ACPI_COMPARE_NAME (&TableDesc->Signature, ACPI_SIG_FACS))
99    {
100        /* Always calculate checksum, ignore bad checksum if requested */
101
102        Status = AcpiTbVerifyChecksum (TableDesc->Pointer, TableDesc->Length);
103    }
104
105    return_ACPI_STATUS (Status);
106}
107
108
109/*******************************************************************************
110 *
111 * FUNCTION:    AcpiTbAddTable
112 *
113 * PARAMETERS:  TableDesc           - Table descriptor
114 *              TableIndex          - Where the table index is returned
115 *
116 * RETURN:      Status
117 *
118 * DESCRIPTION: This function is called to add an ACPI table. It is used to
119 *              dynamically load tables via the Load and LoadTable AML
120 *              operators.
121 *
122 ******************************************************************************/
123
124ACPI_STATUS
125AcpiTbAddTable (
126    ACPI_TABLE_DESC         *TableDesc,
127    UINT32                  *TableIndex)
128{
129    UINT32                  i;
130    ACPI_STATUS             Status = AE_OK;
131    ACPI_TABLE_HEADER       *OverrideTable = NULL;
132
133
134    ACPI_FUNCTION_TRACE (TbAddTable);
135
136
137    if (!TableDesc->Pointer)
138    {
139        Status = AcpiTbVerifyTable (TableDesc);
140        if (ACPI_FAILURE (Status) || !TableDesc->Pointer)
141        {
142            return_ACPI_STATUS (Status);
143        }
144    }
145
146    /*
147     * Originally, we checked the table signature for "SSDT" or "PSDT" here.
148     * Next, we added support for OEMx tables, signature "OEM".
149     * Valid tables were encountered with a null signature, so we've just
150     * given up on validating the signature, since it seems to be a waste
151     * of code. The original code was removed (05/2008).
152     */
153
154    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
155
156    /* Check if table is already registered */
157
158    for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; ++i)
159    {
160        if (!AcpiGbl_RootTableList.Tables[i].Pointer)
161        {
162            Status = AcpiTbVerifyTable (&AcpiGbl_RootTableList.Tables[i]);
163            if (ACPI_FAILURE (Status) ||
164                !AcpiGbl_RootTableList.Tables[i].Pointer)
165            {
166                continue;
167            }
168        }
169
170        /*
171         * Check for a table match on the entire table length,
172         * not just the header.
173         */
174        if (TableDesc->Length != AcpiGbl_RootTableList.Tables[i].Length)
175        {
176            continue;
177        }
178
179        if (ACPI_MEMCMP (TableDesc->Pointer,
180                AcpiGbl_RootTableList.Tables[i].Pointer,
181                AcpiGbl_RootTableList.Tables[i].Length))
182        {
183            continue;
184        }
185
186        /*
187         * Note: the current mechanism does not unregister a table if it is
188         * dynamically unloaded. The related namespace entries are deleted,
189         * but the table remains in the root table list.
190         *
191         * The assumption here is that the number of different tables that
192         * will be loaded is actually small, and there is minimal overhead
193         * in just keeping the table in case it is needed again.
194         *
195         * If this assumption changes in the future (perhaps on large
196         * machines with many table load/unload operations), tables will
197         * need to be unregistered when they are unloaded, and slots in the
198         * root table list should be reused when empty.
199         */
200
201        /*
202         * Table is already registered.
203         * We can delete the table that was passed as a parameter.
204         */
205        AcpiTbDeleteTable (TableDesc);
206        *TableIndex = i;
207
208        if (AcpiGbl_RootTableList.Tables[i].Flags & ACPI_TABLE_IS_LOADED)
209        {
210            /* Table is still loaded, this is an error */
211
212            Status = AE_ALREADY_EXISTS;
213            goto Release;
214        }
215        else
216        {
217            /* Table was unloaded, allow it to be reloaded */
218
219            TableDesc->Pointer = AcpiGbl_RootTableList.Tables[i].Pointer;
220            TableDesc->Address = AcpiGbl_RootTableList.Tables[i].Address;
221            Status = AE_OK;
222            goto PrintHeader;
223        }
224    }
225
226    /*
227     * ACPI Table Override:
228     * Allow the host to override dynamically loaded tables.
229     */
230    Status = AcpiOsTableOverride (TableDesc->Pointer, &OverrideTable);
231    if (ACPI_SUCCESS (Status) && OverrideTable)
232    {
233        ACPI_INFO ((AE_INFO,
234            "%4.4s @ 0x%p Table override, replaced with:",
235            TableDesc->Pointer->Signature,
236            ACPI_CAST_PTR (void, TableDesc->Address)));
237
238        /* We can delete the table that was passed as a parameter */
239
240        AcpiTbDeleteTable (TableDesc);
241
242        /* Setup descriptor for the new table */
243
244        TableDesc->Address = ACPI_PTR_TO_PHYSADDR (OverrideTable);
245        TableDesc->Pointer = OverrideTable;
246        TableDesc->Length = OverrideTable->Length;
247        TableDesc->Flags = ACPI_TABLE_ORIGIN_OVERRIDE;
248    }
249
250    /* Add the table to the global root table list */
251
252    Status = AcpiTbStoreTable (TableDesc->Address, TableDesc->Pointer,
253                TableDesc->Length, TableDesc->Flags, TableIndex);
254    if (ACPI_FAILURE (Status))
255    {
256        goto Release;
257    }
258
259PrintHeader:
260    AcpiTbPrintTableHeader (TableDesc->Address, TableDesc->Pointer);
261
262Release:
263    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
264    return_ACPI_STATUS (Status);
265}
266
267
268/*******************************************************************************
269 *
270 * FUNCTION:    AcpiTbResizeRootTableList
271 *
272 * PARAMETERS:  None
273 *
274 * RETURN:      Status
275 *
276 * DESCRIPTION: Expand the size of global table array
277 *
278 ******************************************************************************/
279
280ACPI_STATUS
281AcpiTbResizeRootTableList (
282    void)
283{
284    ACPI_TABLE_DESC         *Tables;
285
286
287    ACPI_FUNCTION_TRACE (TbResizeRootTableList);
288
289
290    /* AllowResize flag is a parameter to AcpiInitializeTables */
291
292    if (!(AcpiGbl_RootTableList.Flags & ACPI_ROOT_ALLOW_RESIZE))
293    {
294        ACPI_ERROR ((AE_INFO, "Resize of Root Table Array is not allowed"));
295        return_ACPI_STATUS (AE_SUPPORT);
296    }
297
298    /* Increase the Table Array size */
299
300    Tables = ACPI_ALLOCATE_ZEROED (
301        ((ACPI_SIZE) AcpiGbl_RootTableList.MaxTableCount +
302            ACPI_ROOT_TABLE_SIZE_INCREMENT) *
303        sizeof (ACPI_TABLE_DESC));
304    if (!Tables)
305    {
306        ACPI_ERROR ((AE_INFO, "Could not allocate new root table array"));
307        return_ACPI_STATUS (AE_NO_MEMORY);
308    }
309
310    /* Copy and free the previous table array */
311
312    if (AcpiGbl_RootTableList.Tables)
313    {
314        ACPI_MEMCPY (Tables, AcpiGbl_RootTableList.Tables,
315            (ACPI_SIZE) AcpiGbl_RootTableList.MaxTableCount * sizeof (ACPI_TABLE_DESC));
316
317        if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED)
318        {
319            ACPI_FREE (AcpiGbl_RootTableList.Tables);
320        }
321    }
322
323    AcpiGbl_RootTableList.Tables = Tables;
324    AcpiGbl_RootTableList.MaxTableCount += ACPI_ROOT_TABLE_SIZE_INCREMENT;
325    AcpiGbl_RootTableList.Flags |= (UINT8) ACPI_ROOT_ORIGIN_ALLOCATED;
326
327    return_ACPI_STATUS (AE_OK);
328}
329
330
331/*******************************************************************************
332 *
333 * FUNCTION:    AcpiTbStoreTable
334 *
335 * PARAMETERS:  Address             - Table address
336 *              Table               - Table header
337 *              Length              - Table length
338 *              Flags               - flags
339 *
340 * RETURN:      Status and table index.
341 *
342 * DESCRIPTION: Add an ACPI table to the global table list
343 *
344 ******************************************************************************/
345
346ACPI_STATUS
347AcpiTbStoreTable (
348    ACPI_PHYSICAL_ADDRESS   Address,
349    ACPI_TABLE_HEADER       *Table,
350    UINT32                  Length,
351    UINT8                   Flags,
352    UINT32                  *TableIndex)
353{
354    ACPI_STATUS             Status;
355    ACPI_TABLE_DESC         *NewTable;
356
357
358    /* Ensure that there is room for the table in the Root Table List */
359
360    if (AcpiGbl_RootTableList.CurrentTableCount >=
361        AcpiGbl_RootTableList.MaxTableCount)
362    {
363        Status = AcpiTbResizeRootTableList();
364        if (ACPI_FAILURE (Status))
365        {
366            return (Status);
367        }
368    }
369
370    NewTable = &AcpiGbl_RootTableList.Tables[AcpiGbl_RootTableList.CurrentTableCount];
371
372    /* Initialize added table */
373
374    NewTable->Address = Address;
375    NewTable->Pointer = Table;
376    NewTable->Length = Length;
377    NewTable->OwnerId = 0;
378    NewTable->Flags = Flags;
379
380    ACPI_MOVE_32_TO_32 (&NewTable->Signature, Table->Signature);
381
382    *TableIndex = AcpiGbl_RootTableList.CurrentTableCount;
383    AcpiGbl_RootTableList.CurrentTableCount++;
384    return (AE_OK);
385}
386
387
388/*******************************************************************************
389 *
390 * FUNCTION:    AcpiTbDeleteTable
391 *
392 * PARAMETERS:  TableIndex          - Table index
393 *
394 * RETURN:      None
395 *
396 * DESCRIPTION: Delete one internal ACPI table
397 *
398 ******************************************************************************/
399
400void
401AcpiTbDeleteTable (
402    ACPI_TABLE_DESC         *TableDesc)
403{
404
405    /* Table must be mapped or allocated */
406
407    if (!TableDesc->Pointer)
408    {
409        return;
410    }
411
412    switch (TableDesc->Flags & ACPI_TABLE_ORIGIN_MASK)
413    {
414    case ACPI_TABLE_ORIGIN_MAPPED:
415        AcpiOsUnmapMemory (TableDesc->Pointer, TableDesc->Length);
416        break;
417
418    case ACPI_TABLE_ORIGIN_ALLOCATED:
419        ACPI_FREE (TableDesc->Pointer);
420        break;
421
422    default:
423        break;
424    }
425
426    TableDesc->Pointer = NULL;
427}
428
429
430/*******************************************************************************
431 *
432 * FUNCTION:    AcpiTbTerminate
433 *
434 * PARAMETERS:  None
435 *
436 * RETURN:      None
437 *
438 * DESCRIPTION: Delete all internal ACPI tables
439 *
440 ******************************************************************************/
441
442void
443AcpiTbTerminate (
444    void)
445{
446    UINT32                  i;
447
448
449    ACPI_FUNCTION_TRACE (TbTerminate);
450
451
452    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
453
454    /* Delete the individual tables */
455
456    for (i = 0; i < AcpiGbl_RootTableList.CurrentTableCount; i++)
457    {
458        AcpiTbDeleteTable (&AcpiGbl_RootTableList.Tables[i]);
459    }
460
461    /*
462     * Delete the root table array if allocated locally. Array cannot be
463     * mapped, so we don't need to check for that flag.
464     */
465    if (AcpiGbl_RootTableList.Flags & ACPI_ROOT_ORIGIN_ALLOCATED)
466    {
467        ACPI_FREE (AcpiGbl_RootTableList.Tables);
468    }
469
470    AcpiGbl_RootTableList.Tables = NULL;
471    AcpiGbl_RootTableList.Flags = 0;
472    AcpiGbl_RootTableList.CurrentTableCount = 0;
473
474    ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Tables freed\n"));
475    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
476}
477
478
479/*******************************************************************************
480 *
481 * FUNCTION:    AcpiTbDeleteNamespaceByOwner
482 *
483 * PARAMETERS:  TableIndex          - Table index
484 *
485 * RETURN:      Status
486 *
487 * DESCRIPTION: Delete all namespace objects created when this table was loaded.
488 *
489 ******************************************************************************/
490
491ACPI_STATUS
492AcpiTbDeleteNamespaceByOwner (
493    UINT32                  TableIndex)
494{
495    ACPI_OWNER_ID           OwnerId;
496    ACPI_STATUS             Status;
497
498
499    ACPI_FUNCTION_TRACE (TbDeleteNamespaceByOwner);
500
501
502    Status = AcpiUtAcquireMutex (ACPI_MTX_TABLES);
503    if (ACPI_FAILURE (Status))
504    {
505        return_ACPI_STATUS (Status);
506    }
507
508    if (TableIndex >= AcpiGbl_RootTableList.CurrentTableCount)
509    {
510        /* The table index does not exist */
511
512        (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
513        return_ACPI_STATUS (AE_NOT_EXIST);
514    }
515
516    /* Get the owner ID for this table, used to delete namespace nodes */
517
518    OwnerId = AcpiGbl_RootTableList.Tables[TableIndex].OwnerId;
519    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
520
521    /*
522     * Need to acquire the namespace writer lock to prevent interference
523     * with any concurrent namespace walks. The interpreter must be
524     * released during the deletion since the acquisition of the deletion
525     * lock may block, and also since the execution of a namespace walk
526     * must be allowed to use the interpreter.
527     */
528    (void) AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
529    Status = AcpiUtAcquireWriteLock (&AcpiGbl_NamespaceRwLock);
530
531    AcpiNsDeleteNamespaceByOwner (OwnerId);
532    if (ACPI_FAILURE (Status))
533    {
534        return_ACPI_STATUS (Status);
535    }
536
537    AcpiUtReleaseWriteLock (&AcpiGbl_NamespaceRwLock);
538
539    Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
540    return_ACPI_STATUS (Status);
541}
542
543
544/*******************************************************************************
545 *
546 * FUNCTION:    AcpiTbAllocateOwnerId
547 *
548 * PARAMETERS:  TableIndex          - Table index
549 *
550 * RETURN:      Status
551 *
552 * DESCRIPTION: Allocates OwnerId in TableDesc
553 *
554 ******************************************************************************/
555
556ACPI_STATUS
557AcpiTbAllocateOwnerId (
558    UINT32                  TableIndex)
559{
560    ACPI_STATUS             Status = AE_BAD_PARAMETER;
561
562
563    ACPI_FUNCTION_TRACE (TbAllocateOwnerId);
564
565
566    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
567    if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount)
568    {
569        Status = AcpiUtAllocateOwnerId
570                    (&(AcpiGbl_RootTableList.Tables[TableIndex].OwnerId));
571    }
572
573    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
574    return_ACPI_STATUS (Status);
575}
576
577
578/*******************************************************************************
579 *
580 * FUNCTION:    AcpiTbReleaseOwnerId
581 *
582 * PARAMETERS:  TableIndex          - Table index
583 *
584 * RETURN:      Status
585 *
586 * DESCRIPTION: Releases OwnerId in TableDesc
587 *
588 ******************************************************************************/
589
590ACPI_STATUS
591AcpiTbReleaseOwnerId (
592    UINT32                  TableIndex)
593{
594    ACPI_STATUS             Status = AE_BAD_PARAMETER;
595
596
597    ACPI_FUNCTION_TRACE (TbReleaseOwnerId);
598
599
600    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
601    if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount)
602    {
603        AcpiUtReleaseOwnerId (
604            &(AcpiGbl_RootTableList.Tables[TableIndex].OwnerId));
605        Status = AE_OK;
606    }
607
608    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
609    return_ACPI_STATUS (Status);
610}
611
612
613/*******************************************************************************
614 *
615 * FUNCTION:    AcpiTbGetOwnerId
616 *
617 * PARAMETERS:  TableIndex          - Table index
618 *              OwnerId             - Where the table OwnerId is returned
619 *
620 * RETURN:      Status
621 *
622 * DESCRIPTION: returns OwnerId for the ACPI table
623 *
624 ******************************************************************************/
625
626ACPI_STATUS
627AcpiTbGetOwnerId (
628    UINT32                  TableIndex,
629    ACPI_OWNER_ID           *OwnerId)
630{
631    ACPI_STATUS             Status = AE_BAD_PARAMETER;
632
633
634    ACPI_FUNCTION_TRACE (TbGetOwnerId);
635
636
637    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
638    if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount)
639    {
640        *OwnerId = AcpiGbl_RootTableList.Tables[TableIndex].OwnerId;
641        Status = AE_OK;
642    }
643
644    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
645    return_ACPI_STATUS (Status);
646}
647
648
649/*******************************************************************************
650 *
651 * FUNCTION:    AcpiTbIsTableLoaded
652 *
653 * PARAMETERS:  TableIndex          - Table index
654 *
655 * RETURN:      Table Loaded Flag
656 *
657 ******************************************************************************/
658
659BOOLEAN
660AcpiTbIsTableLoaded (
661    UINT32                  TableIndex)
662{
663    BOOLEAN                 IsLoaded = FALSE;
664
665
666    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
667    if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount)
668    {
669        IsLoaded = (BOOLEAN)
670            (AcpiGbl_RootTableList.Tables[TableIndex].Flags &
671            ACPI_TABLE_IS_LOADED);
672    }
673
674    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
675    return (IsLoaded);
676}
677
678
679/*******************************************************************************
680 *
681 * FUNCTION:    AcpiTbSetTableLoadedFlag
682 *
683 * PARAMETERS:  TableIndex          - Table index
684 *              IsLoaded            - TRUE if table is loaded, FALSE otherwise
685 *
686 * RETURN:      None
687 *
688 * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
689 *
690 ******************************************************************************/
691
692void
693AcpiTbSetTableLoadedFlag (
694    UINT32                  TableIndex,
695    BOOLEAN                 IsLoaded)
696{
697
698    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
699    if (TableIndex < AcpiGbl_RootTableList.CurrentTableCount)
700    {
701        if (IsLoaded)
702        {
703            AcpiGbl_RootTableList.Tables[TableIndex].Flags |=
704                ACPI_TABLE_IS_LOADED;
705        }
706        else
707        {
708            AcpiGbl_RootTableList.Tables[TableIndex].Flags &=
709                ~ACPI_TABLE_IS_LOADED;
710        }
711    }
712
713    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
714}
715
716