exutils.c revision 245582
1/******************************************************************************
2 *
3 * Module Name: exutils - interpreter/scanner utilities
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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 __EXUTILS_C__
45
46/*
47 * DEFINE_AML_GLOBALS is tested in amlcode.h
48 * to determine whether certain global names should be "defined" or only
49 * "declared" in the current compilation. This enhances maintainability
50 * by enabling a single header file to embody all knowledge of the names
51 * in question.
52 *
53 * Exactly one module of any executable should #define DEFINE_GLOBALS
54 * before #including the header files which use this convention. The
55 * names in question will be defined and initialized in that module,
56 * and declared as extern in all other modules which #include those
57 * header files.
58 */
59
60#define DEFINE_AML_GLOBALS
61
62#include <contrib/dev/acpica/include/acpi.h>
63#include <contrib/dev/acpica/include/accommon.h>
64#include <contrib/dev/acpica/include/acinterp.h>
65#include <contrib/dev/acpica/include/amlcode.h>
66
67#define _COMPONENT          ACPI_EXECUTER
68        ACPI_MODULE_NAME    ("exutils")
69
70/* Local prototypes */
71
72static UINT32
73AcpiExDigitsNeeded (
74    UINT64                  Value,
75    UINT32                  Base);
76
77
78#ifndef ACPI_NO_METHOD_EXECUTION
79/*******************************************************************************
80 *
81 * FUNCTION:    AcpiExEnterInterpreter
82 *
83 * PARAMETERS:  None
84 *
85 * RETURN:      None
86 *
87 * DESCRIPTION: Enter the interpreter execution region. Failure to enter
88 *              the interpreter region is a fatal system error. Used in
89 *              conjunction with ExitInterpreter.
90 *
91 ******************************************************************************/
92
93void
94AcpiExEnterInterpreter (
95    void)
96{
97    ACPI_STATUS             Status;
98
99
100    ACPI_FUNCTION_TRACE (ExEnterInterpreter);
101
102
103    Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
104    if (ACPI_FAILURE (Status))
105    {
106        ACPI_ERROR ((AE_INFO, "Could not acquire AML Interpreter mutex"));
107    }
108
109    return_VOID;
110}
111
112
113/*******************************************************************************
114 *
115 * FUNCTION:    AcpiExReacquireInterpreter
116 *
117 * PARAMETERS:  None
118 *
119 * RETURN:      None
120 *
121 * DESCRIPTION: Reacquire the interpreter execution region from within the
122 *              interpreter code. Failure to enter the interpreter region is a
123 *              fatal system error. Used in conjunction with
124 *              RelinquishInterpreter
125 *
126 ******************************************************************************/
127
128void
129AcpiExReacquireInterpreter (
130    void)
131{
132    ACPI_FUNCTION_TRACE (ExReacquireInterpreter);
133
134
135    /*
136     * If the global serialized flag is set, do not release the interpreter,
137     * since it was not actually released by AcpiExRelinquishInterpreter.
138     * This forces the interpreter to be single threaded.
139     */
140    if (!AcpiGbl_AllMethodsSerialized)
141    {
142        AcpiExEnterInterpreter ();
143    }
144
145    return_VOID;
146}
147
148
149/*******************************************************************************
150 *
151 * FUNCTION:    AcpiExExitInterpreter
152 *
153 * PARAMETERS:  None
154 *
155 * RETURN:      None
156 *
157 * DESCRIPTION: Exit the interpreter execution region. This is the top level
158 *              routine used to exit the interpreter when all processing has
159 *              been completed.
160 *
161 ******************************************************************************/
162
163void
164AcpiExExitInterpreter (
165    void)
166{
167    ACPI_STATUS             Status;
168
169
170    ACPI_FUNCTION_TRACE (ExExitInterpreter);
171
172
173    Status = AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
174    if (ACPI_FAILURE (Status))
175    {
176        ACPI_ERROR ((AE_INFO, "Could not release AML Interpreter mutex"));
177    }
178
179    return_VOID;
180}
181
182
183/*******************************************************************************
184 *
185 * FUNCTION:    AcpiExRelinquishInterpreter
186 *
187 * PARAMETERS:  None
188 *
189 * RETURN:      None
190 *
191 * DESCRIPTION: Exit the interpreter execution region, from within the
192 *              interpreter - before attempting an operation that will possibly
193 *              block the running thread.
194 *
195 * Cases where the interpreter is unlocked internally
196 *      1) Method to be blocked on a Sleep() AML opcode
197 *      2) Method to be blocked on an Acquire() AML opcode
198 *      3) Method to be blocked on a Wait() AML opcode
199 *      4) Method to be blocked to acquire the global lock
200 *      5) Method to be blocked waiting to execute a serialized control method
201 *          that is currently executing
202 *      6) About to invoke a user-installed opregion handler
203 *
204 ******************************************************************************/
205
206void
207AcpiExRelinquishInterpreter (
208    void)
209{
210    ACPI_FUNCTION_TRACE (ExRelinquishInterpreter);
211
212
213    /*
214     * If the global serialized flag is set, do not release the interpreter.
215     * This forces the interpreter to be single threaded.
216     */
217    if (!AcpiGbl_AllMethodsSerialized)
218    {
219        AcpiExExitInterpreter ();
220    }
221
222    return_VOID;
223}
224
225
226/*******************************************************************************
227 *
228 * FUNCTION:    AcpiExTruncateFor32bitTable
229 *
230 * PARAMETERS:  ObjDesc         - Object to be truncated
231 *
232 * RETURN:      TRUE if a truncation was performed, FALSE otherwise.
233 *
234 * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
235 *              32-bit, as determined by the revision of the DSDT.
236 *
237 ******************************************************************************/
238
239BOOLEAN
240AcpiExTruncateFor32bitTable (
241    ACPI_OPERAND_OBJECT     *ObjDesc)
242{
243
244    ACPI_FUNCTION_ENTRY ();
245
246
247    /*
248     * Object must be a valid number and we must be executing
249     * a control method. Object could be NS node for AML_INT_NAMEPATH_OP.
250     */
251    if ((!ObjDesc) ||
252        (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) ||
253        (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
254    {
255        return (FALSE);
256    }
257
258    if ((AcpiGbl_IntegerByteWidth == 4) &&
259        (ObjDesc->Integer.Value > (UINT64) ACPI_UINT32_MAX))
260    {
261        /*
262         * We are executing in a 32-bit ACPI table.
263         * Truncate the value to 32 bits by zeroing out the upper 32-bit field
264         */
265        ObjDesc->Integer.Value &= (UINT64) ACPI_UINT32_MAX;
266        return (TRUE);
267    }
268
269    return (FALSE);
270}
271
272
273/*******************************************************************************
274 *
275 * FUNCTION:    AcpiExAcquireGlobalLock
276 *
277 * PARAMETERS:  FieldFlags            - Flags with Lock rule:
278 *                                      AlwaysLock or NeverLock
279 *
280 * RETURN:      None
281 *
282 * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
283 *              flags specifiy that it is to be obtained before field access.
284 *
285 ******************************************************************************/
286
287void
288AcpiExAcquireGlobalLock (
289    UINT32                  FieldFlags)
290{
291    ACPI_STATUS             Status;
292
293
294    ACPI_FUNCTION_TRACE (ExAcquireGlobalLock);
295
296
297    /* Only use the lock if the AlwaysLock bit is set */
298
299    if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
300    {
301        return_VOID;
302    }
303
304    /* Attempt to get the global lock, wait forever */
305
306    Status = AcpiExAcquireMutexObject (ACPI_WAIT_FOREVER,
307                AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
308
309    if (ACPI_FAILURE (Status))
310    {
311        ACPI_EXCEPTION ((AE_INFO, Status,
312            "Could not acquire Global Lock"));
313    }
314
315    return_VOID;
316}
317
318
319/*******************************************************************************
320 *
321 * FUNCTION:    AcpiExReleaseGlobalLock
322 *
323 * PARAMETERS:  FieldFlags            - Flags with Lock rule:
324 *                                      AlwaysLock or NeverLock
325 *
326 * RETURN:      None
327 *
328 * DESCRIPTION: Release the ACPI hardware Global Lock
329 *
330 ******************************************************************************/
331
332void
333AcpiExReleaseGlobalLock (
334    UINT32                  FieldFlags)
335{
336    ACPI_STATUS             Status;
337
338
339    ACPI_FUNCTION_TRACE (ExReleaseGlobalLock);
340
341
342    /* Only use the lock if the AlwaysLock bit is set */
343
344    if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
345    {
346        return_VOID;
347    }
348
349    /* Release the global lock */
350
351    Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
352    if (ACPI_FAILURE (Status))
353    {
354        /* Report the error, but there isn't much else we can do */
355
356        ACPI_EXCEPTION ((AE_INFO, Status,
357            "Could not release Global Lock"));
358    }
359
360    return_VOID;
361}
362
363
364/*******************************************************************************
365 *
366 * FUNCTION:    AcpiExDigitsNeeded
367 *
368 * PARAMETERS:  Value           - Value to be represented
369 *              Base            - Base of representation
370 *
371 * RETURN:      The number of digits.
372 *
373 * DESCRIPTION: Calculate the number of digits needed to represent the Value
374 *              in the given Base (Radix)
375 *
376 ******************************************************************************/
377
378static UINT32
379AcpiExDigitsNeeded (
380    UINT64                  Value,
381    UINT32                  Base)
382{
383    UINT32                  NumDigits;
384    UINT64                  CurrentValue;
385
386
387    ACPI_FUNCTION_TRACE (ExDigitsNeeded);
388
389
390    /* UINT64 is unsigned, so we don't worry about a '-' prefix */
391
392    if (Value == 0)
393    {
394        return_VALUE (1);
395    }
396
397    CurrentValue = Value;
398    NumDigits = 0;
399
400    /* Count the digits in the requested base */
401
402    while (CurrentValue)
403    {
404        (void) AcpiUtShortDivide (CurrentValue, Base, &CurrentValue, NULL);
405        NumDigits++;
406    }
407
408    return_VALUE (NumDigits);
409}
410
411
412/*******************************************************************************
413 *
414 * FUNCTION:    AcpiExEisaIdToString
415 *
416 * PARAMETERS:  CompressedId    - EISAID to be converted
417 *              OutString       - Where to put the converted string (8 bytes)
418 *
419 * RETURN:      None
420 *
421 * DESCRIPTION: Convert a numeric EISAID to string representation. Return
422 *              buffer must be large enough to hold the string. The string
423 *              returned is always exactly of length ACPI_EISAID_STRING_SIZE
424 *              (includes null terminator). The EISAID is always 32 bits.
425 *
426 ******************************************************************************/
427
428void
429AcpiExEisaIdToString (
430    char                    *OutString,
431    UINT64                  CompressedId)
432{
433    UINT32                  SwappedId;
434
435
436    ACPI_FUNCTION_ENTRY ();
437
438
439    /* The EISAID should be a 32-bit integer */
440
441    if (CompressedId > ACPI_UINT32_MAX)
442    {
443        ACPI_WARNING ((AE_INFO,
444            "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating",
445            ACPI_FORMAT_UINT64 (CompressedId)));
446    }
447
448    /* Swap ID to big-endian to get contiguous bits */
449
450    SwappedId = AcpiUtDwordByteSwap ((UINT32) CompressedId);
451
452    /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */
453
454    OutString[0] = (char) (0x40 + (((unsigned long) SwappedId >> 26) & 0x1F));
455    OutString[1] = (char) (0x40 + ((SwappedId >> 21) & 0x1F));
456    OutString[2] = (char) (0x40 + ((SwappedId >> 16) & 0x1F));
457    OutString[3] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 12);
458    OutString[4] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 8);
459    OutString[5] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 4);
460    OutString[6] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 0);
461    OutString[7] = 0;
462}
463
464
465/*******************************************************************************
466 *
467 * FUNCTION:    AcpiExIntegerToString
468 *
469 * PARAMETERS:  OutString       - Where to put the converted string. At least
470 *                                21 bytes are needed to hold the largest
471 *                                possible 64-bit integer.
472 *              Value           - Value to be converted
473 *
474 * RETURN:      None, string
475 *
476 * DESCRIPTION: Convert a 64-bit integer to decimal string representation.
477 *              Assumes string buffer is large enough to hold the string. The
478 *              largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1).
479 *
480 ******************************************************************************/
481
482void
483AcpiExIntegerToString (
484    char                    *OutString,
485    UINT64                  Value)
486{
487    UINT32                  Count;
488    UINT32                  DigitsNeeded;
489    UINT32                  Remainder;
490
491
492    ACPI_FUNCTION_ENTRY ();
493
494
495    DigitsNeeded = AcpiExDigitsNeeded (Value, 10);
496    OutString[DigitsNeeded] = 0;
497
498    for (Count = DigitsNeeded; Count > 0; Count--)
499    {
500        (void) AcpiUtShortDivide (Value, 10, &Value, &Remainder);
501        OutString[Count-1] = (char) ('0' + Remainder);\
502    }
503}
504
505
506/*******************************************************************************
507 *
508 * FUNCTION:    AcpiIsValidSpaceId
509 *
510 * PARAMETERS:  SpaceId             - ID to be validated
511 *
512 * RETURN:      TRUE if valid/supported ID.
513 *
514 * DESCRIPTION: Validate an operation region SpaceID.
515 *
516 ******************************************************************************/
517
518BOOLEAN
519AcpiIsValidSpaceId (
520    UINT8                   SpaceId)
521{
522
523    if ((SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) &&
524        (SpaceId < ACPI_USER_REGION_BEGIN) &&
525        (SpaceId != ACPI_ADR_SPACE_DATA_TABLE) &&
526        (SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE))
527    {
528        return (FALSE);
529    }
530
531    return (TRUE);
532}
533
534
535#endif
536