VBoxAcpi.cpp revision ec7708c74d7fc8feb18fbe1f84b320ec86fb11ef
616c4e73368513b3c835881ff9f2386083afad01vboxsync/* $Id$ */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync/** @file
616c4e73368513b3c835881ff9f2386083afad01vboxsync * VBoxAcpi - VirtualBox ACPI maniputation functionality.
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync/*
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * Copyright (C) 2009 Sun Microsystems, Inc.
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync *
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * available from http://www.virtualbox.org. This file is free software;
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * you can redistribute it and/or modify it under the terms of the GNU
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * General Public License (GPL) as published by the Free Software
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync *
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * additional information or have any questions.
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#if !defined(IN_RING3)
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#error Pure R3 code
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#endif
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
3854599844436d009da0f32760d657fc7690a5a8vboxsync#define LOG_GROUP LOG_GROUP_DEV_ACPI
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <VBox/pdmdev.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <VBox/pgm.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <VBox/log.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <VBox/param.h>
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync#include <VBox/cfgm.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <VBox/mm.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <iprt/assert.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <iprt/alloc.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <iprt/string.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#include <iprt/file.h>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#ifdef VBOX_WITH_DYNAMIC_DSDT
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync/* vbox.dsl - input to generate proper DSDT on the fly */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync# include <vboxdsl.hex>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#else
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync/* Statically compiled AML */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync# include <vboxaml.hex>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync# include <vboxssdt-standard.hex>
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync# include <vboxssdt-cpuhotplug.hex>
616c4e73368513b3c835881ff9f2386083afad01vboxsync#endif
616c4e73368513b3c835881ff9f2386083afad01vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#ifdef VBOX_WITH_DYNAMIC_DSDT
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsyncstatic int prepareDynamicDsdt(PPDMDEVINS pDevIns,
3854599844436d009da0f32760d657fc7690a5a8vboxsync void* *ppPtr,
3854599844436d009da0f32760d657fc7690a5a8vboxsync size_t *puDsdtLen)
3854599844436d009da0f32760d657fc7690a5a8vboxsync{
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync *ppPtr = NULL;
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync *puDsdtLen = 0;
616c4e73368513b3c835881ff9f2386083afad01vboxsync return 0;
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync}
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsyncstatic int cleanupDynamicDsdt(PPDMDEVINS pDevIns,
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync void* pPtr)
ecb074924ed761fe89e91113482db5b7374441b0vboxsync{
ecb074924ed761fe89e91113482db5b7374441b0vboxsync return 0;
ecb074924ed761fe89e91113482db5b7374441b0vboxsync}
ecb074924ed761fe89e91113482db5b7374441b0vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync#else
ecb074924ed761fe89e91113482db5b7374441b0vboxsyncstatic int patchAml(PPDMDEVINS pDevIns, uint8_t* pAml, size_t uAmlLen)
616c4e73368513b3c835881ff9f2386083afad01vboxsync{
ecb074924ed761fe89e91113482db5b7374441b0vboxsync uint16_t cNumCpus;
616c4e73368513b3c835881ff9f2386083afad01vboxsync int rc;
ecb074924ed761fe89e91113482db5b7374441b0vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync rc = CFGMR3QueryU16Def(pDevIns->pCfg, "NumCPUs", &cNumCpus, 1);
616c4e73368513b3c835881ff9f2386083afad01vboxsync
a2779f5bd9cc55216a2911d7714ede6a77cac3b2vboxsync if (RT_FAILURE(rc))
3854599844436d009da0f32760d657fc7690a5a8vboxsync return rc;
3854599844436d009da0f32760d657fc7690a5a8vboxsync
3854599844436d009da0f32760d657fc7690a5a8vboxsync /* Clear CPU objects at all, if needed */
24eb79e9b779a21a256c7e15e5ad8ef97f7b6178vboxsync bool fShowCpu;
3854599844436d009da0f32760d657fc7690a5a8vboxsync rc = CFGMR3QueryBoolDef(pDevIns->pCfg, "ShowCpu", &fShowCpu, false);
3854599844436d009da0f32760d657fc7690a5a8vboxsync if (RT_FAILURE(rc))
24eb79e9b779a21a256c7e15e5ad8ef97f7b6178vboxsync return rc;
24eb79e9b779a21a256c7e15e5ad8ef97f7b6178vboxsync
616c4e73368513b3c835881ff9f2386083afad01vboxsync if (!fShowCpu)
ecb074924ed761fe89e91113482db5b7374441b0vboxsync cNumCpus = 0;
ecb074924ed761fe89e91113482db5b7374441b0vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync /**
616c4e73368513b3c835881ff9f2386083afad01vboxsync * Now search AML for:
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * AML_PROCESSOR_OP (UINT16) 0x5b83
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * and replace whole block with
3854599844436d009da0f32760d657fc7690a5a8vboxsync * AML_NOOP_OP (UINT16) 0xa3
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * for VCPU not configured
ecb074924ed761fe89e91113482db5b7374441b0vboxsync */
616c4e73368513b3c835881ff9f2386083afad01vboxsync for (uint32_t i = 0; i < uAmlLen - 7; i++)
ecb074924ed761fe89e91113482db5b7374441b0vboxsync {
616c4e73368513b3c835881ff9f2386083afad01vboxsync /*
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * AML_PROCESSOR_OP
ecb074924ed761fe89e91113482db5b7374441b0vboxsync *
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * DefProcessor := ProcessorOp PkgLength NameString ProcID
ecb074924ed761fe89e91113482db5b7374441b0vboxsync PblkAddr PblkLen ObjectList
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * ProcessorOp := ExtOpPrefix 0x83
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * ProcID := ByteData
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * PblkAddr := DwordData
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * PblkLen := ByteData
ecb074924ed761fe89e91113482db5b7374441b0vboxsync */
ecb074924ed761fe89e91113482db5b7374441b0vboxsync if ((pAml[i] == 0x5b) && (pAml[i+1] == 0x83))
ecb074924ed761fe89e91113482db5b7374441b0vboxsync {
616c4e73368513b3c835881ff9f2386083afad01vboxsync if ((pAml[i+3] != 'C') || (pAml[i+4] != 'P'))
3854599844436d009da0f32760d657fc7690a5a8vboxsync /* false alarm, not named starting CP */
3854599844436d009da0f32760d657fc7690a5a8vboxsync continue;
3854599844436d009da0f32760d657fc7690a5a8vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync /* Processor ID */
ecb074924ed761fe89e91113482db5b7374441b0vboxsync if (pAml[i+7] < cNumCpus)
616c4e73368513b3c835881ff9f2386083afad01vboxsync continue;
616c4e73368513b3c835881ff9f2386083afad01vboxsync
616c4e73368513b3c835881ff9f2386083afad01vboxsync /* Will fill unwanted CPU block with NOOPs */
ecb074924ed761fe89e91113482db5b7374441b0vboxsync /*
ecb074924ed761fe89e91113482db5b7374441b0vboxsync * See 18.2.4 Package Length Encoding in ACPI spec
616c4e73368513b3c835881ff9f2386083afad01vboxsync * for full format
ecb074924ed761fe89e91113482db5b7374441b0vboxsync */
616c4e73368513b3c835881ff9f2386083afad01vboxsync uint32_t cBytes = pAml[i + 2];
ecb074924ed761fe89e91113482db5b7374441b0vboxsync AssertReleaseMsg((cBytes >> 6) == 0,
ecb074924ed761fe89e91113482db5b7374441b0vboxsync ("So far, we only understand simple package length"));
ecb074924ed761fe89e91113482db5b7374441b0vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync /* including AML_PROCESSOR_OP itself */
ecb074924ed761fe89e91113482db5b7374441b0vboxsync for (uint32_t j = 0; j < cBytes + 2; j++)
ecb074924ed761fe89e91113482db5b7374441b0vboxsync pAml[i+j] = 0xa3;
ecb074924ed761fe89e91113482db5b7374441b0vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync /* Can increase i by cBytes + 1, but not really worth it */
ecb074924ed761fe89e91113482db5b7374441b0vboxsync }
ecb074924ed761fe89e91113482db5b7374441b0vboxsync }
ecb074924ed761fe89e91113482db5b7374441b0vboxsync
ecb074924ed761fe89e91113482db5b7374441b0vboxsync /* now recompute checksum, whole file byte sum must be 0 */
ecb074924ed761fe89e91113482db5b7374441b0vboxsync pAml[9] = 0;
ecb074924ed761fe89e91113482db5b7374441b0vboxsync uint8_t aSum = 0;
616c4e73368513b3c835881ff9f2386083afad01vboxsync for (uint32_t i = 0; i < uAmlLen; i++)
ecb074924ed761fe89e91113482db5b7374441b0vboxsync aSum = aSum + (uint8_t)pAml[i];
ecb074924ed761fe89e91113482db5b7374441b0vboxsync pAml[9] = (uint8_t) (0 - aSum);
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync return 0;
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync}
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync#endif
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync/* Two only public functions */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsyncint acpiPrepareDsdt(PPDMDEVINS pDevIns, void * *ppPtr, size_t *puDsdtLen)
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync{
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync#ifdef VBOX_WITH_DYNAMIC_DSDT
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync return prepareDynamicDsdt(pDevIns, ppPtr, puDsdtLen);
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync#else
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync uint8_t *pbAmlCode = NULL;
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync size_t cbAmlCode = 0;
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync char *pszAmlFilePath = NULL;
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync int rc = CFGMR3QueryStringAlloc(pDevIns->pCfg, "AmlFilePath", &pszAmlFilePath);
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync if (RT_SUCCESS(rc))
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync {
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync /* Load from file. */
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync RTFILE FileAml = NIL_RTFILE;
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync rc = RTFileOpen(&FileAml, pszAmlFilePath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync if (RT_SUCCESS(rc))
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync {
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync /*
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync * An AML file contains the raw DSDT thus the size of the file
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync * is equal to the size of the DSDT.
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync */
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync uint64_t cbAmlFile = 0;
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync rc = RTFileGetSize(FileAml, &cbAmlFile);
eb90548e8e40e597d65cdcc16ec958a3e09c1d73vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync cbAmlCode = (size_t)cbAmlFile;
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync /* Don't use AML files over 4GB ;) */
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync if ( RT_SUCCESS(rc)
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync && ((uint64_t)cbAmlCode == cbAmlFile))
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync {
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync pbAmlCode = (uint8_t *)RTMemAllocZ(cbAmlCode);
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync if (pbAmlCode)
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync {
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync rc = RTFileReadAt(FileAml, 0, pbAmlCode, cbAmlCode, NULL);
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync /*
7f8a04081173dbe3c72bddd0ffeb237e7f9070b0vboxsync * We fail if reading failed or the identifier at the
616c4e73368513b3c835881ff9f2386083afad01vboxsync * beginning is wrong.
*/
if ( RT_FAILURE(rc)
|| strncmp((const char *)pbAmlCode, pcszSignature, 4))
{
RTMemFree(pbAmlCode);
pbAmlCode = NULL;
/* Return error if file header check failed */
if (RT_SUCCESS(rc))
rc = VERR_PARSE_ERROR;
}
else
{
*ppbAmlCode = pbAmlCode;
*pcbAmlCode = cbAmlCode;
rc = VINF_SUCCESS;
}
}
else
rc = VERR_NO_MEMORY;
}
RTFileClose(FileAml);
}
MMR3HeapFree(pszAmlFilePath);
}
return rc;
}
/* Two only public functions */
int acpiPrepareDsdt(PPDMDEVINS pDevIns, void * *ppPtr, size_t *puDsdtLen)
{
#ifdef VBOX_WITH_DYNAMIC_DSDT
return prepareDynamicDsdt(pDevIns, ppPtr, puDsdtLen);
#else
uint8_t *pbAmlCodeDsdt = NULL;
size_t cbAmlCodeDsdt = 0;
int rc = acpiAmlLoadExternal(pDevIns, "DsdtFilePath", "DSDT", &pbAmlCodeDsdt, &cbAmlCodeDsdt);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
rc = VINF_SUCCESS;
/* Use the compiled in AML code */
cbAmlCodeDsdt = sizeof(AmlCode);
pbAmlCodeDsdt = (uint8_t *)RTMemAllocZ(cbAmlCodeDsdt);
if (pbAmlCodeDsdt)
memcpy(pbAmlCodeDsdt, AmlCode, cbAmlCodeDsdt);
else
rc = VERR_NO_MEMORY;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"DsdtFilePath\""));
if (RT_SUCCESS(rc))
{
patchAml(pDevIns, pbAmlCodeDsdt, cbAmlCodeDsdt);
*ppPtr = pbAmlCodeDsdt;
*puDsdtLen = cbAmlCodeDsdt;
}
return rc;
#endif
}
int acpiCleanupDsdt(PPDMDEVINS pDevIns, void * pPtr)
{
#ifdef VBOX_WITH_DYNAMIC_DSDT
return cleanupDynamicDsdt(pDevIns, pPtr);
#else
if (pPtr)
RTMemFree(pPtr);
return VINF_SUCCESS;
#endif
}
int acpiPrepareSsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puSsdtLen)
{
uint8_t *pbAmlCodeSsdt = NULL;
size_t cbAmlCodeSsdt = 0;
int rc = acpiAmlLoadExternal(pDevIns, "SsdtFilePath", "SSDT", &pbAmlCodeSsdt, &cbAmlCodeSsdt);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
bool fCpuHotPlug = false;
uint8_t *pbAmlCode = NULL;
rc = CFGMR3QueryBoolDef(pDevIns->pCfgHandle, "CpuHotPlug", &fCpuHotPlug, false);
if (RT_FAILURE(rc))
return rc;
if (fCpuHotPlug)
{
pbAmlCode = AmlCodeSsdtCpuHotPlug;
cbAmlCodeSsdt = sizeof(AmlCodeSsdtCpuHotPlug);
}
else
{
pbAmlCode = AmlCodeSsdtStandard;
cbAmlCodeSsdt = sizeof(AmlCodeSsdtStandard);
}
pbAmlCodeSsdt = (uint8_t *)RTMemAllocZ(cbAmlCodeSsdt);
if (pbAmlCodeSsdt)
memcpy(pbAmlCodeSsdt, pbAmlCode, cbAmlCodeSsdt);
else
rc = VERR_NO_MEMORY;
}
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"SsdtFilePath\""));
if (RT_SUCCESS(rc))
{
patchAml(pDevIns, pbAmlCodeSsdt, cbAmlCodeSsdt);
*ppPtr = pbAmlCodeSsdt;
*puSsdtLen = cbAmlCodeSsdt;
}
return VINF_SUCCESS;
}
int acpiCleanupSsdt(PPDMDEVINS pDevIns, void* pPtr)
{
if (pPtr)
RTMemFree(pPtr);
return VINF_SUCCESS;
}