VirtualBox

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

Last change on this file since 75265 was 72303, checked in by vboxsync, 7 years ago

Devices/Makefile.kmk: Make it work with recent iasl versions, the generated headers have include guards based on the filename now but iasl doesn't convert dashes in the filename to underscores breaking the build. They also generate the identifier for the array containing the tables based on filename instead of the using the standard AmlCode we expect (missing file)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
Line 
1/* $Id: VBoxAcpi.cpp 72303 2018-05-23 15:35:45Z vboxsync $ */
2/** @file
3 * VBoxAcpi - VirtualBox ACPI manipulation functionality.
4 */
5
6/*
7 * Copyright (C) 2009-2017 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#endif
48
49#include "VBoxDD.h"
50
51
52#ifdef VBOX_WITH_DYNAMIC_DSDT
53
54static int prepareDynamicDsdt(PPDMDEVINS pDevIns, void **ppvPtr, size_t *pcbDsdt)
55{
56 *ppvPtr = NULL;
57 *pcbDsdt = 0;
58 return 0;
59}
60
61static int cleanupDynamicDsdt(PPDMDEVINS pDevIns, void *pvPtr)
62{
63 return 0;
64}
65
66#else /* VBOX_WITH_DYNAMIC_DSDT */
67
68static int patchAml(PPDMDEVINS pDevIns, uint8_t *pabAml, size_t cbAml)
69{
70 uint16_t cNumCpus;
71 int rc;
72
73 rc = CFGMR3QueryU16Def(pDevIns->pCfg, "NumCPUs", &cNumCpus, 1);
74
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 cNumCpus = 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
100 PblkAddr PblkLen ObjectList
101 * ProcessorOp := ExtOpPrefix 0x83
102 * ProcID := ByteData
103 * PblkAddr := DwordData
104 * PblkLen := ByteData
105 */
106 if (pabAml[i] == 0x5b && pabAml[i+1] == 0x83)
107 {
108 if (pabAml[i+3] != 'C' || pabAml[i+4] != 'P')
109 /* false alarm, not named starting CP */
110 continue;
111
112 /* Processor ID */
113 if (pabAml[i+7] < cNumCpus)
114 continue;
115
116 /* Will fill unwanted CPU block with NOOPs */
117 /*
118 * See 18.2.4 Package Length Encoding in ACPI spec
119 * for full format
120 */
121 uint32_t cBytes = pabAml[i + 2];
122 AssertReleaseMsg((cBytes >> 6) == 0,
123 ("So far, we only understand simple package length"));
124
125 /* including AML_PROCESSOR_OP itself */
126 for (uint32_t j = 0; j < cBytes + 2; j++)
127 pabAml[i+j] = 0xa3;
128
129 /* Can increase i by cBytes + 1, but not really worth it */
130 }
131 }
132
133 /* now recompute checksum, whole file byte sum must be 0 */
134 pabAml[9] = 0;
135 uint8_t bSum = 0;
136 for (uint32_t i = 0; i < cbAml; i++)
137 bSum = bSum + pabAml[i];
138 pabAml[9] = (uint8_t)(0 - bSum);
139
140 return 0;
141}
142
143/**
144 * Patch the CPU hot-plug SSDT version to
145 * only contain the ACPI containers which may have a CPU
146 */
147static int patchAmlCpuHotPlug(PPDMDEVINS pDevIns, uint8_t *pabAml, size_t cbAml)
148{
149 uint16_t cNumCpus;
150 int rc;
151 uint32_t idxAml = 0;
152
153 rc = CFGMR3QueryU16Def(pDevIns->pCfg, "NumCPUs", &cNumCpus, 1);
154
155 if (RT_FAILURE(rc))
156 return rc;
157
158 /**
159 * Now search AML for:
160 * AML_DEVICE_OP (UINT16) 0x5b82
161 * and replace whole block with
162 * AML_NOOP_OP (UINT16) 0xa3
163 * for VCPU not configured
164 */
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 < cNumCpus)
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 0;
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, uint8_t **ppabAmlCode, size_t *pcbAmlCode)
290{
291 uint8_t *pabAmlCode = NULL;
292 size_t cbAmlCode = 0;
293 char *pszAmlFilePath = NULL;
294 int rc = CFGMR3QueryStringAlloc(pDevIns->pCfg, pcszCfgName, &pszAmlFilePath);
295
296 if (RT_SUCCESS(rc))
297 {
298 /* Load from file. */
299 RTFILE FileAml = NIL_RTFILE;
300
301 rc = RTFileOpen(&FileAml, pszAmlFilePath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
302 if (RT_SUCCESS(rc))
303 {
304 /*
305 * An AML file contains the raw DSDT thus the size of the file
306 * is equal to the size of the DSDT.
307 */
308 uint64_t cbAmlFile = 0;
309 rc = RTFileGetSize(FileAml, &cbAmlFile);
310
311 cbAmlCode = (size_t)cbAmlFile;
312
313 /* Don't use AML files over 4GB ;) */
314 if ( RT_SUCCESS(rc)
315 && ((uint64_t)cbAmlCode == cbAmlFile))
316 {
317 pabAmlCode = (uint8_t *)RTMemAllocZ(cbAmlCode);
318 if (pabAmlCode)
319 {
320 rc = RTFileReadAt(FileAml, 0, pabAmlCode, cbAmlCode, NULL);
321
322 /*
323 * We fail if reading failed or the identifier at the
324 * beginning is wrong.
325 */
326 if ( RT_FAILURE(rc)
327 || strncmp((const char *)pabAmlCode, pcszSignature, 4))
328 {
329 RTMemFree(pabAmlCode);
330 pabAmlCode = NULL;
331
332 /* Return error if file header check failed */
333 if (RT_SUCCESS(rc))
334 rc = VERR_PARSE_ERROR;
335 }
336 else
337 {
338 *ppabAmlCode = pabAmlCode;
339 *pcbAmlCode = cbAmlCode;
340 rc = VINF_SUCCESS;
341 }
342 }
343 else
344 rc = VERR_NO_MEMORY;
345 }
346
347 RTFileClose(FileAml);
348 }
349 MMR3HeapFree(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
366 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
367 {
368 rc = VINF_SUCCESS;
369
370 /* Use the compiled in AML code */
371 cbAmlCodeDsdt = sizeof(AmlCode);
372 pabAmlCodeDsdt = (uint8_t *)RTMemAllocZ(cbAmlCodeDsdt);
373 if (pabAmlCodeDsdt)
374 memcpy(pabAmlCodeDsdt, AmlCode, cbAmlCodeDsdt);
375 else
376 rc = VERR_NO_MEMORY;
377 }
378 else if (RT_FAILURE(rc))
379 return PDMDEV_SET_ERROR(pDevIns, rc,
380 N_("Configuration error: Failed to read \"DsdtFilePath\""));
381
382 if (RT_SUCCESS(rc))
383 {
384 patchAml(pDevIns, pabAmlCodeDsdt, cbAmlCodeDsdt);
385 *ppvPtr = pabAmlCodeDsdt;
386 *pcbDsdt = cbAmlCodeDsdt;
387 }
388 return rc;
389#endif
390}
391
392/** No docs, lazy coder. */
393int acpiCleanupDsdt(PPDMDEVINS pDevIns, void *pvPtr)
394{
395#ifdef VBOX_WITH_DYNAMIC_DSDT
396 return cleanupDynamicDsdt(pDevIns, pvPtr);
397#else
398 RT_NOREF1(pDevIns);
399 if (pvPtr)
400 RTMemFree(pvPtr);
401 return VINF_SUCCESS;
402#endif
403}
404
405/** No docs, lazy coder. */
406int acpiPrepareSsdt(PPDMDEVINS pDevIns, void **ppvPtr, size_t *pcbSsdt)
407{
408 uint8_t *pabAmlCodeSsdt = NULL;
409 size_t cbAmlCodeSsdt = 0;
410 int rc = acpiAmlLoadExternal(pDevIns, "SsdtFilePath", "SSDT", &pabAmlCodeSsdt, &cbAmlCodeSsdt);
411
412 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
413 {
414 bool fCpuHotPlug = false;
415 uint8_t *pabAmlCode = NULL;
416 rc = CFGMR3QueryBoolDef(pDevIns->pCfg, "CpuHotPlug", &fCpuHotPlug, false);
417
418 if (RT_FAILURE(rc))
419 return rc;
420
421 if (fCpuHotPlug)
422 {
423 pabAmlCode = AmlCodeSsdtCpuHotPlug;
424 cbAmlCodeSsdt = sizeof(AmlCodeSsdtCpuHotPlug);
425 }
426 else
427 {
428 pabAmlCode = AmlCodeSsdtStandard;
429 cbAmlCodeSsdt = sizeof(AmlCodeSsdtStandard);
430 }
431
432 pabAmlCodeSsdt = (uint8_t *)RTMemAllocZ(cbAmlCodeSsdt);
433 if (pabAmlCodeSsdt)
434 {
435 memcpy(pabAmlCodeSsdt, pabAmlCode, cbAmlCodeSsdt);
436
437 if (fCpuHotPlug)
438 patchAmlCpuHotPlug(pDevIns, pabAmlCodeSsdt, cbAmlCodeSsdt);
439 else
440 patchAml(pDevIns, pabAmlCodeSsdt, cbAmlCodeSsdt);
441 }
442 else
443 rc = VERR_NO_MEMORY;
444 }
445 else if (RT_FAILURE(rc))
446 return PDMDEV_SET_ERROR(pDevIns, rc,
447 N_("Configuration error: Failed to read \"SsdtFilePath\""));
448
449 if (RT_SUCCESS(rc))
450 {
451 *ppvPtr = pabAmlCodeSsdt;
452 *pcbSsdt = cbAmlCodeSsdt;
453 }
454
455 return VINF_SUCCESS;
456}
457
458/** No docs, lazy coder. */
459int acpiCleanupSsdt(PPDMDEVINS pDevIns, void *pvPtr)
460{
461 RT_NOREF1(pDevIns);
462 if (pvPtr)
463 RTMemFree(pvPtr);
464 return VINF_SUCCESS;
465}
466
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