VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/ACPI/VBoxAcpi.cpp

Last change on this file was 107456, checked in by vboxsync, 8 days ago

Devices/PC/ACPI: Fix unused variable parfait warning for code which is only used when RT_STRICT is defined, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
1/* $Id: VBoxAcpi.cpp 107456 2025-01-07 10:50:27Z vboxsync $ */
2/** @file
3 * VBoxAcpi - VirtualBox ACPI manipulation functionality.
4 */
5
6/*
7 * Copyright (C) 2009-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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/cdefs.h>
33#if !defined(IN_RING3)
34# error Pure R3 code
35#endif
36
37#define LOG_GROUP LOG_GROUP_DEV_ACPI
38#include <VBox/vmm/pdmdev.h>
39#include <VBox/vmm/pgm.h>
40#include <VBox/log.h>
41#include <VBox/param.h>
42#include <VBox/vmm/cfgm.h>
43#include <VBox/vmm/mm.h>
44#include <iprt/assert.h>
45#include <iprt/alloc.h>
46#include <iprt/string.h>
47#include <iprt/file.h>
48
49#ifdef VBOX_WITH_DYNAMIC_DSDT
50/* vbox.dsl - input to generate proper DSDT on the fly */
51# include <vboxdsl.hex>
52#else
53/* Statically compiled AML */
54# include <vboxaml.hex>
55# include <vboxssdt_standard.hex>
56# include <vboxssdt_cpuhotplug.hex>
57# ifdef VBOX_WITH_TPM
58# include <vboxssdt_tpm.hex>
59# endif
60#endif
61
62#include "VBoxDD.h"
63
64
65#ifdef VBOX_WITH_DYNAMIC_DSDT
66
67static int prepareDynamicDsdt(PPDMDEVINS pDevIns, void **ppvPtr, size_t *pcbDsdt)
68{
69 *ppvPtr = NULL;
70 *pcbDsdt = 0;
71 return 0;
72}
73
74static int cleanupDynamicDsdt(PPDMDEVINS pDevIns, void *pvPtr)
75{
76 return 0;
77}
78
79#else /* VBOX_WITH_DYNAMIC_DSDT */
80
81static int patchAml(PPDMDEVINS pDevIns, uint8_t *pabAml, size_t cbAml)
82{
83 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
84
85 uint16_t cCpus;
86 int rc = pHlp->pfnCFGMQueryU16Def(pDevIns->pCfg, "NumCPUs", &cCpus, 1);
87 if (RT_FAILURE(rc))
88 return rc;
89
90 /* Clear CPU objects at all, if needed */
91 bool fShowCpu;
92 rc = pHlp->pfnCFGMQueryBoolDef(pDevIns->pCfg, "ShowCpu", &fShowCpu, false);
93 if (RT_FAILURE(rc))
94 return rc;
95
96 if (!fShowCpu)
97 cCpus = 0;
98
99 /*
100 * Now search AML for:
101 * AML_PROCESSOR_OP (UINT16) 0x5b83
102 * and replace whole block with
103 * AML_NOOP_OP (UINT16) 0xa3
104 * for VCPU not configured
105 */
106 for (uint32_t i = 0; i < cbAml - 7; i++)
107 {
108 /*
109 * AML_PROCESSOR_OP
110 *
111 * DefProcessor := ProcessorOp PkgLength NameString ProcID PblkAddr PblkLen ObjectList
112 * ProcessorOp := ExtOpPrefix 0x83
113 * ProcID := ByteData
114 * PblkAddr := DwordData
115 * PblkLen := ByteData
116 */
117 if (pabAml[i] == 0x5b && pabAml[i+1] == 0x83)
118 {
119 if (pabAml[i+3] != 'C' || pabAml[i+4] != 'P')
120 /* false alarm, not named starting CP */
121 continue;
122
123 /* Processor ID */
124 if (pabAml[i+7] < cCpus)
125 continue;
126
127 /* Will fill unwanted CPU block with NOOPs */
128 /*
129 * See 18.2.4 Package Length Encoding in ACPI spec
130 * for full format
131 */
132 uint32_t cBytes = pabAml[i + 2];
133 AssertReleaseMsg((cBytes >> 6) == 0,
134 ("So far, we only understand simple package length"));
135
136 /* including AML_PROCESSOR_OP itself */
137 for (uint32_t j = 0; j < cBytes + 2; j++)
138 pabAml[i+j] = 0xa3;
139
140 /* Can increase i by cBytes + 1, but not really worth it */
141 }
142 }
143
144 /* now recompute checksum, whole file byte sum must be 0 */
145 pabAml[9] = 0;
146 uint8_t bSum = 0;
147 for (uint32_t i = 0; i < cbAml; i++)
148 bSum = bSum + pabAml[i];
149 pabAml[9] = (uint8_t)(0 - bSum);
150
151 return VINF_SUCCESS;
152}
153
154/**
155 * Patch the CPU hot-plug SSDT version to
156 * only contain the ACPI containers which may have a CPU
157 */
158static int patchAmlCpuHotPlug(PPDMDEVINS pDevIns, uint8_t *pabAml, size_t cbAml)
159{
160 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
161
162 uint16_t cCpus;
163 int rc = pHlp->pfnCFGMQueryU16Def(pDevIns->pCfg, "NumCPUs", &cCpus, 1);
164 if (RT_FAILURE(rc))
165 return rc;
166
167 /*
168 * Now search AML for:
169 * AML_DEVICE_OP (UINT16) 0x5b82
170 * and replace whole block with
171 * AML_NOOP_OP (UINT16) 0xa3
172 * for VCPU not configured
173 */
174 uint32_t idxAml = 0;
175 while (idxAml < cbAml - 7)
176 {
177 /*
178 * AML_DEVICE_OP
179 *
180 * DefDevice := DeviceOp PkgLength NameString ObjectList
181 * DeviceOp := ExtOpPrefix 0x82
182 */
183 if (pabAml[idxAml] == 0x5b && pabAml[idxAml+1] == 0x82)
184 {
185 /* Check if the enclosed CPU device is configured. */
186 uint8_t *pabAmlPkgLength = &pabAml[idxAml+2];
187 uint32_t cBytes = 0;
188 uint32_t cLengthBytesFollow = pabAmlPkgLength[0] >> 6;
189
190 if (cLengthBytesFollow == 0)
191 {
192 /* Simple package length */
193 cBytes = pabAmlPkgLength[0];
194 }
195 else
196 {
197 unsigned idxLengthByte = 1;
198
199 cBytes = pabAmlPkgLength[0] & 0xF;
200
201 while (idxLengthByte <= cLengthBytesFollow)
202 {
203 cBytes |= pabAmlPkgLength[idxLengthByte] << (4*idxLengthByte);
204 idxLengthByte++;
205 }
206 }
207
208 uint8_t *pabAmlDevName = &pabAmlPkgLength[cLengthBytesFollow+1];
209 uint8_t *pabAmlCpu = &pabAmlDevName[4];
210 bool fCpuConfigured = false;
211#ifdef RT_STRICT
212 bool fCpuFound = false;
213#endif
214
215 if ((pabAmlDevName[0] != 'S') || (pabAmlDevName[1] != 'C') || (pabAmlDevName[2] != 'K'))
216 {
217 /* false alarm, not named starting SCK */
218 idxAml++;
219 continue;
220 }
221
222 for (uint32_t idxAmlCpu = 0; idxAmlCpu < cBytes - 7; idxAmlCpu++)
223 {
224 /*
225 * AML_PROCESSOR_OP
226 *
227 * DefProcessor := ProcessorOp PkgLength NameString ProcID
228 PblkAddr PblkLen ObjectList
229 * ProcessorOp := ExtOpPrefix 0x83
230 * ProcID := ByteData
231 * PblkAddr := DwordData
232 * PblkLen := ByteData
233 */
234 if ((pabAmlCpu[idxAmlCpu] == 0x5b) && (pabAmlCpu[idxAmlCpu+1] == 0x83))
235 {
236 if ((pabAmlCpu[idxAmlCpu+4] != 'C') || (pabAmlCpu[idxAmlCpu+5] != 'P'))
237 /* false alarm, not named starting CP */
238 continue;
239
240#ifdef RT_STRICT
241 fCpuFound = true;
242#endif
243
244 /* Processor ID */
245 uint8_t const idAmlCpu = pabAmlCpu[idxAmlCpu + 8];
246 if (idAmlCpu < cCpus)
247 {
248 LogFlow(("CPU %u is configured\n", idAmlCpu));
249 fCpuConfigured = true;
250 }
251 else
252 {
253 LogFlow(("CPU %u is not configured\n", idAmlCpu));
254 fCpuConfigured = false;
255 }
256 break;
257 }
258 }
259
260 Assert(fCpuFound);
261
262 if (!fCpuConfigured)
263 {
264 /* Will fill unwanted CPU block with NOOPs */
265 /*
266 * See 18.2.4 Package Length Encoding in ACPI spec
267 * for full format
268 */
269
270 /* including AML_DEVICE_OP itself */
271 for (uint32_t j = 0; j < cBytes + 2; j++)
272 pabAml[idxAml+j] = 0xa3;
273 }
274
275 idxAml++;
276 }
277 else
278 idxAml++;
279 }
280
281 /* now recompute checksum, whole file byte sum must be 0 */
282 pabAml[9] = 0;
283 uint8_t bSum = 0;
284 for (uint32_t i = 0; i < cbAml; i++)
285 bSum = bSum + pabAml[i];
286 pabAml[9] = (uint8_t)(0 - bSum);
287
288 return VINF_SUCCESS;
289}
290
291#endif /* VBOX_WITH_DYNAMIC_DSDT */
292
293/**
294 * Loads an AML file if present in CFGM
295 *
296 * @returns VBox status code
297 * @param pDevIns The device instance
298 * @param pcszCfgName The configuration key holding the file path
299 * @param pcszSignature The signature to check for
300 * @param ppabAmlCode Where to store the pointer to the AML code on success.
301 * @param pcbAmlCode Where to store the number of bytes of the AML code on success.
302 */
303static int acpiAmlLoadExternal(PPDMDEVINS pDevIns, const char *pcszCfgName, const char *pcszSignature,
304 uint8_t **ppabAmlCode, size_t *pcbAmlCode)
305{
306 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
307
308 char *pszAmlFilePath = NULL;
309 int rc = pHlp->pfnCFGMQueryStringAlloc(pDevIns->pCfg, pcszCfgName, &pszAmlFilePath);
310 if (RT_SUCCESS(rc))
311 {
312 /* Load from file. */
313 RTFILE hFileAml = NIL_RTFILE;
314 rc = RTFileOpen(&hFileAml, pszAmlFilePath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
315 if (RT_SUCCESS(rc))
316 {
317 /*
318 * An AML file contains the raw DSDT or SSDT thus the size of the file
319 * is equal to the size of the DSDT or SSDT.
320 */
321 uint64_t cbAmlFile = 0;
322 rc = RTFileQuerySize(hFileAml, &cbAmlFile);
323
324 /* Don't use AML files over 32MiB. */
325 if ( RT_SUCCESS(rc)
326 && cbAmlFile <= _32M)
327 {
328 size_t const cbAmlCode = (size_t)cbAmlFile;
329 uint8_t *pabAmlCode = (uint8_t *)RTMemAllocZ(cbAmlCode);
330 if (pabAmlCode)
331 {
332 rc = RTFileReadAt(hFileAml, 0, pabAmlCode, cbAmlCode, NULL);
333
334 /*
335 * We fail if reading failed or the identifier at the
336 * beginning is wrong.
337 */
338 if ( RT_FAILURE(rc)
339 || strncmp((const char *)pabAmlCode, pcszSignature, 4))
340 {
341 RTMemFree(pabAmlCode);
342 pabAmlCode = NULL;
343
344 /* Return error if file header check failed */
345 if (RT_SUCCESS(rc))
346 rc = VERR_PARSE_ERROR;
347 }
348 else
349 {
350 *ppabAmlCode = pabAmlCode;
351 *pcbAmlCode = cbAmlCode;
352 rc = VINF_SUCCESS;
353 }
354 }
355 else
356 rc = VERR_NO_MEMORY;
357 }
358 else if (RT_SUCCESS(rc))
359 rc = VERR_OUT_OF_RANGE;
360
361 RTFileClose(hFileAml);
362 }
363 PDMDevHlpMMHeapFree(pDevIns, pszAmlFilePath);
364 }
365
366 return rc;
367}
368
369
370/** No docs, lazy coder. */
371int acpiPrepareDsdt(PPDMDEVINS pDevIns, void **ppvPtr, size_t *pcbDsdt)
372{
373#ifdef VBOX_WITH_DYNAMIC_DSDT
374 return prepareDynamicDsdt(pDevIns, ppvPtr, pcbDsdt);
375#else
376 uint8_t *pabAmlCodeDsdt = NULL;
377 size_t cbAmlCodeDsdt = 0;
378 int rc = acpiAmlLoadExternal(pDevIns, "DsdtFilePath", "DSDT", &pabAmlCodeDsdt, &cbAmlCodeDsdt);
379 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
380 {
381 /* Use the compiled in AML code */
382 cbAmlCodeDsdt = sizeof(AmlCode);
383 pabAmlCodeDsdt = (uint8_t *)RTMemDup(AmlCode, cbAmlCodeDsdt);
384 if (pabAmlCodeDsdt)
385 rc = VINF_SUCCESS;
386 else
387 rc = VERR_NO_MEMORY;
388 }
389 else if (RT_FAILURE(rc))
390 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DsdtFilePath\""));
391
392 if (RT_SUCCESS(rc))
393 {
394 patchAml(pDevIns, pabAmlCodeDsdt, cbAmlCodeDsdt);
395 *ppvPtr = pabAmlCodeDsdt;
396 *pcbDsdt = cbAmlCodeDsdt;
397 }
398 return rc;
399#endif
400}
401
402/** No docs, lazy coder. */
403int acpiCleanupDsdt(PPDMDEVINS pDevIns, void *pvPtr)
404{
405#ifdef VBOX_WITH_DYNAMIC_DSDT
406 return cleanupDynamicDsdt(pDevIns, pvPtr);
407#else
408 RT_NOREF1(pDevIns);
409 if (pvPtr)
410 RTMemFree(pvPtr);
411 return VINF_SUCCESS;
412#endif
413}
414
415/** No docs, lazy coder. */
416int acpiPrepareSsdt(PPDMDEVINS pDevIns, void **ppvPtr, size_t *pcbSsdt)
417{
418 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
419
420 uint8_t *pabAmlCodeSsdt = NULL;
421 size_t cbAmlCodeSsdt = 0;
422 int rc = acpiAmlLoadExternal(pDevIns, "SsdtFilePath", "SSDT", &pabAmlCodeSsdt, &cbAmlCodeSsdt);
423 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
424 {
425 bool fCpuHotPlug = false;
426 rc = pHlp->pfnCFGMQueryBoolDef(pDevIns->pCfg, "CpuHotPlug", &fCpuHotPlug, false);
427 if (RT_SUCCESS(rc))
428 {
429 if (fCpuHotPlug)
430 {
431 cbAmlCodeSsdt = sizeof(AmlCodeSsdtCpuHotPlug);
432 pabAmlCodeSsdt = (uint8_t *)RTMemDup(AmlCodeSsdtCpuHotPlug, sizeof(AmlCodeSsdtCpuHotPlug));
433 }
434 else
435 {
436 cbAmlCodeSsdt = sizeof(AmlCodeSsdtStandard);
437 pabAmlCodeSsdt = (uint8_t *)RTMemDup(AmlCodeSsdtStandard, sizeof(AmlCodeSsdtStandard));
438 }
439 if (pabAmlCodeSsdt)
440 {
441 if (fCpuHotPlug)
442 patchAmlCpuHotPlug(pDevIns, pabAmlCodeSsdt, cbAmlCodeSsdt);
443 else
444 patchAml(pDevIns, pabAmlCodeSsdt, cbAmlCodeSsdt);
445 }
446 else
447 rc = VERR_NO_MEMORY;
448 }
449 }
450 else if (RT_FAILURE(rc))
451 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"SsdtFilePath\""));
452
453 if (RT_SUCCESS(rc))
454 {
455 *ppvPtr = pabAmlCodeSsdt;
456 *pcbSsdt = cbAmlCodeSsdt;
457 }
458 return rc;
459}
460
461/** No docs, lazy coder. */
462int acpiCleanupSsdt(PPDMDEVINS pDevIns, void *pvPtr)
463{
464 RT_NOREF1(pDevIns);
465 if (pvPtr)
466 RTMemFree(pvPtr);
467 return VINF_SUCCESS;
468}
469
470#ifdef VBOX_WITH_TPM
471/** No docs, lazy coder. */
472int acpiPrepareTpmSsdt(PPDMDEVINS pDevIns, void **ppvPtr, size_t *pcbSsdt)
473{
474 uint8_t *pabAmlCodeSsdt = NULL;
475 size_t cbAmlCodeSsdt = 0;
476 int rc = acpiAmlLoadExternal(pDevIns, "SsdtTpmFilePath", "SSDT", &pabAmlCodeSsdt, &cbAmlCodeSsdt);
477 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
478 {
479 rc = VINF_SUCCESS;
480 cbAmlCodeSsdt = sizeof(AmlCodeSsdtTpm);
481 pabAmlCodeSsdt = (uint8_t *)RTMemDup(AmlCodeSsdtTpm, sizeof(AmlCodeSsdtTpm));
482 if (!pabAmlCodeSsdt)
483 rc = VERR_NO_MEMORY;
484 }
485 else if (RT_FAILURE(rc))
486 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"SsdtFilePath\""));
487
488 if (RT_SUCCESS(rc))
489 {
490 *ppvPtr = pabAmlCodeSsdt;
491 *pcbSsdt = cbAmlCodeSsdt;
492 }
493 return rc;
494}
495
496/** No docs, lazy coder. */
497int acpiCleanupTpmSsdt(PPDMDEVINS pDevIns, void *pvPtr)
498{
499 RT_NOREF1(pDevIns);
500 if (pvPtr)
501 RTMemFree(pvPtr);
502 return VINF_SUCCESS;
503}
504#endif
505
Note: See TracBrowser for help on using the repository browser.

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