VirtualBox

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

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

Runtime/acpi: Some re-arrangement and start with an ASL compiler, bugref:10733 [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1/* $Id: acpi-compiler.cpp 108018 2025-02-01 19:24:44Z 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 = 0,
75 RTACPIASLTERMINAL_KEYWORD_DEFINITION_BLOCK,
76 RTACPIASLTERMINAL_KEYWORD_SCOPE,
77 RTACPIASLTERMINAL_KEYWORD_PROCESSOR,
78
79 RTACPIASLTERMINAL_KEYWORD_AND,
80 RTACPIASLTERMINAL_KEYWORD_ARRAY,
81 RTACPIASLTERMINAL_KEYWORD_ASM,
82 RTACPIASLTERMINAL_KEYWORD_BEGIN,
83 RTACPIASLTERMINAL_KEYWORD_BREAK,
84 RTACPIASLTERMINAL_KEYWORD_CASE,
85 RTACPIASLTERMINAL_KEYWORD_CONSTRUCTOR,
86 RTACPIASLTERMINAL_KEYWORD_CONST,
87 RTACPIASLTERMINAL_KEYWORD_CONTINUE,
88 RTACPIASLTERMINAL_KEYWORD_DESTRUCTOR,
89 RTACPIASLTERMINAL_KEYWORD_DIV,
90 RTACPIASLTERMINAL_KEYWORD_DOWNTO,
91 RTACPIASLTERMINAL_KEYWORD_DO,
92 RTACPIASLTERMINAL_KEYWORD_ELSE,
93 RTACPIASLTERMINAL_KEYWORD_END,
94 RTACPIASLTERMINAL_KEYWORD_FALSE,
95 RTACPIASLTERMINAL_KEYWORD_FILE,
96 RTACPIASLTERMINAL_KEYWORD_FOR,
97 RTACPIASLTERMINAL_KEYWORD_FUNCTION,
98 RTACPIASLTERMINAL_KEYWORD_GOTO,
99 RTACPIASLTERMINAL_KEYWORD_IF,
100 RTACPIASLTERMINAL_KEYWORD_IMPLEMENTATION,
101 RTACPIASLTERMINAL_KEYWORD_INTERFACE,
102 RTACPIASLTERMINAL_KEYWORD_INLINE,
103 RTACPIASLTERMINAL_KEYWORD_IN,
104 RTACPIASLTERMINAL_KEYWORD_LABEL,
105 RTACPIASLTERMINAL_KEYWORD_MOD,
106 RTACPIASLTERMINAL_KEYWORD_NIL,
107 RTACPIASLTERMINAL_KEYWORD_NOT,
108 RTACPIASLTERMINAL_KEYWORD_OBJECT,
109 RTACPIASLTERMINAL_KEYWORD_OF,
110 RTACPIASLTERMINAL_KEYWORD_ON,
111 RTACPIASLTERMINAL_KEYWORD_OPERATOR,
112 RTACPIASLTERMINAL_KEYWORD_OR,
113 RTACPIASLTERMINAL_KEYWORD_PACKED,
114 RTACPIASLTERMINAL_KEYWORD_PROCEDURE,
115 RTACPIASLTERMINAL_KEYWORD_PROGRAM,
116 RTACPIASLTERMINAL_KEYWORD_RECORD,
117 RTACPIASLTERMINAL_KEYWORD_REPEAT,
118 RTACPIASLTERMINAL_KEYWORD_SET,
119 RTACPIASLTERMINAL_KEYWORD_SHL,
120 RTACPIASLTERMINAL_KEYWORD_SHR,
121 RTACPIASLTERMINAL_KEYWORD_STRING,
122 RTACPIASLTERMINAL_KEYWORD_THEN,
123 RTACPIASLTERMINAL_KEYWORD_TO,
124 RTACPIASLTERMINAL_KEYWORD_TRUE,
125 RTACPIASLTERMINAL_KEYWORD_TYPE,
126 RTACPIASLTERMINAL_KEYWORD_UNIT,
127 RTACPIASLTERMINAL_KEYWORD_UNTIL,
128 RTACPIASLTERMINAL_KEYWORD_USES,
129 RTACPIASLTERMINAL_KEYWORD_VAR,
130 RTACPIASLTERMINAL_KEYWORD_WHILE,
131 RTACPIASLTERMINAL_KEYWORD_WITH,
132 RTACPIASLTERMINAL_KEYWORD_XOR,
133
134 RTACPIASLTERMINAL_OPERATOR_EQUALS,
135 RTACPIASLTERMINAL_OPERATOR_ASSIGN,
136 RTACPIASLTERMINAL_OPERATOR_UNEQUAL,
137 RTACPIASLTERMINAL_OPERATOR_GREATER_EQUAL,
138 RTACPIASLTERMINAL_OPERATOR_SMALLER_EQUAL,
139 RTACPIASLTERMINAL_OPERATOR_SHIFT_RIGHT,
140 RTACPIASLTERMINAL_OPERATOR_SHIFT_LEFT,
141 RTACPIASLTERMINAL_OPERATOR_GREATER,
142 RTACPIASLTERMINAL_OPERATOR_SMALLER,
143 RTACPIASLTERMINAL_OPERATOR_PLUS,
144 RTACPIASLTERMINAL_OPERATOR_MINUS,
145 RTACPIASLTERMINAL_OPERATOR_MUL,
146 RTACPIASLTERMINAL_OPERATOR_DIV,
147 RTACPIASLTERMINAL_OPERATOR_MOD,
148 RTACPIASLTERMINAL_OPERATOR_TILDE,
149 RTACPIASLTERMINAL_OPERATOR_NOT,
150
151 RTACPIASLTERMINAL_PUNCTUATOR_COMMA,
152 RTACPIASLTERMINAL_PUNCTUATOR_DOT,
153 RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET,
154 RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET,
155 RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET,
156 RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET
157
158} RTACPIASLTERMINAL;
159
160
161/**
162 * The ACPI ASL compilation unit state.
163 */
164typedef struct RTACPIASLCU
165{
166 /** The lexer handle. */
167 RTSCRIPTLEX hLexSource;
168 /** The VFS I/O input stream. */
169 RTVFSIOSTREAM hVfsIosIn;
170 /** The ACPI table handle. */
171 RTACPITBL hAcpiTbl;
172 /** Error information. */
173 PRTERRINFO pErrInfo;
174} RTACPIASLCU;
175/** Pointer to an ACPI ASL compilation unit state. */
176typedef RTACPIASLCU *PRTACPIASLCU;
177/** Pointer to a constant ACPI ASL compilation unit state. */
178typedef const RTACPIASLCU *PCRTACPIASLCU;
179
180
181/*********************************************************************************************************************************
182* Global Variables *
183*********************************************************************************************************************************/
184
185static DECLCALLBACK(int) rtAcpiAslLexerParseNumber(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser);
186static DECLCALLBACK(int) rtAcpiAslLexerParseNameString(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser);
187
188
189static const char *s_aszSingleStart[] =
190{
191 "//",
192 NULL
193};
194
195
196static const char *s_aszMultiStart[] =
197{
198 "/*",
199 NULL
200};
201
202
203static const char *s_aszMultiEnd[] =
204{
205 "*/",
206 NULL
207};
208
209
210static const RTSCRIPTLEXTOKMATCH s_aMatches[] =
211{
212 /* Keywords */
213 { RT_STR_TUPLE("DefinitionBlock"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_DEFINITION_BLOCK },
214 { RT_STR_TUPLE("Processor"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_PROCESSOR },
215 { RT_STR_TUPLE("Scope"), RTSCRIPTLEXTOKTYPE_KEYWORD, true, RTACPIASLTERMINAL_KEYWORD_SCOPE },
216
217 /* Punctuators */
218 { RT_STR_TUPLE(","), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_COMMA },
219 { RT_STR_TUPLE("."), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_DOT },
220 { RT_STR_TUPLE("("), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET },
221 { RT_STR_TUPLE(")"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET },
222 { RT_STR_TUPLE("{"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET },
223 { RT_STR_TUPLE("}"), RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET },
224 { NULL, 0, RTSCRIPTLEXTOKTYPE_INVALID, false, 0 }
225};
226
227
228static const RTSCRIPTLEXRULE s_aRules[] =
229{
230 { '\"', '\"', RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanStringLiteralC, NULL},
231 { '0', '9', RTSCRIPT_LEX_RULE_CONSUME, rtAcpiAslLexerParseNumber, NULL},
232 { 'A', 'Z', RTSCRIPT_LEX_RULE_CONSUME, rtAcpiAslLexerParseNameString, NULL},
233 { '_', '_', RTSCRIPT_LEX_RULE_CONSUME, rtAcpiAslLexerParseNameString, NULL},
234 { '^', '^', RTSCRIPT_LEX_RULE_CONSUME, rtAcpiAslLexerParseNameString, NULL},
235 { '\\', '\\', RTSCRIPT_LEX_RULE_CONSUME, rtAcpiAslLexerParseNameString, NULL},
236
237 { '\0', '\0', RTSCRIPT_LEX_RULE_DEFAULT, NULL, NULL}
238};
239
240
241static const RTSCRIPTLEXCFG s_AslLexCfg =
242{
243 /** pszName */
244 "AcpiAsl",
245 /** pszDesc */
246 "ACPI ASL lexer",
247 /** fFlags */
248 RTSCRIPT_LEX_CFG_F_DEFAULT,
249 /** pszWhitespace */
250 NULL,
251 /** pszNewline */
252 NULL,
253 /** papszCommentMultiStart */
254 s_aszMultiStart,
255 /** papszCommentMultiEnd */
256 s_aszMultiEnd,
257 /** papszCommentSingleStart */
258 s_aszSingleStart,
259 /** paTokMatches */
260 s_aMatches,
261 /** paRules */
262 s_aRules,
263 /** pfnProdDef */
264 NULL,
265 /** pfnProdDefUser */
266 NULL
267};
268
269
270/*********************************************************************************************************************************
271* Internal Functions *
272*********************************************************************************************************************************/
273
274static DECLCALLBACK(int) rtAcpiAslLexerParseNumber(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser)
275{
276 RT_NOREF(ch, pvUser);
277 return RTScriptLexScanNumber(hScriptLex, 0 /*uBase*/, false /*fAllowReal*/, pToken);
278}
279
280
281static int rtAcpiAslLexerParseNameSeg(RTSCRIPTLEX hScriptLex, PRTSCRIPTLEXTOKEN pTok, char *pachNameSeg)
282{
283 /*
284 * A Nameseg consist of a lead character and up to 3 following characters A-Z, 0-9 or _.
285 * If the name segment is not 4 characters long the remainder is filled with _.
286 */
287 char ch = RTScriptLexGetCh(hScriptLex);
288 if ( ch != '_'
289 && ( ch < 'A'
290 || ch > 'Z'))
291 return RTScriptLexProduceTokError(hScriptLex, pTok, VERR_INVALID_PARAMETER, "Lexer: Name segment starts with invalid character '%c'", ch);
292 RTScriptLexConsumeCh(hScriptLex);
293
294 /* Initialize the default name segment. */
295 pachNameSeg[0] = ch;
296 pachNameSeg[1] = '_';
297 pachNameSeg[2] = '_';
298 pachNameSeg[3] = '_';
299
300 for (uint8_t i = 1; i < 4; i++)
301 {
302 ch = RTScriptLexGetCh(hScriptLex);
303
304 /* Anything not belonging to the allowed characters terminates the parsing. */
305 if ( ch != '_'
306 && ( ch < 'A'
307 || ch > 'Z')
308 && ( ch < '0'
309 || ch > '9'))
310 return VINF_SUCCESS;
311 RTScriptLexConsumeCh(hScriptLex);
312 pachNameSeg[i] = ch;
313 }
314
315 return VINF_SUCCESS;
316}
317
318static DECLCALLBACK(int) rtAcpiAslLexerParseNameString(RTSCRIPTLEX hScriptLex, char ch,
319 PRTSCRIPTLEXTOKEN pTok, void *pvUser)
320{
321 RT_NOREF(pvUser);
322
323 char aszIde[513]; RT_ZERO(aszIde);
324 unsigned idx = 0;
325 aszIde[idx++] = ch;
326
327 if (ch == '^') /* PrefixPath */
328 {
329 ch = RTScriptLexGetCh(hScriptLex);
330 while ( idx < sizeof(aszIde) - 1
331 && ch == '^')
332 {
333 RTScriptLexConsumeCh(hScriptLex);
334 aszIde[idx++] = ch;
335 ch = RTScriptLexGetCh(hScriptLex);
336 }
337
338 if (idx == sizeof(aszIde) - 1)
339 return RTScriptLexProduceTokError(hScriptLex, pTok, VERR_BUFFER_OVERFLOW, "Lexer: PrefixPath exceeds the allowed length");
340 }
341
342 /* Now there is only a sequence of NameSeg allowed (separated by the . separator). */
343 while (idx < sizeof(aszIde) - 1 - 4)
344 {
345 char achNameSeg[4];
346 int rc = rtAcpiAslLexerParseNameSeg(hScriptLex, pTok, &achNameSeg[0]);
347 if (RT_FAILURE(rc))
348 return rc;
349
350 aszIde[idx++] = achNameSeg[0];
351 aszIde[idx++] = achNameSeg[1];
352 aszIde[idx++] = achNameSeg[2];
353 aszIde[idx++] = achNameSeg[3];
354
355 ch = RTScriptLexGetCh(hScriptLex);
356 if (ch != '.')
357 break;
358 }
359
360 if (idx == sizeof(aszIde) - 1)
361 return RTScriptLexProduceTokError(hScriptLex, pTok, VERR_BUFFER_OVERFLOW, "Lexer: Identifier exceeds the allowed length");
362
363 return RTScriptLexProduceTokIde(hScriptLex, pTok, &aszIde[0], idx);
364}
365
366
367static DECLCALLBACK(int) rtAcpiAslLexerRead(RTSCRIPTLEX hScriptLex, size_t offBuf, char *pchCur,
368 size_t cchBuf, size_t *pcchRead, void *pvUser)
369{
370 PCRTACPIASLCU pThis = (PCRTACPIASLCU)pvUser;
371 RT_NOREF(hScriptLex, offBuf);
372
373 size_t cbRead = 0;
374 int rc = RTVfsIoStrmRead(pThis->hVfsIosIn, pchCur, cchBuf, true /*fBlocking*/, &cbRead);
375 if (RT_FAILURE(rc))
376 return rc;
377
378 *pcchRead = cbRead * sizeof(char);
379 if (!cbRead)
380 return VINF_EOF;
381
382 return VINF_SUCCESS;
383}
384
385
386static int rtAcpiAslLexerConsumeIfKeyword(PCRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerm, bool *pfConsumed)
387{
388 PCRTSCRIPTLEXTOKEN pTok;
389 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
390 if (RT_FAILURE(rc))
391 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query keyword token with %Rrc", rc);
392
393 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_KEYWORD
394 && pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)enmTerm)
395 {
396 RTScriptLexConsumeToken(pThis->hLexSource);
397 *pfConsumed = true;
398 return VINF_SUCCESS;
399 }
400
401 *pfConsumed = false;
402 return VINF_SUCCESS;
403}
404
405
406static int rtAcpiAslLexerConsumeIfPunctuator(PCRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerm, bool *pfConsumed)
407{
408 PCRTSCRIPTLEXTOKEN pTok;
409 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
410 if (RT_FAILURE(rc))
411 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query punctuator token with %Rrc", rc);
412
413 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_PUNCTUATOR
414 && pTok->Type.Keyword.pKeyword->u64Val == (uint64_t)enmTerm)
415 {
416 RTScriptLexConsumeToken(pThis->hLexSource);
417 *pfConsumed = true;
418 return VINF_SUCCESS;
419 }
420
421 *pfConsumed = false;
422 return VINF_SUCCESS;
423}
424
425
426static int rtAcpiAslLexerConsumeIfStringLit(PCRTACPIASLCU pThis, const char **ppszStrLit)
427{
428 PCRTSCRIPTLEXTOKEN pTok;
429 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
430 if (RT_FAILURE(rc))
431 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query string literal token with %Rrc", rc);
432
433 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_STRINGLIT)
434 {
435 *ppszStrLit = pTok->Type.StringLit.pszString;
436 RTScriptLexConsumeToken(pThis->hLexSource);
437 return VINF_SUCCESS;
438 }
439
440 return VINF_SUCCESS;
441}
442
443
444static int rtAcpiAslLexerConsumeIfIdentifier(PCRTACPIASLCU pThis, const char **ppszIde)
445{
446 PCRTSCRIPTLEXTOKEN pTok;
447 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
448 if (RT_FAILURE(rc))
449 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query string literal token with %Rrc", rc);
450
451 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_IDENTIFIER)
452 {
453 *ppszIde = pTok->Type.Id.pszIde;
454 RTScriptLexConsumeToken(pThis->hLexSource);
455 return VINF_SUCCESS;
456 }
457
458 return VINF_SUCCESS;
459}
460
461
462static int rtAcpiAslLexerConsumeIfNatural(PCRTACPIASLCU pThis, uint64_t *pu64, bool *pfConsumed)
463{
464 PCRTSCRIPTLEXTOKEN pTok;
465 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
466 if (RT_FAILURE(rc))
467 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query punctuator token with %Rrc", rc);
468
469 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_NUMBER
470 && pTok->Type.Number.enmType == RTSCRIPTLEXTOKNUMTYPE_NATURAL)
471 {
472 RTScriptLexConsumeToken(pThis->hLexSource);
473 *pfConsumed = true;
474 *pu64 = pTok->Type.Number.Type.u64;
475 return VINF_SUCCESS;
476 }
477
478 *pfConsumed = false;
479 return VINF_SUCCESS;
480}
481
482
483static int rtAcpiAslParserConsumeEos(PCRTACPIASLCU pThis)
484{
485 PCRTSCRIPTLEXTOKEN pTok;
486 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
487 if (RT_FAILURE(rc))
488 return RTErrInfoSetF(pThis->pErrInfo, rc, "Lexer: Failed to query punctuator token with %Rrc", rc);
489
490 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_EOS)
491 {
492 RTScriptLexConsumeToken(pThis->hLexSource);
493 return VINF_SUCCESS;
494 }
495
496 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER,
497 "Parser: Found unexpected token after final closing }, expected end of stream");
498}
499
500
501/* Some parser helper macros. */
502#define RTACPIASL_PARSE_KEYWORD(a_enmKeyword, a_pszKeyword) \
503 do { \
504 bool fConsumed = false; \
505 int rc2 = rtAcpiAslLexerConsumeIfKeyword(pThis, a_enmKeyword, &fConsumed); \
506 if (RT_FAILURE(rc2)) \
507 return rc2; \
508 if (!fConsumed) \
509 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected keyword '%s'", a_pszKeyword); \
510 } while(0)
511
512#define RTACPIASL_PARSE_PUNCTUATOR(a_enmPunctuator, a_chPunctuator) \
513 do { \
514 bool fConsumed = false; \
515 int rc2 = rtAcpiAslLexerConsumeIfPunctuator(pThis, a_enmPunctuator, &fConsumed); \
516 if (RT_FAILURE(rc2)) \
517 return rc2; \
518 if (!fConsumed) \
519 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected punctuator '%c'", a_chPunctuator); \
520 } while(0)
521
522#define RTACPIASL_PARSE_STRING_LIT(a_pszStrLit) \
523 const char *a_pszStrLit = NULL; \
524 do { \
525 int rc2 = rtAcpiAslLexerConsumeIfStringLit(pThis, &a_pszStrLit); \
526 if (RT_FAILURE(rc2)) \
527 return rc2; \
528 if (!a_pszStrLit) \
529 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected a string literal"); \
530 } while(0)
531
532#define RTACPIASL_PARSE_NAME_STRING(a_pszIde) \
533 const char *a_pszIde = NULL; \
534 do { \
535 int rc2 = rtAcpiAslLexerConsumeIfIdentifier(pThis, &a_pszIde); \
536 if (RT_FAILURE(rc2)) \
537 return rc2; \
538 if (!a_pszIde) \
539 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected an identifier"); \
540 } while(0)
541
542#define RTACPIASL_PARSE_NATURAL(a_u64) \
543 uint64_t a_u64 = 0; \
544 do { \
545 bool fConsumed = false; \
546 int rc2 = rtAcpiAslLexerConsumeIfNatural(pThis, &a_u64, &fConsumed); \
547 if (RT_FAILURE(rc2)) \
548 return rc2; \
549 if (!fConsumed) \
550 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Expected a natural number"); \
551 } while(0)
552
553static int rtAcpiTblAslParseInner(PRTACPIASLCU pThis);
554
555static int rtAcpiTblAslParseTerminal(PRTACPIASLCU pThis, RTACPIASLTERMINAL enmTerminal)
556{
557 int rc = VINF_SUCCESS;
558
559 switch (enmTerminal)
560 {
561 case RTACPIASLTERMINAL_KEYWORD_SCOPE:
562 {
563 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
564 RTACPIASL_PARSE_NAME_STRING(pszName);
565 RT_NOREF(pszName);
566 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
567 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET, '{');
568 rc = rtAcpiTblAslParseInner(pThis);
569 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET, '}');
570 break;
571 }
572 case RTACPIASLTERMINAL_KEYWORD_PROCESSOR:
573 {
574 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
575 RTACPIASL_PARSE_NAME_STRING(pszName);
576 RT_NOREF(pszName);
577 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
578 AssertFailed();
579 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
580 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET, '{');
581 rc = rtAcpiTblAslParseInner(pThis);
582 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET, '}');
583 break;
584 }
585 default:
586 rc = RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Unexpected keyword encountered");
587 break;
588 }
589
590 return rc;
591}
592
593
594static int rtAcpiTblAslParseInner(PRTACPIASLCU pThis)
595{
596 for (;;)
597 {
598 PCRTSCRIPTLEXTOKEN pTok;
599 int rc = RTScriptLexQueryToken(pThis->hLexSource, &pTok);
600 if (RT_FAILURE(rc))
601 return RTErrInfoSetF(pThis->pErrInfo, rc, "Parser: Failed to query next token with %Rrc", rc);
602
603 if ( pTok->enmType == RTSCRIPTLEXTOKTYPE_PUNCTUATOR
604 && pTok->Type.Keyword.pKeyword->u64Val == RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET)
605 return VINF_SUCCESS;
606
607 if (pTok->enmType == RTSCRIPTLEXTOKTYPE_EOS)
608 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Unexpected end of stream");
609 if (pTok->enmType != RTSCRIPTLEXTOKTYPE_KEYWORD)
610 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Parser: Unexpected token encountered");
611
612 RTACPIASLTERMINAL enmKeyword = (RTACPIASLTERMINAL)pTok->Type.Keyword.pKeyword->u64Val;
613 RTScriptLexConsumeToken(pThis->hLexSource);
614
615 rc = rtAcpiTblAslParseTerminal(pThis, enmKeyword);
616 if (RT_FAILURE(rc))
617 return rc;
618 }
619}
620
621
622static int rtAcpiTblAslParserParse(PRTACPIASLCU pThis)
623{
624 /*
625 * The first keyword must be DefinitionBlock:
626 *
627 * DefinitionBlock ("SSDT.aml", "SSDT", 1, "VBOX ", "VBOXCPUT", 2)
628 */
629 RTACPIASL_PARSE_KEYWORD(RTACPIASLTERMINAL_KEYWORD_DEFINITION_BLOCK, "DefinitionBlock");
630 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_BRACKET, '(');
631 RTACPIASL_PARSE_STRING_LIT(pszOutFile);
632 RT_NOREF(pszOutFile); /* We ignore the output file hint. */
633 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
634 RTACPIASL_PARSE_STRING_LIT(pszTblSig);
635 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
636 RTACPIASL_PARSE_NATURAL(u64ComplianceRev);
637 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
638 RTACPIASL_PARSE_STRING_LIT(pszOemId);
639 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
640 RTACPIASL_PARSE_STRING_LIT(pszOemTblId);
641 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_COMMA, ',');
642 RTACPIASL_PARSE_NATURAL(u64OemRev);
643 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_BRACKET, ')');
644
645 /* Some additional checks. */
646 uint32_t u32TblSig = ACPI_TABLE_HDR_SIGNATURE_MISC;
647 if (!strcmp(pszTblSig, "DSDT"))
648 u32TblSig = ACPI_TABLE_HDR_SIGNATURE_DSDT;
649 else if (!strcmp(pszTblSig, "SSDT"))
650 u32TblSig = ACPI_TABLE_HDR_SIGNATURE_SSDT;
651
652 if (u32TblSig == ACPI_TABLE_HDR_SIGNATURE_MISC)
653 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Table signature must be either 'DSDT' or 'SSDT': %s", pszTblSig);
654
655 if (u64ComplianceRev > UINT8_MAX)
656 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "Compliance revision %RU64 is out of range, must be in range [0..255]", u64ComplianceRev);
657
658 if (strlen(pszOemId) > 6)
659 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "OEM ID string must be at most 6 characters long");
660
661 if (strlen(pszOemTblId) > 8)
662 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "OEM table ID string must be at most 8 characters long");
663
664 if (u64OemRev > UINT32_MAX)
665 return RTErrInfoSetF(pThis->pErrInfo, VERR_INVALID_PARAMETER, "OEM revision ID %RU64 is out of range, must fit into 32-bit unsigned integer", u64OemRev);
666
667 int rc = RTAcpiTblCreate(&pThis->hAcpiTbl, u32TblSig, (uint8_t)u64ComplianceRev, pszOemId,
668 pszOemTblId, (uint32_t)u64OemRev, "VBOX", RTBldCfgRevision());
669 if (RT_SUCCESS(rc))
670 {
671 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_OPEN_CURLY_BRACKET, '{');
672 rc = rtAcpiTblAslParseInner(pThis);
673 if (RT_SUCCESS(rc))
674 {
675 RTACPIASL_PARSE_PUNCTUATOR(RTACPIASLTERMINAL_PUNCTUATOR_CLOSE_CURLY_BRACKET, '}');
676 rc = rtAcpiAslParserConsumeEos(pThis); /* No junk after the final closing bracket. */
677 }
678 }
679
680 return rc;
681}
682
683
684DECLHIDDEN(int) rtAcpiTblConvertFromAslToAml(RTVFSIOSTREAM hVfsIosOut, RTVFSIOSTREAM hVfsIosIn, PRTERRINFO pErrInfo)
685{
686 int rc;
687 PRTACPIASLCU pThis = (PRTACPIASLCU)RTMemAllocZ(sizeof(*pThis));
688 if (pThis)
689 {
690 pThis->hVfsIosIn = hVfsIosIn;
691 pThis->pErrInfo = pErrInfo;
692
693 rc = RTScriptLexCreateFromReader(&pThis->hLexSource, rtAcpiAslLexerRead,
694 NULL /*pfnDtor*/, pThis /*pvUser*/, 0 /*cchBuf*/,
695 NULL /*phStrCacheId*/, NULL /*phStrCacheStringLit*/,
696 &s_AslLexCfg);
697 if (RT_SUCCESS(rc))
698 {
699 rc = rtAcpiTblAslParserParse(pThis);
700 if (RT_SUCCESS(rc))
701 {
702 /* 2. - Optimize AST (constant folding, etc). */
703 /* 3. - Traverse AST and output table. */
704 RT_NOREF(hVfsIosOut);
705 }
706
707 /** @todo Destroy AST. */
708 RTScriptLexDestroy(pThis->hLexSource);
709 }
710 else
711 rc = RTErrInfoSetF(pErrInfo, rc, "Creating the ASL lexer failed with %Rrc", rc);
712
713 RTMemFree(pThis);
714 }
715 else
716 rc = RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Out of memory allocating the ASL compilation unit state");
717
718 return rc;
719}
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