xref: /titanic_50/usr/src/uts/intel/io/acpica/executer/exutils.c (revision 45405cce0657d01714b3d014a0facf3bdce45736)
1 
2 /******************************************************************************
3  *
4  * Module Name: exutils - interpreter/scanner utilities
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2011, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #define __EXUTILS_C__
46 
47 /*
48  * DEFINE_AML_GLOBALS is tested in amlcode.h
49  * to determine whether certain global names should be "defined" or only
50  * "declared" in the current compilation.  This enhances maintainability
51  * by enabling a single header file to embody all knowledge of the names
52  * in question.
53  *
54  * Exactly one module of any executable should #define DEFINE_GLOBALS
55  * before #including the header files which use this convention.  The
56  * names in question will be defined and initialized in that module,
57  * and declared as extern in all other modules which #include those
58  * header files.
59  */
60 
61 #define DEFINE_AML_GLOBALS
62 
63 #include "acpi.h"
64 #include "accommon.h"
65 #include "acinterp.h"
66 #include "amlcode.h"
67 
68 #define _COMPONENT          ACPI_EXECUTER
69         ACPI_MODULE_NAME    ("exutils")
70 
71 /* Local prototypes */
72 
73 static UINT32
74 AcpiExDigitsNeeded (
75     UINT64                  Value,
76     UINT32                  Base);
77 
78 
79 #ifndef ACPI_NO_METHOD_EXECUTION
80 /*******************************************************************************
81  *
82  * FUNCTION:    AcpiExEnterInterpreter
83  *
84  * PARAMETERS:  None
85  *
86  * RETURN:      None
87  *
88  * DESCRIPTION: Enter the interpreter execution region. Failure to enter
89  *              the interpreter region is a fatal system error. Used in
90  *              conjunction with ExitInterpreter.
91  *
92  ******************************************************************************/
93 
94 void
95 AcpiExEnterInterpreter (
96     void)
97 {
98     ACPI_STATUS             Status;
99 
100 
101     ACPI_FUNCTION_TRACE (ExEnterInterpreter);
102 
103 
104     Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
105     if (ACPI_FAILURE (Status))
106     {
107         ACPI_ERROR ((AE_INFO, "Could not acquire AML Interpreter mutex"));
108     }
109 
110     return_VOID;
111 }
112 
113 
114 /*******************************************************************************
115  *
116  * FUNCTION:    AcpiExReacquireInterpreter
117  *
118  * PARAMETERS:  None
119  *
120  * RETURN:      None
121  *
122  * DESCRIPTION: Reacquire the interpreter execution region from within the
123  *              interpreter code. Failure to enter the interpreter region is a
124  *              fatal system error. Used in  conjuction with
125  *              RelinquishInterpreter
126  *
127  ******************************************************************************/
128 
129 void
130 AcpiExReacquireInterpreter (
131     void)
132 {
133     ACPI_FUNCTION_TRACE (ExReacquireInterpreter);
134 
135 
136     /*
137      * If the global serialized flag is set, do not release the interpreter,
138      * since it was not actually released by AcpiExRelinquishInterpreter.
139      * This forces the interpreter to be single threaded.
140      */
141     if (!AcpiGbl_AllMethodsSerialized)
142     {
143         AcpiExEnterInterpreter ();
144     }
145 
146     return_VOID;
147 }
148 
149 
150 /*******************************************************************************
151  *
152  * FUNCTION:    AcpiExExitInterpreter
153  *
154  * PARAMETERS:  None
155  *
156  * RETURN:      None
157  *
158  * DESCRIPTION: Exit the interpreter execution region. This is the top level
159  *              routine used to exit the interpreter when all processing has
160  *              been completed.
161  *
162  ******************************************************************************/
163 
164 void
165 AcpiExExitInterpreter (
166     void)
167 {
168     ACPI_STATUS             Status;
169 
170 
171     ACPI_FUNCTION_TRACE (ExExitInterpreter);
172 
173 
174     Status = AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
175     if (ACPI_FAILURE (Status))
176     {
177         ACPI_ERROR ((AE_INFO, "Could not release AML Interpreter mutex"));
178     }
179 
180     return_VOID;
181 }
182 
183 
184 /*******************************************************************************
185  *
186  * FUNCTION:    AcpiExRelinquishInterpreter
187  *
188  * PARAMETERS:  None
189  *
190  * RETURN:      None
191  *
192  * DESCRIPTION: Exit the interpreter execution region, from within the
193  *              interpreter - before attempting an operation that will possibly
194  *              block the running thread.
195  *
196  * Cases where the interpreter is unlocked internally
197  *      1) Method to be blocked on a Sleep() AML opcode
198  *      2) Method to be blocked on an Acquire() AML opcode
199  *      3) Method to be blocked on a Wait() AML opcode
200  *      4) Method to be blocked to acquire the global lock
201  *      5) Method to be blocked waiting to execute a serialized control method
202  *          that is currently executing
203  *      6) About to invoke a user-installed opregion handler
204  *
205  ******************************************************************************/
206 
207 void
208 AcpiExRelinquishInterpreter (
209     void)
210 {
211     ACPI_FUNCTION_TRACE (ExRelinquishInterpreter);
212 
213 
214     /*
215      * If the global serialized flag is set, do not release the interpreter.
216      * This forces the interpreter to be single threaded.
217      */
218     if (!AcpiGbl_AllMethodsSerialized)
219     {
220         AcpiExExitInterpreter ();
221     }
222 
223     return_VOID;
224 }
225 
226 
227 /*******************************************************************************
228  *
229  * FUNCTION:    AcpiExTruncateFor32bitTable
230  *
231  * PARAMETERS:  ObjDesc         - Object to be truncated
232  *
233  * RETURN:      none
234  *
235  * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
236  *              32-bit, as determined by the revision of the DSDT.
237  *
238  ******************************************************************************/
239 
240 void
241 AcpiExTruncateFor32bitTable (
242     ACPI_OPERAND_OBJECT     *ObjDesc)
243 {
244 
245     ACPI_FUNCTION_ENTRY ();
246 
247 
248     /*
249      * Object must be a valid number and we must be executing
250      * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
251      */
252     if ((!ObjDesc) ||
253         (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) ||
254         (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
255     {
256         return;
257     }
258 
259     if (AcpiGbl_IntegerByteWidth == 4)
260     {
261         /*
262          * We are running a method that exists 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     }
267 }
268 
269 
270 /*******************************************************************************
271  *
272  * FUNCTION:    AcpiExAcquireGlobalLock
273  *
274  * PARAMETERS:  FieldFlags            - Flags with Lock rule:
275  *                                      AlwaysLock or NeverLock
276  *
277  * RETURN:      None
278  *
279  * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
280  *              flags specifiy that it is to be obtained before field access.
281  *
282  ******************************************************************************/
283 
284 void
285 AcpiExAcquireGlobalLock (
286     UINT32                  FieldFlags)
287 {
288     ACPI_STATUS             Status;
289 
290 
291     ACPI_FUNCTION_TRACE (ExAcquireGlobalLock);
292 
293 
294     /* Only use the lock if the AlwaysLock bit is set */
295 
296     if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
297     {
298         return_VOID;
299     }
300 
301     /* Attempt to get the global lock, wait forever */
302 
303     Status = AcpiExAcquireMutexObject (ACPI_WAIT_FOREVER,
304                 AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
305 
306     if (ACPI_FAILURE (Status))
307     {
308         ACPI_EXCEPTION ((AE_INFO, Status,
309             "Could not acquire Global Lock"));
310     }
311 
312     return_VOID;
313 }
314 
315 
316 /*******************************************************************************
317  *
318  * FUNCTION:    AcpiExReleaseGlobalLock
319  *
320  * PARAMETERS:  FieldFlags            - Flags with Lock rule:
321  *                                      AlwaysLock or NeverLock
322  *
323  * RETURN:      None
324  *
325  * DESCRIPTION: Release the ACPI hardware Global Lock
326  *
327  ******************************************************************************/
328 
329 void
330 AcpiExReleaseGlobalLock (
331     UINT32                  FieldFlags)
332 {
333     ACPI_STATUS             Status;
334 
335 
336     ACPI_FUNCTION_TRACE (ExReleaseGlobalLock);
337 
338 
339     /* Only use the lock if the AlwaysLock bit is set */
340 
341     if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
342     {
343         return_VOID;
344     }
345 
346     /* Release the global lock */
347 
348     Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
349     if (ACPI_FAILURE (Status))
350     {
351         /* Report the error, but there isn't much else we can do */
352 
353         ACPI_EXCEPTION ((AE_INFO, Status,
354             "Could not release Global Lock"));
355     }
356 
357     return_VOID;
358 }
359 
360 
361 /*******************************************************************************
362  *
363  * FUNCTION:    AcpiExDigitsNeeded
364  *
365  * PARAMETERS:  Value           - Value to be represented
366  *              Base            - Base of representation
367  *
368  * RETURN:      The number of digits.
369  *
370  * DESCRIPTION: Calculate the number of digits needed to represent the Value
371  *              in the given Base (Radix)
372  *
373  ******************************************************************************/
374 
375 static UINT32
376 AcpiExDigitsNeeded (
377     UINT64                  Value,
378     UINT32                  Base)
379 {
380     UINT32                  NumDigits;
381     UINT64                  CurrentValue;
382 
383 
384     ACPI_FUNCTION_TRACE (ExDigitsNeeded);
385 
386 
387     /* UINT64 is unsigned, so we don't worry about a '-' prefix */
388 
389     if (Value == 0)
390     {
391         return_UINT32 (1);
392     }
393 
394     CurrentValue = Value;
395     NumDigits = 0;
396 
397     /* Count the digits in the requested base */
398 
399     while (CurrentValue)
400     {
401         (void) AcpiUtShortDivide (CurrentValue, Base, &CurrentValue, NULL);
402         NumDigits++;
403     }
404 
405     return_UINT32 (NumDigits);
406 }
407 
408 
409 /*******************************************************************************
410  *
411  * FUNCTION:    AcpiExEisaIdToString
412  *
413  * PARAMETERS:  CompressedId    - EISAID to be converted
414  *              OutString       - Where to put the converted string (8 bytes)
415  *
416  * RETURN:      None
417  *
418  * DESCRIPTION: Convert a numeric EISAID to string representation. Return
419  *              buffer must be large enough to hold the string. The string
420  *              returned is always exactly of length ACPI_EISAID_STRING_SIZE
421  *              (includes null terminator). The EISAID is always 32 bits.
422  *
423  ******************************************************************************/
424 
425 void
426 AcpiExEisaIdToString (
427     char                    *OutString,
428     UINT64                  CompressedId)
429 {
430     UINT32                  SwappedId;
431 
432 
433     ACPI_FUNCTION_ENTRY ();
434 
435 
436     /* The EISAID should be a 32-bit integer */
437 
438     if (CompressedId > ACPI_UINT32_MAX)
439     {
440         ACPI_WARNING ((AE_INFO,
441             "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating",
442             ACPI_FORMAT_UINT64 (CompressedId)));
443     }
444 
445     /* Swap ID to big-endian to get contiguous bits */
446 
447     SwappedId = AcpiUtDwordByteSwap ((UINT32) CompressedId);
448 
449     /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */
450 
451     OutString[0] = (char) (0x40 + (((unsigned long) SwappedId >> 26) & 0x1F));
452     OutString[1] = (char) (0x40 + ((SwappedId >> 21) & 0x1F));
453     OutString[2] = (char) (0x40 + ((SwappedId >> 16) & 0x1F));
454     OutString[3] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 12);
455     OutString[4] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 8);
456     OutString[5] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 4);
457     OutString[6] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 0);
458     OutString[7] = 0;
459 }
460 
461 
462 /*******************************************************************************
463  *
464  * FUNCTION:    AcpiExIntegerToString
465  *
466  * PARAMETERS:  OutString       - Where to put the converted string. At least
467  *                                21 bytes are needed to hold the largest
468  *                                possible 64-bit integer.
469  *              Value           - Value to be converted
470  *
471  * RETURN:      None, string
472  *
473  * DESCRIPTION: Convert a 64-bit integer to decimal string representation.
474  *              Assumes string buffer is large enough to hold the string. The
475  *              largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1).
476  *
477  ******************************************************************************/
478 
479 void
480 AcpiExIntegerToString (
481     char                    *OutString,
482     UINT64                  Value)
483 {
484     UINT32                  Count;
485     UINT32                  DigitsNeeded;
486     UINT32                  Remainder;
487 
488 
489     ACPI_FUNCTION_ENTRY ();
490 
491 
492     DigitsNeeded = AcpiExDigitsNeeded (Value, 10);
493     OutString[DigitsNeeded] = 0;
494 
495     for (Count = DigitsNeeded; Count > 0; Count--)
496     {
497         (void) AcpiUtShortDivide (Value, 10, &Value, &Remainder);
498         OutString[Count-1] = (char) ('0' + Remainder);\
499     }
500 }
501 
502 #endif
503