VirtualBox

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

Last change on this file since 88164 was 85992, checked in by vboxsync, 4 years ago

Devices/VBoxAcpi.cpp: cleanups; make sure to return errors.

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