summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/PC/DevACPI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/PC/DevACPI.cpp')
-rw-r--r--src/VBox/Devices/PC/DevACPI.cpp2666
1 files changed, 1454 insertions, 1212 deletions
diff --git a/src/VBox/Devices/PC/DevACPI.cpp b/src/VBox/Devices/PC/DevACPI.cpp
index f83d1f8f1..b20915635 100644
--- a/src/VBox/Devices/PC/DevACPI.cpp
+++ b/src/VBox/Devices/PC/DevACPI.cpp
@@ -1,10 +1,10 @@
-/* $Id: DevACPI.cpp $ */
+/* $Id: DevACPI.cpp 37526 2011-06-17 10:17:38Z vboxsync $ */
/** @file
* DevACPI - Advanced Configuration and Power Interface (ACPI) Device.
*/
/*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,6 +21,7 @@
#define LOG_GROUP LOG_GROUP_DEV_ACPI
#include <VBox/vmm/pdmdev.h>
#include <VBox/vmm/pgm.h>
+#include <VBox/vmm/dbgftrace.h>
#include <VBox/log.h>
#include <VBox/param.h>
#include <iprt/assert.h>
@@ -51,6 +52,19 @@ int acpiCleanupSsdt(PPDMDEVINS pDevIns, void* pPtr);
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
+#ifdef IN_RING3
+/** Locks the device state, ring-3 only. */
+# define DEVACPI_LOCK_R3(a_pThis) \
+ do { \
+ int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
+ AssertRC(rcLock); \
+ } while (0)
+#endif
+/** Unlocks the device state (all contexts). */
+#define DEVACPI_UNLOCK(a_pThis) \
+ do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
+
+
#define DEBUG_HEX 0x3000
#define DEBUG_CHR 0x3001
@@ -166,7 +180,11 @@ enum
SYSTEM_INFO_INDEX_HBC_ADDRESS = 19, /**< host bus controller PCI address */
SYSTEM_INFO_INDEX_PCI_BASE = 20, /**< PCI bus MCFG MMIO range base */
SYSTEM_INFO_INDEX_PCI_LENGTH = 21, /**< PCI bus MCFG MMIO range length */
- SYSTEM_INFO_INDEX_END = 22,
+ SYSTEM_INFO_INDEX_SERIAL0_IOBASE = 22,
+ SYSTEM_INFO_INDEX_SERIAL0_IRQ = 23,
+ SYSTEM_INFO_INDEX_SERIAL1_IOBASE = 24,
+ SYSTEM_INFO_INDEX_SERIAL1_IRQ = 25,
+ SYSTEM_INFO_INDEX_END = 26,
SYSTEM_INFO_INDEX_INVALID = 0x80,
SYSTEM_INFO_INDEX_VALID = 0x200
};
@@ -193,16 +211,18 @@ enum
typedef struct ACPIState
{
PCIDevice dev;
+ /** Critical section protecting the ACPI state. */
+ PDMCRITSECT CritSect;
+
uint16_t pm1a_en;
uint16_t pm1a_sts;
uint16_t pm1a_ctl;
/** Number of logical CPUs in guest */
uint16_t cCpus;
uint64_t u64PmTimerInitial;
- uint64_t u64PmTimerLastSeen;
- PTMTIMERR3 tsR3;
- PTMTIMERR0 tsR0;
- PTMTIMERRC tsRC;
+ PTMTIMERR3 pPmTimerR3;
+ PTMTIMERR0 pPmTimerR0;
+ PTMTIMERRC pPmTimerRC;
uint32_t gpe0_en;
uint32_t gpe0_sts;
@@ -282,7 +302,14 @@ typedef struct ACPIState
uint64_t u64PciConfigMMioAddress;
/* Length of PCI config space MMIO region */
uint64_t u64PciConfigMMioLength;
-
+ /** Serial 0 IRQ number */
+ uint8_t uSerial0Irq;
+ /** Serial 1 IRQ number */
+ uint8_t uSerial1Irq;
+ /** Serial 0 IO port base */
+ RTIOPORT uSerial0IoPortBase;
+ /** Serial 1 IO port base */
+ RTIOPORT uSerial1IoPortBase;
/** ACPI port base interface. */
PDMIBASE IBase;
/** ACPI port interface. */
@@ -649,9 +676,9 @@ public:
/**
* Size of MADT for given ACPI config, useful to compute layout.
*/
- static uint32_t sizeFor(ACPIState *s, uint32_t cIsos)
+ static uint32_t sizeFor(ACPIState *pThis, uint32_t cIsos)
{
- return AcpiTableMADT(s->cCpus, cIsos).size();
+ return AcpiTableMADT(pThis->cCpus, cIsos).size();
}
/*
@@ -681,391 +708,19 @@ public:
* Internal Functions *
*******************************************************************************/
RT_C_DECLS_BEGIN
-PDMBOTHCBDECL(int) acpiPMTmrRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-#ifdef IN_RING3
-PDMBOTHCBDECL(int) acpiPm1aEnRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiPM1aEnWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiPm1aStsRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiPM1aStsWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiPm1aCtlRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiPM1aCtlWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiSmiWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiBatIndexWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiBatDataRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiSysInfoDataRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiGpe0EnRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiGpe0EnWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiGpe0StsRead( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
-PDMBOTHCBDECL(int) acpiGpe0StsWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiResetWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-# ifdef DEBUG_ACPI
-PDMBOTHCBDECL(int) acpiDhexWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-PDMBOTHCBDECL(int) acpiDchrWrite( PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
-# endif
-#endif /* IN_RING3 */
+PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
RT_C_DECLS_END
-
-
#ifdef IN_RING3
+static int acpiPlantTables(ACPIState *pThis);
+#endif
-static RTIOPORT acpiPmPort(ACPIState* pAcpi, int32_t offset)
-{
- Assert(pAcpi->uPmIoPortBase != 0);
-
- if (offset == -1)
- return 0;
-
- return RTIOPORT(pAcpi->uPmIoPortBase + offset);
-}
-
-/* Simple acpiChecksum: all the bytes must add up to 0. */
-static uint8_t acpiChecksum(const uint8_t * const data, size_t len)
-{
- uint8_t sum = 0;
- for (size_t i = 0; i < len; ++i)
- sum += data[i];
- return -sum;
-}
-
-static void acpiPrepareHeader(ACPITBLHEADER *header, const char au8Signature[4],
- uint32_t u32Length, uint8_t u8Revision)
-{
- memcpy(header->au8Signature, au8Signature, 4);
- header->u32Length = RT_H2LE_U32(u32Length);
- header->u8Revision = u8Revision;
- memcpy(header->au8OemId, "VBOX ", 6);
- memcpy(header->au8OemTabId, "VBOX", 4);
- memcpy(header->au8OemTabId+4, au8Signature, 4);
- header->u32OemRevision = RT_H2LE_U32(1);
- memcpy(header->au8CreatorId, "ASL ", 4);
- header->u32CreatorRev = RT_H2LE_U32(0x61);
-}
-
-static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
- uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
- uint8_t u8AccessSize, uint64_t u64Address)
-{
- g->u8AddressSpaceId = u8AddressSpaceId;
- g->u8RegisterBitWidth = u8RegisterBitWidth;
- g->u8RegisterBitOffset = u8RegisterBitOffset;
- g->u8AccessSize = u8AccessSize;
- g->u64Address = RT_H2LE_U64(u64Address);
-}
-
-static void acpiPhyscpy(ACPIState *s, RTGCPHYS32 dst, const void * const src, size_t size)
-{
- PDMDevHlpPhysWrite(s->pDevIns, dst, src, size);
-}
-
-/** Differentiated System Description Table (DSDT) */
-
-static void acpiSetupDSDT(ACPIState *s, RTGCPHYS32 addr,
- void* pPtr, size_t uDsdtLen)
-{
- acpiPhyscpy(s, addr, pPtr, uDsdtLen);
-}
-
-/** Secondary System Description Table (SSDT) */
-
-static void acpiSetupSSDT(ACPIState *s, RTGCPHYS32 addr,
- void* pPtr, size_t uSsdtLen)
-{
- acpiPhyscpy(s, addr, pPtr, uSsdtLen);
-}
-
-/** Firmware ACPI Control Structure (FACS) */
-static void acpiSetupFACS(ACPIState *s, RTGCPHYS32 addr)
-{
- ACPITBLFACS facs;
-
- memset(&facs, 0, sizeof(facs));
- memcpy(facs.au8Signature, "FACS", 4);
- facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
- facs.u32HWSignature = RT_H2LE_U32(0);
- facs.u32FWVector = RT_H2LE_U32(0);
- facs.u32GlobalLock = RT_H2LE_U32(0);
- facs.u32Flags = RT_H2LE_U32(0);
- facs.u64X_FWVector = RT_H2LE_U64(0);
- facs.u8Version = 1;
-
- acpiPhyscpy(s, addr, (const uint8_t *)&facs, sizeof(facs));
-}
-
-/** Fixed ACPI Description Table (FADT aka FACP) */
-static void acpiSetupFADT(ACPIState *s, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2, RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
-{
- ACPITBLFADT fadt;
-
- /* First the ACPI version 2+ version of the structure. */
- memset(&fadt, 0, sizeof(fadt));
- acpiPrepareHeader(&fadt.header, "FACP", sizeof(fadt), 4);
- fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
- fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
- fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
- fadt.u8PreferredPMProfile = 0; /* unspecified */
- fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
- fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
- fadt.u8AcpiEnable = ACPI_ENABLE;
- fadt.u8AcpiDisable = ACPI_DISABLE;
- fadt.u8S4BIOSReq = 0;
- fadt.u8PStateCnt = 0;
- fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiPmPort(s, PM1a_EVT_OFFSET));
- fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiPmPort(s, PM1b_EVT_OFFSET));
- fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiPmPort(s, PM1a_CTL_OFFSET));
- fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiPmPort(s, PM1b_CTL_OFFSET));
- fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiPmPort(s, PM2_CTL_OFFSET));
- fadt.u32PMTMRBLK = RT_H2LE_U32(acpiPmPort(s, PM_TMR_OFFSET));
- fadt.u32GPE0BLK = RT_H2LE_U32(acpiPmPort(s, GPE0_OFFSET));
- fadt.u32GPE1BLK = RT_H2LE_U32(acpiPmPort(s, GPE1_OFFSET));
- fadt.u8PM1EVTLEN = 4;
- fadt.u8PM1CTLLEN = 2;
- fadt.u8PM2CTLLEN = 0;
- fadt.u8PMTMLEN = 4;
- fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
- fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
- fadt.u8GPE1BASE = GPE1_BASE;
- fadt.u8CSTCNT = 0;
- fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
- fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
- fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
- fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
- fadt.u8DutyOffset = 0;
- fadt.u8DutyWidth = 0;
- fadt.u8DayAlarm = 0;
- fadt.u8MonAlarm = 0;
- fadt.u8Century = 0;
- fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
- /** @note WBINVD is required for ACPI versions newer than 1.0 */
- fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
- | FADT_FL_FIX_RTC
- | FADT_FL_TMR_VAL_EXT
- | FADT_FL_RESET_REG_SUP);
-
- /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
- if (s->fCpuHotPlug)
- fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
-
- acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
- fadt.u8ResetVal = ACPI_RESET_REG_VAL;
- fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
- fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
- acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiPmPort(s, PM1a_EVT_OFFSET));
- acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiPmPort(s, PM1b_EVT_OFFSET));
- acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiPmPort(s, PM1a_CTL_OFFSET));
- acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiPmPort(s, PM1b_CTL_OFFSET));
- acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiPmPort(s, PM2_CTL_OFFSET));
- acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiPmPort(s, PM_TMR_OFFSET));
- acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiPmPort(s, GPE0_OFFSET));
- acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiPmPort(s, GPE1_OFFSET));
- fadt.header.u8Checksum = acpiChecksum((uint8_t *)&fadt, sizeof(fadt));
- acpiPhyscpy(s, GCPhysAcpi2, &fadt, sizeof(fadt));
-
- /* Now the ACPI 1.0 version. */
- fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
- fadt.u8IntModel = INT_MODEL_DUAL_PIC;
- fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
- fadt.header.u8Checksum = acpiChecksum((uint8_t *)&fadt, ACPITBLFADT_VERSION1_SIZE);
- acpiPhyscpy(s, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
-}
-
-/**
- * Root System Description Table.
- * The RSDT and XSDT tables are basically identical. The only difference is 32 vs 64 bits
- * addresses for description headers. RSDT is for ACPI 1.0. XSDT for ACPI 2.0 and up.
- */
-static int acpiSetupRSDT(ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
-{
- ACPITBLRSDT *rsdt;
- const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
-
- rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
- if (!rsdt)
- return PDMDEV_SET_ERROR(s->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
-
- acpiPrepareHeader(&rsdt->header, "RSDT", (uint32_t)size, 1);
- for (unsigned int i = 0; i < nb_entries; ++i)
- {
- rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
- Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
- }
- rsdt->header.u8Checksum = acpiChecksum((uint8_t*)rsdt, size);
- acpiPhyscpy(s, addr, rsdt, size);
- RTMemFree(rsdt);
- return VINF_SUCCESS;
-}
-
-/** Extended System Description Table. */
-static int acpiSetupXSDT(ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
-{
- ACPITBLXSDT *xsdt;
- const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
-
- xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
- if (!xsdt)
- return VERR_NO_TMP_MEMORY;
-
- acpiPrepareHeader(&xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
- for (unsigned int i = 0; i < nb_entries; ++i)
- {
- xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
- Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
- }
- xsdt->header.u8Checksum = acpiChecksum((uint8_t*)xsdt, size);
- acpiPhyscpy(s, addr, xsdt, size);
- RTMemFree(xsdt);
- return VINF_SUCCESS;
-}
-
-/** Root System Description Pointer (RSDP) */
-static void acpiSetupRSDP(ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
-{
- memset(rsdp, 0, sizeof(*rsdp));
-
- /* ACPI 1.0 part (RSDT */
- memcpy(rsdp->au8Signature, "RSD PTR ", 8);
- memcpy(rsdp->au8OemId, "VBOX ", 6);
- rsdp->u8Revision = ACPI_REVISION;
- rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
- rsdp->u8Checksum = acpiChecksum((uint8_t*)rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
-
- /* ACPI 2.0 part (XSDT) */
- rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
- rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
- rsdp->u8ExtChecksum = acpiChecksum((uint8_t*)rsdp, sizeof(ACPITBLRSDP));
-}
-
-/**
- * Multiple APIC Description Table.
- *
- * @note APIC without IO-APIC hangs Windows Vista therefore we setup both
- *
- * @todo All hardcoded, should set this up based on the actual VM config!!!!!
- */
-static void acpiSetupMADT(ACPIState *s, RTGCPHYS32 addr)
-{
- uint16_t cpus = s->cCpus;
- AcpiTableMADT madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
-
- acpiPrepareHeader(madt.header_addr(), "APIC", madt.size(), 2);
-
- *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
- *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
-
- /* LAPICs records */
- ACPITBLLAPIC* lapic = madt.LApics_addr();
- for (uint16_t i = 0; i < cpus; i++)
- {
- lapic->u8Type = 0;
- lapic->u8Length = sizeof(ACPITBLLAPIC);
- lapic->u8ProcId = i;
- /** Must match numbering convention in MPTABLES */
- lapic->u8ApicId = i;
- lapic->u32Flags = VMCPUSET_IS_PRESENT(&s->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
- lapic++;
- }
-
- /* IO-APIC record */
- ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
- ioapic->u8Type = 1;
- ioapic->u8Length = sizeof(ACPITBLIOAPIC);
- /** Must match MP tables ID */
- ioapic->u8IOApicId = cpus;
- ioapic->u8Reserved = 0;
- ioapic->u32Address = RT_H2LE_U32(0xfec00000);
- ioapic->u32GSIB = RT_H2LE_U32(0);
-
- /* Interrupt Source Overrides */
- /* Flags:
- bits[3:2]:
- 00 conforms to the bus
- 01 edge-triggered
- 10 reserved
- 11 level-triggered
- bits[1:0]
- 00 conforms to the bus
- 01 active-high
- 10 reserved
- 11 active-low */
- /* If changing, also update PDMIsaSetIrq() and MPS */
- ACPITBLISO* isos = madt.ISO_addr();
- /* Timer interrupt rule IRQ0 to GSI2 */
- isos[0].u8Type = 2;
- isos[0].u8Length = sizeof(ACPITBLISO);
- isos[0].u8Bus = 0; /* Must be 0 */
- isos[0].u8Source = 0; /* IRQ0 */
- isos[0].u32GSI = 2; /* connected to pin 2 */
- isos[0].u16Flags = 0; /* conform to the bus */
-
- /* ACPI interrupt rule - IRQ9 to GSI9 */
- isos[1].u8Type = 2;
- isos[1].u8Length = sizeof(ACPITBLISO);
- isos[1].u8Bus = 0; /* Must be 0 */
- isos[1].u8Source = 9; /* IRQ9 */
- isos[1].u32GSI = 9; /* connected to pin 9 */
- isos[1].u16Flags = 0xd; /* active high, level triggered */
- Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
-
- madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
- acpiPhyscpy(s, addr, madt.data(), madt.size());
-}
-
-
-/** High Performance Event Timer (HPET) descriptor */
-static void acpiSetupHPET(ACPIState *s, RTGCPHYS32 addr)
-{
- ACPITBLHPET hpet;
-
- memset(&hpet, 0, sizeof(hpet));
-
- acpiPrepareHeader(&hpet.aHeader, "HPET", sizeof(hpet), 1);
- /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
- acpiWriteGenericAddr(&hpet.HpetAddr,
- 0 /* Memory address space */,
- 64 /* Register bit width */,
- 0 /* Bit offset */,
- 0, /* Register access size, is it correct? */
- 0xfed00000 /* Address */);
-
- hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
- hpet.u32Number = 0;
- hpet.u32MinTick = 4096;
- hpet.u8Attributes = 0;
-
- hpet.aHeader.u8Checksum = acpiChecksum((uint8_t *)&hpet, sizeof(hpet));
-
- acpiPhyscpy(s, addr, (const uint8_t *)&hpet, sizeof(hpet));
-}
-
-/** MMCONFIG PCI config space access (MCFG) descriptor */
-static void acpiSetupMCFG(ACPIState *s, RTGCPHYS32 addr)
-{
- struct {
- ACPITBLMCFG hdr;
- ACPITBLMCFGENTRY entry;
- } tbl;
-
- uint8_t u8StartBus = 0;
- uint8_t u8EndBus = (s->u64PciConfigMMioLength >> 20) - 1;
-
- memset(&tbl, 0, sizeof(tbl));
-
- acpiPrepareHeader(&tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
- tbl.entry.u64BaseAddress = s->u64PciConfigMMioAddress;
- tbl.entry.u8StartBus = u8StartBus;
- tbl.entry.u8EndBus = u8EndBus;
- // u16PciSegmentGroup must match _SEG in ACPI table
-
- tbl.hdr.aHeader.u8Checksum = acpiChecksum((uint8_t *)&tbl, sizeof(tbl));
-
- acpiPhyscpy(s, addr, (const uint8_t *)&tbl, sizeof(tbl));
-}
+#ifdef IN_RING3
/* SCI IRQ */
-DECLINLINE(void) acpiSetIrq(ACPIState *s, int level)
+DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
{
- if (s->pm1a_ctl & SCI_EN)
- PDMDevHlpPCISetIrq(s->pDevIns, -1, level);
+ if (pThis->pm1a_ctl & SCI_EN)
+ PDMDevHlpPCISetIrq(pThis->pDevIns, -1, level);
}
DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
@@ -1078,67 +733,99 @@ DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
return sts & ~(RSR_STS | IGN_STS);
}
-DECLINLINE(int) pm1a_level(ACPIState *s)
+DECLINLINE(int) pm1a_level(ACPIState *pThis)
{
- return (pm1a_pure_en(s->pm1a_en) & pm1a_pure_sts(s->pm1a_sts)) != 0;
+ return (pm1a_pure_en(pThis->pm1a_en) & pm1a_pure_sts(pThis->pm1a_sts)) != 0;
}
-DECLINLINE(int) gpe0_level(ACPIState *s)
+DECLINLINE(int) gpe0_level(ACPIState *pThis)
{
- return (s->gpe0_en & s->gpe0_sts) != 0;
+ return (pThis->gpe0_en & pThis->gpe0_sts) != 0;
}
-static void update_pm1a(ACPIState *s, uint32_t sts, uint32_t en)
+/**
+ * Used by acpiPM1aStsWrite, acpiPM1aEnWrite, acpiPmTimer,
+ * acpiPort_PowerBuffonPress and acpiPort_SleepButtonPress to
+ * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
+ *
+ * Caller must hold the state lock.
+ *
+ * @param pThis The ACPI instance.
+ * @param sts The new GPE0.STS value.
+ * @param en The new GPE0.EN value.
+ */
+static void update_pm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
{
- int old_level, new_level;
+ Assert(PDMCritSectIsOwner(&pThis->CritSect));
- if (gpe0_level(s))
+ if (gpe0_level(pThis))
return;
- old_level = pm1a_level(s);
- new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
+ int const old_level = pm1a_level(pThis);
+ int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
Log(("update_pm1a() old=%x new=%x\n", old_level, new_level));
- s->pm1a_en = en;
- s->pm1a_sts = sts;
+ pThis->pm1a_en = en;
+ pThis->pm1a_sts = sts;
if (new_level != old_level)
- acpiSetIrq(s, new_level);
+ acpiSetIrq(pThis, new_level);
}
-static void update_gpe0(ACPIState *s, uint32_t sts, uint32_t en)
+/**
+ * Used by acpiGpe0StsWrite, acpiGpe0EnWrite, acpiAttach and acpiDetach to
+ * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
+ *
+ * Caller must hold the state lock.
+ *
+ * @param pThis The ACPI instance.
+ * @param sts The new GPE0.STS value.
+ * @param en The new GPE0.EN value.
+ */
+static void update_gpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
{
- int old_level, new_level;
+ Assert(PDMCritSectIsOwner(&pThis->CritSect));
- if (pm1a_level(s))
+ if (pm1a_level(pThis))
return;
- old_level = (s->gpe0_en & s->gpe0_sts) != 0;
- new_level = (en & sts) != 0;
+ int const old_level = (pThis->gpe0_en & pThis->gpe0_sts) != 0;
+ int const new_level = (en & sts) != 0;
- s->gpe0_en = en;
- s->gpe0_sts = sts;
+ pThis->gpe0_en = en;
+ pThis->gpe0_sts = sts;
if (new_level != old_level)
- acpiSetIrq(s, new_level);
+ acpiSetIrq(pThis, new_level);
}
-static int acpiPowerDown(ACPIState *s)
+/**
+ * Used by acpiPM1aCtlWrite to power off the VM.
+ *
+ * @param pThis The ACPI instance.
+ * @returns Strict VBox status code.
+ */
+static int acpiPowerOff(ACPIState *pThis)
{
- int rc = PDMDevHlpVMPowerOff(s->pDevIns);
+ int rc = PDMDevHlpVMPowerOff(pThis->pDevIns);
if (RT_FAILURE(rc))
AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
return rc;
}
+/**
+ * Used by acpiPM1aCtlWrite to put the VM to sleep.
+ *
+ * @param pThis The ACPI instance.
+ * @returns Strict VBox status code.
+ */
static int acpiSleep(ACPIState *pThis)
{
- int rc;
-
/* We must set WAK_STS on resume (includes restore) so the guest knows that
we've woken up and can continue executing code. The guest is probably
reading the PMSTS register in a loop to check this. */
+ int rc;
pThis->fSetWakeupOnResume = true;
if (pThis->fSuspendToSavedState)
{
@@ -1160,56 +847,63 @@ static int acpiSleep(ACPIState *pThis)
return rc;
}
-/** Converts a ACPI port interface pointer to an ACPI state pointer. */
-#define IACPIPORT_2_ACPISTATE(pInterface) ( (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IACPIPort)) )
/**
- * Send an ACPI power off event.
- *
- * @returns VBox status code
- * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @interface_method_impl{PDMIACPIPORT,pfnPowerButtonPress}
*/
-static DECLCALLBACK(int) acpiPowerButtonPress(PPDMIACPIPORT pInterface)
+static DECLCALLBACK(int) acpiPort_PowerButtonPress(PPDMIACPIPORT pInterface)
{
- ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
- Log(("acpiPowerButtonPress: handled=%d status=%x\n", s->fPowerButtonHandled, s->pm1a_sts));
- s->fPowerButtonHandled = false;
- update_pm1a(s, s->pm1a_sts | PWRBTN_STS, s->pm1a_en);
+ ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
+ DEVACPI_LOCK_R3(pThis);
+
+ Log(("acpiPort_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
+ pThis->fPowerButtonHandled = false;
+ update_pm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
/**
- * Check if the ACPI power button event was handled.
- *
- * @returns VBox status code
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pfHandled Return true if the power button event was handled by the guest.
+ * @interface_method_impl{PDMIACPIPORT,pfnGetPowerButtonHandled}
*/
-static DECLCALLBACK(int) acpiGetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
+static DECLCALLBACK(int) acpiPort_GetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
{
- ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
- *pfHandled = s->fPowerButtonHandled;
+ ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
+ DEVACPI_LOCK_R3(pThis);
+
+ *pfHandled = pThis->fPowerButtonHandled;
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
/**
- * Check if the Guest entered into G0 (working) or G1 (sleeping).
- *
- * @returns VBox status code
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pfEntered Return true if the guest entered the ACPI mode.
+ * @interface_method_impl{PDMIACPIPORT,pfnGetGuestEnteredACPIMode, Check if the
+ * Guest entered into G0 (working) or G1 (sleeping)}
*/
-static DECLCALLBACK(int) acpiGetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
+static DECLCALLBACK(int) acpiPort_GetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
{
- ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
- *pfEntered = (s->pm1a_ctl & SCI_EN) != 0;
+ ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
+ DEVACPI_LOCK_R3(pThis);
+
+ *pfEntered = (pThis->pm1a_ctl & SCI_EN) != 0;
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) acpiGetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
+/**
+ * @interface_method_impl{PDMIACPIPORT,pfnGetCpuStatus}
+ */
+static DECLCALLBACK(int) acpiPort_GetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
{
- ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
- *pfLocked = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, uCpu);
+ ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
+ DEVACPI_LOCK_R3(pThis);
+
+ *pfLocked = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, uCpu);
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
@@ -1219,196 +913,72 @@ static DECLCALLBACK(int) acpiGetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCp
* @returns VBox status code
* @param pInterface Pointer to the interface structure containing the called function pointer.
*/
-static DECLCALLBACK(int) acpiSleepButtonPress(PPDMIACPIPORT pInterface)
-{
- ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
- update_pm1a(s, s->pm1a_sts | SLPBTN_STS, s->pm1a_en);
- return VINF_SUCCESS;
-}
-
-/* PM1a_EVT_BLK enable */
-static uint32_t acpiPm1aEnReadw(ACPIState *s, uint32_t addr)
-{
- uint16_t val = s->pm1a_en;
- Log(("acpi: acpiPm1aEnReadw -> %#x\n", val));
- return val;
-}
-
-static void acpiPM1aEnWritew(ACPIState *s, uint32_t addr, uint32_t val)
-{
- Log(("acpi: acpiPM1aEnWritew <- %#x (%#x)\n", val, val & ~(RSR_EN | IGN_EN)));
- val &= ~(RSR_EN | IGN_EN);
- update_pm1a(s, s->pm1a_sts, val);
-}
-
-/* PM1a_EVT_BLK status */
-static uint32_t acpiPm1aStsReadw(ACPIState *s, uint32_t addr)
+static DECLCALLBACK(int) acpiPort_SleepButtonPress(PPDMIACPIPORT pInterface)
{
- uint16_t val = s->pm1a_sts;
- Log(("acpi: acpiPm1aStsReadw -> %#x\n", val));
- return val;
-}
-
-static void acpiPM1aStsWritew(ACPIState *s, uint32_t addr, uint32_t val)
-{
- Log(("acpi: acpiPM1aStsWritew <- %#x (%#x)\n", val, val & ~(RSR_STS | IGN_STS)));
- if (val & PWRBTN_STS)
- s->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
- val = s->pm1a_sts & ~(val & ~(RSR_STS | IGN_STS));
- update_pm1a(s, val, s->pm1a_en);
-}
-
-/* PM1a_CTL_BLK */
-static uint32_t acpiPm1aCtlReadw(ACPIState *s, uint32_t addr)
-{
- uint16_t val = s->pm1a_ctl;
- Log(("acpi: acpiPm1aCtlReadw -> %#x\n", val));
- return val;
-}
+ ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
+ DEVACPI_LOCK_R3(pThis);
-static int acpiPM1aCtlWritew(ACPIState *s, uint32_t addr, uint32_t val)
-{
- uint32_t uSleepState;
+ update_pm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
- Log(("acpi: acpiPM1aCtlWritew <- %#x (%#x)\n", val, val & ~(RSR_CNT | IGN_CNT)));
- s->pm1a_ctl = val & ~(RSR_CNT | IGN_CNT);
-
- uSleepState = (s->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
- if (uSleepState != s->uSleepState)
- {
- s->uSleepState = uSleepState;
- switch (uSleepState)
- {
- case 0x00: /* S0 */
- break;
- case 0x01: /* S1 */
- if (s->fS1Enabled)
- {
- LogRel(("Entering S1 power state (powered-on suspend)\n"));
- return acpiSleep(s);
- }
- else
- LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
- case 0x04: /* S4 */
- if (s->fS4Enabled)
- {
- LogRel(("Entering S4 power state (suspend to disk)\n"));
- return acpiPowerDown(s);/* Same behavior as S5 */
- }
- else
- LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
- case 0x05: /* S5 */
- LogRel(("Entering S5 power state (power down)\n"));
- return acpiPowerDown(s);
- default:
- AssertMsgFailed(("Unknown sleep state %#x\n", uSleepState));
- break;
- }
- }
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
-/* GPE0_BLK */
-static uint32_t acpiGpe0EnReadb(ACPIState *s, uint32_t addr)
-{
- uint8_t val = s->gpe0_en;
- Log(("acpi: acpiGpe0EnReadl -> %#x\n", val));
- return val;
-}
-
-static void acpiGpe0EnWriteb(ACPIState *s, uint32_t addr, uint32_t val)
-{
- Log(("acpi: acpiGpe0EnWritel <- %#x\n", val));
- update_gpe0(s, s->gpe0_sts, val);
-}
-
-static uint32_t acpiGpe0StsReadb(ACPIState *s, uint32_t addr)
-{
- uint8_t val = s->gpe0_sts;
- Log(("acpi: acpiGpe0StsReadl -> %#x\n", val));
- return val;
-}
-
-static void acpiGpe0StsWriteb(ACPIState *s, uint32_t addr, uint32_t val)
-{
- val = s->gpe0_sts & ~val;
- update_gpe0(s, val, s->gpe0_en);
- Log(("acpi: acpiGpe0StsWritel <- %#x\n", val));
-}
-
-static int acpiResetWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
-{
- int rc = VINF_SUCCESS;
-
- Log(("ACPI: acpiResetWriteU8: %x %x\n", addr, val));
- if (val == ACPI_RESET_REG_VAL)
- {
-# ifndef IN_RING3
- rc = VINF_IOM_HC_IOPORT_WRITE;
-# else /* IN_RING3 */
- rc = PDMDevHlpVMReset(s->pDevIns);
-# endif /* !IN_RING3 */
- }
- return rc;
-}
-
-/* SMI */
-static void acpiSmiWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
-{
- Log(("acpi: acpiSmiWriteU8 %#x\n", val));
- if (val == ACPI_ENABLE)
- s->pm1a_ctl |= SCI_EN;
- else if (val == ACPI_DISABLE)
- s->pm1a_ctl &= ~SCI_EN;
- else
- Log(("acpi: acpiSmiWriteU8 %#x <- unknown value\n", val));
-}
-
-static uint32_t find_rsdp_space(void)
-{
- return 0xe0000;
-}
-
-static int acpiPMTimerReset(ACPIState *s)
+/**
+ * Used by acpiPmTimer to re-arm the PM timer.
+ *
+ * The caller is expected to either hold the clock lock or to have made sure
+ * the VM is resetting or loading state.
+ *
+ * @param pThis The ACPI instance.
+ * @param uNow The current time.
+ */
+static void acpiPmTimerReset(ACPIState *pThis, uint64_t uNow)
{
- uint64_t interval, freq;
-
- freq = TMTimerGetFreq(s->CTX_SUFF(ts));
- interval = ASMMultU64ByU32DivByU32(0xffffffff, freq, PM_TMR_FREQ);
- Log(("interval = %RU64\n", interval));
- TMTimerSet(s->CTX_SUFF(ts), TMTimerGet(s->CTX_SUFF(ts)) + interval);
-
- return VINF_SUCCESS;
+ uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
+ uint64_t uInterval = ASMMultU64ByU32DivByU32(0xffffffff, uTimerFreq, PM_TMR_FREQ);
+ TMTimerSet(pThis->pPmTimerR3, uNow + uInterval);
+ Log(("acpi: uInterval = %RU64\n", uInterval));
}
-static DECLCALLBACK(void) acpiTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
+/**
+ * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
+ */
+static DECLCALLBACK(void) acpiPmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
{
- ACPIState *s = (ACPIState *)pvUser;
+ ACPIState *pThis = (ACPIState *)pvUser;
+ Assert(TMTimerIsLockOwner(pThis->pPmTimerR3));
+ DEVACPI_LOCK_R3(pThis);
Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
- s->pm1a_sts, (s->pm1a_sts & TMR_STS) != 0,
- s->pm1a_en, (s->pm1a_en & TMR_EN) != 0));
+ pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
+ pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
+ update_pm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
+ DEVACPI_UNLOCK(pThis);
- update_pm1a(s, s->pm1a_sts | TMR_STS, s->pm1a_en);
- acpiPMTimerReset(s);
+ acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
}
/**
- * _BST method.
+ * _BST method - used by acpiBatDataRead to implement BAT_STATUS_STATE and
+ * acpiLoadState.
+ *
+ * @returns VINF_SUCCESS.
+ * @param pThis The ACPI instance.
*/
-static int acpiFetchBatteryStatus(ACPIState *s)
+static int acpiFetchBatteryStatus(ACPIState *pThis)
{
- uint32_t *p = s->au8BatteryInfo;
+ uint32_t *p = pThis->au8BatteryInfo;
bool fPresent; /* battery present? */
PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
PDMACPIBATSTATE hostBatteryState; /* bitfield */
uint32_t hostPresentRate; /* 0..1000 */
int rc;
- if (!s->pDrv)
+ if (!pThis->pDrv)
return VINF_SUCCESS;
- rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
- &hostBatteryState, &hostPresentRate);
+ rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
+ &hostBatteryState, &hostPresentRate);
AssertRC(rc);
/* default values */
@@ -1428,11 +998,15 @@ static int acpiFetchBatteryStatus(ACPIState *s)
}
/**
- * _BIF method.
+ * _BIF method - used by acpiBatDataRead to implement BAT_INFO_UNITS and
+ * acpiLoadState.
+ *
+ * @returns VINF_SUCCESS.
+ * @param pThis The ACPI instance.
*/
-static int acpiFetchBatteryInfo(ACPIState *s)
+static int acpiFetchBatteryInfo(ACPIState *pThis)
{
- uint32_t *p = s->au8BatteryInfo;
+ uint32_t *p = pThis->au8BatteryInfo;
p[BAT_INFO_UNITS] = 0; /* mWh */
p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
@@ -1448,9 +1022,12 @@ static int acpiFetchBatteryInfo(ACPIState *s)
}
/**
- * _STA method.
+ * The _STA method - used by acpiBatDataRead to implement BAT_DEVICE_STATUS.
+ *
+ * @returns status mask or 0.
+ * @param pThis The ACPI instance.
*/
-static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
+static uint32_t acpiGetBatteryDeviceStatus(ACPIState *pThis)
{
bool fPresent; /* battery present? */
PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
@@ -1458,10 +1035,10 @@ static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
uint32_t hostPresentRate; /* 0..1000 */
int rc;
- if (!s->pDrv)
+ if (!pThis->pDrv)
return 0;
- rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
- &hostBatteryState, &hostPresentRate);
+ rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
+ &hostBatteryState, &hostPresentRate);
AssertRC(rc);
return fPresent
@@ -1473,524 +1050,687 @@ static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
: 0; /* device not present */
}
-static uint32_t acpiGetPowerSource(ACPIState *s)
+/**
+ * Used by acpiBatDataRead to implement BAT_POWER_SOURCE.
+ *
+ * @returns status.
+ * @param pThis The ACPI instance.
+ */
+static uint32_t acpiGetPowerSource(ACPIState *pThis)
{
- PDMACPIPOWERSOURCE ps;
-
/* query the current power source from the host driver */
- if (!s->pDrv)
+ if (!pThis->pDrv)
return AC_ONLINE;
- int rc = s->pDrv->pfnQueryPowerSource(s->pDrv, &ps);
+
+ PDMACPIPOWERSOURCE ps;
+ int rc = pThis->pDrv->pfnQueryPowerSource(pThis->pDrv, &ps);
AssertRC(rc);
return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, Battery status index}
+ */
PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- ACPIState *s = (ACPIState *)pvUser;
+ Log(("acpiBatIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
+ if (cb != 4)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
- switch (cb)
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ u32 >>= pThis->u8IndexShift;
+ /* see comment at the declaration of u8IndexShift */
+ if (pThis->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
{
- case 4:
- u32 >>= s->u8IndexShift;
- /* see comment at the declaration of u8IndexShift */
- if (s->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
- {
- s->u8IndexShift = 2;
- u32 >>= 2;
- }
- Assert(u32 < BAT_INDEX_LAST);
- s->uBatteryIndex = u32;
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ pThis->u8IndexShift = 2;
+ u32 >>= 2;
}
+ Assert(u32 < BAT_INDEX_LAST);
+ pThis->uBatteryIndex = u32;
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, Battery status data}
+ */
PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- ACPIState *s = (ACPIState *)pvUser;
+ if (cb != 4)
+ return VERR_IOM_IOPORT_UNUSED;
- switch (cb)
- {
- case 4:
- switch (s->uBatteryIndex)
- {
- case BAT_STATUS_STATE:
- acpiFetchBatteryStatus(s);
- case BAT_STATUS_PRESENT_RATE:
- case BAT_STATUS_REMAINING_CAPACITY:
- case BAT_STATUS_PRESENT_VOLTAGE:
- *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
- break;
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
- case BAT_INFO_UNITS:
- acpiFetchBatteryInfo(s);
- case BAT_INFO_DESIGN_CAPACITY:
- case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
- case BAT_INFO_TECHNOLOGY:
- case BAT_INFO_DESIGN_VOLTAGE:
- case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
- case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
- case BAT_INFO_CAPACITY_GRANULARITY_1:
- case BAT_INFO_CAPACITY_GRANULARITY_2:
- *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
- break;
+ int rc = VINF_SUCCESS;
+ switch (pThis->uBatteryIndex)
+ {
+ case BAT_STATUS_STATE:
+ acpiFetchBatteryStatus(pThis);
+ /* fall thru */
+ case BAT_STATUS_PRESENT_RATE:
+ case BAT_STATUS_REMAINING_CAPACITY:
+ case BAT_STATUS_PRESENT_VOLTAGE:
+ *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
+ break;
- case BAT_DEVICE_STATUS:
- *pu32 = acpiGetBatteryDeviceStatus(s);
- break;
+ case BAT_INFO_UNITS:
+ acpiFetchBatteryInfo(pThis);
+ /* fall thru */
+ case BAT_INFO_DESIGN_CAPACITY:
+ case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
+ case BAT_INFO_TECHNOLOGY:
+ case BAT_INFO_DESIGN_VOLTAGE:
+ case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
+ case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
+ case BAT_INFO_CAPACITY_GRANULARITY_1:
+ case BAT_INFO_CAPACITY_GRANULARITY_2:
+ *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
+ break;
- case BAT_POWER_SOURCE:
- *pu32 = acpiGetPowerSource(s);
- break;
+ case BAT_DEVICE_STATUS:
+ *pu32 = acpiGetBatteryDeviceStatus(pThis);
+ break;
- default:
- AssertMsgFailed(("Invalid battery index %d\n", s->uBatteryIndex));
- break;
- }
+ case BAT_POWER_SOURCE:
+ *pu32 = acpiGetPowerSource(pThis);
break;
+
default:
- return VERR_IOM_IOPORT_UNUSED;
+ rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
+ *pu32 = UINT32_MAX;
+ break;
}
- return VINF_SUCCESS;
+
+ DEVACPI_UNLOCK(pThis);
+ return rc;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, System info index}
+ */
PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- ACPIState *s = (ACPIState *)pvUser;
+ Log(("acpiSysInfoIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
+ if (cb != 4)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
- Log(("system_index = %d, %d\n", u32, u32 >> 2));
- switch (cb)
- {
- case 4:
- if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
- s->uSystemInfoIndex = u32;
- else
- {
- /* see comment at the declaration of u8IndexShift */
- if ((u32 > SYSTEM_INFO_INDEX_END) && (s->u8IndexShift == 0))
- {
- if (((u32 >> 2) < SYSTEM_INFO_INDEX_END) && ((u32 & 0x3)) == 0)
- {
- s->u8IndexShift = 2;
- }
- }
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
- u32 >>= s->u8IndexShift;
- Assert(u32 < SYSTEM_INFO_INDEX_END);
- s->uSystemInfoIndex = u32;
- }
- break;
+ if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
+ pThis->uSystemInfoIndex = u32;
+ else
+ {
+ /* see comment at the declaration of u8IndexShift */
+ if (u32 > SYSTEM_INFO_INDEX_END && pThis->u8IndexShift == 0)
+ {
+ if ((u32 >> 2) < SYSTEM_INFO_INDEX_END && (u32 & 0x3) == 0)
+ pThis->u8IndexShift = 2;
+ }
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ u32 >>= pThis->u8IndexShift;
+ Assert(u32 < SYSTEM_INFO_INDEX_END);
+ pThis->uSystemInfoIndex = u32;
}
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, System info data}
+ */
PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- ACPIState *s = (ACPIState *)pvUser;
+ if (cb != 4)
+ return VERR_IOM_IOPORT_UNUSED;
- switch (cb)
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ int rc = VINF_SUCCESS;
+ unsigned const uSystemInfoIndex = pThis->uSystemInfoIndex;
+ switch (uSystemInfoIndex)
{
- case 4:
- switch (s->uSystemInfoIndex)
- {
- case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
- *pu32 = s->cbRamLow;
- break;
+ case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
+ *pu32 = pThis->cbRamLow;
+ break;
- case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
- *pu32 = s->cbRamHigh >> 16; /* 64KB units */
- Assert(((uint64_t)*pu32 << 16) == s->cbRamHigh);
- break;
+ case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
+ *pu32 = pThis->cbRamHigh >> 16; /* 64KB units */
+ Assert(((uint64_t)*pu32 << 16) == pThis->cbRamHigh);
+ break;
- case SYSTEM_INFO_INDEX_USE_IOAPIC:
- *pu32 = s->u8UseIOApic;
- break;
+ case SYSTEM_INFO_INDEX_USE_IOAPIC:
+ *pu32 = pThis->u8UseIOApic;
+ break;
- case SYSTEM_INFO_INDEX_HPET_STATUS:
- *pu32 = s->fUseHpet ? ( STA_DEVICE_PRESENT_MASK
- | STA_DEVICE_ENABLED_MASK
- | STA_DEVICE_SHOW_IN_UI_MASK
- | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
- : 0;
- break;
+ case SYSTEM_INFO_INDEX_HPET_STATUS:
+ *pu32 = pThis->fUseHpet
+ ? ( STA_DEVICE_PRESENT_MASK
+ | STA_DEVICE_ENABLED_MASK
+ | STA_DEVICE_SHOW_IN_UI_MASK
+ | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
+ : 0;
+ break;
- case SYSTEM_INFO_INDEX_SMC_STATUS:
- *pu32 = s->fUseSmc ? ( STA_DEVICE_PRESENT_MASK
- | STA_DEVICE_ENABLED_MASK
- /* no need to show this device in the UI */
- | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
- : 0;
- break;
+ case SYSTEM_INFO_INDEX_SMC_STATUS:
+ *pu32 = pThis->fUseSmc
+ ? ( STA_DEVICE_PRESENT_MASK
+ | STA_DEVICE_ENABLED_MASK
+ /* no need to show this device in the UI */
+ | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
+ : 0;
+ break;
- case SYSTEM_INFO_INDEX_FDC_STATUS:
- *pu32 = s->fUseFdc ? ( STA_DEVICE_PRESENT_MASK
- | STA_DEVICE_ENABLED_MASK
- | STA_DEVICE_SHOW_IN_UI_MASK
- | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
- : 0;
- break;
+ case SYSTEM_INFO_INDEX_FDC_STATUS:
+ *pu32 = pThis->fUseFdc
+ ? ( STA_DEVICE_PRESENT_MASK
+ | STA_DEVICE_ENABLED_MASK
+ | STA_DEVICE_SHOW_IN_UI_MASK
+ | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
+ : 0;
+ break;
- case SYSTEM_INFO_INDEX_NIC_ADDRESS:
- *pu32 = s->u32NicPciAddress;
- break;
+ case SYSTEM_INFO_INDEX_NIC_ADDRESS:
+ *pu32 = pThis->u32NicPciAddress;
+ break;
- case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
- *pu32 = s->u32AudioPciAddress;
- break;
+ case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
+ *pu32 = pThis->u32AudioPciAddress;
+ break;
- case SYSTEM_INFO_INDEX_POWER_STATES:
- *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
- if (s->fS1Enabled) /* Optionally expose S1 and S4 */
- *pu32 |= RT_BIT(1);
- if (s->fS4Enabled)
- *pu32 |= RT_BIT(4);
- break;
+ case SYSTEM_INFO_INDEX_POWER_STATES:
+ *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
+ if (pThis->fS1Enabled) /* Optionally expose S1 and S4 */
+ *pu32 |= RT_BIT(1);
+ if (pThis->fS4Enabled)
+ *pu32 |= RT_BIT(4);
+ break;
- case SYSTEM_INFO_INDEX_IOC_ADDRESS:
- *pu32 = s->u32IocPciAddress;
- break;
+ case SYSTEM_INFO_INDEX_IOC_ADDRESS:
+ *pu32 = pThis->u32IocPciAddress;
+ break;
- case SYSTEM_INFO_INDEX_HBC_ADDRESS:
- *pu32 = s->u32HbcPciAddress;
- break;
+ case SYSTEM_INFO_INDEX_HBC_ADDRESS:
+ *pu32 = pThis->u32HbcPciAddress;
+ break;
- case SYSTEM_INFO_INDEX_PCI_BASE:
- /** @todo: couldn't MCFG be in 64-bit range? */
- Assert(s->u64PciConfigMMioAddress < 0xffffffff);
- *pu32 = (uint32_t)s->u64PciConfigMMioAddress;
- break;
+ case SYSTEM_INFO_INDEX_PCI_BASE:
+ /** @todo couldn't MCFG be in 64-bit range? */
+ Assert(pThis->u64PciConfigMMioAddress < 0xffffffff);
+ *pu32 = (uint32_t)pThis->u64PciConfigMMioAddress;
+ break;
- case SYSTEM_INFO_INDEX_PCI_LENGTH:
- /** @todo: couldn't MCFG be in 64-bit range? */
- Assert(s->u64PciConfigMMioLength< 0xffffffff);
- *pu32 = (uint32_t)s->u64PciConfigMMioLength;
- break;
+ case SYSTEM_INFO_INDEX_PCI_LENGTH:
+ /** @todo couldn't MCFG be in 64-bit range? */
+ Assert(pThis->u64PciConfigMMioLength< 0xffffffff);
+ *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
+ break;
- /* This is only for compatibility with older saved states that
- may include ACPI code that read these values. Legacy is
- a wonderful thing, isn't it? :-) */
- case SYSTEM_INFO_INDEX_CPU0_STATUS:
- case SYSTEM_INFO_INDEX_CPU1_STATUS:
- case SYSTEM_INFO_INDEX_CPU2_STATUS:
- case SYSTEM_INFO_INDEX_CPU3_STATUS:
- *pu32 = ( s->fShowCpu
- && s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < s->cCpus
- && VMCPUSET_IS_PRESENT(&s->CpuSetAttached,
- s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS))
- ? ( STA_DEVICE_PRESENT_MASK
- | STA_DEVICE_ENABLED_MASK
- | STA_DEVICE_SHOW_IN_UI_MASK
- | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
- : 0;
- break;
+ /* This is only for compatibility with older saved states that
+ may include ACPI code that read these values. Legacy is
+ a wonderful thing, isn't it? :-) */
+ case SYSTEM_INFO_INDEX_CPU0_STATUS:
+ case SYSTEM_INFO_INDEX_CPU1_STATUS:
+ case SYSTEM_INFO_INDEX_CPU2_STATUS:
+ case SYSTEM_INFO_INDEX_CPU3_STATUS:
+ *pu32 = ( pThis->fShowCpu
+ && pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < pThis->cCpus
+ && VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached,
+ pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS) )
+ ? ( STA_DEVICE_PRESENT_MASK
+ | STA_DEVICE_ENABLED_MASK
+ | STA_DEVICE_SHOW_IN_UI_MASK
+ | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
+ : 0;
+ break;
- case SYSTEM_INFO_INDEX_RTC_STATUS:
- *pu32 = s->fShowRtc ? ( STA_DEVICE_PRESENT_MASK
- | STA_DEVICE_ENABLED_MASK
- | STA_DEVICE_SHOW_IN_UI_MASK
- | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
- : 0;
- break;
+ case SYSTEM_INFO_INDEX_RTC_STATUS:
+ *pu32 = pThis->fShowRtc
+ ? ( STA_DEVICE_PRESENT_MASK
+ | STA_DEVICE_ENABLED_MASK
+ | STA_DEVICE_SHOW_IN_UI_MASK
+ | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
+ : 0;
+ break;
- case SYSTEM_INFO_INDEX_CPU_LOCKED:
- {
- if (s->idCpuLockCheck < VMM_MAX_CPU_COUNT)
- {
- *pu32 = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, s->idCpuLockCheck);
- s->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
- }
- else
- {
- AssertMsgFailed(("ACPI: CPU lock check protocol violation\n"));
- /* Always return locked status just to be safe */
- *pu32 = 1;
- }
- break;
- }
+ case SYSTEM_INFO_INDEX_CPU_LOCKED:
+ if (pThis->idCpuLockCheck < VMM_MAX_CPU_COUNT)
+ {
+ *pu32 = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, pThis->idCpuLockCheck);
+ pThis->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
+ }
+ else
+ {
+ rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "CPU lock check protocol violation (idCpuLockCheck=%#x)\n",
+ pThis->idCpuLockCheck);
+ /* Always return locked status just to be safe */
+ *pu32 = 1;
+ }
+ break;
- case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
- *pu32 = s->u32CpuEventType;
- break;
+ case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
+ *pu32 = pThis->u32CpuEventType;
+ break;
- case SYSTEM_INFO_INDEX_CPU_EVENT:
- *pu32 = s->u32CpuEvent;
- break;
+ case SYSTEM_INFO_INDEX_CPU_EVENT:
+ *pu32 = pThis->u32CpuEvent;
+ break;
- /* Solaris 9 tries to read from this index */
- case SYSTEM_INFO_INDEX_INVALID:
- *pu32 = 0;
- break;
+ case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
+ *pu32 = pThis->uSerial0IoPortBase;
+ break;
- default:
- AssertMsgFailed(("Invalid system info index %d\n", s->uSystemInfoIndex));
- break;
- }
+ case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
+ *pu32 = pThis->uSerial0Irq;
+ break;
+
+ case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
+ *pu32 = pThis->uSerial1IoPortBase;
+ break;
+
+ case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
+ *pu32 = pThis->uSerial1Irq;
+ break;
+
+ case SYSTEM_INFO_INDEX_END:
+ /** @todo why isn't this setting any output value? */
+ break;
+
+ /* Solaris 9 tries to read from this index */
+ case SYSTEM_INFO_INDEX_INVALID:
+ *pu32 = 0;
break;
default:
- return VERR_IOM_IOPORT_UNUSED;
+ *pu32 = UINT32_MAX;
+ rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
+ break;
}
- Log(("index %d val %d\n", s->uSystemInfoIndex, *pu32));
- return VINF_SUCCESS;
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiSysInfoDataRead: idx=%d val=%#x (%d) rc=%Rrc\n", uSystemInfoIndex, *pu32, *pu32, rc));
+ return rc;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, System info data}
+ */
PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- ACPIState *s = (ACPIState *)pvUser;
+ ACPIState *pThis = (ACPIState *)pvUser;
+ if (cb != 4)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
- Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, s->uSystemInfoIndex));
+ DEVACPI_LOCK_R3(pThis);
+ Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, pThis->uSystemInfoIndex));
- if (cb == 4)
+ int rc = VINF_SUCCESS;
+ switch (pThis->uSystemInfoIndex)
{
- switch (s->uSystemInfoIndex)
- {
- case SYSTEM_INFO_INDEX_INVALID:
- AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
- s->u8IndexShift = 0;
- break;
+ case SYSTEM_INFO_INDEX_INVALID:
+ AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
+ pThis->u8IndexShift = 0;
+ break;
- case SYSTEM_INFO_INDEX_VALID:
- AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
- s->u8IndexShift = 2;
- break;
+ case SYSTEM_INFO_INDEX_VALID:
+ AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
+ pThis->u8IndexShift = 2;
+ break;
- case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
- s->idCpuLockCheck = u32;
- break;
+ case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
+ pThis->idCpuLockCheck = u32;
+ break;
- case SYSTEM_INFO_INDEX_CPU_LOCKED:
- if (u32 < s->cCpus)
- VMCPUSET_DEL(&s->CpuSetLocked, u32); /* Unlock the CPU */
- else
- LogRel(("ACPI: CPU %u does not exist\n", u32));
- break;
+ case SYSTEM_INFO_INDEX_CPU_LOCKED:
+ if (u32 < pThis->cCpus)
+ VMCPUSET_DEL(&pThis->CpuSetLocked, u32); /* Unlock the CPU */
+ else
+ LogRel(("ACPI: CPU %u does not exist\n", u32));
+ break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x system_index=%#x\n",
- Port, cb, u32, s->uSystemInfoIndex));
- break;
- }
+ default:
+ rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
+ break;
}
- else
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- return VINF_SUCCESS;
-}
-/** @todo Don't call functions, but do the job in the read/write handlers
- * here! */
+ DEVACPI_UNLOCK(pThis);
+ return rc;
+}
-/* IO Helpers */
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, PM1a Enable}
+ */
PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- switch (cb)
- {
- case 2:
- *pu32 = acpiPm1aEnReadw((ACPIState*)pvUser, Port);
- break;
- default:
- return VERR_IOM_IOPORT_UNUSED;
- }
+ if (cb != 2)
+ return VERR_IOM_IOPORT_UNUSED;
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ *pu32 = pThis->pm1a_en;
+
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiPm1aEnRead -> %#x\n", *pu32));
return VINF_SUCCESS;
}
-PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, PM1a Enable}
+ */
+PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
- {
- case 2:
- *pu32 = acpiPm1aStsReadw((ACPIState*)pvUser, Port);
- break;
- default:
- AssertMsgFailed(("PM1 status read: width %d\n", cb));
- return VERR_IOM_IOPORT_UNUSED;
- }
+ if (cb != 2 && cb != 4)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ Log(("acpiPM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
+ u32 &= ~(RSR_EN | IGN_EN);
+ u32 &= 0xffff;
+ update_pm1a(pThis, pThis->pm1a_sts, u32);
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
-PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, PM1a Status}
+ */
+PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- switch (cb)
+ if (cb != 2)
{
- case 2:
- *pu32 = acpiPm1aCtlReadw((ACPIState*)pvUser, Port);
- break;
- default:
- AssertMsgFailed(("PM1 control read: width %d\n", cb));
- return VERR_IOM_IOPORT_UNUSED;
+ int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
+ return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
}
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ *pu32 = pThis->pm1a_sts;
+
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiPm1aStsRead: %#x\n", *pu32));
return VINF_SUCCESS;
}
-PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, PM1a Status}
+ */
+PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
- {
- case 2:
- acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32);
- break;
- case 4:
- acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
- }
+ if (cb != 2 && cb != 4)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ Log(("acpiPM1aStsWrite: %#x (%#x)\n", u32, u32 & ~(RSR_STS | IGN_STS) & 0xffff));
+ u32 &= 0xffff;
+ if (u32 & PWRBTN_STS)
+ pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
+ u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
+ update_pm1a(pThis, u32, pThis->pm1a_en);
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
-PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, PM1a Control}
+ */
+PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- switch (cb)
+ if (cb != 2)
{
- case 2:
- acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32);
- break;
- case 4:
- acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
+ return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
}
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ *pu32 = pThis->pm1a_ctl;
+
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiPm1aCtlRead: %#x\n", *pu32));
return VINF_SUCCESS;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, PM1a Control}
+ */
PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
+ if (cb != 2 && cb != 4)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ Log(("acpiPM1aCtlWrite: %#x (%#x)\n", u32, u32 & ~(RSR_CNT | IGN_CNT) & 0xffff));
+ u32 &= 0xffff;
+ pThis->pm1a_ctl = u32 & ~(RSR_CNT | IGN_CNT);
+
+ int rc = VINF_SUCCESS;
+ uint32_t const uSleepState = (pThis->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
+ if (uSleepState != pThis->uSleepState)
{
- case 2:
- return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32);
- case 4:
- return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ pThis->uSleepState = uSleepState;
+ switch (uSleepState)
+ {
+ case 0x00: /* S0 */
+ break;
+
+ case 0x01: /* S1 */
+ if (pThis->fS1Enabled)
+ {
+ LogRel(("Entering S1 power state (powered-on suspend)\n"));
+ rc = acpiSleep(pThis);
+ break;
+ }
+ LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
+ /* fall thru */
+
+ case 0x04: /* S4 */
+ if (pThis->fS4Enabled)
+ {
+ LogRel(("Entering S4 power state (suspend to disk)\n"));
+ rc = acpiPowerOff(pThis);/* Same behavior as S5 */
+ break;
+ }
+ LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
+ /* fall thru */
+
+ case 0x05: /* S5 */
+ LogRel(("Entering S5 power state (power down)\n"));
+ rc = acpiPowerOff(pThis);
+ break;
+
+ default:
+ rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Unknown sleep state %#x (u32=%#x)\n", uSleepState, u32);
+ break;
+ }
}
- return VINF_SUCCESS;
+
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiPM1aCtlWrite: rc=%Rrc\n", rc));
+ return rc;
}
#endif /* IN_RING3 */
/**
- * PMTMR readable from host/guest.
+ * @callback_method_impl{FNIOMIOPORTIN, PMTMR}
+ *
+ * @remarks Only I/O port currently implemented in all contexts.
*/
PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- if (cb == 4)
+ if (cb != 4)
+ return VERR_IOM_IOPORT_UNUSED;
+
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
+
+ /*
+ * We use the clock lock to serialize access to u64PmTimerInitial and to
+ * make sure we get a reliable time from the clock.
+ */
+ int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_HC_IOPORT_READ);
+ if (rc == VINF_SUCCESS)
{
- ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
- uint64_t u64Now = TMTimerGet(s->CTX_SUFF(ts));
- uint64_t u64Seen;
- do
- {
- u64Seen = ASMAtomicReadU64(&s->u64PmTimerLastSeen);
- if (u64Now < u64Seen)
- u64Now = u64Seen + 1;
- } while (!ASMAtomicCmpXchgU64(&s->u64PmTimerLastSeen, u64Now, u64Seen));
+ uint64_t const u64PmTimerInitial = pThis->u64PmTimerInitial;
+ uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
+ TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
- uint64_t u64Elapsed = u64Now - s->u64PmTimerInitial;
- *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(s->CTX_SUFF(ts)));
+ /*
+ * Calculate the return value.
+ */
+ DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
+ uint64_t u64Elapsed = u64Now - u64PmTimerInitial;
+ *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer)));
Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
- return VINF_SUCCESS;
}
- return VERR_IOM_IOPORT_UNUSED;
+
+ return rc;
}
#ifdef IN_RING3
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, GPE0 Status}
+ */
PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- switch (cb)
+ if (cb != 1)
{
- case 1:
- *pu32 = acpiGpe0StsReadb((ACPIState*)pvUser, Port);
- break;
- default:
- return VERR_IOM_IOPORT_UNUSED;
+ int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
+ return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
}
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ *pu32 = pThis->gpe0_sts & 0xff;
+
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiGpe0StsRead: %#x\n", *pu32));
return VINF_SUCCESS;
}
-PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Status}
+ */
+PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
- {
- case 1:
- *pu32 = acpiGpe0EnReadb((ACPIState*)pvUser, Port);
- break;
- default:
- return VERR_IOM_IOPORT_UNUSED;
- }
+ if (cb != 1)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ Log(("acpiGpe0StsWrite: %#x (%#x)\n", u32, pThis->gpe0_sts & ~u32));
+ u32 = pThis->gpe0_sts & ~u32;
+ update_gpe0(pThis, u32, pThis->gpe0_en);
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
-PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
+/**
+ * @callback_method_impl{FNIOMIOPORTIN, GPE0 Enable}
+ */
+PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
- switch (cb)
+ if (cb != 1)
{
- case 1:
- acpiGpe0StsWriteb((ACPIState*)pvUser, Port, u32);
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
+ return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
}
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ *pu32 = pThis->gpe0_en & 0xff;
+
+ DEVACPI_UNLOCK(pThis);
+ Log(("acpiGpe0EnRead: %#x\n", *pu32));
return VINF_SUCCESS;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Enable}
+ */
PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
- {
- case 1:
- acpiGpe0EnWriteb((ACPIState*)pvUser, Port, u32);
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
- }
+ if (cb != 1)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ Log(("acpiGpe0EnWrite: %#x\n", u32));
+ update_gpe0(pThis, pThis->gpe0_sts, u32);
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, SMI_CMD}
+ */
PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
- {
- case 1:
- acpiSmiWriteU8((ACPIState*)pvUser, Port, u32);
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
- }
+ Log(("acpiSmiWrite %#x\n", u32));
+ if (cb != 1)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ ACPIState *pThis = (ACPIState *)pvUser;
+ DEVACPI_LOCK_R3(pThis);
+
+ if (u32 == ACPI_ENABLE)
+ pThis->pm1a_ctl |= SCI_EN;
+ else if (u32 == ACPI_DISABLE)
+ pThis->pm1a_ctl &= ~SCI_EN;
+ else
+ Log(("acpiSmiWrite: %#x <- unknown value\n", u32));
+
+ DEVACPI_UNLOCK(pThis);
return VINF_SUCCESS;
}
+/**
+ * @{FNIOMIOPORTOUT, ACPI_RESET_BLK}
+ */
PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
- switch (cb)
- {
- case 1:
- return acpiResetWriteU8((ACPIState*)pvUser, Port, u32);
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
- }
- return VINF_SUCCESS;
+ Log(("acpiResetWrite: %#x\n", u32));
+ if (cb != 1)
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
+
+ /* No state locking required. */
+ int rc = VINF_SUCCESS;
+ if (u32 == ACPI_RESET_REG_VAL)
+ rc = PDMDevHlpVMReset(pDevIns);
+ else
+ Log(("acpiResetWrite: %#x <- unknown value\n", u32));
+
+ return rc;
}
-#ifdef DEBUG_ACPI
+# ifdef DEBUG_ACPI
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
+ */
PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
switch (cb)
@@ -2004,12 +1744,14 @@ PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port
Log(("%#10x\n", u32));
break;
default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
}
return VINF_SUCCESS;
}
+/**
+ * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
+ */
PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
switch (cb)
@@ -2018,21 +1760,44 @@ PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port
Log(("%c", u32 & 0xff));
break;
default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
- break;
+ return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
}
return VINF_SUCCESS;
}
-#endif /* DEBUG_ACPI */
+# endif /* DEBUG_ACPI */
+
+/**
+ * Used to calculate the value of a PM I/O port.
+ *
+ * @returns The actual I/O port value.
+ * @param pThis The ACPI instance.
+ * @param offset The offset into the I/O space, or -1 if invalid.
+ */
+static RTIOPORT acpiCalcPmPort(ACPIState *pThis, int32_t offset)
+{
+ Assert(pThis->uPmIoPortBase != 0);
-static int acpiRegisterPmHandlers(ACPIState* pThis)
+ if (offset == -1)
+ return 0;
+
+ return (RTIOPORT)(pThis->uPmIoPortBase + offset);
+}
+
+/**
+ * Called by acpiLoadState and acpiUpdatePmHandlers to register the PM1a, PM
+ * timer and GPE0 I/O ports.
+ *
+ * @returns VBox status code.
+ * @param pThis The ACPI instance.
+ */
+static int acpiRegisterPmHandlers(ACPIState *pThis)
{
int rc = VINF_SUCCESS;
#define R(offset, cnt, writer, reader, description) \
do { \
- rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt, pThis, writer, reader, \
+ rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
NULL, NULL, description); \
if (RT_FAILURE(rc)) \
return rc; \
@@ -2051,7 +1816,7 @@ static int acpiRegisterPmHandlers(ACPIState* pThis)
/* register RC stuff */
if (pThis->fGCEnabled)
{
- rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
+ rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
1, 0, NULL, "acpiPMTmrRead",
NULL, NULL, "ACPI PM Timer");
AssertRCReturn(rc, rc);
@@ -2060,7 +1825,7 @@ static int acpiRegisterPmHandlers(ACPIState* pThis)
/* register R0 stuff */
if (pThis->fR0Enabled)
{
- rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
+ rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
1, 0, NULL, "acpiPMTmrRead",
NULL, NULL, "ACPI PM Timer");
AssertRCReturn(rc, rc);
@@ -2069,11 +1834,18 @@ static int acpiRegisterPmHandlers(ACPIState* pThis)
return rc;
}
+/**
+ * Called by acpiLoadState and acpiUpdatePmHandlers to unregister the PM1a, PM
+ * timer and GPE0 I/O ports.
+ *
+ * @returns VBox status code.
+ * @param pThis The ACPI instance.
+ */
static int acpiUnregisterPmHandlers(ACPIState *pThis)
{
#define U(offset, cnt) \
do { \
- int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt); \
+ int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt); \
AssertRCReturn(rc, rc); \
} while (0)
#define L (GPE0_BLK_LEN / 2)
@@ -2091,6 +1863,41 @@ static int acpiUnregisterPmHandlers(ACPIState *pThis)
}
/**
+ * Called by acpiPciConfigWrite and acpiReset to change the location of the
+ * PM1a, PM timer and GPE0 ports.
+ *
+ * @returns VBox status code.
+ *
+ * @param pThis The ACPI instance.
+ * @param NewIoPortBase The new base address of the I/O ports.
+ */
+static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
+{
+ Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
+ if (NewIoPortBase != pThis->uPmIoPortBase)
+ {
+ int rc = acpiUnregisterPmHandlers(pThis);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ pThis->uPmIoPortBase = NewIoPortBase;
+
+ rc = acpiRegisterPmHandlers(pThis);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* We have to update FADT table acccording to the new base */
+ rc = acpiPlantTables(pThis);
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
* Saved state structure description, version 4.
*/
static const SSMFIELD g_AcpiSavedStateFields4[] =
@@ -2202,9 +2009,9 @@ static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle
rc = acpiFetchBatteryInfo(pThis);
if (RT_FAILURE(rc))
return rc;
- rc = acpiPMTimerReset(pThis);
- if (RT_FAILURE(rc))
- return rc;
+ TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
+ acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
+ TMTimerUnlock(pThis->pPmTimerR3);
}
return rc;
}
@@ -2221,28 +2028,425 @@ static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char
}
/**
- * Create the ACPI tables.
+ * Calculate the check sum for some ACPI data before planting it.
+ *
+ * All the bytes must add up to 0.
+ *
+ * @returns check sum.
+ * @param pvSrc What to check sum.
+ * @param cbData The amount of data to checksum.
+ */
+static uint8_t acpiChecksum(const void * const pvSrc, size_t cbData)
+{
+ uint8_t const *pbSrc = (uint8_t const *)pvSrc;
+ uint8_t uSum = 0;
+ for (size_t i = 0; i < cbData; ++i)
+ uSum += pbSrc[i];
+ return -uSum;
+}
+
+/**
+ * Prepare a ACPI table header.
+ */
+static void acpiPrepareHeader(ACPITBLHEADER *header, const char au8Signature[4],
+ uint32_t u32Length, uint8_t u8Revision)
+{
+ memcpy(header->au8Signature, au8Signature, 4);
+ header->u32Length = RT_H2LE_U32(u32Length);
+ header->u8Revision = u8Revision;
+ memcpy(header->au8OemId, "VBOX ", 6);
+ memcpy(header->au8OemTabId, "VBOX", 4);
+ memcpy(header->au8OemTabId+4, au8Signature, 4);
+ header->u32OemRevision = RT_H2LE_U32(1);
+ memcpy(header->au8CreatorId, "ASL ", 4);
+ header->u32CreatorRev = RT_H2LE_U32(0x61);
+}
+
+/**
+ * Initialize a generic address structure (ACPIGENADDR).
*/
-static int acpiPlantTables(ACPIState *s)
+static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
+ uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
+ uint8_t u8AccessSize, uint64_t u64Address)
+{
+ g->u8AddressSpaceId = u8AddressSpaceId;
+ g->u8RegisterBitWidth = u8RegisterBitWidth;
+ g->u8RegisterBitOffset = u8RegisterBitOffset;
+ g->u8AccessSize = u8AccessSize;
+ g->u64Address = RT_H2LE_U64(u64Address);
+}
+
+/**
+ * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
+ */
+static void acpiPhyscpy(ACPIState *pThis, RTGCPHYS32 dst, const void * const src, size_t size)
+{
+ PDMDevHlpPhysWrite(pThis->pDevIns, dst, src, size);
+}
+
+/**
+ * Plant the Differentiated System Description Table (DSDT).
+ */
+static void acpiSetupDSDT(ACPIState *pThis, RTGCPHYS32 addr,
+ void* pPtr, size_t uDsdtLen)
+{
+ acpiPhyscpy(pThis, addr, pPtr, uDsdtLen);
+}
+
+/**
+ * Plan the Secondary System Description Table (SSDT).
+ */
+static void acpiSetupSSDT(ACPIState *pThis, RTGCPHYS32 addr,
+ void* pPtr, size_t uSsdtLen)
+{
+ acpiPhyscpy(pThis, addr, pPtr, uSsdtLen);
+}
+
+/**
+ * Plant the Firmware ACPI Control Structure (FACS).
+ */
+static void acpiSetupFACS(ACPIState *pThis, RTGCPHYS32 addr)
+{
+ ACPITBLFACS facs;
+
+ memset(&facs, 0, sizeof(facs));
+ memcpy(facs.au8Signature, "FACS", 4);
+ facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
+ facs.u32HWSignature = RT_H2LE_U32(0);
+ facs.u32FWVector = RT_H2LE_U32(0);
+ facs.u32GlobalLock = RT_H2LE_U32(0);
+ facs.u32Flags = RT_H2LE_U32(0);
+ facs.u64X_FWVector = RT_H2LE_U64(0);
+ facs.u8Version = 1;
+
+ acpiPhyscpy(pThis, addr, (const uint8_t *)&facs, sizeof(facs));
+}
+
+/**
+ * Plant the Fixed ACPI Description Table (FADT aka FACP).
+ */
+static void acpiSetupFADT(ACPIState *pThis, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2, RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
+{
+ ACPITBLFADT fadt;
+
+ /* First the ACPI version 2+ version of the structure. */
+ memset(&fadt, 0, sizeof(fadt));
+ acpiPrepareHeader(&fadt.header, "FACP", sizeof(fadt), 4);
+ fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
+ fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
+ fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
+ fadt.u8PreferredPMProfile = 0; /* unspecified */
+ fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
+ fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
+ fadt.u8AcpiEnable = ACPI_ENABLE;
+ fadt.u8AcpiDisable = ACPI_DISABLE;
+ fadt.u8S4BIOSReq = 0;
+ fadt.u8PStateCnt = 0;
+ fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
+ fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
+ fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
+ fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
+ fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
+ fadt.u32PMTMRBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM_TMR_OFFSET));
+ fadt.u32GPE0BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE0_OFFSET));
+ fadt.u32GPE1BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE1_OFFSET));
+ fadt.u8PM1EVTLEN = 4;
+ fadt.u8PM1CTLLEN = 2;
+ fadt.u8PM2CTLLEN = 0;
+ fadt.u8PMTMLEN = 4;
+ fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
+ fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
+ fadt.u8GPE1BASE = GPE1_BASE;
+ fadt.u8CSTCNT = 0;
+ fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
+ fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
+ fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
+ fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
+ fadt.u8DutyOffset = 0;
+ fadt.u8DutyWidth = 0;
+ fadt.u8DayAlarm = 0;
+ fadt.u8MonAlarm = 0;
+ fadt.u8Century = 0;
+ fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
+ /** @note WBINVD is required for ACPI versions newer than 1.0 */
+ fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
+ | FADT_FL_FIX_RTC
+ | FADT_FL_TMR_VAL_EXT
+ | FADT_FL_RESET_REG_SUP);
+
+ /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
+ if (pThis->fCpuHotPlug)
+ fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
+
+ acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
+ fadt.u8ResetVal = ACPI_RESET_REG_VAL;
+ fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
+ fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
+ acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiCalcPmPort(pThis, PM_TMR_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiCalcPmPort(pThis, GPE0_OFFSET));
+ acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, GPE1_OFFSET));
+ fadt.header.u8Checksum = acpiChecksum(&fadt, sizeof(fadt));
+ acpiPhyscpy(pThis, GCPhysAcpi2, &fadt, sizeof(fadt));
+
+ /* Now the ACPI 1.0 version. */
+ fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
+ fadt.u8IntModel = INT_MODEL_DUAL_PIC;
+ fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
+ fadt.header.u8Checksum = acpiChecksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
+ acpiPhyscpy(pThis, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
+}
+
+/**
+ * Plant the root System Description Table.
+ *
+ * The RSDT and XSDT tables are basically identical. The only difference is 32
+ * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
+ * ACPI 2.0 and up.
+ */
+static int acpiSetupRSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
+{
+ ACPITBLRSDT *rsdt;
+ const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
+
+ rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
+ if (!rsdt)
+ return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
+
+ acpiPrepareHeader(&rsdt->header, "RSDT", (uint32_t)size, 1);
+ for (unsigned int i = 0; i < nb_entries; ++i)
+ {
+ rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
+ Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
+ }
+ rsdt->header.u8Checksum = acpiChecksum(rsdt, size);
+ acpiPhyscpy(pThis, addr, rsdt, size);
+ RTMemFree(rsdt);
+ return VINF_SUCCESS;
+}
+
+/**
+ * Plant the Extended System Description Table.
+ */
+static int acpiSetupXSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
+{
+ ACPITBLXSDT *xsdt;
+ const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
+
+ xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
+ if (!xsdt)
+ return VERR_NO_TMP_MEMORY;
+
+ acpiPrepareHeader(&xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
+ for (unsigned int i = 0; i < nb_entries; ++i)
+ {
+ xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
+ Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
+ }
+ xsdt->header.u8Checksum = acpiChecksum(xsdt, size);
+ acpiPhyscpy(pThis, addr, xsdt, size);
+ RTMemFree(xsdt);
+ return VINF_SUCCESS;
+}
+
+/**
+ * Plant the Root System Description Pointer (RSDP).
+ */
+static void acpiSetupRSDP(ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
+{
+ memset(rsdp, 0, sizeof(*rsdp));
+
+ /* ACPI 1.0 part (RSDT */
+ memcpy(rsdp->au8Signature, "RSD PTR ", 8);
+ memcpy(rsdp->au8OemId, "VBOX ", 6);
+ rsdp->u8Revision = ACPI_REVISION;
+ rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
+ rsdp->u8Checksum = acpiChecksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
+
+ /* ACPI 2.0 part (XSDT) */
+ rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
+ rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
+ rsdp->u8ExtChecksum = acpiChecksum(rsdp, sizeof(ACPITBLRSDP));
+}
+
+/**
+ * Plant the Multiple APIC Description Table (MADT).
+ *
+ * @note APIC without IO-APIC hangs Windows Vista therefore we setup both.
+ *
+ * @todo All hardcoded, should set this up based on the actual VM config!!!!!
+ */
+static void acpiSetupMADT(ACPIState *pThis, RTGCPHYS32 addr)
+{
+ uint16_t cpus = pThis->cCpus;
+ AcpiTableMADT madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
+
+ acpiPrepareHeader(madt.header_addr(), "APIC", madt.size(), 2);
+
+ *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
+ *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
+
+ /* LAPICs records */
+ ACPITBLLAPIC* lapic = madt.LApics_addr();
+ for (uint16_t i = 0; i < cpus; i++)
+ {
+ lapic->u8Type = 0;
+ lapic->u8Length = sizeof(ACPITBLLAPIC);
+ lapic->u8ProcId = i;
+ /** Must match numbering convention in MPTABLES */
+ lapic->u8ApicId = i;
+ lapic->u32Flags = VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
+ lapic++;
+ }
+
+ /* IO-APIC record */
+ ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
+ ioapic->u8Type = 1;
+ ioapic->u8Length = sizeof(ACPITBLIOAPIC);
+ /** Must match MP tables ID */
+ ioapic->u8IOApicId = cpus;
+ ioapic->u8Reserved = 0;
+ ioapic->u32Address = RT_H2LE_U32(0xfec00000);
+ ioapic->u32GSIB = RT_H2LE_U32(0);
+
+ /* Interrupt Source Overrides */
+ /* Flags:
+ bits[3:2]:
+ 00 conforms to the bus
+ 01 edge-triggered
+ 10 reserved
+ 11 level-triggered
+ bits[1:0]
+ 00 conforms to the bus
+ 01 active-high
+ 10 reserved
+ 11 active-low */
+ /* If changing, also update PDMIsaSetIrq() and MPS */
+ ACPITBLISO* isos = madt.ISO_addr();
+ /* Timer interrupt rule IRQ0 to GSI2 */
+ isos[0].u8Type = 2;
+ isos[0].u8Length = sizeof(ACPITBLISO);
+ isos[0].u8Bus = 0; /* Must be 0 */
+ isos[0].u8Source = 0; /* IRQ0 */
+ isos[0].u32GSI = 2; /* connected to pin 2 */
+ isos[0].u16Flags = 0; /* conform to the bus */
+
+ /* ACPI interrupt rule - IRQ9 to GSI9 */
+ isos[1].u8Type = 2;
+ isos[1].u8Length = sizeof(ACPITBLISO);
+ isos[1].u8Bus = 0; /* Must be 0 */
+ isos[1].u8Source = 9; /* IRQ9 */
+ isos[1].u32GSI = 9; /* connected to pin 9 */
+ isos[1].u16Flags = 0xd; /* active high, level triggered */
+ Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
+
+ madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
+ acpiPhyscpy(pThis, addr, madt.data(), madt.size());
+}
+
+/**
+ * Plant the High Performance Event Timer (HPET) descriptor.
+ */
+static void acpiSetupHPET(ACPIState *pThis, RTGCPHYS32 addr)
+{
+ ACPITBLHPET hpet;
+
+ memset(&hpet, 0, sizeof(hpet));
+
+ acpiPrepareHeader(&hpet.aHeader, "HPET", sizeof(hpet), 1);
+ /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
+ acpiWriteGenericAddr(&hpet.HpetAddr,
+ 0 /* Memory address space */,
+ 64 /* Register bit width */,
+ 0 /* Bit offset */,
+ 0, /* Register access size, is it correct? */
+ 0xfed00000 /* Address */);
+
+ hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
+ hpet.u32Number = 0;
+ hpet.u32MinTick = 4096;
+ hpet.u8Attributes = 0;
+
+ hpet.aHeader.u8Checksum = acpiChecksum(&hpet, sizeof(hpet));
+
+ acpiPhyscpy(pThis, addr, (const uint8_t *)&hpet, sizeof(hpet));
+}
+
+
+/**
+ * Used by acpiPlantTables to plant a MMCONFIG PCI config space access (MCFG)
+ * descriptor.
+ *
+ * @param pThis The ACPI instance.
+ * @param GCPhysDst Where to plant it.
+ */
+static void acpiSetupMCFG(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
+{
+ struct
+ {
+ ACPITBLMCFG hdr;
+ ACPITBLMCFGENTRY entry;
+ } tbl;
+ uint8_t u8StartBus = 0;
+ uint8_t u8EndBus = (pThis->u64PciConfigMMioLength >> 20) - 1;
+
+ RT_ZERO(tbl);
+
+ acpiPrepareHeader(&tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
+ tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
+ tbl.entry.u8StartBus = u8StartBus;
+ tbl.entry.u8EndBus = u8EndBus;
+ // u16PciSegmentGroup must match _SEG in ACPI table
+
+ tbl.hdr.aHeader.u8Checksum = acpiChecksum(&tbl, sizeof(tbl));
+
+ acpiPhyscpy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
+}
+
+/**
+ * Used by acpiPlantTables and acpiConstruct.
+ *
+ * @returns Guest memory address.
+ */
+static uint32_t find_rsdp_space(void)
+{
+ return 0xe0000;
+}
+
+/**
+ * Create the ACPI tables in guest memory.
+ */
+static int acpiPlantTables(ACPIState *pThis)
{
int rc;
RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
- RTGCPHYS32 GCPhysHpet = 0, GCPhysApic = 0, GCPhysSsdt = 0, GCPhysMcfg = 0;
+ RTGCPHYS32 GCPhysHpet = 0;
+ RTGCPHYS32 GCPhysApic = 0;
+ RTGCPHYS32 GCPhysSsdt = 0;
+ RTGCPHYS32 GCPhysMcfg = 0;
uint32_t addend = 0;
RTGCPHYS32 aGCPhysRsdt[8];
RTGCPHYS32 aGCPhysXsdt[8];
- uint32_t cAddr, iMadt = 0, iHpet = 0, iSsdt = 0, iMcfg = 0;
+ uint32_t cAddr;
+ uint32_t iMadt = 0;
+ uint32_t iHpet = 0;
+ uint32_t iSsdt = 0;
+ uint32_t iMcfg = 0;
size_t cbRsdt = sizeof(ACPITBLHEADER);
size_t cbXsdt = sizeof(ACPITBLHEADER);
cAddr = 1; /* FADT */
- if (s->u8UseIOApic)
+ if (pThis->u8UseIOApic)
iMadt = cAddr++; /* MADT */
- if (s->fUseHpet)
+ if (pThis->fUseHpet)
iHpet = cAddr++; /* HPET */
- if (s->fUseMcfg)
+ if (pThis->fUseMcfg)
iMcfg = cAddr++; /* MCFG */
iSsdt = cAddr++; /* SSDT */
@@ -2253,30 +2457,30 @@ static int acpiPlantTables(ACPIState *s)
cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
- rc = CFGMR3QueryU64(s->pDevIns->pCfg, "RamSize", &s->u64RamSize);
+ rc = CFGMR3QueryU64(pThis->pDevIns->pCfg, "RamSize", &pThis->u64RamSize);
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(s->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
N_("Configuration error: Querying \"RamSize\" as integer failed"));
uint32_t cbRamHole;
- rc = CFGMR3QueryU32Def(s->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
+ rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(s->pDevIns, rc,
+ return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
/*
* Calculate the sizes for the high and low regions.
*/
const uint64_t offRamHole = _4G - cbRamHole;
- s->cbRamHigh = offRamHole < s->u64RamSize ? s->u64RamSize - offRamHole : 0;
- uint64_t cbRamLow = offRamHole < s->u64RamSize ? offRamHole : s->u64RamSize;
+ pThis->cbRamHigh = offRamHole < pThis->u64RamSize ? pThis->u64RamSize - offRamHole : 0;
+ uint64_t cbRamLow = offRamHole < pThis->u64RamSize ? offRamHole : pThis->u64RamSize;
if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
{
/* Note: This is also enforced by DevPcBios.cpp. */
LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
cbRamLow = UINT32_C(0xffe00000);
}
- s->cbRamLow = (uint32_t)cbRamLow;
+ pThis->cbRamLow = (uint32_t)cbRamLow;
GCPhysCur = 0;
GCPhysRsdt = GCPhysCur;
@@ -2294,26 +2498,26 @@ static int acpiPlantTables(ACPIState *s)
GCPhysFacs = GCPhysCur;
GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
- if (s->u8UseIOApic)
+ if (pThis->u8UseIOApic)
{
GCPhysApic = GCPhysCur;
- GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(s, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
+ GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
}
- if (s->fUseHpet)
+ if (pThis->fUseHpet)
{
GCPhysHpet = GCPhysCur;
GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
}
- if (s->fUseMcfg)
+ if (pThis->fUseMcfg)
{
GCPhysMcfg = GCPhysCur;
/* Assume one entry */
GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
}
- void* pSsdtCode = NULL;
+ void *pvSsdtCode = NULL;
size_t cbSsdtSize = 0;
- rc = acpiPrepareSsdt(s->pDevIns, &pSsdtCode, &cbSsdtSize);
+ rc = acpiPrepareSsdt(pThis->pDevIns, &pvSsdtCode, &cbSsdtSize);
if (RT_FAILURE(rc))
return rc;
@@ -2322,114 +2526,92 @@ static int acpiPlantTables(ACPIState *s)
GCPhysDsdt = GCPhysCur;
- void* pDsdtCode = NULL;
+ void *pvDsdtCode = NULL;
size_t cbDsdtSize = 0;
- rc = acpiPrepareDsdt(s->pDevIns, &pDsdtCode, &cbDsdtSize);
+ rc = acpiPrepareDsdt(pThis->pDevIns, &pvDsdtCode, &cbDsdtSize);
if (RT_FAILURE(rc))
return rc;
GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
if (GCPhysCur > 0x10000)
- return PDMDEV_SET_ERROR(s->pDevIns, VERR_TOO_MUCH_DATA,
+ return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_TOO_MUCH_DATA,
N_("Error: ACPI tables bigger than 64KB"));
Log(("RSDP 0x%08X\n", find_rsdp_space()));
- addend = s->cbRamLow - 0x10000;
+ addend = pThis->cbRamLow - 0x10000;
Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
Log(("DSDT 0x%08X", GCPhysDsdt + addend));
- if (s->u8UseIOApic)
+ if (pThis->u8UseIOApic)
Log((" MADT 0x%08X", GCPhysApic + addend));
- if (s->fUseHpet)
+ if (pThis->fUseHpet)
Log((" HPET 0x%08X", GCPhysHpet + addend));
- if (s->fUseMcfg)
+ if (pThis->fUseMcfg)
Log((" MCFG 0x%08X", GCPhysMcfg + addend));
Log((" SSDT 0x%08X", GCPhysSsdt + addend));
Log(("\n"));
- acpiSetupRSDP((ACPITBLRSDP*)s->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
- acpiSetupDSDT(s, GCPhysDsdt + addend, pDsdtCode, cbDsdtSize);
- acpiCleanupDsdt(s->pDevIns, pDsdtCode);
- acpiSetupFACS(s, GCPhysFacs + addend);
- acpiSetupFADT(s, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
+ acpiSetupRSDP((ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
+ acpiSetupDSDT(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdtSize);
+ acpiCleanupDsdt(pThis->pDevIns, pvDsdtCode);
+ acpiSetupFACS(pThis, GCPhysFacs + addend);
+ acpiSetupFADT(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
- if (s->u8UseIOApic)
+ if (pThis->u8UseIOApic)
{
- acpiSetupMADT(s, GCPhysApic + addend);
+ acpiSetupMADT(pThis, GCPhysApic + addend);
aGCPhysRsdt[iMadt] = GCPhysApic + addend;
aGCPhysXsdt[iMadt] = GCPhysApic + addend;
}
- if (s->fUseHpet)
+ if (pThis->fUseHpet)
{
- acpiSetupHPET(s, GCPhysHpet + addend);
+ acpiSetupHPET(pThis, GCPhysHpet + addend);
aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
}
- if (s->fUseMcfg)
+ if (pThis->fUseMcfg)
{
- acpiSetupMCFG(s, GCPhysMcfg + addend);
+ acpiSetupMCFG(pThis, GCPhysMcfg + addend);
aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
}
- acpiSetupSSDT(s, GCPhysSsdt + addend, pSsdtCode, cbSsdtSize);
- acpiCleanupSsdt(s->pDevIns, pSsdtCode);
+ acpiSetupSSDT(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdtSize);
+ acpiCleanupSsdt(pThis->pDevIns, pvSsdtCode);
aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
- rc = acpiSetupRSDT(s, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
+ rc = acpiSetupRSDT(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
if (RT_FAILURE(rc))
return rc;
- return acpiSetupXSDT(s, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
+ return acpiSetupXSDT(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
}
-static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT uNewBase)
-{
- Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, uNewBase));
- if (uNewBase != pThis->uPmIoPortBase)
- {
- int rc;
-
- rc = acpiUnregisterPmHandlers(pThis);
- if (RT_FAILURE(rc))
- return rc;
-
- pThis->uPmIoPortBase = uNewBase;
-
- rc = acpiRegisterPmHandlers(pThis);
- if (RT_FAILURE(rc))
- return rc;
-
- /* We have to update FADT table acccording to the new base */
- rc = acpiPlantTables(pThis);
- AssertRC(rc);
- if (RT_FAILURE(rc))
- return rc;
- }
-
- return VINF_SUCCESS;
-}
-
-static uint32_t acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
+/**
+ * @callback_method_impl{FNPCICONFIGREAD}
+ */
+static DECLCALLBACK(uint32_t) acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
{
PPDMDEVINS pDevIns = pPciDev->pDevIns;
- ACPIState* pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
-
return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
}
-static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
+/**
+ * @callback_method_impl{FNPCICONFIGWRITE}
+ */
+static DECLCALLBACK(void) acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
{
PPDMDEVINS pDevIns = pPciDev->pDevIns;
ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
-
+ DEVACPI_LOCK_R3(pThis);
if (Address == VBOX_PCI_INTERRUPT_LINE)
{
@@ -2445,15 +2627,15 @@ static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u3
/* Check Power Management IO Space Enable (PMIOSE) bit */
if (pPciDev->config[0x80] & 0x1)
{
- int rc;
-
- RTIOPORT uNewBase = RTIOPORT(PCIDevGetDWord(pPciDev, 0x40));
- uNewBase &= 0xffc0;
+ RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
+ NewIoPortBase &= 0xffc0;
- rc = acpiUpdatePmHandlers(pThis, uNewBase);
+ int rc = acpiUpdatePmHandlers(pThis, NewIoPortBase);
AssertRC(rc);
}
}
+
+ DEVACPI_UNLOCK(pThis);
}
/**
@@ -2468,8 +2650,7 @@ static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u3
*/
static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
{
- ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
-
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
@@ -2478,27 +2659,30 @@ static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t
AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
/* Check if it was already attached */
- if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
- return VINF_SUCCESS;
-
- PPDMIBASE IBaseTmp;
- int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &s->IBase, &IBaseTmp, "ACPI CPU");
-
- if (RT_SUCCESS(rc))
+ int rc = VINF_SUCCESS;
+ DEVACPI_LOCK_R3(pThis);
+ if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
{
- /* Enable the CPU */
- VMCPUSET_ADD(&s->CpuSetAttached, iLUN);
-
- /*
- * Lock the CPU because we don't know if the guest will use it or not.
- * Prevents ejection while the CPU is still used
- */
- VMCPUSET_ADD(&s->CpuSetLocked, iLUN);
- s->u32CpuEventType = CPU_EVENT_TYPE_ADD;
- s->u32CpuEvent = iLUN;
- /* Notify the guest */
- update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
+ PPDMIBASE IBaseTmp;
+ rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
+ if (RT_SUCCESS(rc))
+ {
+ /* Enable the CPU */
+ VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
+
+ /*
+ * Lock the CPU because we don't know if the guest will use it or not.
+ * Prevents ejection while the CPU is still used
+ */
+ VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
+ pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
+ pThis->u32CpuEvent = iLUN;
+
+ /* Notify the guest */
+ update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
+ }
}
+ DEVACPI_UNLOCK(pThis);
return rc;
}
@@ -2511,7 +2695,7 @@ static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t
*/
static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
{
- ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
@@ -2519,17 +2703,23 @@ static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t
("Hot-plug flag is not set\n"));
/* Check if it was already detached */
- if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
+ DEVACPI_LOCK_R3(pThis);
+ if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
{
- AssertMsgReturnVoid(!(VMCPUSET_IS_PRESENT(&s->CpuSetLocked, iLUN)), ("CPU is still locked by the guest\n"));
-
- /* Disable the CPU */
- VMCPUSET_DEL(&s->CpuSetAttached, iLUN);
- s->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
- s->u32CpuEvent = iLUN;
- /* Notify the guest */
- update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
+ if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
+ {
+ /* Disable the CPU */
+ VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
+ pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
+ pThis->u32CpuEvent = iLUN;
+
+ /* Notify the guest */
+ update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
+ }
+ else
+ AssertMsgFailed(("CPU is still locked by the guest\n"));
}
+ DEVACPI_UNLOCK(pThis);
}
/**
@@ -2551,23 +2741,25 @@ static DECLCALLBACK(void) acpiResume(PPDMDEVINS pDevIns)
*/
static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
{
- ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
- s->pm1a_en = 0;
- s->pm1a_sts = 0;
- s->pm1a_ctl = 0;
- s->u64PmTimerInitial = TMTimerGet(s->CTX_SUFF(ts));
- acpiPMTimerReset(s);
- s->uBatteryIndex = 0;
- s->uSystemInfoIndex = 0;
- s->gpe0_en = 0;
- s->gpe0_sts = 0;
- s->uSleepState = 0;
+ TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
+ pThis->pm1a_en = 0;
+ pThis->pm1a_sts = 0;
+ pThis->pm1a_ctl = 0;
+ pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
+ acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
+ pThis->uBatteryIndex = 0;
+ pThis->uSystemInfoIndex = 0;
+ pThis->gpe0_en = 0;
+ pThis->gpe0_sts = 0;
+ pThis->uSleepState = 0;
+ TMTimerUnlock(pThis->pPmTimerR3);
/** @todo Should we really reset PM base? */
- acpiUpdatePmHandlers(s, PM_PORT_BASE);
+ acpiUpdatePmHandlers(pThis, PM_PORT_BASE);
- acpiPlantTables(s);
+ acpiPlantTables(pThis);
}
/**
@@ -2575,8 +2767,8 @@ static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
*/
static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
{
- ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
- s->tsRC = TMTimerRCPtr(s->CTX_SUFF(ts));
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
+ pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
}
/**
@@ -2584,11 +2776,44 @@ static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
*/
static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
- ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
- PCIDevice *dev = &s->dev;
+ ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- /* Validate and read the configuration. */
+ /*
+ * Init data and set defaults.
+ */
+ /** @todo move more of the code up! */
+
+ pThis->pDevIns = pDevIns;
+ VMCPUSET_EMPTY(&pThis->CpuSetAttached);
+ VMCPUSET_EMPTY(&pThis->CpuSetLocked);
+ pThis->idCpuLockCheck = UINT32_C(0xffffffff);
+ pThis->u32CpuEventType = 0;
+ pThis->u32CpuEvent = UINT32_C(0xffffffff);
+
+ /* The first CPU can't be attached/detached */
+ VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
+ VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
+
+ /* IBase */
+ pThis->IBase.pfnQueryInterface = acpiQueryInterface;
+ /* IACPIPort */
+ pThis->IACPIPort.pfnSleepButtonPress = acpiPort_SleepButtonPress;
+ pThis->IACPIPort.pfnPowerButtonPress = acpiPort_PowerButtonPress;
+ pThis->IACPIPort.pfnGetPowerButtonHandled = acpiPort_GetPowerButtonHandled;
+ pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiPort_GetGuestEnteredACPIMode;
+ pThis->IACPIPort.pfnGetCpuStatus = acpiPort_GetCpuStatus;
+
+ /* Set the default critical section to NOP (related to the PM timer). */
+ int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
+ AssertRCReturn(rc, rc);
+
+ rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi%u", iInstance);
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Validate and read the configuration.
+ */
if (!CFGMR3AreValuesValid(pCfg,
"RamSize\0"
"RamHoleSize\0"
@@ -2613,159 +2838,161 @@ static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
"PowerS4Enabled\0"
"CpuHotPlug\0"
"AmlFilePath\0"
+ "Serial0IoPortBase\0"
+ "Serial1IoPortBase\0"
+ "Serial0Irq\0"
+ "Serial1Irq\0"
))
return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
N_("Configuration error: Invalid config key for ACPI device"));
- s->pDevIns = pDevIns;
-
/* query whether we are supposed to present an IOAPIC */
- int rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &s->u8UseIOApic, 1);
+ rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"IOAPIC\""));
- rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &s->cCpus, 1);
+ rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
/* query whether we are supposed to present an FDC controller */
- rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &s->fUseFdc, true);
+ rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"FdcEnabled\""));
/* query whether we are supposed to present HPET */
- rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &s->fUseHpet, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"HpetEnabled\""));
/* query MCFG configuration */
- rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &s->u64PciConfigMMioAddress, 0);
+ rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"McfgBase\""));
- rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &s->u64PciConfigMMioLength, 0);
+ rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"McfgLength\""));
- s->fUseMcfg = (s->u64PciConfigMMioAddress != 0) && (s->u64PciConfigMMioLength != 0);
+ pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
/* query whether we are supposed to present SMC */
- rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &s->fUseSmc, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"SmcEnabled\""));
/* query whether we are supposed to present RTC object */
- rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &s->fShowRtc, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"ShowRtc\""));
/* query whether we are supposed to present CPU objects */
- rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &s->fShowCpu, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"ShowCpu\""));
/* query primary NIC PCI address */
- rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &s->u32NicPciAddress, 0);
+ rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"NicPciAddress\""));
/* query primary NIC PCI address */
- rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &s->u32AudioPciAddress, 0);
+ rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"AudioPciAddress\""));
/* query IO controller (southbridge) PCI address */
- rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &s->u32IocPciAddress, 0);
+ rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"IocPciAddress\""));
/* query host bus controller PCI address */
- rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &s->u32HbcPciAddress, 0);
+ rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"HostBusPciAddress\""));
/* query whether S1 power state should be exposed */
- rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &s->fS1Enabled, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"PowerS1Enabled\""));
/* query whether S4 power state should be exposed */
- rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &s->fS4Enabled, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"PowerS4Enabled\""));
/* query whether S1 power state should save the VM state */
- rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &s->fSuspendToSavedState, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
/* query whether we are allow CPU hot plugging */
- rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &s->fCpuHotPlug, false);
+ rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"CpuHotPlug\""));
- rc = CFGMR3QueryBool(pCfg, "GCEnabled", &s->fGCEnabled);
+ rc = CFGMR3QueryBool(pCfg, "GCEnabled", &pThis->fGCEnabled);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- s->fGCEnabled = true;
+ pThis->fGCEnabled = true;
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to read \"GCEnabled\""));
- rc = CFGMR3QueryBool(pCfg, "R0Enabled", &s->fR0Enabled);
+ rc = CFGMR3QueryBool(pCfg, "R0Enabled", &pThis->fR0Enabled);
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
- s->fR0Enabled = true;
+ pThis->fR0Enabled = true;
else if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("configuration error: failed to read R0Enabled as boolean"));
- /*
- * Interfaces
- */
- /* IBase */
- s->IBase.pfnQueryInterface = acpiQueryInterface;
- /* IACPIPort */
- s->IACPIPort.pfnSleepButtonPress = acpiSleepButtonPress;
- s->IACPIPort.pfnPowerButtonPress = acpiPowerButtonPress;
- s->IACPIPort.pfnGetPowerButtonHandled = acpiGetPowerButtonHandled;
- s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiGetGuestEnteredACPIMode;
- s->IACPIPort.pfnGetCpuStatus = acpiGetCpuStatus;
-
- VMCPUSET_EMPTY(&s->CpuSetAttached);
- VMCPUSET_EMPTY(&s->CpuSetLocked);
- s->idCpuLockCheck = UINT32_C(0xffffffff);
- s->u32CpuEventType = 0;
- s->u32CpuEvent = UINT32_C(0xffffffff);
+ /* query serial info */
+ rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to read \"Serial0Irq\""));
- /* The first CPU can't be attached/detached */
- VMCPUSET_ADD(&s->CpuSetAttached, 0);
- VMCPUSET_ADD(&s->CpuSetLocked, 0);
+ rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
+
+ /* Serial 1 is enabled, get config data */
+ rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to read \"Serial1Irq\""));
+
+ rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
/* Try to attach the other CPUs */
- for (unsigned i = 1; i < s->cCpus; i++)
+ for (unsigned i = 1; i < pThis->cCpus; i++)
{
- if (s->fCpuHotPlug)
+ if (pThis->fCpuHotPlug)
{
PPDMIBASE IBaseTmp;
- rc = PDMDevHlpDriverAttach(pDevIns, i, &s->IBase, &IBaseTmp, "ACPI CPU");
+ rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
if (RT_SUCCESS(rc))
{
- VMCPUSET_ADD(&s->CpuSetAttached, i);
- VMCPUSET_ADD(&s->CpuSetLocked, i);
+ VMCPUSET_ADD(&pThis->CpuSetAttached, i);
+ VMCPUSET_ADD(&pThis->CpuSetLocked, i);
Log(("acpi: Attached CPU %u\n", i));
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
@@ -2776,44 +3003,49 @@ static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
else
{
/* CPU is always attached if hot-plug is not enabled. */
- VMCPUSET_ADD(&s->CpuSetAttached, i);
- VMCPUSET_ADD(&s->CpuSetLocked, i);
+ VMCPUSET_ADD(&pThis->CpuSetAttached, i);
+ VMCPUSET_ADD(&pThis->CpuSetLocked, i);
}
}
/* Set default port base */
- s->uPmIoPortBase = PM_PORT_BASE;
+ pThis->uPmIoPortBase = PM_PORT_BASE;
/*
* FDC and SMC try to use the same non-shareable interrupt (6),
* enable only one device.
*/
- if (s->fUseSmc)
- s->fUseFdc = false;
+ if (pThis->fUseSmc)
+ pThis->fUseFdc = false;
- /* */
+ /*
+ * Plant ACPI tables.
+ */
RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
if (!GCPhysRsdp)
return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
N_("Can not find space for RSDP. ACPI is disabled"));
- rc = acpiPlantTables(s);
+ rc = acpiPlantTables(pThis);
if (RT_FAILURE(rc))
return rc;
- rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, s->au8RSDPPage, 0x1000,
+ rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
if (RT_FAILURE(rc))
return rc;
- rc = acpiRegisterPmHandlers(s);
+ /*
+ * Register I/O ports.
+ */
+ rc = acpiRegisterPmHandlers(pThis);
if (RT_FAILURE(rc))
return rc;
#define R(addr, cnt, writer, reader, description) \
do { \
- rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, s, writer, reader, \
+ rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
NULL, NULL, description); \
if (RT_FAILURE(rc)) \
return rc; \
@@ -2830,40 +3062,47 @@ static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
#undef R
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiTimer, dev,
- TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "ACPI Timer", &s->tsR3);
- if (RT_FAILURE(rc))
- {
- AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
- return rc;
- }
-
- s->tsR0 = TMTimerR0Ptr(s->tsR3);
- s->tsRC = TMTimerRCPtr(s->tsR3);
- s->u64PmTimerInitial = TMTimerGet(s->tsR3);
- acpiPMTimerReset(s);
+ /*
+ * Create the PM timer.
+ */
+ PTMTIMER pTimer;
+ rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiPmTimer, &pThis->dev,
+ TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
+ AssertRCReturn(rc, rc);
+ pThis->pPmTimerR3 = pTimer;
+ pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
+ pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
+
+ rc = TMTimerLock(pTimer, VERR_IGNORED);
+ AssertRCReturn(rc, rc);
+ pThis->u64PmTimerInitial = TMTimerGet(pTimer);
+ acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
+ TMTimerUnlock(pTimer);
- PCIDevSetVendorId(dev, 0x8086); /* Intel */
- PCIDevSetDeviceId(dev, 0x7113); /* 82371AB */
+ /*
+ * Set up the PCI device.
+ */
+ PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
+ PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
/* See p. 50 of PIIX4 manual */
- PCIDevSetCommand(dev, 0x01);
- PCIDevSetStatus(dev, 0x0280);
+ PCIDevSetCommand(&pThis->dev, 0x01);
+ PCIDevSetStatus(&pThis->dev, 0x0280);
- PCIDevSetRevisionId(dev, 0x08);
+ PCIDevSetRevisionId(&pThis->dev, 0x08);
- PCIDevSetClassProg(dev, 0x00);
- PCIDevSetClassSub(dev, 0x80);
- PCIDevSetClassBase(dev, 0x06);
+ PCIDevSetClassProg(&pThis->dev, 0x00);
+ PCIDevSetClassSub(&pThis->dev, 0x80);
+ PCIDevSetClassBase(&pThis->dev, 0x06);
- PCIDevSetHeaderType(dev, 0x80);
+ PCIDevSetHeaderType(&pThis->dev, 0x80);
- PCIDevSetBIST(dev, 0x00);
+ PCIDevSetBIST(&pThis->dev, 0x00);
- PCIDevSetInterruptLine(dev, SCI_INT);
- PCIDevSetInterruptPin (dev, 0x01);
+ PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
+ PCIDevSetInterruptPin (&pThis->dev, 0x01);
- dev->config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
+ pThis->dev.config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
#if 0
int smb_io_base = 0xb100;
@@ -2871,26 +3110,29 @@ static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
dev->config[0x90] = smb_io_base >> 8;
#endif
- rc = PDMDevHlpPCIRegister(pDevIns, dev);
+ rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
if (RT_FAILURE(rc))
return rc;
- PDMDevHlpPCISetConfigCallbacks(pDevIns, dev,
- acpiPciConfigRead, &s->pfnAcpiPciConfigRead,
- acpiPciConfigWrite, &s->pfnAcpiPciConfigWrite);
+ PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
+ acpiPciConfigRead, &pThis->pfnAcpiPciConfigRead,
+ acpiPciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
- rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*s), acpiSaveState, acpiLoadState);
+ /*
+ * Register the saved state.
+ */
+ rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*pThis), acpiSaveState, acpiLoadState);
if (RT_FAILURE(rc))
return rc;
/*
* Get the corresponding connector interface
*/
- rc = PDMDevHlpDriverAttach(pDevIns, 0, &s->IBase, &s->pDrvBase, "ACPI Driver Port");
+ rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
if (RT_SUCCESS(rc))
{
- s->pDrv = PDMIBASE_QUERY_INTERFACE(s->pDrvBase, PDMIACPICONNECTOR);
- if (!s->pDrv)
+ pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
+ if (!pThis->pDrv)
return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
N_("LUN #0 doesn't have an ACPI connector interface"));
}