VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/acpi/acpi.cpp@ 108167

Last change on this file since 108167 was 108167, checked in by vboxsync, 3 months ago

Runtime/RTAcpi*: Continue with resource template parsing, bugref:10733

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.0 KB
Line 
1/* $Id: acpi.cpp 108167 2025-02-11 21:22:02Z vboxsync $ */
2/** @file
3 * IPRT - Advanced Configuration and Power Interface (ACPI) Table generation API.
4 */
5
6/*
7 * Copyright (C) 2024 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/file.h>
45#include <iprt/mem.h>
46#include <iprt/string.h>
47#include <iprt/utf16.h>
48#include <iprt/uuid.h>
49
50#include <iprt/formats/acpi-aml.h>
51#include <iprt/formats/acpi-resources.h>
52
53#include "internal/acpi.h"
54
55
56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
59
60
61
62/*********************************************************************************************************************************
63* Structures and Typedefs *
64*********************************************************************************************************************************/
65
66/**
67 * Package stack element.
68 */
69typedef struct RTACPITBLSTACKELEM
70{
71 /** Offset into the table buffer memory where the PkgLength object starts. */
72 uint32_t offPkgLength;
73 /** Current size of the package in bytes, without the PkgLength object. */
74 uint32_t cbPkg;
75 /** The operator creating the package, UINT8_MAX denotes the special root operator. */
76 uint8_t bOp;
77} RTACPITBLSTACKELEM;
78/** Pointer to a package stack element. */
79typedef RTACPITBLSTACKELEM *PRTACPITBLSTACKELEM;
80/** Pointer to a const package stack element. */
81typedef const RTACPITBLSTACKELEM *PCRTACPITBLSTACKELEM;
82
83
84/**
85 * ACPI table generator instance.
86 */
87typedef struct RTACPITBLINT
88{
89 /** Pointer to the ACPI table header, needed when finalizing the table. */
90 PACPITBLHDR pHdr;
91 /** Byte buffer holding the actual table. */
92 uint8_t *pbTblBuf;
93 /** Size of the table buffer. */
94 uint32_t cbTblBuf;
95 /** Current offset into the table buffer. */
96 uint32_t offTblBuf;
97 /** Flag whether the table is finalized. */
98 bool fFinalized;
99 /** First error code encountered. */
100 int rcErr;
101 /** Pointer to the package element stack. */
102 PRTACPITBLSTACKELEM paPkgStack;
103 /** Number of elements the package stack can hold. */
104 uint32_t cPkgStackElems;
105 /** Index of the current package in the package stack. */
106 uint32_t idxPkgStackElem;
107} RTACPITBLINT;
108/** Pointer to an ACPI table generator instance. */
109typedef RTACPITBLINT *PRTACPITBLINT;
110
111
112/**
113 * ACPI resource builder instance.
114 */
115typedef struct RTACPIRESINT
116{
117 /** Byte buffer holding the resource. */
118 uint8_t *pbResBuf;
119 /** Size of the resource buffer. */
120 size_t cbResBuf;
121 /** Current offset into the resource buffer. */
122 uint32_t offResBuf;
123 /** Flag whether the resource is sealed. */
124 bool fSealed;
125 /** First error code encountered. */
126 int rcErr;
127} RTACPIRESINT;
128/** Pointer to an ACPI resource builder instance. */
129typedef RTACPIRESINT *PRTACPIRESINT;
130
131
132/*********************************************************************************************************************************
133* Global Variables *
134*********************************************************************************************************************************/
135
136
137/*********************************************************************************************************************************
138* Internal Functions *
139*********************************************************************************************************************************/
140
141
142/**
143 * Copies the given string into the given buffer padding the remainder with the given character.
144 *
145 * @param pbId The destination to copy the string to.
146 * @param cbId Size of the buffer in bytes.
147 * @param pszStr The string to copy.
148 * @param chPad The character to pad with.
149 */
150static void rtAcpiTblCopyStringPadWith(uint8_t *pbId, size_t cbId, const char *pszStr, char chPad)
151{
152 Assert(strlen(pszStr) <= cbId);
153
154 uint32_t idx = 0;
155 while (*pszStr != '\0')
156 pbId[idx++] = (uint8_t)*pszStr++;
157
158 while (idx < cbId)
159 pbId[idx++] = chPad;
160}
161
162
163/**
164 * Updates the package length of the current package in the stack
165 *
166 * @param pThis The ACPI table instance.
167 * @param cbAdd How many bytes to add to the package length.
168 */
169DECL_FORCE_INLINE(void) rtAcpiTblUpdatePkgLength(PRTACPITBLINT pThis, uint32_t cbAdd)
170{
171 PRTACPITBLSTACKELEM pPkgElem = &pThis->paPkgStack[pThis->idxPkgStackElem];
172 pPkgElem->cbPkg += cbAdd;
173}
174
175
176/**
177 * Ensures there is the given amount of room in the ACPI table buffer returning the pointer.
178 *
179 * @returns The pointer to the free space on success or NULL if out of memory.
180 * @param pThis The ACPI table instance.
181 * @param cbReq Amount of bytes requested.
182 */
183static uint8_t *rtAcpiTblBufEnsureSpace(PRTACPITBLINT pThis, uint32_t cbReq)
184{
185 if (RT_LIKELY(pThis->cbTblBuf - pThis->offTblBuf >= cbReq))
186 {
187 uint8_t *pb = &pThis->pbTblBuf[pThis->offTblBuf];
188 pThis->offTblBuf += cbReq;
189 return pb;
190 }
191
192 uint32_t const cbNew = RT_ALIGN_32(pThis->cbTblBuf + cbReq, _4K);
193 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pThis->pbTblBuf, cbNew);
194 if (RT_UNLIKELY(!pbNew))
195 {
196 pThis->rcErr = VERR_NO_MEMORY;
197 return NULL;
198 }
199
200 pThis->pbTblBuf = pbNew;
201 pThis->cbTblBuf = cbNew;
202 pThis->pHdr = (PACPITBLHDR)pbNew;
203
204 uint8_t *pb = &pThis->pbTblBuf[pThis->offTblBuf];
205 pThis->offTblBuf += cbReq;
206 return pb;
207}
208
209
210/**
211 * Appends a new package in the given ACPI table instance package stack.
212 *
213 * @returns IPRT status code.
214 * @retval VERR_NO_MEMORY if allocating additional resources to hold the new package failed.
215 * @param pThis The ACPI table instance.
216 * @param bOp The opcode byte the package starts with (for verification purposes when finalizing the package).
217 * @param offPkgBuf Offset of the start of the package buffer.
218 */
219static int rtAcpiTblPkgAppendEx(PRTACPITBLINT pThis, uint8_t bOp, uint32_t offPkgBuf)
220{
221 /* Get a new stack element. */
222 if (pThis->idxPkgStackElem + 1 == pThis->cPkgStackElems)
223 {
224 uint32_t const cPkgElemsNew = pThis->cPkgStackElems + 8;
225 PRTACPITBLSTACKELEM paPkgStackNew = (PRTACPITBLSTACKELEM)RTMemRealloc(pThis->paPkgStack, cPkgElemsNew * sizeof(*paPkgStackNew));
226 if (!paPkgStackNew)
227 {
228 pThis->rcErr = VERR_NO_MEMORY;
229 return VERR_NO_MEMORY;
230 }
231
232 pThis->paPkgStack = paPkgStackNew;
233 pThis->cPkgStackElems = cPkgElemsNew;
234 }
235
236 PRTACPITBLSTACKELEM pStackElem = &pThis->paPkgStack[++pThis->idxPkgStackElem];
237 pStackElem->offPkgLength = offPkgBuf;
238 pStackElem->cbPkg = 0;
239 pStackElem->bOp = bOp;
240 return VINF_SUCCESS;
241}
242
243
244/**
245 * Starts a new ACPI package in the given ACPI table instance.
246 *
247 * @returns IPRT status code.
248 * @retval VERR_NO_MEMORY if allocating additional resources to hold the new package failed.
249 * @param pThis The ACPI table instance.
250 * @param bOp The opcode byte identifying the package content.
251 */
252static int rtAcpiTblPkgStart(PRTACPITBLINT pThis, uint8_t bOp)
253{
254 /*
255 * Allocate 1 byte for opcode + always 4 bytes for the PkgLength, as we don't know how much we will need upfront.
256 * This will be corrected when the package is finalized.
257 */
258 uint8_t *pbPkg = rtAcpiTblBufEnsureSpace(pThis, 5);
259 if (!pbPkg)
260 {
261 pThis->rcErr = VERR_NO_MEMORY;
262 return VERR_NO_MEMORY;
263 }
264
265 *pbPkg = bOp;
266 /*
267 * Update the package length of the outer package for the opcode,
268 * the PkgLength object's final length will be added in rtAcpiTblPkgFinish().
269 */
270 rtAcpiTblUpdatePkgLength(pThis, sizeof(bOp));
271 return rtAcpiTblPkgAppendEx(pThis, bOp, (pbPkg + 1) - pThis->pbTblBuf);
272}
273
274
275/**
276 * Starts a new ACPI package in the given ACPI table instance. This is for opcodes prefixed with
277 * ACPI_AML_BYTE_CODE_PREFIX_EXT_O, which will be added automatically.
278 *
279 * @returns IPRT status code.
280 * @retval VERR_NO_MEMORY if allocating additional resources to hold the new package failed.
281 * @param pThis The ACPI table instance.
282 * @param bOp The opcode byte identifying the package content.
283 */
284static int rtAcpiTblPkgStartExt(PRTACPITBLINT pThis, uint8_t bOp)
285{
286 /*
287 * Allocate 2 bytes for ExtOpPrefix opcode + always 4 bytes for the PkgLength, as we don't know how much we will need upfront.
288 * This will be corrected when the package is finalized.
289 */
290 uint8_t *pbPkg = rtAcpiTblBufEnsureSpace(pThis, 6);
291 if (!pbPkg)
292 {
293 pThis->rcErr = VERR_NO_MEMORY;
294 return VERR_NO_MEMORY;
295 }
296
297 pbPkg[0] = ACPI_AML_BYTE_CODE_PREFIX_EXT_OP;
298 pbPkg[1] = bOp;
299
300 /*
301 * Update the package length of the outer package for the opcode,
302 * the PkgLength object's final length will be added in rtAcpiTblPkgFinish().
303 */
304 rtAcpiTblUpdatePkgLength(pThis, sizeof(uint8_t) + sizeof(bOp));
305 return rtAcpiTblPkgAppendEx(pThis, bOp, (pbPkg + 2) - pThis->pbTblBuf);
306}
307
308
309/**
310 * Finishes the current package on the top of the package stack, setting the
311 * package length accordingly.
312 *
313 * @returns IPRT status code.
314 * @retval VERR_INVALID_STATE if bOp doesn't match the opcode the package was started with (asserted in debug builds).
315 * @retval VERR_BUFFER_OVERFLOW if the package length exceeds what can be encoded in the package length field.
316 * @param pThis The ACPI table instance.
317 * @param bOp The opcode byte identifying the package content the package was started with.
318 */
319static int rtAcpiTblPkgFinish(PRTACPITBLINT pThis, uint8_t bOp)
320{
321 /* Ensure the op matches what is current on the top of the stack. */
322 AssertReturn(pThis->paPkgStack[pThis->idxPkgStackElem].bOp == bOp, VERR_INVALID_STATE);
323
324 /* Pop the topmost stack element from the stack. */
325 PRTACPITBLSTACKELEM pPkgElem = &pThis->paPkgStack[pThis->idxPkgStackElem--];
326
327 /*
328 * Determine how many bytes we actually need for the PkgLength and re-arrange the ACPI table.
329 *
330 * Note! PkgLength will also include its own length.
331 */
332 uint8_t *pbPkgLength = &pThis->pbTblBuf[pPkgElem->offPkgLength];
333 uint32_t cbThisPkg = pPkgElem->cbPkg;
334 if (cbThisPkg + 1 <= 63)
335 {
336 /* Remove the gap. */
337 memmove(pbPkgLength + 1, pbPkgLength + 4, cbThisPkg);
338 pThis->offTblBuf -= 3;
339
340 /* PkgLength only consists of the package lead byte. */
341 cbThisPkg += 1;
342 *pbPkgLength = (cbThisPkg & 0x3f);
343 }
344 else if (cbThisPkg + 2 < RT_BIT_32(12))
345 {
346 /* Remove the gap. */
347 memmove(pbPkgLength + 2, pbPkgLength + 4, cbThisPkg);
348 pThis->offTblBuf -= 2;
349
350 cbThisPkg += 2;
351 pbPkgLength[0] = (1 << 6) | (cbThisPkg & 0xf);
352 pbPkgLength[1] = (cbThisPkg >> 4) & 0xff;
353 }
354 else if (cbThisPkg + 3 < RT_BIT_32(20))
355 {
356 /* Remove the gap. */
357 memmove(pbPkgLength + 3, pbPkgLength + 4, cbThisPkg);
358 pThis->offTblBuf -= 1;
359
360 cbThisPkg += 3;
361 pbPkgLength[0] = (2 << 6) | (cbThisPkg & 0xf);
362 pbPkgLength[1] = (cbThisPkg >> 4) & 0xff;
363 pbPkgLength[2] = (cbThisPkg >> 12) & 0xff;
364 }
365 else if (cbThisPkg + 4 < RT_BIT_32(28))
366 {
367 cbThisPkg += 4;
368 pbPkgLength[0] = (3 << 6) | (cbThisPkg & 0xf);
369 pbPkgLength[1] = (cbThisPkg >> 4) & 0xff;
370 pbPkgLength[2] = (cbThisPkg >> 12) & 0xff;
371 pbPkgLength[3] = (cbThisPkg >> 20) & 0xff;
372 }
373 else
374 return VERR_BUFFER_OVERFLOW;
375
376 /* Update the size of the outer package. */
377 pThis->paPkgStack[pThis->idxPkgStackElem].cbPkg += cbThisPkg;
378
379 return VINF_SUCCESS;
380}
381
382
383/**
384 * Appends the given byte to the ACPI table, updating the package length of the current package.
385 *
386 * @param pThis The ACPI table instance.
387 * @param bData The byte data to append.
388 */
389DECLINLINE(void) rtAcpiTblAppendByte(PRTACPITBLINT pThis, uint8_t bData)
390{
391 uint8_t *pb = rtAcpiTblBufEnsureSpace(pThis, sizeof(bData));
392 if (pb)
393 {
394 *pb = bData;
395 rtAcpiTblUpdatePkgLength(pThis, sizeof(bData));
396 }
397}
398
399
400/**
401 * Appends the given double word to the ACPI table, updating the package length of the current package.
402 *
403 * @param pThis The ACPI table instance.
404 * @param u32 The data to append.
405 */
406DECLINLINE(void) rtAcpiTblAppendDword(PRTACPITBLINT pThis, uint32_t u32)
407{
408 uint8_t *pb = rtAcpiTblBufEnsureSpace(pThis, sizeof(u32));
409 if (pb)
410 {
411 pb[0] = (uint8_t)u32;
412 pb[1] = (uint8_t)(u32 >> 8);
413 pb[2] = (uint8_t)(u32 >> 16);
414 pb[3] = (uint8_t)(u32 >> 24);
415 rtAcpiTblUpdatePkgLength(pThis, sizeof(u32));
416 }
417}
418
419
420/**
421 * Appends the given date to the ACPI table, updating the package length of the current package.
422 *
423 * @param pThis The ACPI table instance.
424 * @param pvData The data to append.
425 * @param cbData Size of the data in bytes.
426 */
427DECLINLINE(void) rtAcpiTblAppendData(PRTACPITBLINT pThis, const void *pvData, uint32_t cbData)
428{
429 uint8_t *pb = rtAcpiTblBufEnsureSpace(pThis, cbData);
430 if (pb)
431 {
432 memcpy(pb, pvData, cbData);
433 rtAcpiTblUpdatePkgLength(pThis, cbData);
434 }
435}
436
437
438/**
439 * Appends the given name segment to the destination padding the segment with '_' if the
440 * name segment is shorter than 4 characters.
441 *
442 * @returns Pointer to the character after the given name segment.
443 * @param pbDst Where to store the name segment.
444 * @param pachNameSeg The name segment to append.
445 */
446DECLINLINE(const char *) rtAcpiTblAppendNameSeg(uint8_t *pbDst, const char *pachNameSeg)
447{
448 Assert(pachNameSeg[0] != '.' && pachNameSeg[0] != '\0');
449
450 uint8_t cch = 1;
451 pbDst[0] = pachNameSeg[0];
452
453 for (uint8_t i = 1; i < 4; i++)
454 {
455 if ( pachNameSeg[cch] != '.'
456 && pachNameSeg[cch] != '\0')
457 {
458 pbDst[i] = pachNameSeg[cch];
459 cch++;
460 }
461 else
462 pbDst[i] = '_';
463 }
464
465 return &pachNameSeg[cch];
466}
467
468
469/**
470 * Appends the given namestring to the ACPI table, updating the package length of the current package
471 * and padding the name with _ if too short.
472 *
473 * @param pThis The ACPI table instance.
474 * @param pszName The name string to append.
475 */
476static void rtAcpiTblAppendNameString(PRTACPITBLINT pThis, const char *pszName)
477{
478 if (*pszName == '\\')
479 {
480 /* Root prefix. */
481 rtAcpiTblAppendByte(pThis, '\\');
482 pszName++;
483 }
484 else if (*pszName == '^')
485 {
486 /* PrefixPath */
487 do
488 {
489 rtAcpiTblAppendByte(pThis, '^');
490 pszName++;
491 }
492 while (*pszName == '^');
493 }
494
495 /*
496 * We need to count the number of segments to decide whether a
497 * NameSeg, DualNamePath or MultiNamePath is needed.
498 */
499 uint8_t cSegments = 1;
500 const char *pszTmp = pszName;
501 while (*pszTmp != '\0')
502 {
503 if (*pszTmp++ == '.')
504 cSegments++;
505 }
506
507 uint32_t cbReq = cSegments * 4 * sizeof(uint8_t);
508 if (cSegments == 2)
509 cbReq++; /* DualName Prefix */
510 else if (cSegments != 1)
511 cbReq += 2; /* MultiName prefix + segment count */
512 uint8_t *pb = rtAcpiTblBufEnsureSpace(pThis, cbReq);
513 if (pb)
514 {
515 if (cSegments == 1)
516 {
517 rtAcpiTblAppendNameSeg(pb, pszName);
518 rtAcpiTblUpdatePkgLength(pThis, 4);
519 }
520 else if (cSegments == 2)
521 {
522 *pb++ = ACPI_AML_BYTE_CODE_PREFIX_DUAL_NAME;
523 pszName = rtAcpiTblAppendNameSeg(pb, pszName);
524 pb += 4;
525 Assert(*pszName == '.');
526 pszName++;
527 pszName = rtAcpiTblAppendNameSeg(pb, pszName);
528 Assert(*pszName == '\0'); RT_NOREF(pszName);
529 rtAcpiTblUpdatePkgLength(pThis, 1 + 8);
530 }
531 else
532 {
533 *pb++ = ACPI_AML_BYTE_CODE_PREFIX_MULTI_NAME;
534 *pb++ = cSegments;
535 for (uint8_t i = 0; i < cSegments; i++)
536 {
537 pszName = rtAcpiTblAppendNameSeg(pb, pszName);
538 Assert(*pszName == '.' || *pszName == '\0');
539 pb += 4;
540 pszName++;
541 }
542 rtAcpiTblUpdatePkgLength(pThis, 2 + cSegments * 4);
543 }
544 }
545}
546
547
548/**
549 * Appends a name segment or the NullName to the given ACPI table.
550 *
551 * @returns nothing.
552 * @param pThis The ACPI table instance.
553 * @param pszName The name to append, maximum is 4 chracters. If less than 4 characters
554 * anything left is padded with _. NULL means append the NullName.
555 */
556DECLINLINE(void) rtAcpiTblAppendNameSegOrNullName(PRTACPITBLINT pThis, const char *pszName)
557{
558 if (!pszName)
559 {
560 uint8_t *pb = rtAcpiTblBufEnsureSpace(pThis, 1);
561 if (pb)
562 {
563 *pb = ACPI_AML_BYTE_CODE_PREFIX_NULL_NAME;
564 rtAcpiTblUpdatePkgLength(pThis, 1);
565 }
566 }
567 else
568 {
569 AssertReturnVoidStmt(strlen(pszName) <= 4, pThis->rcErr = VERR_INVALID_PARAMETER);
570 uint8_t *pb = rtAcpiTblBufEnsureSpace(pThis, 4);
571 if (pb)
572 {
573 rtAcpiTblCopyStringPadWith(pb, 4, pszName, '_');
574 rtAcpiTblUpdatePkgLength(pThis, 4);
575 }
576 }
577}
578
579
580/**
581 * Encodes a PkgLength item for the given number.
582 *
583 * @returns IPRT status code.
584 * @param pThis The ACPI table instance.
585 * @param u64Length The length to encode.
586 */
587DECLINLINE(int) rtAcpiTblEncodePkgLength(PRTACPITBLINT pThis, uint64_t u64Length)
588{
589 AssertReturn(u64Length < RT_BIT_32(28), VERR_BUFFER_OVERFLOW);
590
591 if (u64Length <= 63)
592 {
593 /* PkgLength only consists of the package lead byte. */
594 rtAcpiTblAppendByte(pThis, (u64Length & 0x3f));
595 }
596 else if (u64Length < RT_BIT_32(12))
597 {
598 uint8_t abData[2];
599 abData[0] = (1 << 6) | (u64Length & 0xf);
600 abData[1] = (u64Length >> 4) & 0xff;
601 rtAcpiTblAppendData(pThis, &abData[0], sizeof(abData));
602 }
603 else if (u64Length < RT_BIT_32(20))
604 {
605 uint8_t abData[3];
606 abData[0] = (2 << 6) | (u64Length & 0xf);
607 abData[1] = (u64Length >> 4) & 0xff;
608 abData[2] = (u64Length >> 12) & 0xff;
609 rtAcpiTblAppendData(pThis, &abData[0], sizeof(abData));
610 }
611 else if (u64Length < RT_BIT_32(28))
612 {
613 uint8_t abData[4];
614 abData[0] = (3 << 6) | (u64Length & 0xf);
615 abData[1] = (u64Length >> 4) & 0xff;
616 abData[2] = (u64Length >> 12) & 0xff;
617 abData[3] = (u64Length >> 20) & 0xff;
618 rtAcpiTblAppendData(pThis, &abData[0], sizeof(abData));
619 }
620 else
621 AssertReleaseFailed();
622
623 return VINF_SUCCESS;
624}
625
626
627RTDECL(uint8_t) RTAcpiChecksumGenerate(const void *pvData, size_t cbData)
628{
629 uint8_t const *pbSrc = (uint8_t const *)pvData;
630 uint8_t bSum = 0;
631 for (size_t i = 0; i < cbData; ++i)
632 bSum += pbSrc[i];
633
634 return -bSum;
635}
636
637
638RTDECL(void) RTAcpiTblHdrChecksumGenerate(PACPITBLHDR pTbl, size_t cbTbl)
639{
640 pTbl->bChkSum = 0;
641 pTbl->bChkSum = RTAcpiChecksumGenerate(pTbl, cbTbl);
642}
643
644
645RTDECL(int) RTAcpiTblCreate(PRTACPITBL phAcpiTbl, uint32_t u32TblSig, uint8_t bRevision, const char *pszOemId,
646 const char *pszOemTblId, uint32_t u32OemRevision, const char *pszCreatorId,
647 uint32_t u32CreatorRevision)
648{
649 AssertPtrReturn(phAcpiTbl, VERR_INVALID_POINTER);
650 AssertPtrReturn(pszOemId, VERR_INVALID_POINTER);
651 AssertPtrReturn(pszOemTblId, VERR_INVALID_POINTER);
652 AssertReturn(strlen(pszOemId) <= 6, VERR_INVALID_PARAMETER);
653 AssertReturn(strlen(pszOemTblId) <= 8, VERR_INVALID_PARAMETER);
654 AssertReturn(!pszCreatorId || strlen(pszCreatorId) <= 4, VERR_INVALID_PARAMETER);
655
656 PRTACPITBLINT pThis = (PRTACPITBLINT)RTMemAllocZ(sizeof(*pThis));
657 if (pThis)
658 {
659 pThis->pbTblBuf = (uint8_t *)RTMemAlloc(_4K);
660 if (pThis->pbTblBuf)
661 {
662 pThis->pHdr = (PACPITBLHDR)pThis->pbTblBuf;
663 pThis->offTblBuf = sizeof(*pThis->pHdr);
664 pThis->cbTblBuf = _4K;
665 pThis->fFinalized = false;
666 pThis->rcErr = VINF_SUCCESS;
667 pThis->paPkgStack = NULL;
668 pThis->cPkgStackElems = 0;
669 pThis->idxPkgStackElem = 0;
670
671 /* Add the root stack element for the table, aka DefinitionBlock() in ASL. */
672 uint32_t const cPkgElemsInitial = 8;
673 pThis->paPkgStack = (PRTACPITBLSTACKELEM)RTMemAlloc(cPkgElemsInitial * sizeof(*pThis->paPkgStack));
674 if (pThis->paPkgStack)
675 {
676 pThis->cPkgStackElems = cPkgElemsInitial;
677
678 PRTACPITBLSTACKELEM pStackElem = &pThis->paPkgStack[pThis->idxPkgStackElem];
679 pStackElem->offPkgLength = 0; /* Starts with the header. */
680 pStackElem->cbPkg = sizeof(*pThis->pHdr);
681 pStackElem->bOp = UINT8_MAX;
682
683 /* Init the table header with static things. */
684 pThis->pHdr->u32Signature = u32TblSig;
685 pThis->pHdr->bRevision = bRevision;
686 pThis->pHdr->u32OemRevision = RT_H2LE_U32(u32OemRevision);
687 pThis->pHdr->u32CreatorRevision = RT_H2LE_U32(u32CreatorRevision);
688
689 rtAcpiTblCopyStringPadWith(&pThis->pHdr->abOemId[0], sizeof(pThis->pHdr->abOemId), pszOemId, ' ');
690 rtAcpiTblCopyStringPadWith(&pThis->pHdr->abOemTblId[0], sizeof(pThis->pHdr->abOemTblId), pszOemTblId, ' ');
691 rtAcpiTblCopyStringPadWith(&pThis->pHdr->abCreatorId[0], sizeof(pThis->pHdr->abCreatorId),
692 pszCreatorId ? pszCreatorId : "IPRT", ' ');
693
694 *phAcpiTbl = pThis;
695 return VINF_SUCCESS;
696 }
697
698 RTMemFree(pThis->pbTblBuf);
699 }
700
701 RTMemFree(pThis);
702 }
703
704 return VERR_NO_MEMORY;
705}
706
707
708RTDECL(void) RTAcpiTblDestroy(RTACPITBL hAcpiTbl)
709{
710 PRTACPITBLINT pThis = hAcpiTbl;
711 AssertPtrReturnVoid(pThis);
712
713 RTMemFree(pThis->paPkgStack);
714 RTMemFree(pThis->pbTblBuf);
715 pThis->pHdr = NULL;
716 pThis->pbTblBuf = NULL;
717 pThis->cbTblBuf = 0;
718 pThis->offTblBuf = 0;
719 pThis->paPkgStack = NULL;
720 pThis->cPkgStackElems = 0;
721 pThis->idxPkgStackElem = 0;
722 RTMemFree(pThis);
723}
724
725
726RTDECL(int) RTAcpiTblFinalize(RTACPITBL hAcpiTbl)
727{
728 PRTACPITBLINT pThis = hAcpiTbl;
729 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
730 AssertRCReturn(pThis->rcErr, pThis->rcErr);
731 AssertReturn(!pThis->fFinalized, VERR_INVALID_PARAMETER);
732 AssertReturn(pThis->idxPkgStackElem == 0, VERR_INVALID_STATE); /** @todo Better status code. */
733 AssertReturn(pThis->paPkgStack[0].bOp == UINT8_MAX, VERR_INVALID_STATE);
734
735 pThis->pHdr->cbTbl = RT_H2LE_U32(pThis->paPkgStack[0].cbPkg);
736 RTAcpiTblHdrChecksumGenerate(pThis->pHdr, pThis->paPkgStack[0].cbPkg);
737
738 pThis->fFinalized = true;
739 return VINF_SUCCESS;
740}
741
742
743RTDECL(uint32_t) RTAcpiTblGetSize(RTACPITBL hAcpiTbl)
744{
745 PRTACPITBLINT pThis = hAcpiTbl;
746 AssertPtrReturn(pThis, 0);
747 AssertRCReturn(pThis->rcErr, 0);
748 AssertReturn(pThis->fFinalized, 0);
749
750 return pThis->paPkgStack[0].cbPkg;
751}
752
753
754RTDECL(int) RTAcpiTblDumpToVfsIoStrm(RTACPITBL hAcpiTbl, RTACPITBLTYPE enmOutType, RTVFSIOSTREAM hVfsIos)
755{
756 PRTACPITBLINT pThis = hAcpiTbl;
757 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
758 AssertRCReturn(pThis->rcErr, 0);
759 AssertReturn(enmOutType == RTACPITBLTYPE_AML, VERR_NOT_SUPPORTED);
760
761 return RTVfsIoStrmWrite(hVfsIos, pThis->pbTblBuf, pThis->paPkgStack[0].cbPkg,
762 true /*fBlocking*/, NULL /*pcbWritten*/);
763}
764
765
766RTDECL(int) RTAcpiTblDumpToFile(RTACPITBL hAcpiTbl, RTACPITBLTYPE enmOutType, const char *pszFilename)
767{
768 RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM;
769 int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE,
770 &hVfsIos, NULL /*poffError*/, NULL);
771 if (RT_FAILURE(rc))
772 return rc;
773
774 rc = RTAcpiTblDumpToVfsIoStrm(hAcpiTbl, enmOutType, hVfsIos);
775 RTVfsIoStrmRelease(hVfsIos);
776 return rc;
777}
778
779
780RTDECL(int) RTAcpiTblDumpToBufferA(RTACPITBL hAcpiTbl, RTACPITBLTYPE enmOutType, uint8_t **ppbAcpiTbl, size_t *pcbAcpiTbl)
781{
782 PRTACPITBLINT pThis = hAcpiTbl;
783 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
784 AssertPtrReturn(ppbAcpiTbl, VERR_INVALID_POINTER);
785 AssertPtrReturn(pcbAcpiTbl, VERR_INVALID_POINTER);
786 AssertRCReturn(pThis->rcErr, 0);
787 AssertReturn(pThis->fFinalized, VERR_INVALID_STATE);
788 AssertReturn(enmOutType == RTACPITBLTYPE_AML, VERR_NOT_SUPPORTED);
789
790 *ppbAcpiTbl = (uint8_t *)RTMemDup(pThis->pbTblBuf, pThis->paPkgStack[0].cbPkg);
791 *pcbAcpiTbl = pThis->paPkgStack[0].cbPkg;
792 return *ppbAcpiTbl != NULL ? VINF_SUCCESS : VERR_NO_MEMORY;
793}
794
795
796RTDECL(int) RTAcpiTblScopeFinalize(RTACPITBL hAcpiTbl)
797{
798 PRTACPITBLINT pThis = hAcpiTbl;
799 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
800
801 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_SCOPE);
802}
803
804
805RTDECL(int) RTAcpiTblScopeStart(RTACPITBL hAcpiTbl, const char *pszName)
806{
807 PRTACPITBLINT pThis = hAcpiTbl;
808 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
809
810 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_SCOPE);
811 rtAcpiTblAppendNameString(pThis, pszName);
812 return pThis->rcErr;
813}
814
815
816RTDECL(int) RTAcpiTblPackageStart(RTACPITBL hAcpiTbl, uint8_t cElements)
817{
818 PRTACPITBLINT pThis = hAcpiTbl;
819 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
820
821 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_PACKAGE);
822 rtAcpiTblAppendByte(pThis, cElements);
823 return pThis->rcErr;
824}
825
826
827RTDECL(int) RTAcpiTblPackageFinalize(RTACPITBL hAcpiTbl)
828{
829 PRTACPITBLINT pThis = hAcpiTbl;
830 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
831
832 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_PACKAGE);
833}
834
835
836RTDECL(int) RTAcpiTblDeviceStart(RTACPITBL hAcpiTbl, const char *pszName)
837{
838 PRTACPITBLINT pThis = hAcpiTbl;
839 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
840
841 rtAcpiTblPkgStartExt(pThis, ACPI_AML_BYTE_CODE_EXT_OP_DEVICE);
842 rtAcpiTblAppendNameString(pThis, pszName);
843 return pThis->rcErr;
844}
845
846
847RTDECL(int) RTAcpiTblDeviceStartF(RTACPITBL hAcpiTbl, const char *pszNameFmt, ...)
848{
849 va_list va;
850 va_start(va, pszNameFmt);
851 int rc = RTAcpiTblDeviceStartV(hAcpiTbl, pszNameFmt, va);
852 va_end(va);
853 return rc;
854}
855
856
857RTDECL(int) RTAcpiTblDeviceStartV(RTACPITBL hAcpiTbl, const char *pszNameFmt, va_list va)
858{
859 char szName[128];
860 ssize_t cch = RTStrPrintf2V(&szName[0], sizeof(szName), pszNameFmt, va);
861 if (cch <= 0)
862 return VERR_BUFFER_OVERFLOW;
863
864 return RTAcpiTblDeviceStart(hAcpiTbl, &szName[0]);
865}
866
867
868RTDECL(int) RTAcpiTblDeviceFinalize(RTACPITBL hAcpiTbl)
869{
870 PRTACPITBLINT pThis = hAcpiTbl;
871 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
872
873 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_EXT_OP_DEVICE);
874}
875
876
877RTDECL(int) RTAcpiTblProcessorStart(RTACPITBL hAcpiTbl, const char *pszName, uint8_t bProcId, uint32_t u32PBlkAddr,
878 uint8_t cbPBlk)
879{
880 PRTACPITBLINT pThis = hAcpiTbl;
881 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
882
883 rtAcpiTblPkgStartExt(pThis, ACPI_AML_BYTE_CODE_EXT_OP_PROCESSOR);
884 rtAcpiTblAppendNameString(pThis, pszName);
885 rtAcpiTblAppendByte(pThis, bProcId);
886 rtAcpiTblAppendDword(pThis, u32PBlkAddr);
887 rtAcpiTblAppendByte(pThis, cbPBlk);
888 return pThis->rcErr;
889}
890
891
892RTDECL(int) RTAcpiTblProcessorStartF(RTACPITBL hAcpiTbl, uint8_t bProcId, uint32_t u32PBlkAddr, uint8_t cbPBlk,
893 const char *pszNameFmt, ...)
894{
895 va_list va;
896 va_start(va, pszNameFmt);
897 int rc = RTAcpiTblProcessorStartV(hAcpiTbl, bProcId, u32PBlkAddr, cbPBlk, pszNameFmt, va);
898 va_end(va);
899 return rc;
900}
901
902
903RTDECL(int) RTAcpiTblProcessorStartV(RTACPITBL hAcpiTbl, uint8_t bProcId, uint32_t u32PBlkAddr, uint8_t cbPBlk,
904 const char *pszNameFmt, va_list va)
905{
906 char szName[128];
907 ssize_t cch = RTStrPrintf2V(&szName[0], sizeof(szName), pszNameFmt, va);
908 if (cch <= 0)
909 return VERR_BUFFER_OVERFLOW;
910
911 return RTAcpiTblProcessorStart(hAcpiTbl, &szName[0], bProcId, u32PBlkAddr, cbPBlk);
912}
913
914
915RTDECL(int) RTAcpiTblProcessorFinalize(RTACPITBL hAcpiTbl)
916{
917 PRTACPITBLINT pThis = hAcpiTbl;
918 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
919
920 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_EXT_OP_PROCESSOR);
921}
922
923
924RTDECL(int) RTAcpiTblMethodStart(RTACPITBL hAcpiTbl, const char *pszName, uint8_t cArgs, uint32_t fFlags, uint8_t uSyncLvl)
925{
926 PRTACPITBLINT pThis = hAcpiTbl;
927 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
928 AssertReturn(cArgs < 8, VERR_INVALID_PARAMETER);
929 AssertReturn(uSyncLvl < 0x10, VERR_INVALID_PARAMETER);
930
931 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_METHOD);
932 rtAcpiTblAppendNameString(pThis, pszName);
933
934 uint8_t bFlags = cArgs;
935 bFlags |= fFlags & RTACPI_METHOD_F_SERIALIZED ? RT_BIT(3) : 0;
936 bFlags |= uSyncLvl << 4;
937
938 rtAcpiTblAppendByte(pThis, bFlags);
939 return pThis->rcErr;
940}
941
942
943RTDECL(int) RTAcpiTblMethodFinalize(RTACPITBL hAcpiTbl)
944{
945 PRTACPITBLINT pThis = hAcpiTbl;
946 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
947
948 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_METHOD);
949}
950
951
952RTDECL(int) RTAcpiTblNameAppend(RTACPITBL hAcpiTbl, const char *pszName)
953{
954 PRTACPITBLINT pThis = hAcpiTbl;
955 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
956
957 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_OP_NAME);
958 rtAcpiTblAppendNameString(pThis, pszName);
959 return pThis->rcErr;
960}
961
962
963RTDECL(int) RTAcpiTblNullNameAppend(RTACPITBL hAcpiTbl)
964{
965 PRTACPITBLINT pThis = hAcpiTbl;
966 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
967
968 rtAcpiTblAppendByte(pThis, 0x00);
969 return pThis->rcErr;
970}
971
972
973RTDECL(int) RTAcpiTblNameStringAppend(RTACPITBL hAcpiTbl, const char *pszName)
974{
975 PRTACPITBLINT pThis = hAcpiTbl;
976 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
977
978 rtAcpiTblAppendNameString(pThis, pszName);
979 return pThis->rcErr;
980}
981
982
983RTDECL(int) RTAcpiTblNameStringAppendF(RTACPITBL hAcpiTbl, const char *pszNameFmt, ...)
984{
985 va_list va;
986 va_start(va, pszNameFmt);
987 int rc = RTAcpiTblNameStringAppendV(hAcpiTbl, pszNameFmt, va);
988 va_end(va);
989 return rc;
990}
991
992
993RTDECL(int) RTAcpiTblNameStringAppendV(RTACPITBL hAcpiTbl, const char *pszNameFmt, va_list va)
994{
995 char szName[512];
996 ssize_t cch = RTStrPrintf2V(&szName[0], sizeof(szName), pszNameFmt, va);
997 if (cch <= 0)
998 return VERR_BUFFER_OVERFLOW;
999
1000 return RTAcpiTblNameStringAppend(hAcpiTbl, &szName[0]);
1001}
1002
1003
1004RTDECL(int) RTAcpiTblStringAppend(RTACPITBL hAcpiTbl, const char *psz)
1005{
1006 PRTACPITBLINT pThis = hAcpiTbl;
1007 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1008
1009 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_PREFIX_STRING);
1010 rtAcpiTblAppendData(pThis, psz, (uint32_t)strlen(psz) + 1);
1011 return pThis->rcErr;
1012}
1013
1014
1015RTDECL(int) RTAcpiTblStringAppendF(RTACPITBL hAcpiTbl, const char *pszNameFmt, ...)
1016{
1017 va_list va;
1018 va_start(va, pszNameFmt);
1019 int rc = RTAcpiTblStringAppendV(hAcpiTbl, pszNameFmt, va);
1020 va_end(va);
1021 return rc;
1022}
1023
1024
1025RTDECL(int) RTAcpiTblStringAppendV(RTACPITBL hAcpiTbl, const char *pszNameFmt, va_list va)
1026{
1027 char szName[512];
1028 ssize_t cch = RTStrPrintf2V(&szName[0], sizeof(szName), pszNameFmt, va);
1029 if (cch <= 0)
1030 return VERR_BUFFER_OVERFLOW;
1031
1032 return RTAcpiTblStringAppend(hAcpiTbl, &szName[0]);
1033}
1034
1035
1036RTDECL(int) RTAcpiTblStringAppendAsUtf16(RTACPITBL hAcpiTbl, const char *psz)
1037{
1038 PRTACPITBLINT pThis = hAcpiTbl;
1039 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1040 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1041
1042 PRTUTF16 pwsz = NULL;
1043 size_t cwc = 0;
1044 int rc = RTStrToUtf16Ex(psz, RTSTR_MAX, &pwsz, 0, &cwc);
1045 if (RT_SUCCESS(rc))
1046 {
1047 RTAcpiTblBufferAppend(hAcpiTbl, pwsz, (cwc + 1) * sizeof(*pwsz));
1048 RTUtf16Free(pwsz);
1049 }
1050 else
1051 pThis->rcErr = rc;
1052 return pThis->rcErr;
1053}
1054
1055
1056RTDECL(int) RTAcpiTblIntegerAppend(RTACPITBL hAcpiTbl, uint64_t u64)
1057{
1058 PRTACPITBLINT pThis = hAcpiTbl;
1059 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1060
1061 if (!u64)
1062 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_OP_ZERO);
1063 else if (u64 == 1)
1064 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_OP_ONE);
1065 else if (u64 <= UINT8_MAX)
1066 {
1067 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_PREFIX_BYTE);
1068 rtAcpiTblAppendByte(pThis, (uint8_t)u64);
1069 }
1070 else if (u64 <= UINT16_MAX)
1071 {
1072 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_PREFIX_WORD);
1073 rtAcpiTblAppendByte(pThis, (uint8_t)u64);
1074 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 8));
1075 }
1076 else if (u64 <= UINT32_MAX)
1077 {
1078 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_PREFIX_DWORD);
1079 rtAcpiTblAppendByte(pThis, (uint8_t)u64);
1080 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 8));
1081 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 16));
1082 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 24));
1083 }
1084 else
1085 {
1086 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_PREFIX_QWORD);
1087 rtAcpiTblAppendByte(pThis, (uint8_t)u64);
1088 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 8));
1089 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 16));
1090 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 24));
1091 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 32));
1092 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 40));
1093 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 48));
1094 rtAcpiTblAppendByte(pThis, (uint8_t)(u64 >> 56));
1095 }
1096 return pThis->rcErr;
1097}
1098
1099
1100RTDECL(int) RTAcpiTblBufferAppend(RTACPITBL hAcpiTbl, const void *pvBuf, size_t cbBuf)
1101{
1102 PRTACPITBLINT pThis = hAcpiTbl;
1103 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1104 AssertReturn(!cbBuf || RT_VALID_PTR(pvBuf), VERR_INVALID_PARAMETER);
1105 AssertReturn(cbBuf <= UINT32_MAX, VERR_BUFFER_OVERFLOW);
1106
1107 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_BUFFER);
1108 RTAcpiTblIntegerAppend(hAcpiTbl, cbBuf);
1109 if (pvBuf)
1110 rtAcpiTblAppendData(pThis, pvBuf, (uint32_t)cbBuf);
1111 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_BUFFER);
1112}
1113
1114
1115RTDECL(int) RTAcpiTblResourceAppend(RTACPITBL hAcpiTbl, RTACPIRES hAcpiRes)
1116{
1117 PRTACPITBLINT pThis = hAcpiTbl;
1118 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1119 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1120
1121 const void *pvRes = NULL;
1122 size_t cbRes = 0;
1123 int rc = RTAcpiResourceQueryBuffer(hAcpiRes, &pvRes, &cbRes);
1124 if (RT_SUCCESS(rc))
1125 rc = RTAcpiTblBufferAppend(pThis, pvRes, cbRes);
1126
1127 return rc;
1128}
1129
1130
1131RTDECL(int) RTAcpiTblStmtSimpleAppend(RTACPITBL hAcpiTbl, RTACPISTMT enmStmt)
1132{
1133 PRTACPITBLINT pThis = hAcpiTbl;
1134 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1135
1136 uint8_t bOp;
1137 bool fExtOp = false;
1138 switch (enmStmt)
1139 {
1140 case kAcpiStmt_Return: bOp = ACPI_AML_BYTE_CODE_OP_RETURN; break;
1141 case kAcpiStmt_Breakpoint: bOp = ACPI_AML_BYTE_CODE_OP_BREAK_POINT; break;
1142 case kAcpiStmt_Nop: bOp = ACPI_AML_BYTE_CODE_OP_NOOP; break;
1143 case kAcpiStmt_Break: bOp = ACPI_AML_BYTE_CODE_OP_BREAK; break;
1144 case kAcpiStmt_Continue: bOp = ACPI_AML_BYTE_CODE_OP_CONTINUE; break;
1145 case kAcpiStmt_Add: bOp = ACPI_AML_BYTE_CODE_OP_ADD; break;
1146 case kAcpiStmt_Subtract: bOp = ACPI_AML_BYTE_CODE_OP_SUBTRACT; break;
1147 case kAcpiStmt_And: bOp = ACPI_AML_BYTE_CODE_OP_AND; break;
1148 case kAcpiStmt_Nand: bOp = ACPI_AML_BYTE_CODE_OP_NAND; break;
1149 case kAcpiStmt_Or: bOp = ACPI_AML_BYTE_CODE_OP_OR; break;
1150 case kAcpiStmt_Xor: bOp = ACPI_AML_BYTE_CODE_OP_XOR; break;
1151 case kAcpiStmt_Not: bOp = ACPI_AML_BYTE_CODE_OP_NOT; break;
1152 case kAcpiStmt_Store: bOp = ACPI_AML_BYTE_CODE_OP_STORE; break;
1153 case kAcpiStmt_Index: bOp = ACPI_AML_BYTE_CODE_OP_INDEX; break;
1154 case kAcpiStmt_DerefOf: bOp = ACPI_AML_BYTE_CODE_OP_DEREF_OF; break;
1155 case kAcpiStmt_Notify: bOp = ACPI_AML_BYTE_CODE_OP_NOTIFY; break;
1156 case kAcpiStmt_SizeOf: bOp = ACPI_AML_BYTE_CODE_OP_SIZE_OF; break;
1157 case kAcpiStmt_Increment: bOp = ACPI_AML_BYTE_CODE_OP_INCREMENT; break;
1158 case kAcpiStmt_Decrement: bOp = ACPI_AML_BYTE_CODE_OP_INCREMENT; break;
1159 case kAcpiStmt_CondRefOf: bOp = ACPI_AML_BYTE_CODE_EXT_OP_COND_REF_OF; fExtOp = true; break;
1160 default:
1161 AssertFailedReturn(VERR_INVALID_PARAMETER);
1162 }
1163 if (fExtOp)
1164 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_PREFIX_EXT_OP);
1165 rtAcpiTblAppendByte(pThis, bOp);
1166 return pThis->rcErr;
1167}
1168
1169
1170RTDECL(int) RTAcpiTblIfStart(RTACPITBL hAcpiTbl)
1171{
1172 PRTACPITBLINT pThis = hAcpiTbl;
1173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1174
1175 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_IF);
1176 return pThis->rcErr;
1177}
1178
1179
1180RTDECL(int) RTAcpiTblIfFinalize(RTACPITBL hAcpiTbl)
1181{
1182 PRTACPITBLINT pThis = hAcpiTbl;
1183 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1184
1185 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_IF);
1186}
1187
1188
1189RTDECL(int) RTAcpiTblElseStart(RTACPITBL hAcpiTbl)
1190{
1191 PRTACPITBLINT pThis = hAcpiTbl;
1192 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1193
1194 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_ELSE);
1195 return pThis->rcErr;
1196}
1197
1198
1199RTDECL(int) RTAcpiTblElseFinalize(RTACPITBL hAcpiTbl)
1200{
1201 PRTACPITBLINT pThis = hAcpiTbl;
1202 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1203
1204 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_ELSE);
1205}
1206
1207
1208RTDECL(int) RTAcpiTblWhileStart(RTACPITBL hAcpiTbl)
1209{
1210 PRTACPITBLINT pThis = hAcpiTbl;
1211 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1212
1213 rtAcpiTblPkgStart(pThis, ACPI_AML_BYTE_CODE_OP_WHILE);
1214 return pThis->rcErr;
1215}
1216
1217
1218RTDECL(int) RTAcpiTblWhileFinalize(RTACPITBL hAcpiTbl)
1219{
1220 PRTACPITBLINT pThis = hAcpiTbl;
1221 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1222
1223 return rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_OP_WHILE);
1224}
1225
1226
1227RTDECL(int) RTAcpiTblBinaryOpAppend(RTACPITBL hAcpiTbl, RTACPIBINARYOP enmBinaryOp)
1228{
1229 PRTACPITBLINT pThis = hAcpiTbl;
1230 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1231
1232 uint8_t bOp;
1233 switch (enmBinaryOp)
1234 {
1235 case kAcpiBinaryOp_LAnd: bOp = ACPI_AML_BYTE_CODE_OP_LAND; break;
1236 case kAcpiBinaryOp_LEqual: bOp = ACPI_AML_BYTE_CODE_OP_LEQUAL; break;
1237 case kAcpiBinaryOp_LGreater: bOp = ACPI_AML_BYTE_CODE_OP_LGREATER; break;
1238 case kAcpiBinaryOp_LLess: bOp = ACPI_AML_BYTE_CODE_OP_LLESS; break;
1239 case kAcpiBinaryOp_LGreaterEqual:
1240 case kAcpiBinaryOp_LLessEqual:
1241 case kAcpiBinaryOp_LNotEqual:
1242 bOp = ACPI_AML_BYTE_CODE_OP_LNOT;
1243 break;
1244 default:
1245 AssertFailedReturn(VERR_INVALID_PARAMETER);
1246 }
1247 rtAcpiTblAppendByte(pThis, bOp);
1248 switch (enmBinaryOp)
1249 {
1250 case kAcpiBinaryOp_LGreaterEqual: bOp = ACPI_AML_BYTE_CODE_OP_LLESS; break;
1251 case kAcpiBinaryOp_LLessEqual: bOp = ACPI_AML_BYTE_CODE_OP_LGREATER; break;
1252 case kAcpiBinaryOp_LNotEqual: bOp = ACPI_AML_BYTE_CODE_OP_LEQUAL; break;
1253 default:
1254 bOp = 0x00;
1255 }
1256 if (bOp != 0x00)
1257 rtAcpiTblAppendByte(pThis, bOp);
1258 return pThis->rcErr;
1259}
1260
1261
1262RTDECL(int) RTAcpiTblArgOpAppend(RTACPITBL hAcpiTbl, uint8_t idArg)
1263{
1264 PRTACPITBLINT pThis = hAcpiTbl;
1265 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1266 AssertReturn(idArg <= 6, VERR_INVALID_PARAMETER);
1267
1268 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_OP_ARG_0 + idArg);
1269 return pThis->rcErr;
1270}
1271
1272
1273RTDECL(int) RTAcpiTblLocalOpAppend(RTACPITBL hAcpiTbl, uint8_t idLocal)
1274{
1275 PRTACPITBLINT pThis = hAcpiTbl;
1276 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1277 AssertReturn(idLocal <= 7, VERR_INVALID_PARAMETER);
1278
1279 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_OP_LOCAL_0 + idLocal);
1280 return pThis->rcErr;
1281}
1282
1283
1284RTDECL(int) RTAcpiTblUuidAppend(RTACPITBL hAcpiTbl, PCRTUUID pUuid)
1285{
1286 /* UUIDs are stored as a buffer object. */
1287 /** @todo Needs conversion on big endian machines. */
1288 return RTAcpiTblBufferAppend(hAcpiTbl, &pUuid->au8[0], sizeof(*pUuid));
1289}
1290
1291
1292RTDECL(int) RTAcpiTblUuidAppendFromStr(RTACPITBL hAcpiTbl, const char *pszUuid)
1293{
1294 PRTACPITBLINT pThis = hAcpiTbl;
1295 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1296
1297 RTUUID Uuid;
1298 pThis->rcErr = RTUuidFromStr(&Uuid, pszUuid);
1299 if (RT_SUCCESS(pThis->rcErr))
1300 return RTAcpiTblUuidAppend(pThis, &Uuid);
1301
1302 return pThis->rcErr;
1303}
1304
1305
1306RTDECL(int) RTAcpiTblOpRegionAppendEx(RTACPITBL hAcpiTbl, const char *pszName, RTACPIOPREGIONSPACE enmSpace)
1307{
1308 PRTACPITBLINT pThis = hAcpiTbl;
1309 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1310
1311 uint8_t abOp[2] = { ACPI_AML_BYTE_CODE_PREFIX_EXT_OP, ACPI_AML_BYTE_CODE_EXT_OP_OP_REGION };
1312 rtAcpiTblAppendData(pThis, &abOp[0], sizeof(abOp));
1313 rtAcpiTblAppendNameString(pThis, pszName);
1314
1315 uint8_t bRegionSpace = 0xff;
1316 switch (enmSpace)
1317 {
1318 case kAcpiOperationRegionSpace_SystemMemory: bRegionSpace = 0x00; break;
1319 case kAcpiOperationRegionSpace_SystemIo: bRegionSpace = 0x01; break;
1320 case kAcpiOperationRegionSpace_PciConfig: bRegionSpace = 0x02; break;
1321 case kAcpiOperationRegionSpace_EmbeddedControl: bRegionSpace = 0x03; break;
1322 case kAcpiOperationRegionSpace_SmBus: bRegionSpace = 0x04; break;
1323 case kAcpiOperationRegionSpace_SystemCmos: bRegionSpace = 0x05; break;
1324 case kAcpiOperationRegionSpace_PciBarTarget: bRegionSpace = 0x06; break;
1325 case kAcpiOperationRegionSpace_Ipmi: bRegionSpace = 0x07; break;
1326 case kAcpiOperationRegionSpace_Gpio: bRegionSpace = 0x08; break;
1327 case kAcpiOperationRegionSpace_GenericSerialBus: bRegionSpace = 0x09; break;
1328 case kAcpiOperationRegionSpace_Pcc: bRegionSpace = 0x0a; break;
1329 default:
1330 pThis->rcErr = VERR_INVALID_PARAMETER;
1331 AssertFailedReturn(pThis->rcErr);
1332 }
1333 rtAcpiTblAppendByte(pThis, bRegionSpace);
1334 return pThis->rcErr;
1335}
1336
1337
1338RTDECL(int) RTAcpiTblOpRegionAppend(RTACPITBL hAcpiTbl, const char *pszName, RTACPIOPREGIONSPACE enmSpace,
1339 uint64_t offRegion, uint64_t cbRegion)
1340{
1341 PRTACPITBLINT pThis = hAcpiTbl;
1342 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1343
1344 int rc = RTAcpiTblOpRegionAppendEx(pThis, pszName, enmSpace);
1345 if (RT_FAILURE(rc))
1346 return rc;
1347
1348 RTAcpiTblIntegerAppend(pThis, offRegion);
1349 RTAcpiTblIntegerAppend(pThis, cbRegion);
1350 return pThis->rcErr;
1351}
1352
1353
1354RTDECL(int) RTAcpiTblFieldAppend(RTACPITBL hAcpiTbl, const char *pszNameRef, RTACPIFIELDACC enmAcc,
1355 bool fLock, RTACPIFIELDUPDATE enmUpdate, PCRTACPIFIELDENTRY paFields,
1356 uint32_t cFields)
1357{
1358 PRTACPITBLINT pThis = hAcpiTbl;
1359 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1360
1361 rtAcpiTblPkgStartExt(pThis, ACPI_AML_BYTE_CODE_EXT_OP_FIELD);
1362 rtAcpiTblAppendNameString(pThis, pszNameRef);
1363
1364 uint8_t fFlags = 0;
1365 switch (enmAcc)
1366 {
1367 case kAcpiFieldAcc_Any: fFlags = 0; break;
1368 case kAcpiFieldAcc_Byte: fFlags = 1; break;
1369 case kAcpiFieldAcc_Word: fFlags = 2; break;
1370 case kAcpiFieldAcc_DWord: fFlags = 3; break;
1371 case kAcpiFieldAcc_QWord: fFlags = 4; break;
1372 case kAcpiFieldAcc_Buffer: fFlags = 5; break;
1373 default:
1374 pThis->rcErr = VERR_INVALID_PARAMETER;
1375 AssertFailedReturn(pThis->rcErr);
1376 }
1377 if (fLock)
1378 fFlags |= RT_BIT(4);
1379 switch (enmUpdate)
1380 {
1381 case kAcpiFieldUpdate_Preserve: fFlags |= 0 << 5; break;
1382 case kAcpiFieldUpdate_WriteAsOnes: fFlags |= 1 << 5; break;
1383 case kAcpiFieldUpdate_WriteAsZeroes: fFlags |= 2 << 5; break;
1384 default:
1385 pThis->rcErr = VERR_INVALID_PARAMETER;
1386 AssertFailedReturn(pThis->rcErr);
1387 }
1388 rtAcpiTblAppendByte(pThis, fFlags);
1389
1390 for (uint32_t i = 0; i < cFields; i++)
1391 {
1392 rtAcpiTblAppendNameSegOrNullName(pThis, paFields[i].pszName);
1393 rtAcpiTblEncodePkgLength(pThis, paFields[i].cBits);
1394 }
1395
1396 rtAcpiTblPkgFinish(pThis, ACPI_AML_BYTE_CODE_EXT_OP_FIELD);
1397 return pThis->rcErr;
1398}
1399
1400
1401RTDECL(int) RTAcpiTblExternalAppend(RTACPITBL hAcpiTbl, const char *pszName, RTACPIOBJTYPE enmObjType, uint8_t cArgs)
1402{
1403 PRTACPITBLINT pThis = hAcpiTbl;
1404 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1405 AssertReturn(cArgs <= 7, VERR_INVALID_PARAMETER);
1406
1407 uint8_t bObjType;
1408 switch (enmObjType)
1409 {
1410 case kAcpiObjType_Unknown: bObjType = ACPI_AML_OBJECT_TYPE_UNINIT; break;
1411 case kAcpiObjType_Int: bObjType = ACPI_AML_OBJECT_TYPE_INTEGER; break;
1412 case kAcpiObjType_Str: bObjType = ACPI_AML_OBJECT_TYPE_STRING; break;
1413 case kAcpiObjType_Buff: bObjType = ACPI_AML_OBJECT_TYPE_BUFFER; break;
1414 case kAcpiObjType_Pkg: bObjType = ACPI_AML_OBJECT_TYPE_PACKAGE; break;
1415 case kAcpiObjType_FieldUnit: bObjType = ACPI_AML_OBJECT_TYPE_FIELD_UNIT; break;
1416 case kAcpiObjType_Device: bObjType = ACPI_AML_OBJECT_TYPE_DEVICE; break;
1417 case kAcpiObjType_Event: bObjType = ACPI_AML_OBJECT_TYPE_EVENT; break;
1418 case kAcpiObjType_Method: bObjType = ACPI_AML_OBJECT_TYPE_METHOD; break;
1419 case kAcpiObjType_MutexObj: bObjType = ACPI_AML_OBJECT_TYPE_MUTEX; break;
1420 case kAcpiObjType_OpRegion: bObjType = ACPI_AML_OBJECT_TYPE_OPERATION_REGION; break;
1421 case kAcpiObjType_PowerRes: bObjType = ACPI_AML_OBJECT_TYPE_POWER_RESOURCE; break;
1422 case kAcpiObjType_ThermalZone: bObjType = ACPI_AML_OBJECT_TYPE_THERMAL_ZONE; break;
1423 case kAcpiObjType_BuffField: bObjType = ACPI_AML_OBJECT_TYPE_BUFFER_FIELD; break;
1424 case kAcpiObjType_Processor: bObjType = ACPI_AML_OBJECT_TYPE_PROCESSOR; break;
1425 default:
1426 pThis->rcErr = VERR_INVALID_PARAMETER;
1427 AssertFailedReturn(pThis->rcErr);
1428 }
1429
1430 rtAcpiTblAppendByte(pThis, ACPI_AML_BYTE_CODE_OP_EXTERNAL);
1431 rtAcpiTblAppendNameString(pThis, pszName);
1432 rtAcpiTblAppendByte(pThis, bObjType);
1433 rtAcpiTblAppendByte(pThis, cArgs);
1434 return pThis->rcErr;
1435}
1436
1437
1438RTDECL(int) RTAcpiTblCreateFromVfsIoStrm(PRTACPITBL phAcpiTbl, RTVFSIOSTREAM hVfsIos, RTACPITBLTYPE enmInType, PRTERRINFO pErrInfo)
1439{
1440 AssertPtrReturn(phAcpiTbl, VERR_INVALID_POINTER);
1441 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
1442
1443 RT_NOREF(pErrInfo, enmInType);
1444#if 0
1445 if (enmInType == RTACPITBLTYPE_AML)
1446 return rtAcpiTblLoadAml(phAcpiTbl, hVfsIos, pErrInfo);
1447#endif
1448
1449 return VERR_NOT_IMPLEMENTED;
1450}
1451
1452
1453RTDECL(int) RTAcpiTblConvertFromVfsIoStrm(RTVFSIOSTREAM hVfsIosOut, RTACPITBLTYPE enmOutType,
1454 RTVFSIOSTREAM hVfsIosIn, RTACPITBLTYPE enmInType, PRTERRINFO pErrInfo)
1455{
1456 AssertReturn(hVfsIosOut != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
1457 AssertReturn(hVfsIosIn != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
1458
1459 if (enmInType == RTACPITBLTYPE_AML && enmOutType == RTACPITBLTYPE_ASL)
1460 return rtAcpiTblConvertFromAmlToAsl(hVfsIosOut, hVfsIosIn, pErrInfo);
1461 else if (enmInType == RTACPITBLTYPE_ASL && enmOutType == RTACPITBLTYPE_AML)
1462 return rtAcpiTblConvertFromAslToAml(hVfsIosOut, hVfsIosIn, pErrInfo);
1463
1464 return VERR_NOT_SUPPORTED;
1465}
1466
1467
1468RTDECL(int) RTAcpiTblCreateFromFile(PRTACPITBL phAcpiTbl, const char *pszFilename, RTACPITBLTYPE enmInType, PRTERRINFO pErrInfo)
1469{
1470 RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM;
1471 int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1472 &hVfsIos, NULL /*poffError*/, pErrInfo);
1473 if (RT_FAILURE(rc))
1474 return rc;
1475
1476 rc = RTAcpiTblCreateFromVfsIoStrm(phAcpiTbl, hVfsIos, enmInType, pErrInfo);
1477 RTVfsIoStrmRelease(hVfsIos);
1478 return rc;
1479}
1480
1481
1482/**
1483 * Ensures there is at least the given amount of space in the given ACPI resource.
1484 *
1485 * @returns Pointer to the free buffer space or NULL if out of memory.
1486 * @param pThis The ACPI resource instance.
1487 * @param cbReq Number of free bytes required.
1488 */
1489static uint8_t *rtAcpiResBufEnsureSpace(PRTACPIRESINT pThis, uint32_t cbReq)
1490{
1491 if (RT_LIKELY(pThis->cbResBuf - pThis->offResBuf >= cbReq))
1492 {
1493 uint8_t *pb = &pThis->pbResBuf[pThis->offResBuf];
1494 pThis->offResBuf += cbReq;
1495 return pb;
1496 }
1497
1498 size_t const cbNew = RT_ALIGN_Z(pThis->cbResBuf + cbReq, _4K);
1499 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pThis->pbResBuf, cbNew);
1500 if (RT_UNLIKELY(!pbNew))
1501 {
1502 pThis->rcErr = VERR_NO_MEMORY;
1503 return NULL;
1504 }
1505
1506 pThis->pbResBuf = pbNew;
1507 pThis->cbResBuf = cbNew;
1508
1509 uint8_t *pb = &pThis->pbResBuf[pThis->offResBuf];
1510 pThis->offResBuf += cbReq;
1511 return pb;
1512}
1513
1514
1515/**
1516 * Encodes an ACPI 16-bit integer in the given byte buffer.
1517 *
1518 * @returns Pointer to after the encoded integer.
1519 * @param pb Where to encode the integer into.
1520 * @param u16 The 16-bit unsigned integere to encode.
1521 */
1522DECLINLINE(uint8_t *) rtAcpiResEncode16BitInteger(uint8_t *pb, uint16_t u16)
1523{
1524 *pb++ = (uint8_t)u16;
1525 *pb++ = (uint8_t)(u16 >> 8);
1526 return pb;
1527}
1528
1529
1530/**
1531 * Encodes an ACPI 32-bit integer in the given byte buffer.
1532 *
1533 * @returns Pointer to after the encoded integer.
1534 * @param pb Where to encode the integer into.
1535 * @param u32 The 32-bit unsigned integere to encode.
1536 */
1537DECLINLINE(uint8_t *) rtAcpiResEncode32BitInteger(uint8_t *pb, uint32_t u32)
1538{
1539 *pb++ = (uint8_t)u32;
1540 *pb++ = (uint8_t)(u32 >> 8);
1541 *pb++ = (uint8_t)(u32 >> 16);
1542 *pb++ = (uint8_t)(u32 >> 24);
1543 return pb;
1544}
1545
1546/**
1547 * Encodes an ACPI 64-bit integer in the given byte buffer.
1548 *
1549 * @returns Pointer to after the encoded integer.
1550 * @param pb Where to encode the integer into.
1551 * @param u64 The 64-bit unsigned integere to encode.
1552 */
1553
1554DECLINLINE(uint8_t *) rtAcpiResEncode64BitInteger(uint8_t *pb, uint64_t u64)
1555{
1556 *pb++ = (uint8_t)u64;
1557 *pb++ = (uint8_t)(u64 >> 8);
1558 *pb++ = (uint8_t)(u64 >> 16);
1559 *pb++ = (uint8_t)(u64 >> 24);
1560 *pb++ = (uint8_t)(u64 >> 32);
1561 *pb++ = (uint8_t)(u64 >> 40);
1562 *pb++ = (uint8_t)(u64 >> 48);
1563 *pb++ = (uint8_t)(u64 >> 56);
1564 return pb;
1565}
1566
1567
1568RTDECL(int) RTAcpiResourceCreate(PRTACPIRES phAcpiRes)
1569{
1570 AssertPtrReturn(phAcpiRes, VERR_INVALID_POINTER);
1571
1572 PRTACPIRESINT pThis = (PRTACPIRESINT)RTMemAllocZ(sizeof(*pThis));
1573 if (pThis)
1574 {
1575 pThis->pbResBuf = (uint8_t *)RTMemAlloc(64);
1576 if (pThis->pbResBuf)
1577 {
1578 pThis->offResBuf = 0;
1579 pThis->cbResBuf = 64;
1580 pThis->fSealed = false;
1581 pThis->rcErr = VINF_SUCCESS;
1582
1583 *phAcpiRes = pThis;
1584 return VINF_SUCCESS;
1585 }
1586
1587 RTMemFree(pThis);
1588 }
1589
1590 return VERR_NO_MEMORY;
1591}
1592
1593
1594RTDECL(void) RTAcpiResourceDestroy(RTACPIRES hAcpiRes)
1595{
1596 PRTACPIRESINT pThis = hAcpiRes;
1597 AssertPtrReturnVoid(pThis);
1598
1599 RTMemFree(pThis->pbResBuf);
1600 pThis->pbResBuf = NULL;
1601 pThis->cbResBuf = 0;
1602 pThis->offResBuf = 0;
1603 RTMemFree(pThis);
1604}
1605
1606
1607RTDECL(void) RTAcpiResourceReset(RTACPIRES hAcpiRes)
1608{
1609 PRTACPIRESINT pThis = hAcpiRes;
1610 AssertPtrReturnVoid(pThis);
1611
1612 pThis->offResBuf = 0;
1613 pThis->fSealed = false;
1614 pThis->rcErr = VINF_SUCCESS;
1615}
1616
1617
1618RTDECL(uint32_t) RTAcpiResourceGetOffset(RTACPIRES hAcpiRes)
1619{
1620 PRTACPIRESINT pThis = hAcpiRes;
1621 AssertReturn(pThis, UINT32_MAX);
1622 AssertRCReturn(pThis->rcErr, UINT32_MAX);
1623
1624 return pThis->offResBuf;
1625}
1626
1627
1628RTDECL(int) RTAcpiResourceSeal(RTACPIRES hAcpiRes)
1629{
1630 PRTACPIRESINT pThis = hAcpiRes;
1631 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1632 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1633 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1634
1635 /* Add the end tag. */
1636 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 2);
1637 if (!pb)
1638 return VERR_NO_MEMORY;
1639
1640 *pb++ = ACPI_RSRCS_TAG_END;
1641 /*
1642 * Generate checksum, we could just write 0 here which will be treated as checksum operation succeeded,
1643 * but having this might catch some bugs.
1644 *
1645 * Checksum algorithm is the same as with the ACPI tables.
1646 */
1647 *pb = RTAcpiChecksumGenerate(pThis->pbResBuf, pThis->offResBuf - 1); /* Exclude the checksum field. */
1648
1649 pThis->fSealed = true;
1650 return VINF_SUCCESS;
1651}
1652
1653
1654RTDECL(int) RTAcpiResourceQueryBuffer(RTACPIRES hAcpiRes, const void **ppvRes, size_t *pcbRes)
1655{
1656 PRTACPIRESINT pThis = hAcpiRes;
1657 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1658 AssertReturn(pThis->fSealed, VERR_INVALID_STATE);
1659 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1660
1661 *ppvRes = pThis->pbResBuf;
1662 *pcbRes = pThis->offResBuf;
1663 return VINF_SUCCESS;
1664}
1665
1666
1667RTDECL(int) RTAcpiResourceAdd32BitFixedMemoryRange(RTACPIRES hAcpiRes, uint32_t u32AddrBase, uint32_t cbRange,
1668 bool fRw)
1669{
1670 PRTACPIRESINT pThis = hAcpiRes;
1671 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1672 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1673 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1674
1675 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 12);
1676 if (!pb)
1677 return VERR_NO_MEMORY;
1678
1679 pb[0] = ACPI_RSRCS_LARGE_TYPE | ACPI_RSRCS_ITEM_32BIT_FIXED_MEMORY_RANGE; /* Tag */
1680 pb[1] = 9; /* Length[7:0] */
1681 pb[2] = 0; /* Length[15:8] */
1682 pb[3] = fRw ? 1 : 0; /* Information */
1683 rtAcpiResEncode32BitInteger(&pb[4], u32AddrBase);
1684 rtAcpiResEncode32BitInteger(&pb[8], cbRange);
1685 return VINF_SUCCESS;
1686}
1687
1688
1689RTDECL(int) RTAcpiResourceAddExtendedInterrupt(RTACPIRES hAcpiRes, bool fConsumer, bool fEdgeTriggered, bool fActiveLow, bool fShared,
1690 bool fWakeCapable, uint8_t cIntrs, uint32_t *pau32Intrs)
1691{
1692 PRTACPIRESINT pThis = hAcpiRes;
1693 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1694 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1695 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1696
1697 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 3 + 2 + cIntrs * sizeof(uint32_t));
1698 if (!pb)
1699 return VERR_NO_MEMORY;
1700
1701 pb[0] = ACPI_RSRCS_LARGE_TYPE | ACPI_RSRCS_ITEM_EXTENDED_INTERRUPT; /* Tag */
1702 rtAcpiResEncode16BitInteger(&pb[1], 2 + cIntrs * sizeof(uint32_t)); /* Length[15:0] */
1703 pb[3] = (fConsumer ? ACPI_RSRCS_EXT_INTR_VEC_F_CONSUMER : ACPI_RSRCS_EXT_INTR_VEC_F_PRODUCER)
1704 | (fEdgeTriggered ? ACPI_RSRCS_EXT_INTR_VEC_F_EDGE_TRIGGERED : ACPI_RSRCS_EXT_INTR_VEC_F_LEVEL_TRIGGERED)
1705 | (fActiveLow ? ACPI_RSRCS_EXT_INTR_VEC_F_ACTIVE_LOW : ACPI_RSRCS_EXT_INTR_VEC_F_ACTIVE_HIGH)
1706 | (fShared ? ACPI_RSRCS_EXT_INTR_VEC_F_SHARED : ACPI_RSRCS_EXT_INTR_VEC_F_EXCLUSIVE)
1707 | (fWakeCapable ? ACPI_RSRCS_EXT_INTR_VEC_F_WAKE_CAP : ACPI_RSRCS_EXT_INTR_VEC_F_NOT_WAKE_CAP);
1708 pb[4] = cIntrs;
1709 pb = &pb[5];
1710 for (uint32_t i = 0; i < cIntrs; i++)
1711 pb = rtAcpiResEncode32BitInteger(pb, pau32Intrs[i]);
1712
1713 return VINF_SUCCESS;
1714}
1715
1716
1717/**
1718 * Common worker for encoding a new quad word (64-bit) address range.
1719 *
1720 * @returns IPRT status code
1721 * @retval VERR_NO_MEMORY if not enough memory could be reserved in the ACPI resource descriptor.
1722 * @param pThis The ACPI resource instance.
1723 * @param bType The ACPI address range type.
1724 * @param fAddrSpace Combination of RTACPI_RESOURCE_ADDR_RANGE_F_XXX.
1725 * @param fType The range flags returned from rtAcpiResourceMemoryRangeToTypeFlags().
1726 * @param u64AddrMin The start address of the memory range.
1727 * @param u64AddrMax Last valid address of the range.
1728 * @param u64OffTrans Translation offset being applied to the address (for a PCIe bridge or IOMMU for example).
1729 * @param u64Granularity The access granularity of the range in bytes.
1730 * @param u64Length Length of the memory range in bytes.
1731 */
1732static int rtAcpiResourceAddQWordAddressRange(PRTACPIRESINT pThis, uint8_t bType, uint32_t fAddrSpace, uint8_t fType,
1733 uint64_t u64AddrMin, uint64_t u64AddrMax, uint64_t u64OffTrans,
1734 uint64_t u64Granularity, uint64_t u64Length)
1735{
1736 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 3 + 43);
1737 if (!pb)
1738 return VERR_NO_MEMORY;
1739
1740 pb[0] = ACPI_RSRCS_LARGE_TYPE | ACPI_RSRCS_ITEM_QWORD_ADDR_SPACE; /* Tag */
1741 pb[1] = 43; /* Length[7:0] */
1742 pb[2] = 0; /* Length[15:8] */
1743 pb[3] = bType;
1744 pb[4] = (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_DECODE_TYPE_SUB ? ACPI_RSRCS_ADDR_SPACE_F_DECODE_TYPE_SUB : ACPI_RSRCS_ADDR_SPACE_F_DECODE_TYPE_POS)
1745 | (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_MIN_ADDR_FIXED ? ACPI_RSRCS_ADDR_SPACE_F_MIN_ADDR_FIXED : ACPI_RSRCS_ADDR_SPACE_F_MIN_ADDR_CHANGEABLE)
1746 | (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_MAX_ADDR_FIXED ? ACPI_RSRCS_ADDR_SPACE_F_MAX_ADDR_FIXED : ACPI_RSRCS_ADDR_SPACE_F_MAX_ADDR_CHANGEABLE);
1747 pb[5] = fType;
1748
1749 pb = rtAcpiResEncode64BitInteger(&pb[6], u64Granularity);
1750 pb = rtAcpiResEncode64BitInteger(pb, u64AddrMin);
1751 pb = rtAcpiResEncode64BitInteger(pb, u64AddrMax);
1752 pb = rtAcpiResEncode64BitInteger(pb, u64OffTrans);
1753 rtAcpiResEncode64BitInteger(pb, u64Length);
1754 return VINF_SUCCESS;
1755}
1756
1757
1758/**
1759 * Common worker for encoding a new double word (32-bit) address range.
1760 *
1761 * @returns IPRT status code
1762 * @retval VERR_NO_MEMORY if not enough memory could be reserved in the ACPI resource descriptor.
1763 * @param pThis The ACPI resource instance.
1764 * @param bType The ACPI address range type.
1765 * @param fAddrSpace Combination of RTACPI_RESOURCE_ADDR_RANGE_F_XXX.
1766 * @param fType The range flags returned from rtAcpiResourceMemoryRangeToTypeFlags().
1767 * @param u32AddrMin The start address of the memory range.
1768 * @param u32AddrMax Last valid address of the range.
1769 * @param u32OffTrans Translation offset being applied to the address (for a PCIe bridge or IOMMU for example).
1770 * @param u32Granularity The access granularity of the range in bytes.
1771 * @param u32Length Length of the memory range in bytes.
1772 */
1773static int rtAcpiResourceAddDWordAddressRange(PRTACPIRESINT pThis, uint8_t bType, uint32_t fAddrSpace, uint8_t fType,
1774 uint32_t u32AddrMin, uint32_t u32AddrMax, uint32_t u32OffTrans,
1775 uint32_t u32Granularity, uint32_t u32Length)
1776{
1777 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 3 + 23);
1778 if (!pb)
1779 return VERR_NO_MEMORY;
1780
1781 pb[0] = ACPI_RSRCS_LARGE_TYPE | ACPI_RSRCS_ITEM_DWORD_ADDR_SPACE; /* Tag */
1782 pb[1] = 23; /* Length[7:0] */
1783 pb[2] = 0; /* Length[15:8] */
1784 pb[3] = bType;
1785 pb[4] = (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_DECODE_TYPE_SUB ? ACPI_RSRCS_ADDR_SPACE_F_DECODE_TYPE_SUB : ACPI_RSRCS_ADDR_SPACE_F_DECODE_TYPE_POS)
1786 | (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_MIN_ADDR_FIXED ? ACPI_RSRCS_ADDR_SPACE_F_MIN_ADDR_FIXED : ACPI_RSRCS_ADDR_SPACE_F_MIN_ADDR_CHANGEABLE)
1787 | (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_MAX_ADDR_FIXED ? ACPI_RSRCS_ADDR_SPACE_F_MAX_ADDR_FIXED : ACPI_RSRCS_ADDR_SPACE_F_MAX_ADDR_CHANGEABLE);
1788 pb[5] = fType;
1789
1790 pb = rtAcpiResEncode32BitInteger(&pb[6], u32Granularity);
1791 pb = rtAcpiResEncode32BitInteger(pb, u32AddrMin);
1792 pb = rtAcpiResEncode32BitInteger(pb, u32AddrMax);
1793 pb = rtAcpiResEncode32BitInteger(pb, u32OffTrans);
1794 rtAcpiResEncode32BitInteger(pb, u32Length);
1795 return VINF_SUCCESS;
1796}
1797
1798
1799/**
1800 * Converts the given cacheability, range type and R/W flag to the ACPI resource flags.
1801 *
1802 * @returns Converted ACPI resource flags.
1803 * @param enmCacheability The cacheability enum to convert.
1804 * @param enmType THe memory range type enum to convert.
1805 * @param fRw The read/write flag.
1806 */
1807DECLINLINE(uint8_t) rtAcpiResourceMemoryRangeToTypeFlags(RTACPIRESMEMRANGECACHEABILITY enmCacheability, RTACPIRESMEMRANGETYPE enmType,
1808 bool fRw)
1809{
1810 uint8_t fType = fRw ? ACPI_RSRCS_ADDR_SPACE_MEM_F_RW : ACPI_RSRCS_ADDR_SPACE_MEM_F_RO;
1811
1812 switch (enmCacheability)
1813 {
1814 case kAcpiResMemRangeCacheability_NonCacheable:
1815 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_CACHE_NON_CACHEABLE;
1816 break;
1817 case kAcpiResMemRangeCacheability_Cacheable:
1818 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_CACHE_CACHEABLE;
1819 break;
1820 case kAcpiResMemRangeCacheability_CacheableWriteCombining:
1821 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_CACHE_CACHEABLE_WR_COMB;
1822 break;
1823 case kAcpiResMemRangeCacheability_CacheablePrefetchable:
1824 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_CACHE_CACHEABLE_PREFETCHABLE;
1825 break;
1826 case kAcpiResMemRangeCacheability_Invalid:
1827 default:
1828 AssertFailedReturn(0);
1829 }
1830
1831 switch (enmType)
1832 {
1833 case kAcpiResMemType_Memory:
1834 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_ATTR_MEMORY;
1835 break;
1836 case kAcpiResMemType_Reserved:
1837 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_ATTR_RESERVED;
1838 break;
1839 case kAcpiResMemType_Acpi:
1840 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_ATTR_ACPI;
1841 break;
1842 case kAcpiResMemType_Nvs:
1843 fType |= ACPI_RSRCS_ADDR_SPACE_MEM_F_ATTR_NVS;
1844 break;
1845 case kAcpiResMemType_Invalid:
1846 default:
1847 AssertFailedReturn(0);
1848 }
1849
1850 return fType;
1851}
1852
1853
1854RTDECL(int) RTAcpiResourceAddQWordMemoryRange(RTACPIRES hAcpiRes, RTACPIRESMEMRANGECACHEABILITY enmCacheability,
1855 RTACPIRESMEMRANGETYPE enmType, bool fRw, uint32_t fAddrSpace,
1856 uint64_t u64AddrMin, uint64_t u64AddrMax, uint64_t u64OffTrans,
1857 uint64_t u64Granularity, uint64_t u64Length)
1858{
1859 PRTACPIRESINT pThis = hAcpiRes;
1860 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1861 AssertReturn(enmCacheability != kAcpiResMemRangeCacheability_Invalid, VERR_INVALID_PARAMETER);
1862 AssertReturn(enmType != kAcpiResMemType_Invalid, VERR_INVALID_PARAMETER);
1863 AssertReturn(!(fAddrSpace & ~RTACPI_RESOURCE_ADDR_RANGE_F_VALID_MASK), VERR_INVALID_PARAMETER);
1864 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1865 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1866
1867 uint8_t fType = rtAcpiResourceMemoryRangeToTypeFlags(enmCacheability, enmType, fRw);
1868 return rtAcpiResourceAddQWordAddressRange(pThis, ACPI_RSRCS_ADDR_SPACE_TYPE_MEMORY, fAddrSpace, fType,
1869 u64AddrMin, u64AddrMax, u64OffTrans, u64Granularity, u64Length);
1870}
1871
1872
1873RTDECL(int) RTAcpiResourceAddDWordMemoryRange(RTACPIRES hAcpiRes, RTACPIRESMEMRANGECACHEABILITY enmCacheability,
1874 RTACPIRESMEMRANGETYPE enmType, bool fRw, uint32_t fAddrSpace,
1875 uint32_t u32AddrMin, uint32_t u32AddrMax, uint32_t u32OffTrans,
1876 uint32_t u32Granularity, uint32_t u32Length)
1877{
1878 PRTACPIRESINT pThis = hAcpiRes;
1879 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1880 AssertReturn(enmCacheability != kAcpiResMemRangeCacheability_Invalid, VERR_INVALID_PARAMETER);
1881 AssertReturn(enmType != kAcpiResMemType_Invalid, VERR_INVALID_PARAMETER);
1882 AssertReturn(!(fAddrSpace & ~RTACPI_RESOURCE_ADDR_RANGE_F_VALID_MASK), VERR_INVALID_PARAMETER);
1883 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1884 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1885
1886 uint8_t fType = rtAcpiResourceMemoryRangeToTypeFlags(enmCacheability, enmType, fRw);
1887 return rtAcpiResourceAddDWordAddressRange(pThis, ACPI_RSRCS_ADDR_SPACE_TYPE_MEMORY, fAddrSpace, fType,
1888 u32AddrMin, u32AddrMax, u32OffTrans, u32Granularity, u32Length);
1889}
1890
1891
1892RTDECL(int) RTAcpiResourceAddQWordIoRange(RTACPIRES hAcpiRes, RTACPIRESIORANGETYPE enmIoType, RTACPIRESIORANGE enmIoRange,
1893 uint32_t fAddrSpace, uint64_t u64AddrMin, uint64_t u64AddrMax, uint64_t u64OffTrans,
1894 uint64_t u64Granularity, uint64_t u64Length)
1895{
1896 PRTACPIRESINT pThis = hAcpiRes;
1897 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1898 AssertReturn(enmIoType != kAcpiResIoRangeType_Invalid, VERR_INVALID_PARAMETER);
1899 AssertReturn(enmIoRange != kAcpiResIoRange_Invalid, VERR_INVALID_PARAMETER);
1900 AssertReturn(!(fAddrSpace & ~RTACPI_RESOURCE_ADDR_RANGE_F_VALID_MASK), VERR_INVALID_PARAMETER);
1901 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1902 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1903
1904 uint8_t fType = 0;
1905 switch (enmIoType)
1906 {
1907 case kAcpiResIoRangeType_Static:
1908 fType = ACPI_RSRCS_ADDR_SPACE_IO_F_TYPE_STATIC;
1909 break;
1910 case kAcpiResIoRangeType_Translation_Sparse:
1911 fType = ACPI_RSRCS_ADDR_SPACE_IO_F_TYPE_TRANSLATION | ACPI_RSRCS_ADDR_SPACE_IO_F_TRANSLATION_SPARSE;
1912 break;
1913 case kAcpiResIoRangeType_Translation_Dense:
1914 fType = ACPI_RSRCS_ADDR_SPACE_IO_F_TYPE_TRANSLATION | ACPI_RSRCS_ADDR_SPACE_IO_F_TRANSLATION_DENSE;
1915 break;
1916 case kAcpiResIoRangeType_Invalid:
1917 default:
1918 AssertFailedReturn(VERR_INVALID_PARAMETER);
1919 }
1920
1921 switch (enmIoRange)
1922 {
1923 case kAcpiResIoRange_NonIsaOnly:
1924 fType |= ACPI_RSRCS_ADDR_SPACE_IO_F_RANGE_NON_ISA_ONLY;
1925 break;
1926 case kAcpiResIoRange_IsaOnly:
1927 fType |= ACPI_RSRCS_ADDR_SPACE_IO_F_RANGE_ISA_ONLY;
1928 break;
1929 case kAcpiResIoRange_Whole:
1930 fType |= ACPI_RSRCS_ADDR_SPACE_IO_F_RANGE_WHOLE;
1931 break;
1932 case kAcpiResIoRange_Invalid:
1933 default:
1934 AssertFailedReturn(VERR_INVALID_PARAMETER);
1935 }
1936
1937 return rtAcpiResourceAddQWordAddressRange(pThis, ACPI_RSRCS_ADDR_SPACE_TYPE_IO, fAddrSpace, fType,
1938 u64AddrMin, u64AddrMax, u64OffTrans, u64Granularity, u64Length);
1939}
1940
1941
1942RTDECL(int) RTAcpiResourceAddWordBusNumber(RTACPIRES hAcpiRes, uint32_t fAddrSpace, uint16_t u16BusMin, uint16_t u16BusMax,
1943 uint16_t u16OffTrans, uint16_t u16Granularity, uint16_t u16Length)
1944{
1945 PRTACPIRESINT pThis = hAcpiRes;
1946 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1947 AssertReturn(!(fAddrSpace & ~RTACPI_RESOURCE_ADDR_RANGE_F_VALID_MASK), VERR_INVALID_PARAMETER);
1948 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1949 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1950
1951 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 3 + 13);
1952 if (!pb)
1953 return VERR_NO_MEMORY;
1954
1955 pb[0] = ACPI_RSRCS_LARGE_TYPE | ACPI_RSRCS_ITEM_WORD_ADDR_SPACE; /* Tag */
1956 pb[1] = 13; /* Length[7:0] */
1957 pb[2] = 0; /* Length[15:8] */
1958 pb[3] = ACPI_RSRCS_ADDR_SPACE_TYPE_BUS_NUM_RANGE;
1959 pb[4] = (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_DECODE_TYPE_SUB ? ACPI_RSRCS_ADDR_SPACE_F_DECODE_TYPE_SUB : ACPI_RSRCS_ADDR_SPACE_F_DECODE_TYPE_POS)
1960 | (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_MIN_ADDR_FIXED ? ACPI_RSRCS_ADDR_SPACE_F_MIN_ADDR_FIXED : ACPI_RSRCS_ADDR_SPACE_F_MIN_ADDR_CHANGEABLE)
1961 | (fAddrSpace & RTACPI_RESOURCE_ADDR_RANGE_F_MAX_ADDR_FIXED ? ACPI_RSRCS_ADDR_SPACE_F_MAX_ADDR_FIXED : ACPI_RSRCS_ADDR_SPACE_F_MAX_ADDR_CHANGEABLE);
1962 pb[5] = 0;
1963
1964 pb = rtAcpiResEncode16BitInteger(&pb[6], u16Granularity);
1965 pb = rtAcpiResEncode16BitInteger(pb, u16BusMin);
1966 pb = rtAcpiResEncode16BitInteger(pb, u16BusMax);
1967 pb = rtAcpiResEncode16BitInteger(pb, u16OffTrans);
1968 rtAcpiResEncode16BitInteger(pb, u16Length);
1969 return VINF_SUCCESS;
1970}
1971
1972
1973RTDECL(int) RTAcpiResourceAddIo(RTACPIRES hAcpiRes, RTACPIRESIODECODETYPE enmDecode, uint16_t u16AddrMin, uint16_t u16AddrMax,
1974 uint8_t u8AddrAlignment, uint8_t u8RangeLength)
1975{
1976 PRTACPIRESINT pThis = hAcpiRes;
1977 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1978 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
1979 AssertRCReturn(pThis->rcErr, pThis->rcErr);
1980
1981 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 8);
1982 if (!pb)
1983 return VERR_NO_MEMORY;
1984
1985 pb[0] = ACPI_RSRCS_SMALL_TYPE | (ACPI_RSRCS_ITEM_IO << 3) | 7; /* Tag */
1986 pb[1] = enmDecode == kAcpiResIoDecodeType_Decode10 ? 0 : 1;
1987 rtAcpiResEncode16BitInteger(&pb[2], u16AddrMin);
1988 rtAcpiResEncode16BitInteger(&pb[4], u16AddrMax);
1989 pb[6] = u8AddrAlignment;
1990 pb[7] = u8RangeLength;
1991
1992 return VINF_SUCCESS;
1993}
1994
1995
1996RTDECL(int) RTAcpiResourceAddIrq(RTACPIRES hAcpiRes, bool fEdgeTriggered, bool fActiveLow, bool fShared,
1997 bool fWakeCapable, uint16_t bmIntrs)
1998{
1999 PRTACPIRESINT pThis = hAcpiRes;
2000 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2001 AssertReturn(!pThis->fSealed, VERR_INVALID_STATE);
2002 AssertRCReturn(pThis->rcErr, pThis->rcErr);
2003
2004 bool fDefaultCfg = fEdgeTriggered && !fActiveLow && !fShared && !fWakeCapable;
2005 uint8_t *pb = rtAcpiResBufEnsureSpace(pThis, 2 + (fDefaultCfg ? 0 : 1));
2006 if (!pb)
2007 return VERR_NO_MEMORY;
2008
2009 pb[0] = ACPI_RSRCS_SMALL_TYPE | (ACPI_RSRCS_ITEM_IRQ << 3) | (fDefaultCfg ? 2 : 3); /* Tag */
2010 rtAcpiResEncode16BitInteger(&pb[1], bmIntrs);
2011 if (!fDefaultCfg)
2012 pb[3] = (fEdgeTriggered ? ACPI_RSRCS_IRQ_F_EDGE_TRIGGERED : ACPI_RSRCS_IRQ_F_LEVEL_TRIGGERED)
2013 | (fActiveLow ? ACPI_RSRCS_IRQ_F_ACTIVE_LOW : ACPI_RSRCS_IRQ_F_ACTIVE_HIGH)
2014 | (fShared ? ACPI_RSRCS_IRQ_F_SHARED : ACPI_RSRCS_IRQ_F_EXCLUSIVE)
2015 | (fWakeCapable ? ACPI_RSRCS_IRQ_F_WAKE_CAP : ACPI_RSRCS_IRQ_F_NOT_WAKE_CAP);
2016
2017 return VINF_SUCCESS;
2018}
Note: See TracBrowser for help on using the repository browser.

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