xref: /freebsd/sys/contrib/dev/acpica/components/executer/exutils.c (revision 9268022b74279434ed6300244e3f977e56a8ceb5)
1 /******************************************************************************
2  *
3  * Module Name: exutils - interpreter/scanner utilities
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 __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 
72 static UINT32
73 AcpiExDigitsNeeded (
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 
93 void
94 AcpiExEnterInterpreter (
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:    AcpiExExitInterpreter
116  *
117  * PARAMETERS:  None
118  *
119  * RETURN:      None
120  *
121  * DESCRIPTION: Exit the interpreter execution region. This is the top level
122  *              routine used to exit the interpreter when all processing has
123  *              been completed, or when the method blocks.
124  *
125  * Cases where the interpreter is unlocked internally:
126  *      1) Method will be blocked on a Sleep() AML opcode
127  *      2) Method will be blocked on an Acquire() AML opcode
128  *      3) Method will be blocked on a Wait() AML opcode
129  *      4) Method will be blocked to acquire the global lock
130  *      5) Method will be blocked waiting to execute a serialized control
131  *          method that is currently executing
132  *      6) About to invoke a user-installed opregion handler
133  *
134  ******************************************************************************/
135 
136 void
137 AcpiExExitInterpreter (
138     void)
139 {
140     ACPI_STATUS             Status;
141 
142 
143     ACPI_FUNCTION_TRACE (ExExitInterpreter);
144 
145 
146     Status = AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
147     if (ACPI_FAILURE (Status))
148     {
149         ACPI_ERROR ((AE_INFO, "Could not release AML Interpreter mutex"));
150     }
151 
152     return_VOID;
153 }
154 
155 
156 /*******************************************************************************
157  *
158  * FUNCTION:    AcpiExTruncateFor32bitTable
159  *
160  * PARAMETERS:  ObjDesc         - Object to be truncated
161  *
162  * RETURN:      TRUE if a truncation was performed, FALSE otherwise.
163  *
164  * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
165  *              32-bit, as determined by the revision of the DSDT.
166  *
167  ******************************************************************************/
168 
169 BOOLEAN
170 AcpiExTruncateFor32bitTable (
171     ACPI_OPERAND_OBJECT     *ObjDesc)
172 {
173 
174     ACPI_FUNCTION_ENTRY ();
175 
176 
177     /*
178      * Object must be a valid number and we must be executing
179      * a control method. Object could be NS node for AML_INT_NAMEPATH_OP.
180      */
181     if ((!ObjDesc) ||
182         (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) ||
183         (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
184     {
185         return (FALSE);
186     }
187 
188     if ((AcpiGbl_IntegerByteWidth == 4) &&
189         (ObjDesc->Integer.Value > (UINT64) ACPI_UINT32_MAX))
190     {
191         /*
192          * We are executing in a 32-bit ACPI table.
193          * Truncate the value to 32 bits by zeroing out the upper 32-bit field
194          */
195         ObjDesc->Integer.Value &= (UINT64) ACPI_UINT32_MAX;
196         return (TRUE);
197     }
198 
199     return (FALSE);
200 }
201 
202 
203 /*******************************************************************************
204  *
205  * FUNCTION:    AcpiExAcquireGlobalLock
206  *
207  * PARAMETERS:  FieldFlags            - Flags with Lock rule:
208  *                                      AlwaysLock or NeverLock
209  *
210  * RETURN:      None
211  *
212  * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
213  *              flags specifiy that it is to be obtained before field access.
214  *
215  ******************************************************************************/
216 
217 void
218 AcpiExAcquireGlobalLock (
219     UINT32                  FieldFlags)
220 {
221     ACPI_STATUS             Status;
222 
223 
224     ACPI_FUNCTION_TRACE (ExAcquireGlobalLock);
225 
226 
227     /* Only use the lock if the AlwaysLock bit is set */
228 
229     if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
230     {
231         return_VOID;
232     }
233 
234     /* Attempt to get the global lock, wait forever */
235 
236     Status = AcpiExAcquireMutexObject (ACPI_WAIT_FOREVER,
237                 AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
238 
239     if (ACPI_FAILURE (Status))
240     {
241         ACPI_EXCEPTION ((AE_INFO, Status,
242             "Could not acquire Global Lock"));
243     }
244 
245     return_VOID;
246 }
247 
248 
249 /*******************************************************************************
250  *
251  * FUNCTION:    AcpiExReleaseGlobalLock
252  *
253  * PARAMETERS:  FieldFlags            - Flags with Lock rule:
254  *                                      AlwaysLock or NeverLock
255  *
256  * RETURN:      None
257  *
258  * DESCRIPTION: Release the ACPI hardware Global Lock
259  *
260  ******************************************************************************/
261 
262 void
263 AcpiExReleaseGlobalLock (
264     UINT32                  FieldFlags)
265 {
266     ACPI_STATUS             Status;
267 
268 
269     ACPI_FUNCTION_TRACE (ExReleaseGlobalLock);
270 
271 
272     /* Only use the lock if the AlwaysLock bit is set */
273 
274     if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
275     {
276         return_VOID;
277     }
278 
279     /* Release the global lock */
280 
281     Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
282     if (ACPI_FAILURE (Status))
283     {
284         /* Report the error, but there isn't much else we can do */
285 
286         ACPI_EXCEPTION ((AE_INFO, Status,
287             "Could not release Global Lock"));
288     }
289 
290     return_VOID;
291 }
292 
293 
294 /*******************************************************************************
295  *
296  * FUNCTION:    AcpiExDigitsNeeded
297  *
298  * PARAMETERS:  Value           - Value to be represented
299  *              Base            - Base of representation
300  *
301  * RETURN:      The number of digits.
302  *
303  * DESCRIPTION: Calculate the number of digits needed to represent the Value
304  *              in the given Base (Radix)
305  *
306  ******************************************************************************/
307 
308 static UINT32
309 AcpiExDigitsNeeded (
310     UINT64                  Value,
311     UINT32                  Base)
312 {
313     UINT32                  NumDigits;
314     UINT64                  CurrentValue;
315 
316 
317     ACPI_FUNCTION_TRACE (ExDigitsNeeded);
318 
319 
320     /* UINT64 is unsigned, so we don't worry about a '-' prefix */
321 
322     if (Value == 0)
323     {
324         return_UINT32 (1);
325     }
326 
327     CurrentValue = Value;
328     NumDigits = 0;
329 
330     /* Count the digits in the requested base */
331 
332     while (CurrentValue)
333     {
334         (void) AcpiUtShortDivide (CurrentValue, Base, &CurrentValue, NULL);
335         NumDigits++;
336     }
337 
338     return_UINT32 (NumDigits);
339 }
340 
341 
342 /*******************************************************************************
343  *
344  * FUNCTION:    AcpiExEisaIdToString
345  *
346  * PARAMETERS:  CompressedId    - EISAID to be converted
347  *              OutString       - Where to put the converted string (8 bytes)
348  *
349  * RETURN:      None
350  *
351  * DESCRIPTION: Convert a numeric EISAID to string representation. Return
352  *              buffer must be large enough to hold the string. The string
353  *              returned is always exactly of length ACPI_EISAID_STRING_SIZE
354  *              (includes null terminator). The EISAID is always 32 bits.
355  *
356  ******************************************************************************/
357 
358 void
359 AcpiExEisaIdToString (
360     char                    *OutString,
361     UINT64                  CompressedId)
362 {
363     UINT32                  SwappedId;
364 
365 
366     ACPI_FUNCTION_ENTRY ();
367 
368 
369     /* The EISAID should be a 32-bit integer */
370 
371     if (CompressedId > ACPI_UINT32_MAX)
372     {
373         ACPI_WARNING ((AE_INFO,
374             "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating",
375             ACPI_FORMAT_UINT64 (CompressedId)));
376     }
377 
378     /* Swap ID to big-endian to get contiguous bits */
379 
380     SwappedId = AcpiUtDwordByteSwap ((UINT32) CompressedId);
381 
382     /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */
383 
384     OutString[0] = (char) (0x40 + (((unsigned long) SwappedId >> 26) & 0x1F));
385     OutString[1] = (char) (0x40 + ((SwappedId >> 21) & 0x1F));
386     OutString[2] = (char) (0x40 + ((SwappedId >> 16) & 0x1F));
387     OutString[3] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 12);
388     OutString[4] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 8);
389     OutString[5] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 4);
390     OutString[6] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 0);
391     OutString[7] = 0;
392 }
393 
394 
395 /*******************************************************************************
396  *
397  * FUNCTION:    AcpiExIntegerToString
398  *
399  * PARAMETERS:  OutString       - Where to put the converted string. At least
400  *                                21 bytes are needed to hold the largest
401  *                                possible 64-bit integer.
402  *              Value           - Value to be converted
403  *
404  * RETURN:      None, string
405  *
406  * DESCRIPTION: Convert a 64-bit integer to decimal string representation.
407  *              Assumes string buffer is large enough to hold the string. The
408  *              largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1).
409  *
410  ******************************************************************************/
411 
412 void
413 AcpiExIntegerToString (
414     char                    *OutString,
415     UINT64                  Value)
416 {
417     UINT32                  Count;
418     UINT32                  DigitsNeeded;
419     UINT32                  Remainder;
420 
421 
422     ACPI_FUNCTION_ENTRY ();
423 
424 
425     DigitsNeeded = AcpiExDigitsNeeded (Value, 10);
426     OutString[DigitsNeeded] = 0;
427 
428     for (Count = DigitsNeeded; Count > 0; Count--)
429     {
430         (void) AcpiUtShortDivide (Value, 10, &Value, &Remainder);
431         OutString[Count-1] = (char) ('0' + Remainder);\
432     }
433 }
434 
435 
436 /*******************************************************************************
437  *
438  * FUNCTION:    AcpiIsValidSpaceId
439  *
440  * PARAMETERS:  SpaceId             - ID to be validated
441  *
442  * RETURN:      TRUE if valid/supported ID.
443  *
444  * DESCRIPTION: Validate an operation region SpaceID.
445  *
446  ******************************************************************************/
447 
448 BOOLEAN
449 AcpiIsValidSpaceId (
450     UINT8                   SpaceId)
451 {
452 
453     if ((SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) &&
454         (SpaceId < ACPI_USER_REGION_BEGIN) &&
455         (SpaceId != ACPI_ADR_SPACE_DATA_TABLE) &&
456         (SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE))
457     {
458         return (FALSE);
459     }
460 
461     return (TRUE);
462 }
463 
464 
465 #endif
466