VirtualBox

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

Last change on this file since 91942 was 91897, checked in by vboxsync, 3 years ago

VMM,Devices: Add callbacks to required MMR3* APIs to the helper callbacks tables and convert devices and drivers to make use of those, bugref:10074

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