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