VirtualBox

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

最後變更 在這個檔案從91607是 90908,由 vboxsync 提交於 4 年 前

Devices/ACPI: Preliminary TPM support (disabled), bugref:10075

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

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