VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/acpi/acpi-compiler.cpp@ 108059

Last change on this file since 108059 was 108059, checked in by vboxsync, 3 weeks ago

Runtime/RTAcpi*: Updates to the ACPI ASL -> AML compiler, bugref:10733

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.4 KB
Line 
1/* $Id: acpi-compiler.cpp 108059 2025-02-04 13:35:41Z vboxsync $ */
2/** @file
3 * IPRT - Advanced Configuration and Power Interface (ACPI) Table generation API.
4 */
5
6/*
7 * Copyright (C) 2025 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_ACPI
42#include <iprt/acpi.h>
43#include <iprt/asm.h>
44#include <iprt/buildconfig.h>
45#include <iprt/ctype.h>
46#include <iprt/err.h>
47#include <iprt/file.h>
48#include <iprt/list.h>
49#include <iprt/mem.h>
50#include <iprt/script.h>
51#include <iprt/string.h>
52#include <iprt/uuid.h>
53
54#include <iprt/formats/acpi-aml.h>
55#include <iprt/formats/acpi-resources.h>
56
57#include "internal/acpi.h"
58
59
60/*********************************************************************************************************************************
61* Defined Constants And Macros *
62*********************************************************************************************************************************/
63
64
65/*********************************************************************************************************************************
66* Structures and Typedefs *
67*********************************************************************************************************************************/
68
69/**
70 * Terminals in the ACPI ASL lnaguage like keywords, operators and punctuators.
71 */
72typedef enum RTACPIASLTERMINAL
73{
74 RTACPIASLTERMINAL_INVALID = 2047,
75
76 /** Miscelleanous keywords not appearing in the parser table. */
77 RTACPIASLTERMINAL_KEYWORD_DEFINITION_BLOCK,
78 RTACPIASLTERMINAL_KEYWORD_UNKNOWN_OBJ,
79 RTACPIASLTERMINAL_KEYWORD_INT_OBJ,
80 RTACPIASLTERMINAL_KEYWORD_STR_OBJ,
81 RTACPIASLTERMINAL_KEYWORD_BUFF_OBJ,
82 RTACPIASLTERMINAL_KEYWORD_PKG_OBJ,
83 RTACPIASLTERMINAL_KEYWORD_FIELD_UNIT_OBJ,
84 RTACPIASLTERMINAL_KEYWORD_DEVICE_OBJ,
85 RTACPIASLTERMINAL_KEYWORD_EVENT_OBJ,
86 RTACPIASLTERMINAL_KEYWORD_METHOD_OBJ,
87 RTACPIASLTERMINAL_KEYWORD_MUTEX_OBJ,
88 RTACPIASLTERMINAL_KEYWORD_OP_REGION_OBJ,
89 RTACPIASLTERMINAL_KEYWORD_POWER_RES_OBJ,
90 RTACPIASLTERMINAL_KEYWORD_THERMAL_ZONE_OBJ,
91 RTACPIASLTERMINAL_KEYWORD_BUFF_FIELD_OBJ,
92 RTACPIASLTERMINAL_KEYWORD_SERIALIZED,
93 RTACPIASLTERMINAL_KEYWORD_NOT_SERIALIZED,
94 RTACPIASLTERMINAL_KEYWORD_SYSTEM_IO,
95 RTACPIASLTERMINAL_KEYWORD_SYSTEM_MEMORY,
96 RTACPIASLTERMINAL_KEYWORD_PCI_CONFIG,
97 RTACPIASLTERMINAL_KEYWORD_EMBEDDED_CONTROL,
98 RTACPIASLTERMINAL_KEYWORD_SMBUS,
99 RTACPIASLTERMINAL_KEYWORD_SYSTEM_CMOS,
100 RTACPIASLTERMINAL_KEYWORD_PCI_BAR_TARGET,
101 RTACPIASLTERMINAL_KEYWORD_IPMI,
102 RTACPIASLTERMINAL_KEYWORD_GENERAL_PURPOSE_IO,
103 RTACPIASLTERMINAL_KEYWORD_GENERIC_SERIAL_BUS,
104 RTACPIASLTERMINAL_KEYWORD_PCC,
105 RTACPIASLTERMINAL_KEYWORD_PRM,
106 RTACPIASLTERMINAL_KEYWORD_FFIXED_HW,
107
108 RTACPIASLTERMINAL_PUNCTUATOR_COMMA,
109 RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET,
110 RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET,
111 RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET,
112 RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET
113
114} RTACPIASLTERMINAL;
115/** Pointer to a terminal enum. */
116typedef RTACPIASLTERMINAL *PRTACPIASLTERMINAL;
117/** Pointer to a const terminal enum. */
118typedef const RTACPIASLTERMINAL *PCRTACPIASLTERMINAL;
119
120
121/**
122 * The ACPI ASL compilation unit state.
123 */
124typedef struct RTACPIASLCU
125{
126 /** The lexer handle. */
127 RTSCRIPTLEX hLexSource;
128 /** The VFS I/O input stream. */
129 RTVFSIOSTREAM hVfsIosIn;
130 /** The ACPI table handle. */
131 RTACPITBL hAcpiTbl;
132 /** Error information. */
133 PRTERRINFO pErrInfo;
134 /** List of AST nodes for the DefinitionBlock() scope. */
135 RTLISTANCHOR LstStmts;
136} RTACPIASLCU;
137/** Pointer to an ACPI ASL compilation unit state. */
138typedef RTACPIASLCU *PRTACPIASLCU;
139/** Pointer to a constant ACPI ASL compilation unit state. */
140typedef const RTACPIASLCU *PCRTACPIASLCU;
141
142
143/** Pointer to a const ASL keyword encoding entry. */
144typedef const struct RTACPIASLKEYWORD *PCRTACPIASLKEYWORD;
145
146/**
147 * ACPI ASL -> AST parse callback.
148 *
149 * @returns IPRT status code.
150 * @param pThis ACPI ASL compiler state.
151 * @param pKeyword The keyword entry being processed.
152 * @param pAstNd The AST node to initialize.
153 */
154typedef DECLCALLBACKTYPE(int, FNRTACPITBLASLPARSE,(PRTACPIASLCU pThis, PCRTACPIASLKEYWORD pKeyword, PRTACPIASTNODE pAstNd));
155/** Pointer to a ACPI AML -> ASL decode callback. */
156typedef FNRTACPITBLASLPARSE *PFNRTACPITBLASLPARSE;
157
158
159/**
160 * ASL keyword encoding entry.
161 */
162typedef struct RTACPIASLKEYWORD
163{
164 /** Name of the opcode. */
165 const char *pszOpc;
166 /** The parsing callback to call, optional.
167 * If not NULL this will have priority over the default parsing. */
168 PFNRTACPITBLASLPARSE pfnParse;
169 /** Number of arguments required. */
170 uint8_t cArgsReq;
171 /** Number of optional arguments. */
172 uint8_t cArgsOpt;
173 /** Flags for the opcode. */
174 uint32_t fFlags;
175 /** Argument type for the required arguments. */
176 RTACPIASTARGTYPE aenmTypes[5];
177 /** Arguments for optional arguments, including the default value if absent. */
178 RTACPIASTARG aArgsOpt[3];
179} RTACPIASLKEYWORD;
180/** Pointer to a ASL keyword encoding entry. */
181typedef RTACPIASLKEYWORD *PRTACPIASLKEYWORD;
182
183
184/*********************************************************************************************************************************
185* Global Variables *
186*********************************************************************************************************************************/
187
188static DECLCALLBACK(int) rtAcpiAslLexerParseNumber(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser);
189static DECLCALLBACK(int) rtAcpiAslLexerParseNameString(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser);
190
191
192static const char *s_aszSingleStart[] =
193{
194 "//",
195 NULL
196};
197
198
199static const char *s_aszMultiStart[] =
200{
201 "/*",
202 NULL
203};
204
205
206static const char *s_aszMultiEnd[] =
207{
208 "*/",
209 NULL
210};
211
212
213static const RTSCRIPTLEXTOKMATCH s_aMatches[] =
214{
215 /* Keywords */
216 { RT_STR_TUPLE("SCOPE"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Scope },
217 { RT_STR_TUPLE("PROCESSOR"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Processor },
218 { RT_STR_TUPLE("EXTERNAL"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_External },
219 { RT_STR_TUPLE("METHOD"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Method },
220 { RT_STR_TUPLE("DEVICE"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Device },
221 { RT_STR_TUPLE("IF"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_If },
222 { RT_STR_TUPLE("ELSE"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Else },
223 { RT_STR_TUPLE("LAND"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LAnd },
224 { RT_STR_TUPLE("LEQUAL"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LEqual },
225 { RT_STR_TUPLE("LGREATER"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LGreater },
226 { RT_STR_TUPLE("LGREATEREQUAL"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LGreaterEqual },
227 { RT_STR_TUPLE("LLESS"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LLess },
228 { RT_STR_TUPLE("LLESSEQUAL"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LLessEqual },
229 { RT_STR_TUPLE("LNOT"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LNot },
230 { RT_STR_TUPLE("LNOTEQUAL"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_LNotEqual },
231 { RT_STR_TUPLE("ZERO"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Zero },
232 { RT_STR_TUPLE("ONE"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_One },
233 { RT_STR_TUPLE("ONES"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Ones },
234 { RT_STR_TUPLE("RETURN"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Return },
235 { RT_STR_TUPLE("UNICODE"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_Unicode },
236 { RT_STR_TUPLE("OPERATIONREGION"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, kAcpiAstNodeOp_OperationRegion },
237
238 { RT_STR_TUPLE("DEFINITIONBLOCK"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_DEFINITION_BLOCK },
239 { RT_STR_TUPLE("UNKNOWNOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_UNKNOWN_OBJ },
240 { RT_STR_TUPLE("INTOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_INT_OBJ },
241 { RT_STR_TUPLE("STROBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_STR_OBJ },
242 { RT_STR_TUPLE("BUFFOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_BUFF_OBJ },
243 { RT_STR_TUPLE("PKGOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_PKG_OBJ },
244 { RT_STR_TUPLE("FIELDUNITOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_FIELD_UNIT_OBJ },
245 { RT_STR_TUPLE("DEVICEOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_DEVICE_OBJ },
246 { RT_STR_TUPLE("EVENTOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_EVENT_OBJ },
247 { RT_STR_TUPLE("METHODOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_METHOD_OBJ },
248 { RT_STR_TUPLE("MUTEXOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_MUTEX_OBJ },
249 { RT_STR_TUPLE("OPREGIONOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_OP_REGION_OBJ },
250 { RT_STR_TUPLE("POWERRESOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_POWER_RES_OBJ },
251 { RT_STR_TUPLE("THERMALZONEOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_THERMAL_ZONE_OBJ },
252 { RT_STR_TUPLE("BUFFFIELDOBJ"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_BUFF_FIELD_OBJ },
253
254 { RT_STR_TUPLE("SERIALIZED"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_SERIALIZED },
255 { RT_STR_TUPLE("NOTSERIALIZED"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_NOT_SERIALIZED },
256
257 { RT_STR_TUPLE("SYSTEMIO"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_SYSTEM_IO },
258 { RT_STR_TUPLE("SYSTEMMEMORY"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_SYSTEM_MEMORY },
259 { RT_STR_TUPLE("PCI_CONFIG"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_PCI_CONFIG },
260 { RT_STR_TUPLE("EMBEDDEDCONTROL"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_EMBEDDED_CONTROL },
261 { RT_STR_TUPLE("SMBUS"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_SMBUS },
262 { RT_STR_TUPLE("SYSTEMCMOS"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_SYSTEM_CMOS },
263 { RT_STR_TUPLE("PCIBARTARGET"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_PCI_BAR_TARGET },
264 { RT_STR_TUPLE("IPMI"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_IPMI },
265 { RT_STR_TUPLE("GENERALPURPOSEIO"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_GENERAL_PURPOSE_IO },
266 { RT_STR_TUPLE("GENERICSERIALBUS"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_GENERIC_SERIAL_BUS },
267 { RT_STR_TUPLE("PCC"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_PCC },
268 { RT_STR_TUPLE("PRM"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_PRM },
269 { RT_STR_TUPLE("FFIXEDHW"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_FFIXED_HW },
270
271 /* Punctuators */
272 { RT_STR_TUPLE(","), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_COMMA },
273 { RT_STR_TUPLE("("), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET },
274 { RT_STR_TUPLE(")"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET },
275 { RT_STR_TUPLE("{"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET },
276 { RT_STR_TUPLE("}"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET },
277 { NULL, 0, RTSCRIPTLEXTOKTYPE_INVALID, false, 0 }
278};
279
280
281static const RTSCRIPTLEXRULE s_aRules[] =
282{
283 { '\"', '\"', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanStringLiteralC, NULL},
284 { '0', '9', RTSCRIPT_LEX_RULE_DEFAULT, rtAcpiAslLexerParseNumber, NULL},
285 { 'A', 'Z', RTSCRIPT_LEX_RULE_DEFAULT, rtAcpiAslLexerParseNameString, NULL},
286 { '_', '_', RTSCRIPT_LEX_RULE_DEFAULT, rtAcpiAslLexerParseNameString, NULL},
287 { '^', '^', RTSCRIPT_LEX_RULE_DEFAULT, rtAcpiAslLexerParseNameString, NULL},
288 { '\\', '\\', RTSCRIPT_LEX_RULE_DEFAULT, rtAcpiAslLexerParseNameString, NULL},
289
290 { '\0', '\0', RTSCRIPT_LEX_RULE_DEFAULT, NULL, NULL}
291};
292
293
294static const RTSCRIPTLEXCFG s_AslLexCfg =
295{
296 /** pszName */
297 "AcpiAsl",
298 /** pszDesc */
299 "ACPI ASL lexer",
300 /** fFlags */
301 RTSCRIPT_LEX_CFG_F_CASE_INSENSITIVE_UPPER,
302 /** pszWhitespace */
303 NULL,
304 /** pszNewline */
305 NULL,
306 /** papszCommentMultiStart */
307 s_aszMultiStart,
308 /** papszCommentMultiEnd */
309 s_aszMultiEnd,
310 /** papszCommentSingleStart */
311 s_aszSingleStart,
312 /** paTokMatches */
313 s_aMatches,
314 /** paRules */
315 s_aRules,
316 /** pfnProdDef */
317 NULL,
318 /** pfnProdDefUser */
319 NULL
320};
321
322
323/*********************************************************************************************************************************
324* Internal Functions *
325*********************************************************************************************************************************/
326
327static DECLCALLBACK(int) rtAcpiAslLexerParseNumber(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser)
328{
329 RT_NOREF(ch, pvUser);
330 return RTScriptLexScanNumber(hScriptLex, 0 /*uBase*/, false /*fAllowReal*/, pToken);
331}
332
333
334static int rtAcpiAslLexerParseNameSeg(RTSCRIPTLEX hScriptLex, PRTSCRIPTLEXTOKEN pTok, char *pachNameSeg)
335{
336 /*
337 * A Nameseg consist of a lead character and up to 3 following characters A-Z, 0-9 or _.
338 * If the name segment is not 4 characters long the remainder is filled with _.
339 */
340 char ch = RTScriptLexGetCh(hScriptLex);
341 if ( ch != '_'
342 && ( ch < 'A'
343 || ch > 'Z'))
344 return RTScriptLexProduceTokError(hScriptLex, pTok, VERR_INVALID_PARAMETER, "Lexer: Name segment starts with invalid character '%c'", ch);
345 RTScriptLexConsumeCh(hScriptLex);
346
347 /* Initialize the default name segment. */
348 pachNameSeg[0] = ch;
349 pachNameSeg[1] = '_';
350 pachNameSeg[2] = '_';
351 pachNameSeg[3] = '_';
352
353 for (uint8_t i = 1; i < 4; i++)
354 {
355 ch = RTScriptLexGetCh(hScriptLex);
356
357 /* Anything not belonging to the allowed characters terminates the parsing. */
358 if ( ch != '_'
359 && ( ch < 'A'
360 || ch > 'Z')
361 && ( ch < '0'
362 || ch > '9'))
363 return VINF_SUCCESS;
364 RTScriptLexConsumeCh(hScriptLex);
365 pachNameSeg[i] = ch;
366 }
367
368 return VINF_SUCCESS;
369}
370
371static DECLCALLBACK(int) rtAcpiAslLexerParseNameString(RTSCRIPTLEX hScriptLex, char ch,
372 PRTSCRIPTLEXTOKEN pTok, void *pvUser)
373{
374 RT_NOREF(pvUser);
375
376 char aszIde[513]; RT_ZERO(aszIde);
377 unsigned idx = 0;
378
379 if (ch == '^') /* PrefixPath */
380 {
381 aszIde[idx++] = '^';
382 RTScriptLexConsumeCh(hScriptLex);
383
384 ch = RTScriptLexGetCh(hScriptLex);
385 while ( idx < sizeof(aszIde) - 1
386 && ch == '^')
387 {
388 RTScriptLexConsumeCh(hScriptLex);
389 aszIde[idx++] = ch;
390 ch = RTScriptLexGetCh(hScriptLex);
391 }
392
393 if (idx == sizeof(aszIde) - 1)
394 return RTScriptLexProduceTokError(hScriptLex, pTok, VERR_BUFFER_OVERFLOW, "Lexer: PrefixPath exceeds the allowed length");
395 }
396 else if (ch == '\\')
397 {
398 aszIde[idx++] = '\\';
399 RTScriptLexConsumeCh(hScriptLex);
400 }
401
402 /* Now there is only a sequence of NameSeg allowed (separated by the . separator). */
403 while (idx < sizeof(aszIde) - 1 - 4)
404 {
405 char achNameSeg[4];
406 int rc = rtAcpiAslLexerParseNameSeg(hScriptLex, pTok, &achNameSeg[0]);
407 if (RT_FAILURE(rc))
408 return rc;
409
410 aszIde[idx++] = achNameSeg[0];
411 aszIde[idx++] = achNameSeg[1];
412 aszIde[idx++] = achNameSeg[2];
413 aszIde[idx++] = achNameSeg[3];
414
415 ch = RTScriptLexGetCh(hScriptLex);
416 if (ch != '.')
417 break;
418 }
419
420 if (idx == sizeof(aszIde) - 1)
421 return RTScriptLexProduceTokError(hScriptLex, pTok, VERR_BUFFER_OVERFLOW, "Lexer: Identifier exceeds the allowed length");
422
423 return RTScriptLexProduceTokIde(hScriptLex, pTok, &aszIde[0], idx);
424}
425
426
427static DECLCALLBACK(int) rtAcpiAslLexerRead(RTSCRIPTLEX hScriptLex, size_t offBuf, char *pchCur,
428 size_t cchBuf, size_t *pcchRead, void *pvUser)
429{
430 PCRTACPIASLCU pThis = (PCRTACPIASLCU)pvUser;
431 RT_NOREF(hScriptLex, offBuf);
432
433 size_t cbRead = 0;
434 int rc = RTVfsIoStrmRead(pThis->hVfsIosIn, pchCur, cchBuf, true /*fBlocking*/, &cbRead);
435 if (RT_FAILURE(rc))
436 return rc;
437
438 *pcchRead = cbRead * sizeof(char);
439 if (!cbRead)
440 return VINF_EOF;
441
442 return VINF_SUCCESS;
443}
444
445
446#if 0
447DECLINLINE(bool) rtAcpiAslLexerIsKeyword(PCRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerm)
448{
449 PCRTSCRIPTLEXTOKEN pTok;
450 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
451 if (RT_FAILURE(rc))
452 return false;
453
454 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD
455 && pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)enmTerm)
456 return true;
457
458 return false;
459}
460#endif
461
462
463DECLINLINE(bool) rtAcpiAslLexerIsPunctuator(PCRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerm)
464{
465 PCRTSCRIPTLEXTOKEN pTok;
466 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
467 if (RT_FAILURE(rc))
468 return false;
469
470 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_PUNCTUATOR
471 && pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)enmTerm)
472 return true;
473
474 return false;
475}
476
477
478static int rtAcpiAslLexerConsumeIfKeywordInList(PCRTACPIASLCU pThis, PCRTACPIASLTERMINAL paenmTerms, PRTACPIASLTERMINAL penmTerm)
479{
480 PCRTSCRIPTLEXTOKEN pTok;
481 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
482 if (RT_FAILURE(rc))
483 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query keyword token with %Rrc", rc);
484
485 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD)
486 {
487 unsigned i = 0;
488 do
489 {
490 if (pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)paenmTerms[i])
491 {
492 RTScriptLexConsumeToken(pThis->hLexSource);
493 *penmTerm = paenmTerms[i];
494 return VINF_SUCCESS;
495 }
496
497 i++;
498 } while (paenmTerms[i] != RTACPIASLTERMINAL_INVALID);
499 }
500
501 *penmTerm = RTACPIASLTERMINAL_INVALID;
502 return VINF_SUCCESS;
503}
504
505
506static int rtAcpiAslLexerConsumeIfKeyword(PCRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerm, bool *pfConsumed)
507{
508 PCRTSCRIPTLEXTOKEN pTok;
509 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
510 if (RT_FAILURE(rc))
511 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query keyword token with %Rrc", rc);
512
513 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD
514 && pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)enmTerm)
515 {
516 RTScriptLexConsumeToken(pThis->hLexSource);
517 *pfConsumed = true;
518 return VINF_SUCCESS;
519 }
520
521 *pfConsumed = false;
522 return VINF_SUCCESS;
523}
524
525
526static int rtAcpiAslLexerConsumeIfPunctuator(PCRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerm, bool *pfConsumed)
527{
528 PCRTSCRIPTLEXTOKEN pTok;
529 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
530 if (RT_FAILURE(rc))
531 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query punctuator token with %Rrc", rc);
532
533 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_PUNCTUATOR
534 && pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)enmTerm)
535 {
536 RTScriptLexConsumeToken(pThis->hLexSource);
537 *pfConsumed = true;
538 return VINF_SUCCESS;
539 }
540
541 *pfConsumed = false;
542 return VINF_SUCCESS;
543}
544
545
546static int rtAcpiAslLexerConsumeIfStringLit(PCRTACPIASLCU pThis, const char **ppszStrLit)
547{
548 PCRTSCRIPTLEXTOKEN pTok;
549 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
550 if (RT_FAILURE(rc))
551 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query string literal token with %Rrc", rc);
552
553 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_STRINGLIT)
554 {
555 *ppszStrLit = pTok->Type.StringLit.pszString;
556 RTScriptLexConsumeToken(pThis->hLexSource);
557 return VINF_SUCCESS;
558 }
559
560 return VINF_SUCCESS;
561}
562
563
564static int rtAcpiAslLexerConsumeIfIdentifier(PCRTACPIASLCU pThis, const char **ppszIde)
565{
566 PCRTSCRIPTLEXTOKEN pTok;
567 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
568 if (RT_FAILURE(rc))
569 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query string literal token with %Rrc", rc);
570
571 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_IDENTIFIER)
572 {
573 *ppszIde = pTok->Type.Id.pszIde;
574 RTScriptLexConsumeToken(pThis->hLexSource);
575 return VINF_SUCCESS;
576 }
577
578 return VINF_SUCCESS;
579}
580
581
582static int rtAcpiAslLexerConsumeIfNatural(PCRTACPIASLCU pThis, uint64_t *pu64, bool *pfConsumed)
583{
584 PCRTSCRIPTLEXTOKEN pTok;
585 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
586 if (RT_FAILURE(rc))
587 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query punctuator token with %Rrc", rc);
588
589 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_NUMBER
590 && pTok->Type.Number.enmType == RTSCRIPTLEXTOKNUMTYPE_NATURAL)
591 {
592 *pfConsumed = true;
593 *pu64 = pTok->Type.Number.Type.u64;
594 RTScriptLexConsumeToken(pThis->hLexSource);
595 return VINF_SUCCESS;
596 }
597
598 *pfConsumed = false;
599 return VINF_SUCCESS;
600}
601
602
603static int rtAcpiAslParserConsumeEos(PCRTACPIASLCU pThis)
604{
605 PCRTSCRIPTLEXTOKEN pTok;
606 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
607 if (RT_FAILURE(rc))
608 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query punctuator token with %Rrc", rc);
609
610 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_EOS)
611 {
612 RTScriptLexConsumeToken(pThis->hLexSource);
613 return VINF_SUCCESS;
614 }
615
616 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
617 "Parser: Found unexpected token after final closing }, expected end of stream");
618}
619
620
621/* Some parser helper macros. */
622#define RTACPIASL_PARSE_KEYWORD(a_enmKeyword, a_pszKeyword) \
623 do { \
624 bool fConsumed2 = false; \
625 int rc2 = rtAcpiAslLexerConsumeIfKeyword(pThis, a_enmKeyword, &fConsumed2); \
626 if (RT_FAILURE(rc2)) \
627 return rc2; \
628 if (!fConsumed2) \
629 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected keyword '%s'", a_pszKeyword); \
630 } while(0)
631
632#define RTACPIASL_PARSE_PUNCTUATOR(a_enmPunctuator, a_chPunctuator) \
633 do { \
634 bool fConsumed2 = false; \
635 int rc2 = rtAcpiAslLexerConsumeIfPunctuator(pThis, a_enmPunctuator, &fConsumed2); \
636 if (RT_FAILURE(rc2)) \
637 return rc2; \
638 if (!fConsumed2) \
639 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected punctuator '%c'", a_chPunctuator); \
640 } while(0)
641
642#define RTACPIASL_PARSE_STRING_LIT(a_pszStrLit) \
643 const char *a_pszStrLit = NULL; \
644 do { \
645 int rc2 = rtAcpiAslLexerConsumeIfStringLit(pThis, &a_pszStrLit); \
646 if (RT_FAILURE(rc2)) \
647 return rc2; \
648 if (!a_pszStrLit) \
649 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected a string literal"); \
650 } while(0)
651
652#define RTACPIASL_PARSE_NAME_STRING(a_pszIde) \
653 const char *a_pszIde = NULL; \
654 do { \
655 int rc2 = rtAcpiAslLexerConsumeIfIdentifier(pThis, &a_pszIde); \
656 if (RT_FAILURE(rc2)) \
657 return rc2; \
658 if (!a_pszIde) \
659 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected an identifier"); \
660 } while(0)
661
662#define RTACPIASL_PARSE_NATURAL(a_u64) \
663 uint64_t a_u64 = 0; \
664 do { \
665 bool fConsumed2 = false; \
666 int rc2 = rtAcpiAslLexerConsumeIfNatural(pThis, &a_u64, &fConsumed2); \
667 if (RT_FAILURE(rc2)) \
668 return rc2; \
669 if (!fConsumed2) \
670 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected a natural number"); \
671 } while(0)
672
673#define RTACPIASL_SKIP_CURRENT_TOKEN() \
674 RTScriptLexConsumeToken(pThis->hLexSource);
675
676
677static int rtAcpiTblAslParseInner(PRTACPIASLCU pThis, PRTLISTANCHOR pLstStmts);
678static int rtAcpiTblAslParseTermArg(PRTACPIASLCU pThis, PRTACPIASTNODE *ppAstNd);
679
680
681static const RTACPIASLTERMINAL g_aenmObjTypeKeywords[] = {
682 RTACPIASLTERMINAL_KEYWORD_UNKNOWN_OBJ,
683 RTACPIASLTERMINAL_KEYWORD_INT_OBJ,
684 RTACPIASLTERMINAL_KEYWORD_STR_OBJ,
685 RTACPIASLTERMINAL_KEYWORD_BUFF_OBJ,
686 RTACPIASLTERMINAL_KEYWORD_PKG_OBJ,
687 RTACPIASLTERMINAL_KEYWORD_FIELD_UNIT_OBJ,
688 RTACPIASLTERMINAL_KEYWORD_DEVICE_OBJ,
689 RTACPIASLTERMINAL_KEYWORD_EVENT_OBJ,
690 RTACPIASLTERMINAL_KEYWORD_METHOD_OBJ,
691 RTACPIASLTERMINAL_KEYWORD_MUTEX_OBJ,
692 RTACPIASLTERMINAL_KEYWORD_OP_REGION_OBJ,
693 RTACPIASLTERMINAL_KEYWORD_POWER_RES_OBJ,
694 RTACPIASLTERMINAL_KEYWORD_THERMAL_ZONE_OBJ,
695 RTACPIASLTERMINAL_KEYWORD_BUFF_FIELD_OBJ,
696 RTACPIASLTERMINAL_INVALID
697};
698
699
700static const RTACPIASLTERMINAL g_aenmSerializeRuleKeywords[] = {
701 RTACPIASLTERMINAL_KEYWORD_SERIALIZED,
702 RTACPIASLTERMINAL_KEYWORD_NOT_SERIALIZED,
703 RTACPIASLTERMINAL_INVALID
704};
705
706
707static const RTACPIASLTERMINAL g_aenmRegionSpaceKeywords[] = {
708 RTACPIASLTERMINAL_KEYWORD_SYSTEM_IO,
709 RTACPIASLTERMINAL_KEYWORD_SYSTEM_MEMORY,
710 RTACPIASLTERMINAL_KEYWORD_PCI_CONFIG,
711 RTACPIASLTERMINAL_KEYWORD_EMBEDDED_CONTROL,
712 RTACPIASLTERMINAL_KEYWORD_SMBUS,
713 RTACPIASLTERMINAL_KEYWORD_SYSTEM_CMOS,
714 RTACPIASLTERMINAL_KEYWORD_PCI_BAR_TARGET,
715 RTACPIASLTERMINAL_KEYWORD_IPMI,
716 RTACPIASLTERMINAL_KEYWORD_GENERAL_PURPOSE_IO,
717 RTACPIASLTERMINAL_KEYWORD_GENERIC_SERIAL_BUS,
718 RTACPIASLTERMINAL_KEYWORD_PCC,
719 RTACPIASLTERMINAL_KEYWORD_PRM,
720 RTACPIASLTERMINAL_KEYWORD_FFIXED_HW,
721 RTACPIASLTERMINAL_INVALID
722};
723
724
725static DECLCALLBACK(int) rtAcpiTblAslParseExternal(PRTACPIASLCU pThis, PCRTACPIASLKEYWORD pKeyword, PRTACPIASTNODE pAstNd)
726{
727 RT_NOREF(pKeyword, pAstNd);
728
729 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
730
731 /* Namestring is required. */
732 RTACPIASL_PARSE_NAME_STRING(pszNameString);
733 pAstNd->aArgs[0].enmType = kAcpiAstArgType_NameString;
734 pAstNd->aArgs[0].u.pszNameString = pszNameString;
735
736 /* Defaults for optional arguments. */
737 pAstNd->aArgs[1].enmType = kAcpiAstArgType_ObjType;
738 pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Unknown;
739 pAstNd->aArgs[2].enmType = kAcpiAstArgType_U8;
740 pAstNd->aArgs[2].u.u8 = 0;
741
742 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
743 {
744 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
745
746 RTACPIASLTERMINAL enmKeyword;
747 int rc = rtAcpiAslLexerConsumeIfKeywordInList(pThis, &g_aenmObjTypeKeywords[0], &enmKeyword);
748 if (RT_FAILURE(rc))
749 return rc;
750
751 if (enmKeyword != RTACPIASLTERMINAL_INVALID)
752 {
753 switch (enmKeyword)
754 {
755 case RTACPIASLTERMINAL_KEYWORD_UNKNOWN_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Unknown; break;
756 case RTACPIASLTERMINAL_KEYWORD_INT_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Int; break;
757 case RTACPIASLTERMINAL_KEYWORD_STR_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Str; break;
758 case RTACPIASLTERMINAL_KEYWORD_BUFF_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Buff; break;
759 case RTACPIASLTERMINAL_KEYWORD_PKG_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Pkg; break;
760 case RTACPIASLTERMINAL_KEYWORD_FIELD_UNIT_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_FieldUnit; break;
761 case RTACPIASLTERMINAL_KEYWORD_DEVICE_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Device; break;
762 case RTACPIASLTERMINAL_KEYWORD_EVENT_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Event; break;
763 case RTACPIASLTERMINAL_KEYWORD_METHOD_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_Method; break;
764 case RTACPIASLTERMINAL_KEYWORD_MUTEX_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_MutexObj; break;
765 case RTACPIASLTERMINAL_KEYWORD_OP_REGION_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_OpRegion; break;
766 case RTACPIASLTERMINAL_KEYWORD_POWER_RES_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_PowerRes; break;
767 case RTACPIASLTERMINAL_KEYWORD_THERMAL_ZONE_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_ThermalZone; break;
768 case RTACPIASLTERMINAL_KEYWORD_BUFF_FIELD_OBJ: pAstNd->aArgs[1].u.enmObjType = kAcpiObjType_BuffField; break;
769 default:
770 AssertFailedReturn(VERR_INTERNAL_ERROR);
771 }
772 }
773
774 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
775 {
776 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
777
778 /** @todo ResultType */
779
780 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
781 {
782 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
783
784 /** @todo ParameterTypes */
785 }
786 }
787 }
788
789 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
790 return VINF_SUCCESS;
791}
792
793
794static DECLCALLBACK(int) rtAcpiTblAslParseMethod(PRTACPIASLCU pThis, PCRTACPIASLKEYWORD pKeyword, PRTACPIASTNODE pAstNd)
795{
796 RT_NOREF(pKeyword, pAstNd);
797
798 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
799
800 /* Namestring is required. */
801 RTACPIASL_PARSE_NAME_STRING(pszNameString);
802 pAstNd->aArgs[0].enmType = kAcpiAstArgType_NameString;
803 pAstNd->aArgs[0].u.pszNameString = pszNameString;
804
805 /* Defaults for optional arguments. */
806 pAstNd->aArgs[1].enmType = kAcpiAstArgType_U8;
807 pAstNd->aArgs[1].u.u8 = 0;
808 pAstNd->aArgs[2].enmType = kAcpiAstArgType_Bool;
809 pAstNd->aArgs[2].u.f = false;
810 pAstNd->aArgs[3].enmType = kAcpiAstArgType_U8;
811 pAstNd->aArgs[3].u.u8 = 0;
812
813 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
814 {
815 /* NumArgs */
816 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
817
818 uint64_t u64 = 0;
819 bool fConsumed = false;
820 int rc = rtAcpiAslLexerConsumeIfNatural(pThis, &u64, &fConsumed);
821 if (RT_FAILURE(rc))
822 return rc;
823
824 if (fConsumed)
825 {
826 if (u64 >= 8)
827 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
828 "Argument count value is out of range [0..7]: %u", u64);
829 pAstNd->aArgs[1].u.u8 = (uint8_t)u64;
830 }
831
832 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
833 {
834 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
835
836 /* Serialized|NotSerialized */
837 RTACPIASLTERMINAL enmKeyword;
838 rc = rtAcpiAslLexerConsumeIfKeywordInList(pThis, &g_aenmSerializeRuleKeywords[0], &enmKeyword);
839 if (RT_FAILURE(rc))
840 return rc;
841
842 if (enmKeyword != RTACPIASLTERMINAL_INVALID)
843 {
844 Assert(enmKeyword == RTACPIASLTERMINAL_KEYWORD_SERIALIZED || enmKeyword == RTACPIASLTERMINAL_KEYWORD_NOT_SERIALIZED);
845 pAstNd->aArgs[2].u.f = enmKeyword == RTACPIASLTERMINAL_KEYWORD_SERIALIZED
846 ? RTACPI_METHOD_F_SERIALIZED
847 : RTACPI_METHOD_F_NOT_SERIALIZED;
848 }
849
850 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
851 {
852 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
853
854 /* Sync Level */
855 u64 = 0;
856 rc = rtAcpiAslLexerConsumeIfNatural(pThis, &u64, &fConsumed);
857 if (RT_FAILURE(rc))
858 return rc;
859
860 if (fConsumed)
861 {
862 if (u64 >= 16)
863 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
864 "SyncLevel value is out of range [0..15]: %u", u64);
865 pAstNd->aArgs[1].u.u8 = (uint8_t)u64;
866 }
867
868 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
869 {
870 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
871
872 /** @todo ReturnType */
873
874 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
875 {
876 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
877
878 /** @todo ParameterTypes */
879 }
880 }
881 }
882 }
883 }
884
885 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
886 return VINF_SUCCESS;
887}
888
889
890
891#define RTACPI_ASL_KEYWORD_DEFINE_INVALID \
892 { \
893 NULL, NULL, 0, 0, RTACPI_AST_NODE_F_DEFAULT, \
894 { kAcpiAstArgType_Invalid, \
895 kAcpiAstArgType_Invalid, \
896 kAcpiAstArgType_Invalid, \
897 kAcpiAstArgType_Invalid, \
898 kAcpiAstArgType_Invalid}, \
899 { \
900 { kAcpiAstArgType_Invalid, { 0 } }, \
901 { kAcpiAstArgType_Invalid, { 0 } }, \
902 { kAcpiAstArgType_Invalid, { 0 } } \
903 } \
904 }
905
906#define RTACPI_ASL_KEYWORD_DEFINE_HANDLER(a_szKeyword, a_pfnHandler, a_cArgReq, a_cArgOpt, a_fFlags) \
907 { \
908 a_szKeyword, a_pfnHandler, a_cArgReq, a_cArgOpt, a_fFlags, \
909 { kAcpiAstArgType_Invalid, \
910 kAcpiAstArgType_Invalid, \
911 kAcpiAstArgType_Invalid, \
912 kAcpiAstArgType_Invalid, \
913 kAcpiAstArgType_Invalid}, \
914 { \
915 { kAcpiAstArgType_Invalid, { 0 } }, \
916 { kAcpiAstArgType_Invalid, { 0 } }, \
917 { kAcpiAstArgType_Invalid, { 0 } } \
918 } \
919 }
920
921#define RTACPI_ASL_KEYWORD_DEFINE_0REQ_0OPT(a_szKeyword, a_fFlags) \
922 { \
923 a_szKeyword, NULL, 0, 0, a_fFlags, \
924 { kAcpiAstArgType_Invalid, \
925 kAcpiAstArgType_Invalid, \
926 kAcpiAstArgType_Invalid, \
927 kAcpiAstArgType_Invalid, \
928 kAcpiAstArgType_Invalid}, \
929 { \
930 { kAcpiAstArgType_Invalid, { 0 } }, \
931 { kAcpiAstArgType_Invalid, { 0 } }, \
932 { kAcpiAstArgType_Invalid, { 0 } } \
933 } \
934 }
935
936#define RTACPI_ASL_KEYWORD_DEFINE_1REQ_0OPT(a_szKeyword, a_fFlags, a_enmArgType0) \
937 { \
938 a_szKeyword, NULL, 1, 0, a_fFlags, \
939 { a_enmArgType0, \
940 kAcpiAstArgType_Invalid, \
941 kAcpiAstArgType_Invalid, \
942 kAcpiAstArgType_Invalid, \
943 kAcpiAstArgType_Invalid}, \
944 { \
945 { kAcpiAstArgType_Invalid, { 0 } }, \
946 { kAcpiAstArgType_Invalid, { 0 } }, \
947 { kAcpiAstArgType_Invalid, { 0 } } \
948 } \
949 }
950
951#define RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT(a_szKeyword, a_fFlags, a_enmArgType0, a_enmArgType1) \
952 { \
953 a_szKeyword, NULL, 2, 0, a_fFlags, \
954 { a_enmArgType0, \
955 a_enmArgType1, \
956 kAcpiAstArgType_Invalid, \
957 kAcpiAstArgType_Invalid, \
958 kAcpiAstArgType_Invalid}, \
959 { \
960 { kAcpiAstArgType_Invalid, { 0 } }, \
961 { kAcpiAstArgType_Invalid, { 0 } }, \
962 { kAcpiAstArgType_Invalid, { 0 } } \
963 } \
964 }
965
966#define RTACPI_ASL_KEYWORD_DEFINE_4REQ_0OPT(a_szKeyword, a_fFlags, a_enmArgType0, a_enmArgType1, a_enmArgType2, a_enmArgType3) \
967 { \
968 a_szKeyword, NULL, 4, 0, a_fFlags, \
969 { a_enmArgType0, \
970 a_enmArgType1, \
971 a_enmArgType2, \
972 a_enmArgType3, \
973 kAcpiAstArgType_Invalid}, \
974 { \
975 { kAcpiAstArgType_Invalid, { 0 } }, \
976 { kAcpiAstArgType_Invalid, { 0 } }, \
977 { kAcpiAstArgType_Invalid, { 0 } } \
978 } \
979 }
980
981/**
982 * Operations encoding table, indexed by kAcpiAstNodeOp_XXX.
983 */
984static const RTACPIASLKEYWORD g_aAslOps[] =
985{
986 /* kAcpiAstNodeOp_Invalid */ RTACPI_ASL_KEYWORD_DEFINE_INVALID,
987 /* kAcpiAstNodeOp_Identifier */ RTACPI_ASL_KEYWORD_DEFINE_INVALID,
988 /* kAcpiAstNodeOp_StringLiteral */ RTACPI_ASL_KEYWORD_DEFINE_INVALID,
989 /* kAcpiAstNodeOp_Number */ RTACPI_ASL_KEYWORD_DEFINE_INVALID,
990 /* kAcpiAstNodeOp_Scope */ RTACPI_ASL_KEYWORD_DEFINE_1REQ_0OPT("Scope", RTACPI_AST_NODE_F_NEW_SCOPE, kAcpiAstArgType_NameString),
991 /* kAcpiAstNodeOp_Processor */ {
992 "Processor", NULL, 2, 2, RTACPI_AST_NODE_F_NEW_SCOPE,
993 {
994 kAcpiAstArgType_NameString,
995 kAcpiAstArgType_U8,
996 kAcpiAstArgType_Invalid,
997 kAcpiAstArgType_Invalid,
998 kAcpiAstArgType_Invalid
999 },
1000 {
1001 { kAcpiAstArgType_U32, { 0 } },
1002 { kAcpiAstArgType_U8, { 0 } },
1003 { kAcpiAstArgType_Invalid, { 0 } }
1004 }
1005 },
1006 /* kAcpiAstNodeOp_External */ RTACPI_ASL_KEYWORD_DEFINE_HANDLER( "External", rtAcpiTblAslParseExternal, 1, 2, RTACPI_AST_NODE_F_DEFAULT),
1007 /* kAcpiAstNodeOp_Method */ RTACPI_ASL_KEYWORD_DEFINE_HANDLER( "Method", rtAcpiTblAslParseMethod, 1, 3, RTACPI_AST_NODE_F_NEW_SCOPE),
1008 /* kAcpiAstNodeOp_Device */ RTACPI_ASL_KEYWORD_DEFINE_1REQ_0OPT("Device", RTACPI_AST_NODE_F_NEW_SCOPE, kAcpiAstArgType_NameString),
1009 /* kAcpiAstNodeOp_If */ RTACPI_ASL_KEYWORD_DEFINE_1REQ_0OPT("If", RTACPI_AST_NODE_F_NEW_SCOPE, kAcpiAstArgType_AstNode),
1010 /* kAcpiAstNodeOp_Else */ RTACPI_ASL_KEYWORD_DEFINE_0REQ_0OPT("Else", RTACPI_AST_NODE_F_NEW_SCOPE),
1011 /* kAcpiAstNodeOp_LAnd */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LAnd", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1012 /* kAcpiAstNodeOp_LEqual */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LEqual", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1013 /* kAcpiAstNodeOp_LGreater */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LGreater", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1014 /* kAcpiAstNodeOp_LGreaterEqual */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LGreaterEqual", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1015 /* kAcpiAstNodeOp_LLess */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LLess", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1016 /* kAcpiAstNodeOp_LLessEqual */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LLessEqual", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1017 /* kAcpiAstNodeOp_LNot */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LNot", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1018 /* kAcpiAstNodeOp_LNotEqual */ RTACPI_ASL_KEYWORD_DEFINE_2REQ_0OPT("LNotEqual", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1019 /* kAcpiAstNodeOp_Zero */ RTACPI_ASL_KEYWORD_DEFINE_0REQ_0OPT("Zero", RTACPI_AST_NODE_F_DEFAULT),
1020 /* kAcpiAstNodeOp_One */ RTACPI_ASL_KEYWORD_DEFINE_0REQ_0OPT("One", RTACPI_AST_NODE_F_DEFAULT),
1021 /* kAcpiAstNodeOp_Ones */ RTACPI_ASL_KEYWORD_DEFINE_0REQ_0OPT("Ones", RTACPI_AST_NODE_F_DEFAULT),
1022 /* kAcpiAstNodeOp_Return */ RTACPI_ASL_KEYWORD_DEFINE_1REQ_0OPT("Return", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode),
1023 /* kAcpiAstNodeOp_Unicode */ RTACPI_ASL_KEYWORD_DEFINE_1REQ_0OPT("Unicode", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_AstNode), /* Actually only String allowed here */
1024 /* kAcpiAstNodeOp_OperationRegion */ RTACPI_ASL_KEYWORD_DEFINE_4REQ_0OPT("OperationRegion", RTACPI_AST_NODE_F_DEFAULT, kAcpiAstArgType_NameString, kAcpiAstArgType_RegionSpace, kAcpiAstArgType_AstNode, kAcpiAstArgType_AstNode),
1025
1026};
1027
1028
1029static int rtAcpiTblAslParseArgument(PRTACPIASLCU pThis, const char *pszKeyword, uint8_t iArg, RTACPIASTARGTYPE enmArgType, PRTACPIASTARG pArg)
1030{
1031 switch (enmArgType)
1032 {
1033 case kAcpiAstArgType_AstNode:
1034 {
1035 PRTACPIASTNODE pAstNd = NULL;
1036 int rc = rtAcpiTblAslParseTermArg(pThis, &pAstNd);
1037 if (RT_FAILURE(rc))
1038 return rc;
1039 pArg->enmType = kAcpiAstArgType_AstNode;
1040 pArg->u.pAstNd = pAstNd;
1041 break;
1042 }
1043 case kAcpiAstArgType_NameString:
1044 {
1045 RTACPIASL_PARSE_NAME_STRING(pszNameString);
1046 pArg->enmType = kAcpiAstArgType_NameString;
1047 pArg->u.pszNameString = pszNameString;
1048 break;
1049 }
1050 case kAcpiAstArgType_U8:
1051 {
1052 RTACPIASL_PARSE_NATURAL(u64);
1053 if (u64 > UINT8_MAX)
1054 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
1055 "Value for byte parameter %u is out of range (%#RX64) while processing keyword '%s'",
1056 iArg, u64, pszKeyword);
1057
1058 pArg->enmType = kAcpiAstArgType_U8;
1059 pArg->u.u8 = (uint8_t)u64;
1060 break;
1061 }
1062 case kAcpiAstArgType_U16:
1063 {
1064 RTACPIASL_PARSE_NATURAL(u64);
1065 if (u64 > UINT16_MAX)
1066 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
1067 "Value for word parameter %u is out of range (%#RX64) while processing keyword '%s'",
1068 iArg, u64, pszKeyword);
1069
1070 pArg->enmType = kAcpiAstArgType_U16;
1071 pArg->u.u16 = (uint16_t)u64;
1072 break;
1073 }
1074 case kAcpiAstArgType_U32:
1075 {
1076 RTACPIASL_PARSE_NATURAL(u64);
1077 if (u64 > UINT32_MAX)
1078 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
1079 "Value for 32-bit parameter %u is out of range (%#RX64) while processing keyword '%s'",
1080 iArg, u64, pszKeyword);
1081
1082 pArg->enmType = kAcpiAstArgType_U32;
1083 pArg->u.u32 = (uint32_t)u64;
1084 break;
1085 }
1086 case kAcpiAstArgType_U64:
1087 {
1088 RTACPIASL_PARSE_NATURAL(u64);
1089 pArg->enmType = kAcpiAstArgType_U64;
1090 pArg->u.u64 = u64;
1091 break;
1092 }
1093 case kAcpiAstArgType_RegionSpace:
1094 {
1095 RTACPIASLTERMINAL enmKeyword;
1096 int rc = rtAcpiAslLexerConsumeIfKeywordInList(pThis, &g_aenmRegionSpaceKeywords[0], &enmKeyword);
1097 if (RT_FAILURE(rc))
1098 return rc;
1099
1100 if (enmKeyword != RTACPIASLTERMINAL_INVALID)
1101 {
1102 pArg->enmType = kAcpiAstArgType_RegionSpace;
1103 switch (enmKeyword)
1104 {
1105 case RTACPIASLTERMINAL_KEYWORD_SYSTEM_IO: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_SystemIo; break;
1106 case RTACPIASLTERMINAL_KEYWORD_SYSTEM_MEMORY: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_SystemMemory; break;
1107 case RTACPIASLTERMINAL_KEYWORD_PCI_CONFIG: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_PciConfig; break;
1108 case RTACPIASLTERMINAL_KEYWORD_EMBEDDED_CONTROL: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_EmbeddedControl; break;
1109 case RTACPIASLTERMINAL_KEYWORD_SMBUS: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_SmBus; break;
1110 case RTACPIASLTERMINAL_KEYWORD_SYSTEM_CMOS: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_SystemCmos; break;
1111 case RTACPIASLTERMINAL_KEYWORD_PCI_BAR_TARGET: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_PciBarTarget; break;
1112 case RTACPIASLTERMINAL_KEYWORD_IPMI: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_Ipmi; break;
1113 case RTACPIASLTERMINAL_KEYWORD_GENERAL_PURPOSE_IO: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_Gpio; break;
1114 case RTACPIASLTERMINAL_KEYWORD_GENERIC_SERIAL_BUS: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_GenericSerialBus; break;
1115 case RTACPIASLTERMINAL_KEYWORD_PCC: pArg->u.enmRegionSpace = kAcpiOperationRegionSpace_Pcc; break;
1116 case RTACPIASLTERMINAL_KEYWORD_PRM:
1117 case RTACPIASLTERMINAL_KEYWORD_FFIXED_HW:
1118 default:
1119 AssertFailedReturn(VERR_INTERNAL_ERROR);
1120 }
1121 }
1122 else
1123 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Unknown RegionSpace keyword encountered");
1124 break;
1125 }
1126 default:
1127 AssertReleaseFailed();
1128 }
1129
1130 return VINF_SUCCESS;
1131}
1132
1133
1134static int rtAcpiTblAslParseOp(PRTACPIASLCU pThis, RTACPIASTNODEOP enmOp, PRTACPIASTNODE *ppAstNd)
1135{
1136 int rc = VINF_SUCCESS;
1137
1138 AssertReturn(enmOp > kAcpiAstNodeOp_Invalid && (unsigned)enmOp < RT_ELEMENTS(g_aAslOps), VERR_INTERNAL_ERROR);
1139
1140 *ppAstNd = NULL;
1141
1142 PCRTACPIASLKEYWORD pAslKeyword = &g_aAslOps[enmOp];
1143 PRTACPIASTNODE pAstNd = rtAcpiAstNodeAlloc(enmOp, pAslKeyword->fFlags, pAslKeyword->cArgsReq + pAslKeyword->cArgsOpt);
1144 if (!pAstNd)
1145 return RTErrInfoSetF(pThis->pErrInfo, VERR_NO_MEMORY, "Failed to allocate ACPI AST node when processing keyword '%s'", pAslKeyword->pszOpc);
1146
1147 *ppAstNd = pAstNd;
1148
1149 /* Call and parse callback if present, otherwise do the default parsing. */
1150 if (pAslKeyword->pfnParse)
1151 {
1152 rc = pAslKeyword->pfnParse(pThis, pAslKeyword, pAstNd);
1153 if (RT_FAILURE(rc))
1154 return rc;
1155 }
1156 else if (pAslKeyword->cArgsReq || pAslKeyword->cArgsOpt)
1157 {
1158 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
1159
1160 /* Process any required arguments. */
1161 for (uint8_t i = 0; i < pAslKeyword->cArgsReq; i++)
1162 {
1163 rc = rtAcpiTblAslParseArgument(pThis, pAslKeyword->pszOpc, i, pAslKeyword->aenmTypes[i], &pAstNd->aArgs[i]);
1164 if (RT_FAILURE(rc))
1165 return rc;
1166
1167 /* There must be a "," between required arguments, not counting the last required argument because it can be closed with ")". */
1168 if (i < (uint8_t)(pAslKeyword->cArgsReq - 1))
1169 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1170 }
1171
1172 /* Process any optional arguments, this is a bit ugly. */
1173 uint8_t iArg = 0;
1174 while (iArg < pAslKeyword->cArgsOpt)
1175 {
1176 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET))
1177 break; /* The end of the argument list was reached. */
1178
1179 /*
1180 * It is possible to have empty arguments in the list by having nothing to parse between the "," or something like ",)"
1181 * (like "Method(NAM, 0,,)" for example).
1182 */
1183 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
1184 {
1185 RTACPIASL_SKIP_CURRENT_TOKEN(); /* Skip "," */
1186
1187 /*
1188 * If the next token is also a "," there is a hole in the argument list and we have to fill in the default,
1189 * if it is ")" we reached the end.
1190 */
1191 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET))
1192 break;
1193 else if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_COMMA))
1194 {
1195 pAstNd->aArgs[pAslKeyword->cArgsReq + iArg] = pAslKeyword->aArgsOpt[iArg];
1196 iArg++;
1197 continue; /* Continue with the next argument. */
1198 }
1199
1200 /* So there is an argument we need to parse. */
1201 rc = rtAcpiTblAslParseArgument(pThis, pAslKeyword->pszOpc, iArg, pAslKeyword->aArgsOpt[iArg].enmType, &pAstNd->aArgs[pAslKeyword->cArgsReq + iArg]);
1202 if (RT_FAILURE(rc))
1203 return rc;
1204
1205 iArg++;
1206 }
1207 }
1208
1209 /* Fill remaining optional arguments with the defaults. */
1210 for (; iArg < pAslKeyword->cArgsOpt; iArg++)
1211 pAstNd->aArgs[pAslKeyword->cArgsReq + iArg] = pAslKeyword->aArgsOpt[iArg];
1212
1213 /* Now there must be a closing ) */
1214 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
1215 }
1216
1217 /* For keywords opening a new scope do the parsing now. */
1218 if (pAslKeyword->fFlags & RTACPI_AST_NODE_F_NEW_SCOPE)
1219 {
1220 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET, '{');
1221 rc = rtAcpiTblAslParseInner(pThis, &pAstNd->LstScopeNodes);
1222 if (RT_SUCCESS(rc))
1223 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET, '}');
1224 }
1225
1226 return rc;
1227}
1228
1229
1230/**
1231 * Parses what looks like an name string, possibly with a call.
1232 *
1233 * @returns IPRT status code.
1234 * @param pThis The ACPI compilation unit state.
1235 * @param pszIde The identifier.
1236 * @param ppAstNd Where to store the AST node on success.
1237 */
1238static int rtAcpiTblAslParseIde(PRTACPIASLCU pThis, const char *pszIde, PRTACPIASTNODE *ppAstNd)
1239{
1240 *ppAstNd = NULL;
1241
1242 /* If there is a ( following this looks like a function call which can have up to 8 arguments. */
1243 uint8_t cArgs = 0;
1244 RTACPIASTARG aArgs[8]; RT_ZERO(aArgs);
1245 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET))
1246 {
1247 RTACPIASL_SKIP_CURRENT_TOKEN(); /* Skip "(" */
1248
1249 while (cArgs < RT_ELEMENTS(aArgs))
1250 {
1251 PRTACPIASTNODE pAstNd = NULL;
1252 int rc = rtAcpiTblAslParseTermArg(pThis, &pAstNd);
1253 if (RT_FAILURE(rc))
1254 return rc;
1255
1256 aArgs[cArgs].enmType = kAcpiAstArgType_AstNode;
1257 aArgs[cArgs].u.pAstNd = pAstNd;
1258 cArgs++;
1259
1260 /* ")" means we are done here. */
1261 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET))
1262 break;
1263
1264 /* Arguments are separated by "," */
1265 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1266 }
1267
1268 /* Now there must be a closing ) */
1269 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
1270 }
1271
1272 PRTACPIASTNODE pAstNd = rtAcpiAstNodeAlloc(kAcpiAstNodeOp_Identifier, RTACPI_AST_NODE_F_DEFAULT, cArgs);
1273 if (!pAstNd)
1274 return RTErrInfoSetF(pThis->pErrInfo, VERR_NO_MEMORY, "Failed to allocate ACPI AST node when processing identifier '%s'", pszIde);
1275
1276 pAstNd->pszIde = pszIde;
1277
1278 /* Fill in the arguments. */
1279 for (uint8_t i = 0; i < cArgs; i++)
1280 pAstNd->aArgs[i] = aArgs[i];
1281
1282 *ppAstNd = pAstNd;
1283 return VINF_SUCCESS;
1284}
1285
1286
1287static int rtAcpiTblAslParseTermArg(PRTACPIASLCU pThis, PRTACPIASTNODE *ppAstNd)
1288{
1289 PCRTSCRIPTLEXTOKEN pTok;
1290 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
1291 if (RT_FAILURE(rc))
1292 return RTErrInfoSetF(pThis->pErrInfo, rc, "Parser: Failed to query next token with %Rrc", rc);
1293
1294 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_ERROR)
1295 return RTErrInfoSet(pThis->pErrInfo, VERR_INVALID_PARAMETER, pTok->Type.Error.pErr->pszMsg);
1296 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_EOS)
1297 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Unexpected end of stream");
1298
1299 PRTACPIASTNODE pAstNd = NULL;
1300 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD)
1301 {
1302 uint64_t idKeyword = pTok->Type.Keyword.pKeyword->u64Val;
1303 if (idKeyword < RT_ELEMENTS(g_aAslOps))
1304 {
1305 RTScriptLexConsumeToken(pThis->hLexSource); /* This must come here as rtAcpiTblAslParseOp() will continue parsing. */
1306 rc = rtAcpiTblAslParseOp(pThis, (RTACPIASTNODEOP)idKeyword, &pAstNd);
1307 }
1308 else
1309 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Unexpected keyword '%s' encountered", pTok->Type.Keyword.pKeyword->pszMatch);
1310 }
1311 else if (pTok->enmType == RTSCRIPTLEXTOKTYPE_IDENTIFIER)
1312 {
1313 /* We can safely consume the token here after getting the pointer to the identifier string as the string is cached and doesn't go away. */
1314 const char *pszIde = pTok->Type.Id.pszIde;
1315 RTScriptLexConsumeToken(pThis->hLexSource);
1316 rc = rtAcpiTblAslParseIde(pThis, pszIde, &pAstNd);
1317 }
1318 else if (pTok->enmType == RTSCRIPTLEXTOKTYPE_STRINGLIT)
1319 {
1320 pAstNd = rtAcpiAstNodeAlloc(kAcpiAstNodeOp_StringLiteral, RTACPI_AST_NODE_F_DEFAULT, 0);
1321 if (!pAstNd)
1322 return RTErrInfoSetF(pThis->pErrInfo, VERR_NO_MEMORY, "Failed to allocate ACPI AST node when processing identifier '%s'",
1323 pTok->Type.StringLit.pszString);
1324
1325 pAstNd->pszStrLit = pTok->Type.StringLit.pszString;
1326 RTScriptLexConsumeToken(pThis->hLexSource);
1327 }
1328 else if (pTok->enmType == RTSCRIPTLEXTOKTYPE_NUMBER)
1329 {
1330 Assert(pTok->Type.Number.enmType == RTSCRIPTLEXTOKNUMTYPE_NATURAL);
1331 pAstNd = rtAcpiAstNodeAlloc(kAcpiAstNodeOp_Number, RTACPI_AST_NODE_F_DEFAULT, 0);
1332 if (!pAstNd)
1333 return RTErrInfoSetF(pThis->pErrInfo, VERR_NO_MEMORY, "Failed to allocate ACPI AST node when processing number '%#RX64'",
1334 pTok->Type.Number.Type.u64);
1335
1336 pAstNd->u64 = pTok->Type.Number.Type.u64;
1337 RTScriptLexConsumeToken(pThis->hLexSource);
1338 }
1339 else
1340 {
1341 AssertFailed();
1342 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Unexpected token encountered");
1343 }
1344
1345 if (RT_FAILURE(rc))
1346 {
1347 if (pAstNd)
1348 rtAcpiAstNodeFree(pAstNd);
1349 return rc;
1350 }
1351
1352 AssertPtr(pAstNd);
1353 *ppAstNd = pAstNd;
1354 return VINF_SUCCESS;
1355}
1356
1357
1358static int rtAcpiTblAslParseInner(PRTACPIASLCU pThis, PRTLISTANCHOR pLstStmts)
1359{
1360 for (;;)
1361 {
1362 /* Need to break out of the loop if done processing this scope (consumption is done by the caller). */
1363 if (rtAcpiAslLexerIsPunctuator(pThis, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET))
1364 return VINF_SUCCESS;
1365
1366 PRTACPIASTNODE pAstNd = NULL;
1367 int rc = rtAcpiTblAslParseTermArg(pThis, &pAstNd);
1368 if (RT_FAILURE(rc))
1369 return rc;
1370
1371 Assert(pAstNd);
1372 RTListAppend(pLstStmts, &pAstNd->NdAst);
1373 }
1374}
1375
1376
1377static int rtAcpiTblAslParserParse(PRTACPIASLCU pThis)
1378{
1379 /*
1380 * The first keyword must be DefinitionBlock:
1381 *
1382 * DefinitionBlock ("SSDT.aml", "SSDT", 1, "VBOX ", "VBOXCPUT", 2)
1383 */
1384 RTACPIASL_PARSE_KEYWORD(RTACPIASLTERMINAL_KEYWORD_DEFINITION_BLOCK, "DefinitionBlock");
1385 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
1386 RTACPIASL_PARSE_STRING_LIT(pszOutFile);
1387 RT_NOREF(pszOutFile); /* We ignore the output file hint. */
1388 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1389 RTACPIASL_PARSE_STRING_LIT(pszTblSig);
1390 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1391 RTACPIASL_PARSE_NATURAL(u64ComplianceRev);
1392 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1393 RTACPIASL_PARSE_STRING_LIT(pszOemId);
1394 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1395 RTACPIASL_PARSE_STRING_LIT(pszOemTblId);
1396 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
1397 RTACPIASL_PARSE_NATURAL(u64OemRev);
1398 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
1399
1400 /* Some additional checks. */
1401 uint32_t u32TblSig = ACPI_TABLE_HDR_SIGNATURE_MISC;
1402 if (!strcmp(pszTblSig, "DSDT"))
1403 u32TblSig = ACPI_TABLE_HDR_SIGNATURE_DSDT;
1404 else if (!strcmp(pszTblSig, "SSDT"))
1405 u32TblSig = ACPI_TABLE_HDR_SIGNATURE_SSDT;
1406
1407 if (u32TblSig == ACPI_TABLE_HDR_SIGNATURE_MISC)
1408 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Table signature must be either 'DSDT' or 'SSDT': %s", pszTblSig);
1409
1410 if (u64ComplianceRev > UINT8_MAX)
1411 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Compliance revision %RU64 is out of range, must be in range [0..255]", u64ComplianceRev);
1412
1413 if (strlen(pszOemId) > 6)
1414 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "OEM ID string must be at most 6 characters long");
1415
1416 if (strlen(pszOemTblId) > 8)
1417 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "OEM table ID string must be at most 8 characters long");
1418
1419 if (u64OemRev > UINT32_MAX)
1420 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "OEM revision ID %RU64 is out of range, must fit into 32-bit unsigned integer", u64OemRev);
1421
1422 int rc = RTAcpiTblCreate(&pThis->hAcpiTbl, u32TblSig, (uint8_t)u64ComplianceRev, pszOemId,
1423 pszOemTblId, (uint32_t)u64OemRev, "VBOX", RTBldCfgRevision());
1424 if (RT_SUCCESS(rc))
1425 {
1426 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET, '{');
1427 rc = rtAcpiTblAslParseInner(pThis, &pThis->LstStmts);
1428 if (RT_SUCCESS(rc))
1429 {
1430 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET, '}');
1431 rc = rtAcpiAslParserConsumeEos(pThis); /* No junk after the final closing bracket. */
1432 }
1433 }
1434 else
1435 rc = RTErrInfoSetF(pThis->pErrInfo, rc, "Call to RTAcpiTblCreate() failed");
1436
1437 return rc;
1438}
1439
1440
1441DECLHIDDEN(int) rtAcpiTblConvertFromAslToAml(RTVFSIOSTREAM hVfsIosOut, RTVFSIOSTREAM hVfsIosIn, PRTERRINFO pErrInfo)
1442{
1443 int rc;
1444 PRTACPIASLCU pThis = (PRTACPIASLCU)RTMemAllocZ(sizeof(*pThis));
1445 if (pThis)
1446 {
1447 pThis->hVfsIosIn = hVfsIosIn;
1448 pThis->pErrInfo = pErrInfo;
1449 RTListInit(&pThis->LstStmts);
1450
1451 rc = RTScriptLexCreateFromReader(&pThis->hLexSource, rtAcpiAslLexerRead,
1452 NULL /*pfnDtor*/, pThis /*pvUser*/, 0 /*cchBuf*/,
1453 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
1454 &s_AslLexCfg);
1455 if (RT_SUCCESS(rc))
1456 {
1457 rc = rtAcpiTblAslParserParse(pThis);
1458 if (RT_SUCCESS(rc))
1459 {
1460 /* 2. - Optimize AST (constant folding, etc). */
1461 /** @todo */
1462
1463 /* 3. - Traverse AST and output table. */
1464 PRTACPIASTNODE pIt;
1465 RTListForEach(&pThis->LstStmts, pIt, RTACPIASTNODE, NdAst)
1466 {
1467 rc = rtAcpiAstDumpToTbl(pIt, pThis->hAcpiTbl);
1468 if (RT_FAILURE(rc))
1469 break;
1470 }
1471
1472 /* Finalize and write to the VFS I/O stream. */
1473 if (RT_SUCCESS(rc))
1474 {
1475 rc = RTAcpiTblFinalize(pThis->hAcpiTbl);
1476 if (RT_SUCCESS(rc))
1477 {
1478 rc = RTAcpiTblDumpToVfsIoStrm(pThis->hAcpiTbl, RTACPITBLTYPE_AML, hVfsIosOut);
1479 if (RT_FAILURE(rc))
1480 rc = RTErrInfoSetF(pErrInfo, rc, "Writing the ACPI table failed with %Rrc", rc);
1481 }
1482 else
1483 rc = RTErrInfoSetF(pErrInfo, rc, "Finalizing the ACPI table failed with %Rrc", rc);
1484 }
1485 else
1486 rc = RTErrInfoSetF(pErrInfo, rc, "Dumping AST to ACPI table failed with %Rrc", rc);
1487 }
1488
1489 RTScriptLexDestroy(pThis->hLexSource);
1490 }
1491 else
1492 rc = RTErrInfoSetF(pErrInfo, rc, "Creating the ASL lexer failed with %Rrc", rc);
1493
1494 /* Destroy the AST nodes. */
1495 PRTACPIASTNODE pIt, pItNext;
1496 RTListForEachSafe(&pThis->LstStmts, pIt, pItNext, RTACPIASTNODE, NdAst)
1497 {
1498 RTListNodeRemove(&pIt->NdAst);
1499 rtAcpiAstNodeFree(pIt);
1500 }
1501
1502 RTMemFree(pThis);
1503 }
1504 else
1505 rc = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Out of memory allocating the ASL compilation unit state");
1506
1507 return rc;
1508}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette