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