VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTIasl.cpp

最後變更 在這個檔案是 108241,由 vboxsync 提交於 4 週 前

Makefile.kmk,src/VBox/Devices/EFI/Firmware: Replace iasl by our RTIasl, bugref:10733

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 16.8 KB
 
1/* $Id: RTIasl.cpp 108241 2025-02-16 18:50:05Z vboxsync $ */
2/** @file
3 * IPRT - iasl (acpica) like utility.
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.alldomusa.eu.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#include <iprt/acpi.h>
42
43#include <iprt/buildconfig.h>
44#include <iprt/errcore.h>
45#include <iprt/file.h>
46#include <iprt/getopt.h>
47#include <iprt/initterm.h>
48#include <iprt/message.h>
49#include <iprt/param.h>
50#include <iprt/path.h>
51#include <iprt/stream.h>
52#include <iprt/string.h>
53#include <iprt/vfs.h>
54#include <iprt/vfslowlevel.h>
55
56
57/*********************************************************************************************************************************
58* Structures and Typedefs *
59*********************************************************************************************************************************/
60/**
61 * IASL command options.
62 */
63typedef struct RTCMDIASLOPTS
64{
65 /** The input format. */
66 RTACPITBLTYPE enmInType;
67 /** The output format. */
68 RTACPITBLTYPE enmOutType;
69 /** The output filename */
70 const char *pszOutFile;
71 /** Output blob version. */
72 uint32_t u32VersionBlobOut;
73 /** The byte array name when converting to a C Header. */
74 const char *pszCHdrArrayName;
75} RTCMDIASLOPTS;
76/** Pointer to const IASL options. */
77typedef RTCMDIASLOPTS const *PCRTCMDIASLOPTS;
78
79
80/**
81 * Private data of the to C header conversion I/O stream.
82 */
83typedef struct RTVFS2CHDRIOS
84{
85 /** The I/O stream handle. */
86 RTVFSIOSTREAM hVfsIos;
87 /** Current stream offset. */
88 RTFOFF offStream;
89 /** Number of characters to indent. */
90 uint32_t cchIndent;
91 /** Number of bytes per line. */
92 uint32_t cBytesPerLine;
93 /** Bytes outputted in the current line. */
94 uint32_t cBytesOutput;
95} RTVFS2CHDRIOS;
96/** Pointer to the private data the to C header conversion I/O stream. */
97typedef RTVFS2CHDRIOS *PRTVFS2CHDRIOS;
98
99
100static char g_szHexDigits[17] = "0123456789abcdef";
101
102/**
103 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
104 */
105static DECLCALLBACK(int) rtVfs2CHdrIos_Close(void *pvThis)
106{
107 PRTVFS2CHDRIOS pThis = (PRTVFS2CHDRIOS)pvThis;
108
109 int rc = RTVfsIoStrmPrintf(pThis->hVfsIos, "\n};\n");
110
111 RTVfsIoStrmRelease(pThis->hVfsIos);
112 pThis->hVfsIos = NIL_RTVFSIOSTREAM;
113 return rc;
114}
115
116
117/**
118 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
119 */
120static DECLCALLBACK(int) rtVfs2CHdrIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
121{
122 PRTVFS2CHDRIOS pThis = (PRTVFS2CHDRIOS)pvThis;
123 return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr); /** @todo This is kind of wrong. */
124}
125
126
127/**
128 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
129 */
130static DECLCALLBACK(int) rtVfs2CHdrIos_Read(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
131{
132 RT_NOREF(pvThis, off, pSgBuf, fBlocking, pcbRead);
133 return VERR_ACCESS_DENIED;
134}
135
136
137/**
138 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
139 */
140static DECLCALLBACK(int) rtVfs2CHdrIos_Write(void *pvThis, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
141{
142 PRTVFS2CHDRIOS pThis = (PRTVFS2CHDRIOS)pvThis;
143 AssertReturn(off == -1 || off == pThis->offStream , VERR_INVALID_PARAMETER);
144 RT_NOREF(fBlocking);
145
146 int rc = VINF_SUCCESS;
147 size_t cbWritten = 0;
148 uint8_t const *pbSrc = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
149 size_t cbLeft = pSgBuf->paSegs[0].cbSeg;
150 char achBuf[_4K];
151 uint32_t offBuf = 0;
152 for (;;)
153 {
154 if (!cbLeft)
155 break;
156
157 /* New line? */
158 if (!pThis->cBytesOutput)
159 {
160 if (offBuf + pThis->cchIndent < RT_ELEMENTS(achBuf))
161 {
162 rc = RTVfsIoStrmWrite(pThis->hVfsIos, &achBuf[0], offBuf, true /*fBlocking*/, NULL /*pcbWritten*/);
163 if (RT_FAILURE(rc))
164 return rc;
165 offBuf = 0;
166 }
167 memset(&achBuf[offBuf], ' ', pThis->cchIndent);
168 offBuf += pThis->cchIndent;
169 }
170
171 while ( cbLeft
172 && pThis->cBytesOutput < pThis->cBytesPerLine)
173 {
174 /* Each byte tykes up to 6 characters '0x00, ' so flush if the buffer is too full. */
175 if (offBuf + pThis->cBytesPerLine * 6 < RT_ELEMENTS(achBuf))
176 {
177 rc = RTVfsIoStrmWrite(pThis->hVfsIos, &achBuf[0], offBuf, true /*fBlocking*/, NULL /*pcbWritten*/);
178 if (RT_FAILURE(rc))
179 return rc;
180 offBuf = 0;
181 }
182
183 achBuf[offBuf++] = '0';
184 achBuf[offBuf++] = 'x';
185 achBuf[offBuf++] = g_szHexDigits[*pbSrc >> 4];
186 achBuf[offBuf++] = g_szHexDigits[*pbSrc & 0xf];
187 cbLeft--;
188 pbSrc++;
189 pThis->cBytesOutput++;
190
191 if (cbLeft)
192 {
193 achBuf[offBuf++] = ',';
194
195 if (pThis->cBytesOutput < pThis->cBytesPerLine)
196 achBuf[offBuf++] = ' ';
197 else
198 {
199 achBuf[offBuf++] = '\n';
200 pThis->cBytesOutput = 0;
201 break;
202 }
203 }
204 }
205 }
206
207 /* Last flush */
208 if (offBuf)
209 rc = RTVfsIoStrmWrite(pThis->hVfsIos, &achBuf[0], offBuf, true /*fBlocking*/, NULL /*pcbWritten*/);
210
211 pThis->offStream += cbWritten;
212 if (pcbWritten)
213 *pcbWritten = cbWritten;
214 RTSgBufAdvance(pSgBuf, cbWritten);
215
216 return rc;
217}
218
219
220/**
221 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
222 */
223static DECLCALLBACK(int) rtVfs2CHdrIos_Flush(void *pvThis)
224{
225 PRTVFS2CHDRIOS pThis = (PRTVFS2CHDRIOS)pvThis;
226 return RTVfsIoStrmFlush(pThis->hVfsIos);
227}
228
229
230/**
231 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
232 */
233static DECLCALLBACK(int) rtVfs2CHdrIos_Tell(void *pvThis, PRTFOFF poffActual)
234{
235 PRTVFS2CHDRIOS pThis = (PRTVFS2CHDRIOS)pvThis;
236 *poffActual = pThis->offStream;
237 return VINF_SUCCESS;
238}
239
240
241/**
242 * I/O stream progress operations.
243 */
244DECL_HIDDEN_CONST(const RTVFSIOSTREAMOPS) g_rtVfs2CHdrIosOps =
245{
246 { /* Obj */
247 RTVFSOBJOPS_VERSION,
248 RTVFSOBJTYPE_IO_STREAM,
249 "I/O Stream 2 C header",
250 rtVfs2CHdrIos_Close,
251 rtVfs2CHdrIos_QueryInfo,
252 NULL,
253 RTVFSOBJOPS_VERSION
254 },
255 RTVFSIOSTREAMOPS_VERSION,
256 RTVFSIOSTREAMOPS_FEAT_NO_SG,
257 rtVfs2CHdrIos_Read,
258 rtVfs2CHdrIos_Write,
259 rtVfs2CHdrIos_Flush,
260 NULL /*PollOne*/,
261 rtVfs2CHdrIos_Tell,
262 NULL /*Skip*/,
263 NULL /*ZeroFill*/,
264 RTVFSIOSTREAMOPS_VERSION,
265};
266
267
268/**
269 * Opens the input file.
270 *
271 * @returns Command exit, error messages written using RTMsg*.
272 *
273 * @param pszFile The input filename.
274 * @param phVfsIos Where to return the input stream handle.
275 */
276static RTEXITCODE rtCmdIaslOpenInput(const char *pszFile, PRTVFSIOSTREAM phVfsIos)
277{
278 int rc;
279
280 if (!strcmp(pszFile, "-"))
281 {
282 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT,
283 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
284 true /*fLeaveOpen*/,
285 phVfsIos);
286 if (RT_FAILURE(rc))
287 return RTMsgErrorExitFailure("Error opening standard input: %Rrc", rc);
288 }
289 else
290 {
291 uint32_t offError = 0;
292 RTERRINFOSTATIC ErrInfo;
293 rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
294 phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
295 if (RT_FAILURE(rc))
296 return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
297 }
298
299 return RTEXITCODE_SUCCESS;
300}
301
302
303/**
304 * Opens the output file.
305 *
306 * @returns IPRT status code.
307 *
308 * @param pszInputFile Input filename (for writing it to the header if enabled).
309 * @param pszFile The output filename.
310 * @param pszCHdrArrayName If not NULL the output will be a C header with the given byte array containing the AML.
311 * @param phVfsIos Where to return the input stream handle.
312 */
313static int rtCmdIaslOpenOutput(const char *pszInputFile, const char *pszFile, const char *pszCHdrArrayName, PRTVFSIOSTREAM phVfsIos)
314{
315 int rc;
316
317 RTVFSIOSTREAM hVfsIosOut = NIL_RTVFSIOSTREAM;
318 if (!strcmp(pszFile, "-"))
319 {
320 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT,
321 RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
322 true /*fLeaveOpen*/,
323 &hVfsIosOut);
324 if (RT_FAILURE(rc))
325 return RTMsgErrorRc(rc, "Error opening standard output: %Rrc", rc);
326 }
327 else
328 {
329 uint32_t offError = 0;
330 RTERRINFOSTATIC ErrInfo;
331 rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE,
332 &hVfsIosOut, &offError, RTErrInfoInitStatic(&ErrInfo));
333 if (RT_FAILURE(rc))
334 {
335 RTVfsChainMsgError("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
336 return rc;
337 }
338 }
339
340 if (pszCHdrArrayName)
341 {
342 /* Print the header. */
343 rc = RTVfsIoStrmPrintf(hVfsIosOut, "/*\n"
344 " * This file was automatically generated\n"
345 " * from %s\n"
346 " * by RTIasl.\n"
347 " */\n"
348 "\n"
349 "\n"
350 "static const unsigned char %s[] =\n"
351 "{\n",
352 pszInputFile, pszCHdrArrayName);
353
354 PRTVFS2CHDRIOS pThis;
355 rc = RTVfsNewIoStream(&g_rtVfs2CHdrIosOps, sizeof(*pThis), RTVfsIoStrmGetOpenFlags(hVfsIosOut),
356 NIL_RTVFS, NIL_RTVFSLOCK, phVfsIos, (void **)&pThis);
357 if (RT_SUCCESS(rc))
358 {
359 pThis->hVfsIos = hVfsIosOut;
360 pThis->offStream = 0;
361 pThis->cchIndent = 4;
362 pThis->cBytesPerLine = 16;
363 pThis->cBytesOutput = 0;
364 }
365 return rc;
366 }
367 else
368 *phVfsIos = hVfsIosOut;
369
370 return VINF_SUCCESS;
371
372}
373
374
375/**
376 * Processes the given input according to the options.
377 *
378 * @returns Command exit code, error messages written using RTMsg*.
379 * @param pszInputFile Input filename (for writing it to the header if enabled).
380 * @param pOpts The command options.
381 * @param hVfsSrc VFS I/O stream handle of the input.
382 */
383static RTEXITCODE rtCmdIaslProcess(const char *pszInputFile, PCRTCMDIASLOPTS pOpts, RTVFSIOSTREAM hVfsSrc)
384{
385 if (pOpts->enmInType == RTACPITBLTYPE_INVALID)
386 return RTMsgErrorExitFailure("iASL input format wasn't given");
387 if (pOpts->enmOutType == RTACPITBLTYPE_INVALID)
388 return RTMsgErrorExitFailure("iASL output format wasn't given");
389
390 RTERRINFOSTATIC ErrInfo;
391 RTVFSIOSTREAM hVfsIosDst = NIL_RTVFSIOSTREAM;
392 int rc = rtCmdIaslOpenOutput(pszInputFile, pOpts->pszOutFile, pOpts->pszCHdrArrayName, &hVfsIosDst);
393 if (RT_SUCCESS(rc))
394 {
395 rc = RTAcpiTblConvertFromVfsIoStrm(hVfsIosDst, pOpts->enmOutType, hVfsSrc, pOpts->enmInType, RTErrInfoInitStatic(&ErrInfo));
396 if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
397 rc = RTMsgErrorRc(rc, "Disassembling the ACPI table failed: %Rrc - %s", rc, ErrInfo.Core.pszMsg);
398 else if (RT_FAILURE(rc))
399 rc = RTMsgErrorRc(rc, "Writing the disassembled ACPI table failed: %Rrc\n", rc);
400 RTVfsIoStrmRelease(hVfsIosDst);
401 }
402
403 if (RT_FAILURE(rc))
404 return RTEXITCODE_FAILURE;
405
406 return RTEXITCODE_SUCCESS;
407}
408
409
410/**
411 * A iasl clone.
412 *
413 * @returns Program exit code.
414 *
415 * @param cArgs The number of arguments.
416 * @param papszArgs The argument vector. (Note that this may be
417 * reordered, so the memory must be writable.)
418 */
419static RTEXITCODE RTCmdIasl(unsigned cArgs, char **papszArgs)
420{
421
422 /*
423 * Parse the command line.
424 */
425 static const RTGETOPTDEF s_aOptions[] =
426 {
427 { "--disassemble", 'd', RTGETOPT_REQ_NOTHING },
428 { "--out", 'o', RTGETOPT_REQ_STRING },
429 { "--path", 'p', RTGETOPT_REQ_STRING },
430 { "--help", 'h', RTGETOPT_REQ_NOTHING },
431 { "--version", 'v', RTGETOPT_REQ_NOTHING },
432 { "--text-c-hdr", 't', RTGETOPT_REQ_STRING }
433 };
434
435 RTCMDIASLOPTS Opts;
436 Opts.enmInType = RTACPITBLTYPE_ASL;
437 Opts.enmOutType = RTACPITBLTYPE_AML;
438 Opts.pszCHdrArrayName = NULL;
439
440 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
441 RTGETOPTSTATE GetState;
442 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
443 RTGETOPTINIT_FLAGS_OPTS_FIRST);
444 if (RT_SUCCESS(rc))
445 {
446 bool fContinue = true;
447 do
448 {
449 RTGETOPTUNION ValueUnion;
450 int chOpt = RTGetOpt(&GetState, &ValueUnion);
451 switch (chOpt)
452 {
453 case VINF_GETOPT_NOT_OPTION:
454 {
455 RTVFSIOSTREAM hVfsSrc;
456 RTEXITCODE rcExit2 = rtCmdIaslOpenInput(ValueUnion.psz, &hVfsSrc);
457 if (rcExit2 == RTEXITCODE_SUCCESS)
458 {
459 rcExit2 = rtCmdIaslProcess(ValueUnion.psz, &Opts, hVfsSrc);
460 RTVfsIoStrmRelease(hVfsSrc);
461 }
462 if (rcExit2 != RTEXITCODE_SUCCESS)
463 rcExit = rcExit2;
464 fContinue = false;
465 break;
466 }
467
468 case 'd':
469 Opts.enmInType = RTACPITBLTYPE_AML;
470 Opts.enmOutType = RTACPITBLTYPE_ASL;
471 break;
472
473 case 'o':
474 case 'p':
475 Opts.pszOutFile = ValueUnion.psz;
476 break;
477
478 case 't':
479 Opts.pszCHdrArrayName = ValueUnion.psz;
480 break;
481
482 case 'h':
483 RTPrintf("Usage: to be written\nOption dump:\n");
484 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
485 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
486 fContinue = false;
487 break;
488
489 case 'v':
490 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
491 fContinue = false;
492 break;
493
494 default:
495 rcExit = RTGetOptPrintError(chOpt, &ValueUnion);
496 fContinue = false;
497 break;
498 }
499 } while (fContinue);
500 }
501 else
502 rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
503 return rcExit;
504}
505
506
507int main(int argc, char **argv)
508{
509 int rc = RTR3InitExe(argc, &argv, 0);
510 if (RT_FAILURE(rc))
511 return RTMsgInitFailure(rc);
512 return RTCmdIasl(argc, argv);
513}
514
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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