VirtualBox

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

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

Runtime/RTAcpi*: Some additions to create GpioInt() resource descriptors, bugref:10732 [build fix]

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