VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevACPI.cpp@ 40754

Last change on this file since 40754 was 40282, checked in by vboxsync, 12 years ago

*: gcc-4.7: ~0 => ~0U in initializers (warning: narrowing conversion of -1' from int' to `unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing])

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 120.6 KB
RevLine 
[2781]1/* $Id: DevACPI.cpp 40282 2012-02-28 21:02:40Z vboxsync $ */
[1]2/** @file
[11166]3 * DevACPI - Advanced Configuration and Power Interface (ACPI) Device.
[1]4 */
5
6/*
[37444]7 * Copyright (C) 2006-2011 Oracle Corporation
[1]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
[5999]12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[1]16 */
17
[17572]18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
[1]21#define LOG_GROUP LOG_GROUP_DEV_ACPI
[35346]22#include <VBox/vmm/pdmdev.h>
23#include <VBox/vmm/pgm.h>
[37444]24#include <VBox/vmm/dbgftrace.h>
[39303]25#include <VBox/vmm/vmcpuset.h>
[1]26#include <VBox/log.h>
[17542]27#include <VBox/param.h>
[1]28#include <iprt/assert.h>
[1912]29#include <iprt/asm.h>
[29250]30#include <iprt/asm-math.h>
[40019]31#include <iprt/file.h>
[1]32#ifdef IN_RING3
[11208]33# include <iprt/alloc.h>
34# include <iprt/string.h>
[25966]35# include <iprt/uuid.h>
[1]36#endif /* IN_RING3 */
37
[35353]38#include "VBoxDD.h"
[1]39
[11208]40#ifdef LOG_ENABLED
41# define DEBUG_ACPI
[1]42#endif
43
[491]44#if defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
[20400]45int acpiPrepareDsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puDsdtLen);
46int acpiCleanupDsdt(PPDMDEVINS pDevIns, void* pPtr);
[26183]47
48int acpiPrepareSsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puSsdtLen);
49int acpiCleanupSsdt(PPDMDEVINS pDevIns, void* pPtr);
[1]50#endif /* !IN_RING3 */
51
52
53
[17572]54/*******************************************************************************
55* Defined Constants And Macros *
56*******************************************************************************/
[37444]57#ifdef IN_RING3
58/** Locks the device state, ring-3 only. */
59# define DEVACPI_LOCK_R3(a_pThis) \
60 do { \
61 int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
62 AssertRC(rcLock); \
63 } while (0)
64#endif
65/** Unlocks the device state (all contexts). */
66#define DEVACPI_UNLOCK(a_pThis) \
67 do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
68
69
[1]70#define DEBUG_HEX 0x3000
71#define DEBUG_CHR 0x3001
72
73#define PM_TMR_FREQ 3579545
[21829]74/* Default base for PM PIIX4 device */
75#define PM_PORT_BASE 0x4000
[21820]76/* Port offsets in PM device */
77enum
78{
[21829]79 PM1a_EVT_OFFSET = 0x00,
[21820]80 PM1b_EVT_OFFSET = -1, /**< not supported */
81 PM1a_CTL_OFFSET = 0x04,
82 PM1b_CTL_OFFSET = -1, /**< not supported */
83 PM2_CTL_OFFSET = -1, /**< not supported */
84 PM_TMR_OFFSET = 0x08,
85 GPE0_OFFSET = 0x20,
[21837]86 GPE1_OFFSET = -1 /**< not supported */
[21820]87};
88
[1]89#define BAT_INDEX 0x00004040
90#define BAT_DATA 0x00004044
91#define SYSI_INDEX 0x00004048
92#define SYSI_DATA 0x0000404c
93#define ACPI_RESET_BLK 0x00004050
94
95/* PM1x status register bits */
[5605]96#define TMR_STS RT_BIT(0)
97#define RSR1_STS (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
98#define BM_STS RT_BIT(4)
99#define GBL_STS RT_BIT(5)
100#define RSR2_STS (RT_BIT(6) | RT_BIT(7))
101#define PWRBTN_STS RT_BIT(8)
102#define SLPBTN_STS RT_BIT(9)
103#define RTC_STS RT_BIT(10)
104#define IGN_STS RT_BIT(11)
105#define RSR3_STS (RT_BIT(12) | RT_BIT(13) | RT_BIT(14))
106#define WAK_STS RT_BIT(15)
[1]107#define RSR_STS (RSR1_STS | RSR2_STS | RSR3_STS)
108
109/* PM1x enable register bits */
[5605]110#define TMR_EN RT_BIT(0)
111#define RSR1_EN (RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
112#define GBL_EN RT_BIT(5)
113#define RSR2_EN (RT_BIT(6) | RT_BIT(7))
114#define PWRBTN_EN RT_BIT(8)
115#define SLPBTN_EN RT_BIT(9)
116#define RTC_EN RT_BIT(10)
117#define RSR3_EN (RT_BIT(11) | RT_BIT(12) | RT_BIT(13) | RT_BIT(14) | RT_BIT(15))
[1]118#define RSR_EN (RSR1_EN | RSR2_EN | RSR3_EN)
119#define IGN_EN 0
120
121/* PM1x control register bits */
[5605]122#define SCI_EN RT_BIT(0)
123#define BM_RLD RT_BIT(1)
124#define GBL_RLS RT_BIT(2)
125#define RSR1_CNT (RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7) | RT_BIT(8))
126#define IGN_CNT RT_BIT(9)
[1]127#define SLP_TYPx_SHIFT 10
128#define SLP_TYPx_MASK 7
[5605]129#define SLP_EN RT_BIT(13)
130#define RSR2_CNT (RT_BIT(14) | RT_BIT(15))
[1]131#define RSR_CNT (RSR1_CNT | RSR2_CNT)
132
[5605]133#define GPE0_BATTERY_INFO_CHANGED RT_BIT(0)
[1]134
135enum
136{
137 BAT_STATUS_STATE = 0x00, /**< BST battery state */
138 BAT_STATUS_PRESENT_RATE = 0x01, /**< BST battery present rate */
139 BAT_STATUS_REMAINING_CAPACITY = 0x02, /**< BST battery remaining capacity */
140 BAT_STATUS_PRESENT_VOLTAGE = 0x03, /**< BST battery present voltage */
141 BAT_INFO_UNITS = 0x04, /**< BIF power unit */
142 BAT_INFO_DESIGN_CAPACITY = 0x05, /**< BIF design capacity */
143 BAT_INFO_LAST_FULL_CHARGE_CAPACITY = 0x06, /**< BIF last full charge capacity */
144 BAT_INFO_TECHNOLOGY = 0x07, /**< BIF battery technology */
145 BAT_INFO_DESIGN_VOLTAGE = 0x08, /**< BIF design voltage */
146 BAT_INFO_DESIGN_CAPACITY_OF_WARNING = 0x09, /**< BIF design capacity of warning */
147 BAT_INFO_DESIGN_CAPACITY_OF_LOW = 0x0A, /**< BIF design capacity of low */
148 BAT_INFO_CAPACITY_GRANULARITY_1 = 0x0B, /**< BIF battery capacity granularity 1 */
149 BAT_INFO_CAPACITY_GRANULARITY_2 = 0x0C, /**< BIF battery capacity granularity 2 */
150 BAT_DEVICE_STATUS = 0x0D, /**< STA device status */
151 BAT_POWER_SOURCE = 0x0E, /**< PSR power source */
152 BAT_INDEX_LAST
153};
154
155enum
156{
[26594]157 CPU_EVENT_TYPE_ADD = 0x01, /**< Event type add */
158 CPU_EVENT_TYPE_REMOVE = 0x03 /**< Event type remove */
159};
160
161enum
162{
[17590]163 SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH = 0,
[1]164 SYSTEM_INFO_INDEX_USE_IOAPIC = 1,
[16170]165 SYSTEM_INFO_INDEX_HPET_STATUS = 2,
166 SYSTEM_INFO_INDEX_SMC_STATUS = 3,
167 SYSTEM_INFO_INDEX_FDC_STATUS = 4,
[33540]168 SYSTEM_INFO_INDEX_CPU0_STATUS = 5, /**< For compatibility with older saved states. */
169 SYSTEM_INFO_INDEX_CPU1_STATUS = 6, /**< For compatibility with older saved states. */
170 SYSTEM_INFO_INDEX_CPU2_STATUS = 7, /**< For compatibility with older saved states. */
171 SYSTEM_INFO_INDEX_CPU3_STATUS = 8, /**< For compatibility with older saved states. */
[21829]172 SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH= 9,
173 SYSTEM_INFO_INDEX_RTC_STATUS = 10,
[26592]174 SYSTEM_INFO_INDEX_CPU_LOCKED = 11, /**< Contains a flag indicating whether the CPU is locked or not */
175 SYSTEM_INFO_INDEX_CPU_LOCK_CHECK = 12, /**< For which CPU the lock status should be checked */
[26594]176 SYSTEM_INFO_INDEX_CPU_EVENT_TYPE = 13, /**< Type of the CPU hot-plug event */
177 SYSTEM_INFO_INDEX_CPU_EVENT = 14, /**< The CPU id the event is for */
[28487]178 SYSTEM_INFO_INDEX_NIC_ADDRESS = 15, /**< NIC PCI address, or 0 */
[31519]179 SYSTEM_INFO_INDEX_AUDIO_ADDRESS = 16, /**< Audio card PCI address, or 0 */
[32477]180 SYSTEM_INFO_INDEX_POWER_STATES = 17,
[32471]181 SYSTEM_INFO_INDEX_IOC_ADDRESS = 18, /**< IO controller PCI address */
[32477]182 SYSTEM_INFO_INDEX_HBC_ADDRESS = 19, /**< host bus controller PCI address */
[32637]183 SYSTEM_INFO_INDEX_PCI_BASE = 20, /**< PCI bus MCFG MMIO range base */
184 SYSTEM_INFO_INDEX_PCI_LENGTH = 21, /**< PCI bus MCFG MMIO range length */
[35746]185 SYSTEM_INFO_INDEX_SERIAL0_IOBASE = 22,
186 SYSTEM_INFO_INDEX_SERIAL0_IRQ = 23,
187 SYSTEM_INFO_INDEX_SERIAL1_IOBASE = 24,
188 SYSTEM_INFO_INDEX_SERIAL1_IRQ = 25,
[35773]189 SYSTEM_INFO_INDEX_END = 26,
[1]190 SYSTEM_INFO_INDEX_INVALID = 0x80,
191 SYSTEM_INFO_INDEX_VALID = 0x200
192};
193
194#define AC_OFFLINE 0
195#define AC_ONLINE 1
196
197#define BAT_TECH_PRIMARY 1
198#define BAT_TECH_SECONDARY 2
199
[16041]200#define STA_DEVICE_PRESENT_MASK RT_BIT(0) /**< present */
201#define STA_DEVICE_ENABLED_MASK RT_BIT(1) /**< enabled and decodes its resources */
202#define STA_DEVICE_SHOW_IN_UI_MASK RT_BIT(2) /**< should be shown in UI */
203#define STA_DEVICE_FUNCTIONING_PROPERLY_MASK RT_BIT(3) /**< functioning properly */
204#define STA_BATTERY_PRESENT_MASK RT_BIT(4) /**< the battery is present */
[1]205
[17572]206
207/*******************************************************************************
208* Structures and Typedefs *
209*******************************************************************************/
210/**
211 * The ACPI device state.
212 */
213typedef struct ACPIState
[1]214{
215 PCIDevice dev;
[37444]216 /** Critical section protecting the ACPI state. */
217 PDMCRITSECT CritSect;
218
[1]219 uint16_t pm1a_en;
220 uint16_t pm1a_sts;
221 uint16_t pm1a_ctl;
[12428]222 /** Number of logical CPUs in guest */
223 uint16_t cCpus;
[37237]224 uint64_t u64PmTimerInitial;
[37444]225 PTMTIMERR3 pPmTimerR3;
226 PTMTIMERR0 pPmTimerR0;
227 PTMTIMERRC pPmTimerRC;
[1]228
229 uint32_t gpe0_en;
230 uint32_t gpe0_sts;
231
[40019]232 uint32_t uBatteryIndex;
[1]233 uint32_t au8BatteryInfo[13];
234
[40019]235 uint32_t uSystemInfoIndex;
[1]236 uint64_t u64RamSize;
[17590]237 /** The number of bytes above 4GB. */
238 uint64_t cbRamHigh;
239 /** The number of bytes below 4GB. */
240 uint32_t cbRamLow;
[1]241
[32189]242 /** Current ACPI S* state. We support S0 and S5. */
[1]243 uint32_t uSleepState;
244 uint8_t au8RSDPPage[0x1000];
[4279]245 /** This is a workaround for incorrect index field handling by Intels ACPICA.
246 * The system info _INI method writes to offset 0x200. We either observe a
247 * write request to index 0x80 (in that case we don't change the index) or a
248 * write request to offset 0x200 (in that case we divide the index value by
249 * 4. Note that the _STA method is sometimes called prior to the _INI method
250 * (ACPI spec 6.3.7, _STA). See the special case for BAT_DEVICE_STATUS in
251 * acpiBatIndexWrite() for handling this. */
[1]252 uint8_t u8IndexShift;
[16247]253 /** provide an I/O-APIC */
[1]254 uint8_t u8UseIOApic;
[16247]255 /** provide a floppy controller */
256 bool fUseFdc;
[16211]257 /** If High Precision Event Timer device should be supported */
[16247]258 bool fUseHpet;
[16211]259 /** If System Management Controller device should be supported */
[16247]260 bool fUseSmc;
261 /** the guest handled the last power button event */
[6852]262 bool fPowerButtonHandled;
[16711]263 /** If ACPI CPU device should be shown */
264 bool fShowCpu;
[19007]265 /** If Real Time Clock ACPI object to be shown */
266 bool fShowRtc;
[21820]267 /** I/O port address of PM device. */
268 RTIOPORT uPmIoPortBase;
269 /** Flag whether the GC part of the device is enabled. */
270 bool fGCEnabled;
271 /** Flag whether the R0 part of the device is enabled. */
272 bool fR0Enabled;
[25817]273 /** Array of flags of attached CPUs */
[25838]274 VMCPUSET CpuSetAttached;
275 /** Which CPU to check for the locked status. */
276 uint32_t idCpuLockCheck;
[32189]277 /** Mask of locked CPUs (used by the guest). */
[25838]278 VMCPUSET CpuSetLocked;
[32189]279 /** The CPU event type. */
[26594]280 uint32_t u32CpuEventType;
[32189]281 /** The CPU id affected. */
[26594]282 uint32_t u32CpuEvent;
[32189]283 /** Flag whether CPU hot plugging is enabled. */
[25825]284 bool fCpuHotPlug;
[32591]285 /** If MCFG ACPI table shown to the guest */
286 bool fUseMcfg;
[32189]287 /** Primary NIC PCI address. */
[31519]288 uint32_t u32NicPciAddress;
[32189]289 /** Primary audio card PCI address. */
[31519]290 uint32_t u32AudioPciAddress;
[32189]291 /** Flag whether S1 power state is enabled. */
[31963]292 bool fS1Enabled;
[32189]293 /** Flag whether S4 power state is enabled. */
[31963]294 bool fS4Enabled;
[32189]295 /** Flag whether S1 triggers a state save. */
296 bool fSuspendToSavedState;
297 /** Flag whether to set WAK_STS on resume (restore included). */
298 bool fSetWakeupOnResume;
[32471]299 /** PCI address of the IO controller device. */
300 uint32_t u32IocPciAddress;
[32477]301 /** PCI address of the host bus controller device. */
302 uint32_t u32HbcPciAddress;
[32591]303 /* Physical address of PCI config space MMIO region */
304 uint64_t u64PciConfigMMioAddress;
[32637]305 /* Length of PCI config space MMIO region */
306 uint64_t u64PciConfigMMioLength;
[35746]307 /** Serial 0 IRQ number */
308 uint8_t uSerial0Irq;
309 /** Serial 1 IRQ number */
310 uint8_t uSerial1Irq;
311 /** Serial 0 IO port base */
312 RTIOPORT uSerial0IoPortBase;
313 /** Serial 1 IO port base */
314 RTIOPORT uSerial1IoPortBase;
[1]315 /** ACPI port base interface. */
316 PDMIBASE IBase;
317 /** ACPI port interface. */
318 PDMIACPIPORT IACPIPort;
319 /** Pointer to the device instance. */
[491]320 PPDMDEVINSR3 pDevIns;
[32189]321 /** Pointer to the driver base interface. */
[491]322 R3PTRTYPE(PPDMIBASE) pDrvBase;
[32189]323 /** Pointer to the driver connector interface. */
[491]324 R3PTRTYPE(PPDMIACPICONNECTOR) pDrv;
[21829]325
[32189]326 /** Pointer to default PCI config read function. */
[21820]327 R3PTRTYPE(PFNPCICONFIGREAD) pfnAcpiPciConfigRead;
[32189]328 /** Pointer to default PCI config write function. */
[21820]329 R3PTRTYPE(PFNPCICONFIGWRITE) pfnAcpiPciConfigWrite;
[40019]330
331 /** If custom table should be supported */
332 bool fUseCust;
333 /** ACPI OEM ID */
334 uint8_t au8OemId[6];
335 /** ACPI Crator ID */
336 uint8_t au8CreatorId[4];
337 /** ACPI Crator Rev */
338 uint32_t u32CreatorRev;
339 /** ACPI custom OEM Tab ID */
340 uint8_t au8OemTabId[8];
341 /** ACPI custom OEM Rev */
342 uint32_t u32OemRevision;
343 uint32_t Alignment0;
344
345 /** The custom table binary data. */
346 R3PTRTYPE(uint8_t *) pu8CustBin;
347 /** The size of the custom table binary. */
348 uint64_t cbCustBin;
[17572]349} ACPIState;
[1]350
351#pragma pack(1)
352
353/** Generic Address Structure (see ACPIspec 3.0, 5.2.3.1) */
354struct ACPIGENADDR
355{
356 uint8_t u8AddressSpaceId; /**< 0=sys, 1=IO, 2=PCICfg, 3=emb, 4=SMBus */
357 uint8_t u8RegisterBitWidth; /**< size in bits of the given register */
358 uint8_t u8RegisterBitOffset; /**< bit offset of register */
359 uint8_t u8AccessSize; /**< 1=byte, 2=word, 3=dword, 4=qword */
360 uint64_t u64Address; /**< 64-bit address of register */
361};
362AssertCompileSize(ACPIGENADDR, 12);
363
364/** Root System Description Pointer */
365struct ACPITBLRSDP
366{
367 uint8_t au8Signature[8]; /**< 'RSD PTR ' */
368 uint8_t u8Checksum; /**< checksum for the first 20 bytes */
369 uint8_t au8OemId[6]; /**< OEM-supplied identifier */
370 uint8_t u8Revision; /**< revision number, currently 2 */
371#define ACPI_REVISION 2 /**< ACPI 3.0 */
372 uint32_t u32RSDT; /**< phys addr of RSDT */
373 uint32_t u32Length; /**< bytes of this table */
374 uint64_t u64XSDT; /**< 64-bit phys addr of XSDT */
375 uint8_t u8ExtChecksum; /**< checksum of entire table */
376 uint8_t u8Reserved[3]; /**< reserved */
377};
378AssertCompileSize(ACPITBLRSDP, 36);
379
380/** System Description Table Header */
381struct ACPITBLHEADER
382{
383 uint8_t au8Signature[4]; /**< table identifier */
384 uint32_t u32Length; /**< length of the table including header */
385 uint8_t u8Revision; /**< revision number */
386 uint8_t u8Checksum; /**< all fields inclusive this add to zero */
387 uint8_t au8OemId[6]; /**< OEM-supplied string */
388 uint8_t au8OemTabId[8]; /**< to identify the particular data table */
389 uint32_t u32OemRevision; /**< OEM-supplied revision number */
390 uint8_t au8CreatorId[4]; /**< ID for the ASL compiler */
391 uint32_t u32CreatorRev; /**< revision for the ASL compiler */
392};
393AssertCompileSize(ACPITBLHEADER, 36);
394
395/** Root System Description Table */
396struct ACPITBLRSDT
397{
398 ACPITBLHEADER header;
399 uint32_t u32Entry[1]; /**< array of phys. addresses to other tables */
400};
401AssertCompileSize(ACPITBLRSDT, 40);
402
403/** Extended System Description Table */
404struct ACPITBLXSDT
405{
406 ACPITBLHEADER header;
407 uint64_t u64Entry[1]; /**< array of phys. addresses to other tables */
408};
409AssertCompileSize(ACPITBLXSDT, 44);
410
411/** Fixed ACPI Description Table */
412struct ACPITBLFADT
413{
414 ACPITBLHEADER header;
415 uint32_t u32FACS; /**< phys. address of FACS */
416 uint32_t u32DSDT; /**< phys. address of DSDT */
417 uint8_t u8IntModel; /**< was eleminated in ACPI 2.0 */
418#define INT_MODEL_DUAL_PIC 1 /**< for ACPI 2+ */
419#define INT_MODEL_MULTIPLE_APIC 2
420 uint8_t u8PreferredPMProfile; /**< preferred power management profile */
421 uint16_t u16SCIInt; /**< system vector the SCI is wired in 8259 mode */
422#define SCI_INT 9
423 uint32_t u32SMICmd; /**< system port address of SMI command port */
424#define SMI_CMD 0x0000442e
[33540]425 uint8_t u8AcpiEnable; /**< SMICmd val to disable ownership of ACPIregs */
[1]426#define ACPI_ENABLE 0xa1
[33540]427 uint8_t u8AcpiDisable; /**< SMICmd val to re-enable ownership of ACPIregs */
[1]428#define ACPI_DISABLE 0xa0
429 uint8_t u8S4BIOSReq; /**< SMICmd val to enter S4BIOS state */
430 uint8_t u8PStateCnt; /**< SMICmd val to assume processor performance
431 state control responsibility */
432 uint32_t u32PM1aEVTBLK; /**< port addr of PM1a event regs block */
433 uint32_t u32PM1bEVTBLK; /**< port addr of PM1b event regs block */
434 uint32_t u32PM1aCTLBLK; /**< port addr of PM1a control regs block */
435 uint32_t u32PM1bCTLBLK; /**< port addr of PM1b control regs block */
436 uint32_t u32PM2CTLBLK; /**< port addr of PM2 control regs block */
437 uint32_t u32PMTMRBLK; /**< port addr of PMTMR regs block */
438 uint32_t u32GPE0BLK; /**< port addr of gen-purp event 0 regs block */
439 uint32_t u32GPE1BLK; /**< port addr of gen-purp event 1 regs block */
440 uint8_t u8PM1EVTLEN; /**< bytes decoded by PM1a_EVT_BLK. >= 4 */
441 uint8_t u8PM1CTLLEN; /**< bytes decoded by PM1b_CNT_BLK. >= 2 */
442 uint8_t u8PM2CTLLEN; /**< bytes decoded by PM2_CNT_BLK. >= 1 or 0 */
443 uint8_t u8PMTMLEN; /**< bytes decoded by PM_TMR_BLK. ==4 */
444 uint8_t u8GPE0BLKLEN; /**< bytes decoded by GPE0_BLK. %2==0 */
445#define GPE0_BLK_LEN 2
446 uint8_t u8GPE1BLKLEN; /**< bytes decoded by GPE1_BLK. %2==0 */
447#define GPE1_BLK_LEN 0
448 uint8_t u8GPE1BASE; /**< offset of GPE1 based events */
449#define GPE1_BASE 0
450 uint8_t u8CSTCNT; /**< SMICmd val to indicate OS supp for C states */
451 uint16_t u16PLVL2LAT; /**< us to enter/exit C2. >100 => unsupported */
452#define P_LVL2_LAT 101 /**< C2 state not supported */
453 uint16_t u16PLVL3LAT; /**< us to enter/exit C3. >1000 => unsupported */
454#define P_LVL3_LAT 1001 /**< C3 state not supported */
455 uint16_t u16FlushSize; /**< # of flush strides to read to flush dirty
456 lines from any processors memory caches */
457#define FLUSH_SIZE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
458 uint16_t u16FlushStride; /**< cache line width */
459#define FLUSH_STRIDE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
460 uint8_t u8DutyOffset;
461 uint8_t u8DutyWidth;
462 uint8_t u8DayAlarm; /**< RTC CMOS RAM index of day-of-month alarm */
463 uint8_t u8MonAlarm; /**< RTC CMOS RAM index of month-of-year alarm */
464 uint8_t u8Century; /**< RTC CMOS RAM index of century */
465 uint16_t u16IAPCBOOTARCH; /**< IA-PC boot architecture flags */
[5605]466#define IAPC_BOOT_ARCH_LEGACY_DEV RT_BIT(0) /**< legacy devices present such as LPT
[1]467 (COM too?) */
[5605]468#define IAPC_BOOT_ARCH_8042 RT_BIT(1) /**< legacy keyboard device present */
469#define IAPC_BOOT_ARCH_NO_VGA RT_BIT(2) /**< VGA not present */
[26057]470 uint8_t u8Must0_0; /**< must be 0 */
471 uint32_t u32Flags; /**< fixed feature flags */
[5605]472#define FADT_FL_WBINVD RT_BIT(0) /**< emulation of WBINVD available */
473#define FADT_FL_WBINVD_FLUSH RT_BIT(1)
474#define FADT_FL_PROC_C1 RT_BIT(2) /**< 1=C1 supported on all processors */
475#define FADT_FL_P_LVL2_UP RT_BIT(3) /**< 1=C2 works on SMP and UNI systems */
476#define FADT_FL_PWR_BUTTON RT_BIT(4) /**< 1=power button handled as ctrl method dev */
477#define FADT_FL_SLP_BUTTON RT_BIT(5) /**< 1=sleep button handled as ctrl method dev */
478#define FADT_FL_FIX_RTC RT_BIT(6) /**< 0=RTC wake status in fixed register */
479#define FADT_FL_RTC_S4 RT_BIT(7) /**< 1=RTC can wake system from S4 */
480#define FADT_FL_TMR_VAL_EXT RT_BIT(8) /**< 1=TMR_VAL implemented as 32 bit */
481#define FADT_FL_DCK_CAP RT_BIT(9) /**< 0=system cannot support docking */
482#define FADT_FL_RESET_REG_SUP RT_BIT(10) /**< 1=system supports system resets */
483#define FADT_FL_SEALED_CASE RT_BIT(11) /**< 1=case is sealed */
484#define FADT_FL_HEADLESS RT_BIT(12) /**< 1=system cannot detect moni/keyb/mouse */
485#define FADT_FL_CPU_SW_SLP RT_BIT(13)
486#define FADT_FL_PCI_EXT_WAK RT_BIT(14) /**< 1=system supports PCIEXP_WAKE_STS */
487#define FADT_FL_USE_PLATFORM_CLOCK RT_BIT(15) /**< 1=system has ACPI PM timer */
488#define FADT_FL_S4_RTC_STS_VALID RT_BIT(16) /**< 1=RTC_STS flag is valid when waking from S4 */
489#define FADT_FL_REMOVE_POWER_ON_CAPABLE RT_BIT(17) /**< 1=platform can remote power on */
490#define FADT_FL_FORCE_APIC_CLUSTER_MODEL RT_BIT(18)
491#define FADT_FL_FORCE_APIC_PHYS_DEST_MODE RT_BIT(19)
[21334]492
493 /** Start of the ACPI 2.0 extension. */
[1]494 ACPIGENADDR ResetReg; /**< ext addr of reset register */
495 uint8_t u8ResetVal; /**< ResetReg value to reset the system */
496#define ACPI_RESET_REG_VAL 0x10
497 uint8_t au8Must0_1[3]; /**< must be 0 */
498 uint64_t u64XFACS; /**< 64-bit phys address of FACS */
499 uint64_t u64XDSDT; /**< 64-bit phys address of DSDT */
500 ACPIGENADDR X_PM1aEVTBLK; /**< ext addr of PM1a event regs block */
501 ACPIGENADDR X_PM1bEVTBLK; /**< ext addr of PM1b event regs block */
502 ACPIGENADDR X_PM1aCTLBLK; /**< ext addr of PM1a control regs block */
503 ACPIGENADDR X_PM1bCTLBLK; /**< ext addr of PM1b control regs block */
504 ACPIGENADDR X_PM2CTLBLK; /**< ext addr of PM2 control regs block */
505 ACPIGENADDR X_PMTMRBLK; /**< ext addr of PMTMR control regs block */
506 ACPIGENADDR X_GPE0BLK; /**< ext addr of GPE1 regs block */
507 ACPIGENADDR X_GPE1BLK; /**< ext addr of GPE1 regs block */
508};
509AssertCompileSize(ACPITBLFADT, 244);
[21334]510#define ACPITBLFADT_VERSION1_SIZE RT_OFFSETOF(ACPITBLFADT, ResetReg)
[1]511
512/** Firmware ACPI Control Structure */
513struct ACPITBLFACS
514{
515 uint8_t au8Signature[4]; /**< 'FACS' */
516 uint32_t u32Length; /**< bytes of entire FACS structure >= 64 */
517 uint32_t u32HWSignature; /**< systems HW signature at last boot */
518 uint32_t u32FWVector; /**< address of waking vector */
519 uint32_t u32GlobalLock; /**< global lock to sync HW/SW */
520 uint32_t u32Flags; /**< FACS flags */
521 uint64_t u64X_FWVector; /**< 64-bit waking vector */
522 uint8_t u8Version; /**< version of this table */
523 uint8_t au8Reserved[31]; /**< zero */
524};
525AssertCompileSize(ACPITBLFACS, 64);
526
527/** Processor Local APIC Structure */
528struct ACPITBLLAPIC
529{
530 uint8_t u8Type; /**< 0 = LAPIC */
531 uint8_t u8Length; /**< 8 */
532 uint8_t u8ProcId; /**< processor ID */
533 uint8_t u8ApicId; /**< local APIC ID */
534 uint32_t u32Flags; /**< Flags */
535#define LAPIC_ENABLED 0x1
536};
537AssertCompileSize(ACPITBLLAPIC, 8);
538
539/** I/O APIC Structure */
540struct ACPITBLIOAPIC
541{
542 uint8_t u8Type; /**< 1 == I/O APIC */
543 uint8_t u8Length; /**< 12 */
544 uint8_t u8IOApicId; /**< I/O APIC ID */
545 uint8_t u8Reserved; /**< 0 */
546 uint32_t u32Address; /**< phys address to access I/O APIC */
547 uint32_t u32GSIB; /**< global system interrupt number to start */
548};
549AssertCompileSize(ACPITBLIOAPIC, 12);
550
[26939]551/** Interrupt Source Override Structure */
552struct ACPITBLISO
553{
554 uint8_t u8Type; /**< 2 == Interrupt Source Override*/
555 uint8_t u8Length; /**< 10 */
556 uint8_t u8Bus; /**< Bus */
557 uint8_t u8Source; /**< Bus-relative interrupt source (IRQ) */
558 uint32_t u32GSI; /**< Global System Interrupt */
559 uint16_t u16Flags; /**< MPS INTI flags Global */
560};
561AssertCompileSize(ACPITBLISO, 10);
[34035]562#define NUMBER_OF_IRQ_SOURCE_OVERRIDES 2
[25928]563
[26057]564/** HPET Descriptor Structure */
[25928]565struct ACPITBLHPET
566{
567 ACPITBLHEADER aHeader;
[26057]568 uint32_t u32Id; /**< hardware ID of event timer block
569 [31:16] PCI vendor ID of first timer block
570 [15] legacy replacement IRQ routing capable
571 [14] reserved
572 [13] COUNT_SIZE_CAP counter size
[26157]573 [12:8] number of comparators in first timer block
[26057]574 [7:0] hardware rev ID */
575 ACPIGENADDR HpetAddr; /**< lower 32-bit base address */
576 uint8_t u32Number; /**< sequence number starting at 0 */
577 uint16_t u32MinTick; /**< minimum clock ticks which can be set without
578 lost interrupts while the counter is programmed
579 to operate in periodic mode. Unit: clock tick. */
[33540]580 uint8_t u8Attributes; /**< page protection and OEM attribute. */
[25928]581};
[26057]582AssertCompileSize(ACPITBLHPET, 56);
[25928]583
[32591]584/** MCFG Descriptor Structure */
[32825]585typedef struct ACPITBLMCFG
[32591]586{
587 ACPITBLHEADER aHeader;
588 uint64_t u64Reserved;
[32825]589} ACPITBLMCFG;
[32591]590AssertCompileSize(ACPITBLMCFG, 44);
591
[32825]592/** Number of such entries can be computed from the whole table length in header */
593typedef struct ACPITBLMCFGENTRY
[32591]594{
595 uint64_t u64BaseAddress;
596 uint16_t u16PciSegmentGroup;
597 uint8_t u8StartBus;
598 uint8_t u8EndBus;
599 uint32_t u32Reserved;
[32825]600} ACPITBLMCFGENTRY;
[32591]601AssertCompileSize(ACPITBLMCFGENTRY, 16);
602
[21829]603# ifdef IN_RING3 /** @todo r=bird: Move this down to where it's used. */
[12428]604
[17572]605# define PCAT_COMPAT 0x1 /**< system has also a dual-8259 setup */
[12428]606
[40019]607/** Custom Description Table */
608struct ACPITBLCUST
609{
610 ACPITBLHEADER header;
611 uint8_t au8Data[476];
612};
613AssertCompileSize(ACPITBLCUST, 512);
614
[12431]615/**
616 * Multiple APIC Description Table.
617 *
[12428]618 * This structure looks somewhat convoluted due layout of MADT table in MP case.
[12431]619 * There extpected to be multiple LAPIC records for each CPU, thus we cannot
[12428]620 * use regular C structure and proxy to raw memory instead.
621 */
[12431]622class AcpiTableMADT
[12428]623{
[12431]624 /**
[12428]625 * All actual data stored in dynamically allocated memory pointed by this field.
626 */
[17572]627 uint8_t *m_pbData;
[12431]628 /**
[12428]629 * Number of CPU entries in this MADT.
630 */
[17572]631 uint32_t m_cCpus;
[12431]632
[26939]633 /**
634 * Number of interrupt overrides.
635 */
636 uint32_t m_cIsos;
637
[17572]638public:
[12431]639 /**
[12428]640 * Address of ACPI header
641 */
[17572]642 inline ACPITBLHEADER *header_addr(void) const
[12428]643 {
[17572]644 return (ACPITBLHEADER *)m_pbData;
[12428]645 }
[12431]646
647 /**
[12428]648 * Address of local APIC for each CPU. Note that different CPUs address different LAPICs,
649 * although address is the same for all of them.
650 */
[17572]651 inline uint32_t *u32LAPIC_addr(void) const
[12428]652 {
[17572]653 return (uint32_t *)(header_addr() + 1);
[12428]654 }
[12431]655
656 /**
[12428]657 * Address of APIC flags
658 */
[17572]659 inline uint32_t *u32Flags_addr(void) const
[12428]660 {
[17572]661 return (uint32_t *)(u32LAPIC_addr() + 1);
[12428]662 }
[12431]663
664 /**
[26939]665 * Address of ISO description
666 */
667 inline ACPITBLISO *ISO_addr(void) const
668 {
669 return (ACPITBLISO *)(u32Flags_addr() + 1);
670 }
671
672 /**
[12428]673 * Address of per-CPU LAPIC descriptions
674 */
[17572]675 inline ACPITBLLAPIC *LApics_addr(void) const
[12428]676 {
[26939]677 return (ACPITBLLAPIC *)(ISO_addr() + m_cIsos);
[12428]678 }
679
[12431]680 /**
[12428]681 * Address of IO APIC description
682 */
[17572]683 inline ACPITBLIOAPIC *IOApic_addr(void) const
[12428]684 {
[17572]685 return (ACPITBLIOAPIC *)(LApics_addr() + m_cCpus);
[12428]686 }
687
[12431]688 /**
[12428]689 * Size of MADT.
690 * Note that this function assumes IOApic to be the last field in structure.
691 */
[17572]692 inline uint32_t size(void) const
[12428]693 {
[17572]694 return (uint8_t *)(IOApic_addr() + 1) - (uint8_t *)header_addr();
[12428]695 }
696
[12431]697 /**
[12428]698 * Raw data of MADT.
699 */
[17572]700 inline const uint8_t *data(void) const
[12428]701 {
[17572]702 return m_pbData;
[12428]703 }
704
[12431]705 /**
[12428]706 * Size of MADT for given ACPI config, useful to compute layout.
707 */
[37446]708 static uint32_t sizeFor(ACPIState *pThis, uint32_t cIsos)
[12428]709 {
[37446]710 return AcpiTableMADT(pThis->cCpus, cIsos).size();
[12428]711 }
712
713 /*
714 * Constructor, only works in Ring 3, doesn't look like a big deal.
715 */
[26939]716 AcpiTableMADT(uint32_t cCpus, uint32_t cIsos)
[12428]717 {
[24669]718 m_cCpus = cCpus;
[26939]719 m_cIsos = cIsos;
[33540]720 m_pbData = NULL; /* size() uses this and gcc will complain if not initialized. */
[17572]721 uint32_t cb = size();
722 m_pbData = (uint8_t *)RTMemAllocZ(cb);
[12428]723 }
724
[12431]725 ~AcpiTableMADT()
[12428]726 {
[17572]727 RTMemFree(m_pbData);
[12428]728 }
729};
[17572]730# endif /* IN_RING3 */
[12431]731
[1]732#pragma pack()
733
[491]734
[17572]735#ifndef VBOX_DEVICE_STRUCT_TESTCASE /* exclude the rest of the file */
736/*******************************************************************************
737* Internal Functions *
738*******************************************************************************/
[20374]739RT_C_DECLS_BEGIN
[37444]740PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
741RT_C_DECLS_END
[1]742#ifdef IN_RING3
[37446]743static int acpiPlantTables(ACPIState *pThis);
[37444]744#endif
[1]745
746#ifdef IN_RING3
747
748/* SCI IRQ */
[37446]749DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
[1]750{
[37446]751 if (pThis->pm1a_ctl & SCI_EN)
752 PDMDevHlpPCISetIrq(pThis->pDevIns, -1, level);
[1]753}
754
[17572]755DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
[1]756{
757 return en & ~(RSR_EN | IGN_EN);
758}
759
[17572]760DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
[1]761{
762 return sts & ~(RSR_STS | IGN_STS);
763}
764
[37446]765DECLINLINE(int) pm1a_level(ACPIState *pThis)
[1]766{
[37446]767 return (pm1a_pure_en(pThis->pm1a_en) & pm1a_pure_sts(pThis->pm1a_sts)) != 0;
[1]768}
769
[37446]770DECLINLINE(int) gpe0_level(ACPIState *pThis)
[1]771{
[37446]772 return (pThis->gpe0_en & pThis->gpe0_sts) != 0;
[1]773}
774
[37444]775/**
776 * Used by acpiPM1aStsWrite, acpiPM1aEnWrite, acpiPmTimer,
777 * acpiPort_PowerBuffonPress and acpiPort_SleepButtonPress to
778 * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
779 *
780 * Caller must hold the state lock.
781 *
782 * @param pThis The ACPI instance.
783 * @param sts The new GPE0.STS value.
784 * @param en The new GPE0.EN value.
785 */
786static void update_pm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
[1]787{
[37444]788 Assert(PDMCritSectIsOwner(&pThis->CritSect));
[1]789
[37444]790 if (gpe0_level(pThis))
[1]791 return;
792
[37444]793 int const old_level = pm1a_level(pThis);
794 int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
[1]795
[34035]796 Log(("update_pm1a() old=%x new=%x\n", old_level, new_level));
797
[37444]798 pThis->pm1a_en = en;
799 pThis->pm1a_sts = sts;
[1]800
801 if (new_level != old_level)
[37444]802 acpiSetIrq(pThis, new_level);
[1]803}
804
[37444]805/**
806 * Used by acpiGpe0StsWrite, acpiGpe0EnWrite, acpiAttach and acpiDetach to
807 * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
808 *
809 * Caller must hold the state lock.
810 *
811 * @param pThis The ACPI instance.
812 * @param sts The new GPE0.STS value.
813 * @param en The new GPE0.EN value.
814 */
815static void update_gpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
[1]816{
[37444]817 Assert(PDMCritSectIsOwner(&pThis->CritSect));
[1]818
[37444]819 if (pm1a_level(pThis))
[1]820 return;
821
[37444]822 int const old_level = (pThis->gpe0_en & pThis->gpe0_sts) != 0;
823 int const new_level = (en & sts) != 0;
[1]824
[37444]825 pThis->gpe0_en = en;
826 pThis->gpe0_sts = sts;
[1]827
828 if (new_level != old_level)
[37444]829 acpiSetIrq(pThis, new_level);
[1]830}
831
[37444]832/**
833 * Used by acpiPM1aCtlWrite to power off the VM.
834 *
835 * @param pThis The ACPI instance.
836 * @returns Strict VBox status code.
837 */
838static int acpiPowerOff(ACPIState *pThis)
[1]839{
[37444]840 int rc = PDMDevHlpVMPowerOff(pThis->pDevIns);
[17572]841 if (RT_FAILURE(rc))
842 AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
[1]843 return rc;
844}
845
[37444]846/**
847 * Used by acpiPM1aCtlWrite to put the VM to sleep.
848 *
849 * @param pThis The ACPI instance.
850 * @returns Strict VBox status code.
851 */
[32189]852static int acpiSleep(ACPIState *pThis)
[31963]853{
[32189]854 /* We must set WAK_STS on resume (includes restore) so the guest knows that
855 we've woken up and can continue executing code. The guest is probably
856 reading the PMSTS register in a loop to check this. */
[37444]857 int rc;
[32189]858 pThis->fSetWakeupOnResume = true;
859 if (pThis->fSuspendToSavedState)
860 {
861 rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
[32190]862 if (rc != VERR_NOT_SUPPORTED)
863 AssertRC(rc);
864 else
865 {
866 LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
867 rc = PDMDevHlpVMSuspend(pThis->pDevIns);
868 AssertRC(rc);
869 }
[31963]870 }
[32189]871 else
872 {
873 rc = PDMDevHlpVMSuspend(pThis->pDevIns);
874 AssertRC(rc);
875 }
[31963]876 return rc;
877}
878
[1]879
880/**
[37444]881 * @interface_method_impl{PDMIACPIPORT,pfnPowerButtonPress}
[1]882 */
[37444]883static DECLCALLBACK(int) acpiPort_PowerButtonPress(PPDMIACPIPORT pInterface)
[1]884{
[37444]885 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
886 DEVACPI_LOCK_R3(pThis);
887
888 Log(("acpiPort_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
889 pThis->fPowerButtonHandled = false;
890 update_pm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
891
892 DEVACPI_UNLOCK(pThis);
[1]893 return VINF_SUCCESS;
894}
895
[13079]896/**
[37444]897 * @interface_method_impl{PDMIACPIPORT,pfnGetPowerButtonHandled}
[13079]898 */
[37444]899static DECLCALLBACK(int) acpiPort_GetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
[6852]900{
[37444]901 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
902 DEVACPI_LOCK_R3(pThis);
903
904 *pfHandled = pThis->fPowerButtonHandled;
905
906 DEVACPI_UNLOCK(pThis);
[6852]907 return VINF_SUCCESS;
908}
909
[6156]910/**
[37444]911 * @interface_method_impl{PDMIACPIPORT,pfnGetGuestEnteredACPIMode, Check if the
912 * Guest entered into G0 (working) or G1 (sleeping)}
[13079]913 */
[37444]914static DECLCALLBACK(int) acpiPort_GetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
[13079]915{
[37444]916 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
917 DEVACPI_LOCK_R3(pThis);
918
919 *pfEntered = (pThis->pm1a_ctl & SCI_EN) != 0;
920
921 DEVACPI_UNLOCK(pThis);
[13079]922 return VINF_SUCCESS;
923}
924
[37444]925/**
926 * @interface_method_impl{PDMIACPIPORT,pfnGetCpuStatus}
927 */
928static DECLCALLBACK(int) acpiPort_GetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
[25817]929{
[37444]930 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
931 DEVACPI_LOCK_R3(pThis);
932
933 *pfLocked = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, uCpu);
934
935 DEVACPI_UNLOCK(pThis);
[25817]936 return VINF_SUCCESS;
937}
938
[13079]939/**
[6156]940 * Send an ACPI sleep button event.
941 *
942 * @returns VBox status code
943 * @param pInterface Pointer to the interface structure containing the called function pointer.
944 */
[37444]945static DECLCALLBACK(int) acpiPort_SleepButtonPress(PPDMIACPIPORT pInterface)
[6156]946{
[37444]947 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
948 DEVACPI_LOCK_R3(pThis);
[6156]949
[37444]950 update_pm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
[1]951
[37444]952 DEVACPI_UNLOCK(pThis);
[1]953 return VINF_SUCCESS;
954}
955
[37444]956/**
957 * Used by acpiPmTimer to re-arm the PM timer.
958 *
959 * The caller is expected to either hold the clock lock or to have made sure
960 * the VM is resetting or loading state.
961 *
962 * @param pThis The ACPI instance.
963 * @param uNow The current time.
964 */
965static void acpiPmTimerReset(ACPIState *pThis, uint64_t uNow)
[1]966{
[37444]967 uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
968 uint64_t uInterval = ASMMultU64ByU32DivByU32(0xffffffff, uTimerFreq, PM_TMR_FREQ);
969 TMTimerSet(pThis->pPmTimerR3, uNow + uInterval);
970 Log(("acpi: uInterval = %RU64\n", uInterval));
[1]971}
972
[37444]973/**
974 * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
975 */
976static DECLCALLBACK(void) acpiPmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
[1]977{
[37444]978 ACPIState *pThis = (ACPIState *)pvUser;
[39091]979 Assert(TMTimerIsLockOwner(pTimer));
980 NOREF(pDevIns);
[1]981
[37444]982 DEVACPI_LOCK_R3(pThis);
[17572]983 Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
[37444]984 pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
985 pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
986 update_pm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
987 DEVACPI_UNLOCK(pThis);
[1]988
[39091]989 acpiPmTimerReset(pThis, TMTimerGet(pTimer));
[1]990}
991
992/**
[37444]993 * _BST method - used by acpiBatDataRead to implement BAT_STATUS_STATE and
994 * acpiLoadState.
995 *
996 * @returns VINF_SUCCESS.
997 * @param pThis The ACPI instance.
[1]998 */
[37444]999static int acpiFetchBatteryStatus(ACPIState *pThis)
[1]1000{
[37444]1001 uint32_t *p = pThis->au8BatteryInfo;
[1]1002 bool fPresent; /* battery present? */
1003 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1004 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1005 uint32_t hostPresentRate; /* 0..1000 */
1006 int rc;
1007
[37444]1008 if (!pThis->pDrv)
[21820]1009 return VINF_SUCCESS;
[37444]1010 rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
1011 &hostBatteryState, &hostPresentRate);
[17572]1012 AssertRC(rc);
[1]1013
1014 /* default values */
1015 p[BAT_STATUS_STATE] = hostBatteryState;
1016 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
1017 : hostPresentRate * 50; /* mW */
1018 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
1019 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
1020
1021 /* did we get a valid battery state? */
1022 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
1023 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
1024 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
1025 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
[21820]1026
1027 return VINF_SUCCESS;
[1]1028}
1029
1030/**
[37444]1031 * _BIF method - used by acpiBatDataRead to implement BAT_INFO_UNITS and
1032 * acpiLoadState.
1033 *
1034 * @returns VINF_SUCCESS.
1035 * @param pThis The ACPI instance.
[1]1036 */
[37444]1037static int acpiFetchBatteryInfo(ACPIState *pThis)
[1]1038{
[37444]1039 uint32_t *p = pThis->au8BatteryInfo;
[1]1040
1041 p[BAT_INFO_UNITS] = 0; /* mWh */
1042 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
1043 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
1044 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
1045 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
1046 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
1047 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
1048 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
1049 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
[21820]1050
1051 return VINF_SUCCESS;
[1]1052}
1053
1054/**
[37444]1055 * The _STA method - used by acpiBatDataRead to implement BAT_DEVICE_STATUS.
1056 *
1057 * @returns status mask or 0.
1058 * @param pThis The ACPI instance.
[1]1059 */
[37444]1060static uint32_t acpiGetBatteryDeviceStatus(ACPIState *pThis)
[1]1061{
1062 bool fPresent; /* battery present? */
1063 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1064 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1065 uint32_t hostPresentRate; /* 0..1000 */
1066 int rc;
1067
[37444]1068 if (!pThis->pDrv)
[4195]1069 return 0;
[37444]1070 rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
1071 &hostBatteryState, &hostPresentRate);
[17572]1072 AssertRC(rc);
[1]1073
1074 return fPresent
1075 ? STA_DEVICE_PRESENT_MASK /* present */
1076 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1077 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1078 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1079 | STA_BATTERY_PRESENT_MASK /* battery is present */
1080 : 0; /* device not present */
1081}
1082
[37444]1083/**
1084 * Used by acpiBatDataRead to implement BAT_POWER_SOURCE.
1085 *
1086 * @returns status.
1087 * @param pThis The ACPI instance.
1088 */
1089static uint32_t acpiGetPowerSource(ACPIState *pThis)
[1]1090{
1091 /* query the current power source from the host driver */
[37444]1092 if (!pThis->pDrv)
[4195]1093 return AC_ONLINE;
[37444]1094
1095 PDMACPIPOWERSOURCE ps;
1096 int rc = pThis->pDrv->pfnQueryPowerSource(pThis->pDrv, &ps);
[17572]1097 AssertRC(rc);
[1]1098 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1099}
1100
[37444]1101/**
1102 * @callback_method_impl{FNIOMIOPORTOUT, Battery status index}
1103 */
[17572]1104PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1105{
[37444]1106 Log(("acpiBatIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
1107 if (cb != 4)
1108 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
[1]1109
[37444]1110 ACPIState *pThis = (ACPIState *)pvUser;
1111 DEVACPI_LOCK_R3(pThis);
1112
1113 u32 >>= pThis->u8IndexShift;
1114 /* see comment at the declaration of u8IndexShift */
1115 if (pThis->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
[1]1116 {
[37444]1117 pThis->u8IndexShift = 2;
1118 u32 >>= 2;
[1]1119 }
[37444]1120 Assert(u32 < BAT_INDEX_LAST);
1121 pThis->uBatteryIndex = u32;
1122
1123 DEVACPI_UNLOCK(pThis);
[1]1124 return VINF_SUCCESS;
1125}
1126
[37444]1127/**
1128 * @callback_method_impl{FNIOMIOPORTIN, Battery status data}
1129 */
[17572]1130PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1131{
[37444]1132 if (cb != 4)
1133 return VERR_IOM_IOPORT_UNUSED;
[1]1134
[37444]1135 ACPIState *pThis = (ACPIState *)pvUser;
1136 DEVACPI_LOCK_R3(pThis);
1137
1138 int rc = VINF_SUCCESS;
1139 switch (pThis->uBatteryIndex)
[1]1140 {
[37444]1141 case BAT_STATUS_STATE:
1142 acpiFetchBatteryStatus(pThis);
1143 /* fall thru */
1144 case BAT_STATUS_PRESENT_RATE:
1145 case BAT_STATUS_REMAINING_CAPACITY:
1146 case BAT_STATUS_PRESENT_VOLTAGE:
1147 *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
1148 break;
[1]1149
[37444]1150 case BAT_INFO_UNITS:
1151 acpiFetchBatteryInfo(pThis);
1152 /* fall thru */
1153 case BAT_INFO_DESIGN_CAPACITY:
1154 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1155 case BAT_INFO_TECHNOLOGY:
1156 case BAT_INFO_DESIGN_VOLTAGE:
1157 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1158 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1159 case BAT_INFO_CAPACITY_GRANULARITY_1:
1160 case BAT_INFO_CAPACITY_GRANULARITY_2:
1161 *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
1162 break;
[1]1163
[37444]1164 case BAT_DEVICE_STATUS:
1165 *pu32 = acpiGetBatteryDeviceStatus(pThis);
1166 break;
[1]1167
[37444]1168 case BAT_POWER_SOURCE:
1169 *pu32 = acpiGetPowerSource(pThis);
1170 break;
[1]1171
[37444]1172 default:
1173 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
1174 *pu32 = UINT32_MAX;
[1]1175 break;
1176 }
[37444]1177
1178 DEVACPI_UNLOCK(pThis);
1179 return rc;
[1]1180}
1181
[37444]1182/**
1183 * @callback_method_impl{FNIOMIOPORTOUT, System info index}
1184 */
[17572]1185PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1186{
[37444]1187 Log(("acpiSysInfoIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
1188 if (cb != 4)
1189 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
[1]1190
[37444]1191 ACPIState *pThis = (ACPIState *)pvUser;
1192 DEVACPI_LOCK_R3(pThis);
1193
1194 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1195 pThis->uSystemInfoIndex = u32;
1196 else
[17572]1197 {
[37444]1198 /* see comment at the declaration of u8IndexShift */
1199 if (u32 > SYSTEM_INFO_INDEX_END && pThis->u8IndexShift == 0)
1200 {
1201 if ((u32 >> 2) < SYSTEM_INFO_INDEX_END && (u32 & 0x3) == 0)
1202 pThis->u8IndexShift = 2;
1203 }
[17572]1204
[37444]1205 u32 >>= pThis->u8IndexShift;
1206 Assert(u32 < SYSTEM_INFO_INDEX_END);
1207 pThis->uSystemInfoIndex = u32;
1208 }
[16170]1209
[37444]1210 DEVACPI_UNLOCK(pThis);
[1]1211 return VINF_SUCCESS;
1212}
1213
[37444]1214/**
1215 * @callback_method_impl{FNIOMIOPORTIN, System info data}
1216 */
[17572]1217PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1218{
[37444]1219 if (cb != 4)
1220 return VERR_IOM_IOPORT_UNUSED;
[16042]1221
[37444]1222 ACPIState *pThis = (ACPIState *)pvUser;
1223 DEVACPI_LOCK_R3(pThis);
1224
1225 int rc = VINF_SUCCESS;
[40019]1226 uint32_t const uSystemInfoIndex = pThis->uSystemInfoIndex;
[37444]1227 switch (uSystemInfoIndex)
[1]1228 {
[37444]1229 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
1230 *pu32 = pThis->cbRamLow;
1231 break;
[1]1232
[37444]1233 case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
1234 *pu32 = pThis->cbRamHigh >> 16; /* 64KB units */
1235 Assert(((uint64_t)*pu32 << 16) == pThis->cbRamHigh);
1236 break;
[17590]1237
[37444]1238 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1239 *pu32 = pThis->u8UseIOApic;
1240 break;
[16170]1241
[37444]1242 case SYSTEM_INFO_INDEX_HPET_STATUS:
1243 *pu32 = pThis->fUseHpet
1244 ? ( STA_DEVICE_PRESENT_MASK
1245 | STA_DEVICE_ENABLED_MASK
1246 | STA_DEVICE_SHOW_IN_UI_MASK
1247 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1248 : 0;
1249 break;
[16170]1250
[37444]1251 case SYSTEM_INFO_INDEX_SMC_STATUS:
1252 *pu32 = pThis->fUseSmc
1253 ? ( STA_DEVICE_PRESENT_MASK
1254 | STA_DEVICE_ENABLED_MASK
1255 /* no need to show this device in the UI */
1256 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1257 : 0;
1258 break;
[16170]1259
[37444]1260 case SYSTEM_INFO_INDEX_FDC_STATUS:
1261 *pu32 = pThis->fUseFdc
1262 ? ( STA_DEVICE_PRESENT_MASK
1263 | STA_DEVICE_ENABLED_MASK
1264 | STA_DEVICE_SHOW_IN_UI_MASK
1265 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1266 : 0;
1267 break;
[20087]1268
[37444]1269 case SYSTEM_INFO_INDEX_NIC_ADDRESS:
1270 *pu32 = pThis->u32NicPciAddress;
1271 break;
[28487]1272
[37444]1273 case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
1274 *pu32 = pThis->u32AudioPciAddress;
1275 break;
[31519]1276
[37444]1277 case SYSTEM_INFO_INDEX_POWER_STATES:
1278 *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
1279 if (pThis->fS1Enabled) /* Optionally expose S1 and S4 */
1280 *pu32 |= RT_BIT(1);
1281 if (pThis->fS4Enabled)
1282 *pu32 |= RT_BIT(4);
1283 break;
[31963]1284
[37444]1285 case SYSTEM_INFO_INDEX_IOC_ADDRESS:
1286 *pu32 = pThis->u32IocPciAddress;
1287 break;
[32471]1288
[37444]1289 case SYSTEM_INFO_INDEX_HBC_ADDRESS:
1290 *pu32 = pThis->u32HbcPciAddress;
1291 break;
[32477]1292
[37444]1293 case SYSTEM_INFO_INDEX_PCI_BASE:
1294 /** @todo couldn't MCFG be in 64-bit range? */
1295 Assert(pThis->u64PciConfigMMioAddress < 0xffffffff);
1296 *pu32 = (uint32_t)pThis->u64PciConfigMMioAddress;
1297 break;
[32637]1298
[37444]1299 case SYSTEM_INFO_INDEX_PCI_LENGTH:
1300 /** @todo couldn't MCFG be in 64-bit range? */
1301 Assert(pThis->u64PciConfigMMioLength< 0xffffffff);
1302 *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
1303 break;
[32637]1304
[37444]1305 /* This is only for compatibility with older saved states that
1306 may include ACPI code that read these values. Legacy is
1307 a wonderful thing, isn't it? :-) */
1308 case SYSTEM_INFO_INDEX_CPU0_STATUS:
1309 case SYSTEM_INFO_INDEX_CPU1_STATUS:
1310 case SYSTEM_INFO_INDEX_CPU2_STATUS:
1311 case SYSTEM_INFO_INDEX_CPU3_STATUS:
1312 *pu32 = ( pThis->fShowCpu
1313 && pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < pThis->cCpus
1314 && VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached,
1315 pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS) )
1316 ? ( STA_DEVICE_PRESENT_MASK
1317 | STA_DEVICE_ENABLED_MASK
1318 | STA_DEVICE_SHOW_IN_UI_MASK
1319 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1320 : 0;
1321 break;
[27666]1322
[37444]1323 case SYSTEM_INFO_INDEX_RTC_STATUS:
1324 *pu32 = pThis->fShowRtc
1325 ? ( STA_DEVICE_PRESENT_MASK
1326 | STA_DEVICE_ENABLED_MASK
1327 | STA_DEVICE_SHOW_IN_UI_MASK
1328 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1329 : 0;
1330 break;
[19007]1331
[37444]1332 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1333 if (pThis->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1334 {
1335 *pu32 = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, pThis->idCpuLockCheck);
1336 pThis->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1337 }
1338 else
1339 {
1340 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "CPU lock check protocol violation (idCpuLockCheck=%#x)\n",
1341 pThis->idCpuLockCheck);
1342 /* Always return locked status just to be safe */
1343 *pu32 = 1;
1344 }
1345 break;
[25817]1346
[37444]1347 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1348 *pu32 = pThis->u32CpuEventType;
1349 break;
[26594]1350
[37444]1351 case SYSTEM_INFO_INDEX_CPU_EVENT:
1352 *pu32 = pThis->u32CpuEvent;
1353 break;
[26594]1354
[37444]1355 case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
1356 *pu32 = pThis->uSerial0IoPortBase;
1357 break;
[35746]1358
[37444]1359 case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
1360 *pu32 = pThis->uSerial0Irq;
1361 break;
[35746]1362
[37444]1363 case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
1364 *pu32 = pThis->uSerial1IoPortBase;
1365 break;
[35746]1366
[37444]1367 case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
1368 *pu32 = pThis->uSerial1Irq;
1369 break;
[35746]1370
[37444]1371 case SYSTEM_INFO_INDEX_END:
1372 /** @todo why isn't this setting any output value? */
1373 break;
[35746]1374
[37444]1375 /* Solaris 9 tries to read from this index */
1376 case SYSTEM_INFO_INDEX_INVALID:
1377 *pu32 = 0;
[1]1378 break;
1379
1380 default:
[37444]1381 *pu32 = UINT32_MAX;
1382 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
1383 break;
[1]1384 }
1385
[37444]1386 DEVACPI_UNLOCK(pThis);
1387 Log(("acpiSysInfoDataRead: idx=%d val=%#x (%d) rc=%Rrc\n", uSystemInfoIndex, *pu32, *pu32, rc));
1388 return rc;
[1]1389}
1390
[37444]1391/**
1392 * @callback_method_impl{FNIOMIOPORTOUT, System info data}
1393 */
[17572]1394PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1395{
[37444]1396 ACPIState *pThis = (ACPIState *)pvUser;
1397 if (cb != 4)
1398 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
[1]1399
[37444]1400 DEVACPI_LOCK_R3(pThis);
1401 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, pThis->uSystemInfoIndex));
[1]1402
[37444]1403 int rc = VINF_SUCCESS;
1404 switch (pThis->uSystemInfoIndex)
[1]1405 {
[37444]1406 case SYSTEM_INFO_INDEX_INVALID:
1407 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1408 pThis->u8IndexShift = 0;
1409 break;
[1]1410
[37444]1411 case SYSTEM_INFO_INDEX_VALID:
1412 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1413 pThis->u8IndexShift = 2;
1414 break;
[1]1415
[37444]1416 case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
1417 pThis->idCpuLockCheck = u32;
1418 break;
[26057]1419
[37444]1420 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1421 if (u32 < pThis->cCpus)
1422 VMCPUSET_DEL(&pThis->CpuSetLocked, u32); /* Unlock the CPU */
1423 else
1424 LogRel(("ACPI: CPU %u does not exist\n", u32));
1425 break;
[25817]1426
[37444]1427 default:
1428 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
1429 break;
[1]1430 }
[37444]1431
1432 DEVACPI_UNLOCK(pThis);
1433 return rc;
[1]1434}
1435
[37444]1436/**
1437 * @callback_method_impl{FNIOMIOPORTIN, PM1a Enable}
1438 */
[17572]1439PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1440{
[39091]1441 NOREF(pDevIns); NOREF(Port);
[37444]1442 if (cb != 2)
1443 return VERR_IOM_IOPORT_UNUSED;
1444
1445 ACPIState *pThis = (ACPIState *)pvUser;
1446 DEVACPI_LOCK_R3(pThis);
1447
1448 *pu32 = pThis->pm1a_en;
1449
1450 DEVACPI_UNLOCK(pThis);
1451 Log(("acpiPm1aEnRead -> %#x\n", *pu32));
[1]1452 return VINF_SUCCESS;
1453}
1454
[37444]1455/**
1456 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Enable}
1457 */
1458PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1459{
[37444]1460 if (cb != 2 && cb != 4)
1461 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1462
1463 ACPIState *pThis = (ACPIState *)pvUser;
1464 DEVACPI_LOCK_R3(pThis);
1465
1466 Log(("acpiPM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
1467 u32 &= ~(RSR_EN | IGN_EN);
1468 u32 &= 0xffff;
1469 update_pm1a(pThis, pThis->pm1a_sts, u32);
1470
1471 DEVACPI_UNLOCK(pThis);
[1]1472 return VINF_SUCCESS;
1473}
1474
[37444]1475/**
1476 * @callback_method_impl{FNIOMIOPORTIN, PM1a Status}
1477 */
1478PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1479{
[37444]1480 if (cb != 2)
[1]1481 {
[37444]1482 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1483 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
[1]1484 }
[37444]1485
1486 ACPIState *pThis = (ACPIState *)pvUser;
1487 DEVACPI_LOCK_R3(pThis);
1488
1489 *pu32 = pThis->pm1a_sts;
1490
1491 DEVACPI_UNLOCK(pThis);
1492 Log(("acpiPm1aStsRead: %#x\n", *pu32));
[1]1493 return VINF_SUCCESS;
1494}
1495
[37444]1496/**
1497 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Status}
1498 */
1499PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1500{
[37444]1501 if (cb != 2 && cb != 4)
1502 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1503
1504 ACPIState *pThis = (ACPIState *)pvUser;
1505 DEVACPI_LOCK_R3(pThis);
1506
1507 Log(("acpiPM1aStsWrite: %#x (%#x)\n", u32, u32 & ~(RSR_STS | IGN_STS) & 0xffff));
1508 u32 &= 0xffff;
1509 if (u32 & PWRBTN_STS)
1510 pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
1511 u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
1512 update_pm1a(pThis, u32, pThis->pm1a_en);
1513
1514 DEVACPI_UNLOCK(pThis);
[1]1515 return VINF_SUCCESS;
1516}
1517
[37444]1518/**
1519 * @callback_method_impl{FNIOMIOPORTIN, PM1a Control}
1520 */
1521PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1522{
[37444]1523 if (cb != 2)
[1]1524 {
[37444]1525 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1526 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
[1]1527 }
[37444]1528
1529 ACPIState *pThis = (ACPIState *)pvUser;
1530 DEVACPI_LOCK_R3(pThis);
1531
1532 *pu32 = pThis->pm1a_ctl;
1533
1534 DEVACPI_UNLOCK(pThis);
1535 Log(("acpiPm1aCtlRead: %#x\n", *pu32));
[1]1536 return VINF_SUCCESS;
1537}
1538
[37444]1539/**
1540 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Control}
1541 */
[17572]1542PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1543{
[37444]1544 if (cb != 2 && cb != 4)
1545 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1546
1547 ACPIState *pThis = (ACPIState *)pvUser;
1548 DEVACPI_LOCK_R3(pThis);
1549
1550 Log(("acpiPM1aCtlWrite: %#x (%#x)\n", u32, u32 & ~(RSR_CNT | IGN_CNT) & 0xffff));
1551 u32 &= 0xffff;
1552 pThis->pm1a_ctl = u32 & ~(RSR_CNT | IGN_CNT);
1553
1554 int rc = VINF_SUCCESS;
1555 uint32_t const uSleepState = (pThis->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
1556 if (uSleepState != pThis->uSleepState)
[1]1557 {
[37444]1558 pThis->uSleepState = uSleepState;
1559 switch (uSleepState)
1560 {
1561 case 0x00: /* S0 */
1562 break;
1563
1564 case 0x01: /* S1 */
1565 if (pThis->fS1Enabled)
1566 {
1567 LogRel(("Entering S1 power state (powered-on suspend)\n"));
1568 rc = acpiSleep(pThis);
1569 break;
1570 }
1571 LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
1572 /* fall thru */
1573
1574 case 0x04: /* S4 */
1575 if (pThis->fS4Enabled)
1576 {
1577 LogRel(("Entering S4 power state (suspend to disk)\n"));
1578 rc = acpiPowerOff(pThis);/* Same behavior as S5 */
1579 break;
1580 }
1581 LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
1582 /* fall thru */
1583
1584 case 0x05: /* S5 */
1585 LogRel(("Entering S5 power state (power down)\n"));
1586 rc = acpiPowerOff(pThis);
1587 break;
1588
1589 default:
1590 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Unknown sleep state %#x (u32=%#x)\n", uSleepState, u32);
1591 break;
1592 }
[1]1593 }
[37444]1594
1595 DEVACPI_UNLOCK(pThis);
1596 Log(("acpiPM1aCtlWrite: rc=%Rrc\n", rc));
1597 return rc;
[1]1598}
1599
1600#endif /* IN_RING3 */
1601
1602/**
[37444]1603 * @callback_method_impl{FNIOMIOPORTIN, PMTMR}
1604 *
1605 * @remarks Only I/O port currently implemented in all contexts.
[1]1606 */
[17572]1607PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1608{
[37444]1609 if (cb != 4)
1610 return VERR_IOM_IOPORT_UNUSED;
1611
1612 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
1613
1614 /*
1615 * We use the clock lock to serialize access to u64PmTimerInitial and to
1616 * make sure we get a reliable time from the clock.
1617 */
[40280]1618 int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_R3_IOPORT_READ);
[37444]1619 if (rc == VINF_SUCCESS)
[1]1620 {
[37444]1621 uint64_t const u64PmTimerInitial = pThis->u64PmTimerInitial;
1622 uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
1623 TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
1624
1625 /*
1626 * Calculate the return value.
1627 */
1628 DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
1629 uint64_t u64Elapsed = u64Now - u64PmTimerInitial;
1630 *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer)));
[17572]1631 Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
[1]1632 }
[37444]1633
[39091]1634 NOREF(pvUser); NOREF(Port);
[37444]1635 return rc;
[1]1636}
1637
1638#ifdef IN_RING3
1639
[37444]1640/**
1641 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Status}
1642 */
[17572]1643PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1644{
[37444]1645 if (cb != 1)
[1]1646 {
[37444]1647 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1648 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
[1]1649 }
[37444]1650
1651 ACPIState *pThis = (ACPIState *)pvUser;
1652 DEVACPI_LOCK_R3(pThis);
1653
1654 *pu32 = pThis->gpe0_sts & 0xff;
1655
1656 DEVACPI_UNLOCK(pThis);
1657 Log(("acpiGpe0StsRead: %#x\n", *pu32));
[1]1658 return VINF_SUCCESS;
1659}
1660
[37444]1661/**
1662 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Status}
1663 */
1664PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1665{
[37444]1666 if (cb != 1)
1667 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1668
1669 ACPIState *pThis = (ACPIState *)pvUser;
1670 DEVACPI_LOCK_R3(pThis);
1671
1672 Log(("acpiGpe0StsWrite: %#x (%#x)\n", u32, pThis->gpe0_sts & ~u32));
1673 u32 = pThis->gpe0_sts & ~u32;
1674 update_gpe0(pThis, u32, pThis->gpe0_en);
1675
1676 DEVACPI_UNLOCK(pThis);
[1]1677 return VINF_SUCCESS;
1678}
1679
[37444]1680/**
1681 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Enable}
1682 */
1683PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[1]1684{
[37444]1685 if (cb != 1)
[1]1686 {
[37444]1687 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1688 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
[1]1689 }
[37444]1690
1691 ACPIState *pThis = (ACPIState *)pvUser;
1692 DEVACPI_LOCK_R3(pThis);
1693
1694 *pu32 = pThis->gpe0_en & 0xff;
1695
1696 DEVACPI_UNLOCK(pThis);
1697 Log(("acpiGpe0EnRead: %#x\n", *pu32));
[1]1698 return VINF_SUCCESS;
1699}
1700
[37444]1701/**
1702 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Enable}
1703 */
[17572]1704PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1705{
[37444]1706 if (cb != 1)
1707 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1708
1709 ACPIState *pThis = (ACPIState *)pvUser;
1710 DEVACPI_LOCK_R3(pThis);
1711
1712 Log(("acpiGpe0EnWrite: %#x\n", u32));
1713 update_gpe0(pThis, pThis->gpe0_sts, u32);
1714
1715 DEVACPI_UNLOCK(pThis);
[1]1716 return VINF_SUCCESS;
1717}
1718
[37444]1719/**
1720 * @callback_method_impl{FNIOMIOPORTOUT, SMI_CMD}
1721 */
[17572]1722PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1723{
[37444]1724 Log(("acpiSmiWrite %#x\n", u32));
1725 if (cb != 1)
1726 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1727
1728 ACPIState *pThis = (ACPIState *)pvUser;
1729 DEVACPI_LOCK_R3(pThis);
1730
1731 if (u32 == ACPI_ENABLE)
1732 pThis->pm1a_ctl |= SCI_EN;
1733 else if (u32 == ACPI_DISABLE)
1734 pThis->pm1a_ctl &= ~SCI_EN;
1735 else
1736 Log(("acpiSmiWrite: %#x <- unknown value\n", u32));
1737
1738 DEVACPI_UNLOCK(pThis);
[1]1739 return VINF_SUCCESS;
1740}
1741
[37444]1742/**
1743 * @{FNIOMIOPORTOUT, ACPI_RESET_BLK}
1744 */
[17572]1745PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1746{
[37444]1747 Log(("acpiResetWrite: %#x\n", u32));
[39091]1748 NOREF(pvUser);
[37444]1749 if (cb != 1)
1750 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1751
1752 /* No state locking required. */
1753 int rc = VINF_SUCCESS;
1754 if (u32 == ACPI_RESET_REG_VAL)
1755 rc = PDMDevHlpVMReset(pDevIns);
1756 else
1757 Log(("acpiResetWrite: %#x <- unknown value\n", u32));
1758
1759 return rc;
[1]1760}
1761
[37444]1762# ifdef DEBUG_ACPI
[1]1763
[37444]1764/**
1765 * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
1766 */
[17572]1767PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1768{
[39091]1769 NOREF(pvUser);
[1]1770 switch (cb)
1771 {
1772 case 1:
[17572]1773 Log(("%#x\n", u32 & 0xff));
[1]1774 break;
1775 case 2:
[17572]1776 Log(("%#6x\n", u32 & 0xffff));
[1]1777 case 4:
[17572]1778 Log(("%#10x\n", u32));
[1]1779 break;
1780 default:
[37444]1781 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
[1]1782 }
1783 return VINF_SUCCESS;
1784}
1785
[37444]1786/**
1787 * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
1788 */
[17572]1789PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
[1]1790{
[39091]1791 NOREF(pvUser);
[1]1792 switch (cb)
1793 {
1794 case 1:
[17572]1795 Log(("%c", u32 & 0xff));
[1]1796 break;
1797 default:
[37444]1798 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
[1]1799 }
1800 return VINF_SUCCESS;
1801}
1802
[37444]1803# endif /* DEBUG_ACPI */
[1]1804
[37444]1805/**
1806 * Used to calculate the value of a PM I/O port.
1807 *
1808 * @returns The actual I/O port value.
1809 * @param pThis The ACPI instance.
1810 * @param offset The offset into the I/O space, or -1 if invalid.
1811 */
1812static RTIOPORT acpiCalcPmPort(ACPIState *pThis, int32_t offset)
[21820]1813{
[37444]1814 Assert(pThis->uPmIoPortBase != 0);
1815
1816 if (offset == -1)
1817 return 0;
1818
1819 return (RTIOPORT)(pThis->uPmIoPortBase + offset);
1820}
1821
1822/**
1823 * Called by acpiLoadState and acpiUpdatePmHandlers to register the PM1a, PM
1824 * timer and GPE0 I/O ports.
1825 *
1826 * @returns VBox status code.
1827 * @param pThis The ACPI instance.
1828 */
1829static int acpiRegisterPmHandlers(ACPIState *pThis)
1830{
[21820]1831 int rc = VINF_SUCCESS;
[1]1832
[21820]1833#define R(offset, cnt, writer, reader, description) \
1834 do { \
[37444]1835 rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
[21820]1836 NULL, NULL, description); \
1837 if (RT_FAILURE(rc)) \
1838 return rc; \
1839 } while (0)
1840#define L (GPE0_BLK_LEN / 2)
1841
1842 R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
1843 R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
1844 R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
1845 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
1846 R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
1847 R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
1848#undef L
1849#undef R
1850
[26157]1851 /* register RC stuff */
[21820]1852 if (pThis->fGCEnabled)
1853 {
[37444]1854 rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
[21820]1855 1, 0, NULL, "acpiPMTmrRead",
1856 NULL, NULL, "ACPI PM Timer");
1857 AssertRCReturn(rc, rc);
1858 }
1859
1860 /* register R0 stuff */
1861 if (pThis->fR0Enabled)
1862 {
[37444]1863 rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
[21820]1864 1, 0, NULL, "acpiPMTmrRead",
1865 NULL, NULL, "ACPI PM Timer");
1866 AssertRCReturn(rc, rc);
1867 }
1868
1869 return rc;
1870}
1871
[37444]1872/**
1873 * Called by acpiLoadState and acpiUpdatePmHandlers to unregister the PM1a, PM
1874 * timer and GPE0 I/O ports.
1875 *
1876 * @returns VBox status code.
1877 * @param pThis The ACPI instance.
1878 */
[21829]1879static int acpiUnregisterPmHandlers(ACPIState *pThis)
[21820]1880{
[21829]1881#define U(offset, cnt) \
[21820]1882 do { \
[37444]1883 int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt); \
[21829]1884 AssertRCReturn(rc, rc); \
[21820]1885 } while (0)
1886#define L (GPE0_BLK_LEN / 2)
1887
1888 U(PM1a_EVT_OFFSET+2, 1);
1889 U(PM1a_EVT_OFFSET, 1);
1890 U(PM1a_CTL_OFFSET, 1);
1891 U(PM_TMR_OFFSET, 1);
1892 U(GPE0_OFFSET + L, L);
1893 U(GPE0_OFFSET, L);
1894#undef L
1895#undef U
1896
[21829]1897 return VINF_SUCCESS;
[21820]1898}
1899
[1]1900/**
[37444]1901 * Called by acpiPciConfigWrite and acpiReset to change the location of the
1902 * PM1a, PM timer and GPE0 ports.
1903 *
1904 * @returns VBox status code.
1905 *
1906 * @param pThis The ACPI instance.
1907 * @param NewIoPortBase The new base address of the I/O ports.
1908 */
1909static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
1910{
1911 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
1912 if (NewIoPortBase != pThis->uPmIoPortBase)
1913 {
1914 int rc = acpiUnregisterPmHandlers(pThis);
1915 if (RT_FAILURE(rc))
1916 return rc;
1917
1918 pThis->uPmIoPortBase = NewIoPortBase;
1919
1920 rc = acpiRegisterPmHandlers(pThis);
1921 if (RT_FAILURE(rc))
1922 return rc;
1923
1924 /* We have to update FADT table acccording to the new base */
1925 rc = acpiPlantTables(pThis);
1926 AssertRC(rc);
1927 if (RT_FAILURE(rc))
1928 return rc;
1929 }
1930
1931 return VINF_SUCCESS;
1932}
1933
1934
1935/**
[21820]1936 * Saved state structure description, version 4.
[1]1937 */
[21820]1938static const SSMFIELD g_AcpiSavedStateFields4[] =
[1]1939{
[17572]1940 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1941 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1942 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
[37237]1943 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
[17572]1944 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1945 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1946 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1947 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
[21829]1948 SSMFIELD_ENTRY(ACPIState, u64RamSize),
[17572]1949 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1950 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
1951 SSMFIELD_ENTRY(ACPIState, uSleepState),
1952 SSMFIELD_ENTRY_TERM()
[1]1953};
1954
[21820]1955/**
1956 * Saved state structure description, version 5.
1957 */
1958static const SSMFIELD g_AcpiSavedStateFields5[] =
1959{
1960 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1961 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1962 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
[37237]1963 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
[21820]1964 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1965 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1966 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1967 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1968 SSMFIELD_ENTRY(ACPIState, uSleepState),
1969 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1970 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1971 SSMFIELD_ENTRY_TERM()
1972};
1973
[32189]1974/**
1975 * Saved state structure description, version 6.
1976 */
1977static const SSMFIELD g_AcpiSavedStateFields6[] =
1978{
1979 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1980 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1981 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
[37237]1982 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
[32189]1983 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1984 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1985 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1986 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1987 SSMFIELD_ENTRY(ACPIState, uSleepState),
1988 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1989 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1990 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
1991 SSMFIELD_ENTRY_TERM()
1992};
[21820]1993
[32189]1994
1995/**
1996 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1997 */
1998static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
[1]1999{
[32189]2000 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2001 return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
[1]2002}
2003
[32189]2004/**
2005 * @callback_method_impl{FNSSMDEVLOADEXEC}
2006 */
2007static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
2008 uint32_t uVersion, uint32_t uPass)
[1]2009{
[32189]2010 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2011 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
[1]2012
[21837]2013 /*
[32189]2014 * Unregister PM handlers, will register with actual base after state
2015 * successfully loaded.
[21837]2016 */
[32189]2017 int rc = acpiUnregisterPmHandlers(pThis);
[21837]2018 if (RT_FAILURE(rc))
2019 return rc;
2020
[22480]2021 switch (uVersion)
[21820]2022 {
2023 case 4:
[32189]2024 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
[21820]2025 break;
2026 case 5:
[32189]2027 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
[21820]2028 break;
[32189]2029 case 6:
2030 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2031 break;
[21829]2032 default:
[32189]2033 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2034 break;
[21820]2035 }
[17572]2036 if (RT_SUCCESS(rc))
[1]2037 {
[32189]2038 rc = acpiRegisterPmHandlers(pThis);
[21820]2039 if (RT_FAILURE(rc))
2040 return rc;
[32189]2041 rc = acpiFetchBatteryStatus(pThis);
[21820]2042 if (RT_FAILURE(rc))
2043 return rc;
[32189]2044 rc = acpiFetchBatteryInfo(pThis);
[21820]2045 if (RT_FAILURE(rc))
2046 return rc;
[37526]2047 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
[37444]2048 acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
[37526]2049 TMTimerUnlock(pThis->pPmTimerR3);
[1]2050 }
2051 return rc;
2052}
2053
2054/**
[25966]2055 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
[1]2056 */
[25966]2057static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
[1]2058{
[25966]2059 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
[25985]2060 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
[25984]2061 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
[25966]2062 return NULL;
[1]2063}
2064
2065/**
[37444]2066 * Calculate the check sum for some ACPI data before planting it.
2067 *
2068 * All the bytes must add up to 0.
2069 *
2070 * @returns check sum.
2071 * @param pvSrc What to check sum.
2072 * @param cbData The amount of data to checksum.
[1]2073 */
[37444]2074static uint8_t acpiChecksum(const void * const pvSrc, size_t cbData)
2075{
2076 uint8_t const *pbSrc = (uint8_t const *)pvSrc;
2077 uint8_t uSum = 0;
2078 for (size_t i = 0; i < cbData; ++i)
2079 uSum += pbSrc[i];
2080 return -uSum;
2081}
2082
2083/**
2084 * Prepare a ACPI table header.
2085 */
[40019]2086static void acpiPrepareHeader(ACPIState *pThis, ACPITBLHEADER *header,
2087 const char au8Signature[4],
[37444]2088 uint32_t u32Length, uint8_t u8Revision)
2089{
2090 memcpy(header->au8Signature, au8Signature, 4);
2091 header->u32Length = RT_H2LE_U32(u32Length);
2092 header->u8Revision = u8Revision;
[40019]2093 memcpy(header->au8OemId, pThis->au8OemId, 6);
[37444]2094 memcpy(header->au8OemTabId, "VBOX", 4);
2095 memcpy(header->au8OemTabId+4, au8Signature, 4);
2096 header->u32OemRevision = RT_H2LE_U32(1);
[40019]2097 memcpy(header->au8CreatorId, pThis->au8CreatorId, 4);
2098 header->u32CreatorRev = pThis->u32CreatorRev;
[37444]2099}
2100
2101/**
2102 * Initialize a generic address structure (ACPIGENADDR).
2103 */
2104static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
2105 uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
2106 uint8_t u8AccessSize, uint64_t u64Address)
2107{
2108 g->u8AddressSpaceId = u8AddressSpaceId;
2109 g->u8RegisterBitWidth = u8RegisterBitWidth;
2110 g->u8RegisterBitOffset = u8RegisterBitOffset;
2111 g->u8AccessSize = u8AccessSize;
2112 g->u64Address = RT_H2LE_U64(u64Address);
2113}
2114
2115/**
2116 * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
2117 */
[37446]2118static void acpiPhyscpy(ACPIState *pThis, RTGCPHYS32 dst, const void * const src, size_t size)
[37444]2119{
[37446]2120 PDMDevHlpPhysWrite(pThis->pDevIns, dst, src, size);
[37444]2121}
2122
2123/**
2124 * Plant the Differentiated System Description Table (DSDT).
2125 */
[37446]2126static void acpiSetupDSDT(ACPIState *pThis, RTGCPHYS32 addr,
[37444]2127 void* pPtr, size_t uDsdtLen)
2128{
[37446]2129 acpiPhyscpy(pThis, addr, pPtr, uDsdtLen);
[37444]2130}
2131
2132/**
2133 * Plan the Secondary System Description Table (SSDT).
2134 */
[37446]2135static void acpiSetupSSDT(ACPIState *pThis, RTGCPHYS32 addr,
[37444]2136 void* pPtr, size_t uSsdtLen)
2137{
[37446]2138 acpiPhyscpy(pThis, addr, pPtr, uSsdtLen);
[37444]2139}
2140
2141/**
2142 * Plant the Firmware ACPI Control Structure (FACS).
2143 */
[37446]2144static void acpiSetupFACS(ACPIState *pThis, RTGCPHYS32 addr)
[37444]2145{
2146 ACPITBLFACS facs;
2147
2148 memset(&facs, 0, sizeof(facs));
2149 memcpy(facs.au8Signature, "FACS", 4);
2150 facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
2151 facs.u32HWSignature = RT_H2LE_U32(0);
2152 facs.u32FWVector = RT_H2LE_U32(0);
2153 facs.u32GlobalLock = RT_H2LE_U32(0);
2154 facs.u32Flags = RT_H2LE_U32(0);
2155 facs.u64X_FWVector = RT_H2LE_U64(0);
2156 facs.u8Version = 1;
2157
[37446]2158 acpiPhyscpy(pThis, addr, (const uint8_t *)&facs, sizeof(facs));
[37444]2159}
2160
2161/**
2162 * Plant the Fixed ACPI Description Table (FADT aka FACP).
2163 */
[37446]2164static void acpiSetupFADT(ACPIState *pThis, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2, RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
[37444]2165{
2166 ACPITBLFADT fadt;
2167
2168 /* First the ACPI version 2+ version of the structure. */
2169 memset(&fadt, 0, sizeof(fadt));
[40019]2170 acpiPrepareHeader(pThis, &fadt.header, "FACP", sizeof(fadt), 4);
[37444]2171 fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
2172 fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
2173 fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
2174 fadt.u8PreferredPMProfile = 0; /* unspecified */
2175 fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
2176 fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
2177 fadt.u8AcpiEnable = ACPI_ENABLE;
2178 fadt.u8AcpiDisable = ACPI_DISABLE;
2179 fadt.u8S4BIOSReq = 0;
2180 fadt.u8PStateCnt = 0;
[37446]2181 fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
2182 fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
2183 fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
2184 fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
2185 fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
2186 fadt.u32PMTMRBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM_TMR_OFFSET));
2187 fadt.u32GPE0BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE0_OFFSET));
2188 fadt.u32GPE1BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE1_OFFSET));
[37444]2189 fadt.u8PM1EVTLEN = 4;
2190 fadt.u8PM1CTLLEN = 2;
2191 fadt.u8PM2CTLLEN = 0;
2192 fadt.u8PMTMLEN = 4;
2193 fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
2194 fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
2195 fadt.u8GPE1BASE = GPE1_BASE;
2196 fadt.u8CSTCNT = 0;
2197 fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
2198 fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
2199 fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
2200 fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
2201 fadt.u8DutyOffset = 0;
2202 fadt.u8DutyWidth = 0;
2203 fadt.u8DayAlarm = 0;
2204 fadt.u8MonAlarm = 0;
2205 fadt.u8Century = 0;
2206 fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
2207 /** @note WBINVD is required for ACPI versions newer than 1.0 */
2208 fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
2209 | FADT_FL_FIX_RTC
2210 | FADT_FL_TMR_VAL_EXT
2211 | FADT_FL_RESET_REG_SUP);
2212
2213 /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
[37446]2214 if (pThis->fCpuHotPlug)
[37444]2215 fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
2216
2217 acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
2218 fadt.u8ResetVal = ACPI_RESET_REG_VAL;
2219 fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
2220 fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
[37446]2221 acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
2222 acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
2223 acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
2224 acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
2225 acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
2226 acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiCalcPmPort(pThis, PM_TMR_OFFSET));
2227 acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiCalcPmPort(pThis, GPE0_OFFSET));
2228 acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, GPE1_OFFSET));
[37444]2229 fadt.header.u8Checksum = acpiChecksum(&fadt, sizeof(fadt));
[37446]2230 acpiPhyscpy(pThis, GCPhysAcpi2, &fadt, sizeof(fadt));
[37444]2231
2232 /* Now the ACPI 1.0 version. */
2233 fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
2234 fadt.u8IntModel = INT_MODEL_DUAL_PIC;
2235 fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
2236 fadt.header.u8Checksum = acpiChecksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
[37446]2237 acpiPhyscpy(pThis, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
[37444]2238}
2239
2240/**
2241 * Plant the root System Description Table.
2242 *
2243 * The RSDT and XSDT tables are basically identical. The only difference is 32
2244 * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
2245 * ACPI 2.0 and up.
2246 */
[37446]2247static int acpiSetupRSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
[37444]2248{
2249 ACPITBLRSDT *rsdt;
2250 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
2251
2252 rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
2253 if (!rsdt)
[37446]2254 return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
[37444]2255
[40019]2256 acpiPrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
[37444]2257 for (unsigned int i = 0; i < nb_entries; ++i)
2258 {
2259 rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
2260 Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
2261 }
2262 rsdt->header.u8Checksum = acpiChecksum(rsdt, size);
[37446]2263 acpiPhyscpy(pThis, addr, rsdt, size);
[37444]2264 RTMemFree(rsdt);
2265 return VINF_SUCCESS;
2266}
2267
2268/**
2269 * Plant the Extended System Description Table.
2270 */
[37446]2271static int acpiSetupXSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
[37444]2272{
2273 ACPITBLXSDT *xsdt;
2274 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
2275
2276 xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
2277 if (!xsdt)
2278 return VERR_NO_TMP_MEMORY;
2279
[40019]2280 acpiPrepareHeader(pThis, &xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
2281
2282 if (pThis->fUseCust)
2283 memcpy(xsdt->header.au8OemTabId, pThis->au8OemTabId, 8);
2284
[37444]2285 for (unsigned int i = 0; i < nb_entries; ++i)
2286 {
2287 xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
2288 Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
2289 }
2290 xsdt->header.u8Checksum = acpiChecksum(xsdt, size);
[37446]2291 acpiPhyscpy(pThis, addr, xsdt, size);
[37444]2292 RTMemFree(xsdt);
2293 return VINF_SUCCESS;
2294}
2295
2296/**
2297 * Plant the Root System Description Pointer (RSDP).
2298 */
[40019]2299static void acpiSetupRSDP(ACPIState *pThis, ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
[37444]2300{
2301 memset(rsdp, 0, sizeof(*rsdp));
2302
2303 /* ACPI 1.0 part (RSDT */
2304 memcpy(rsdp->au8Signature, "RSD PTR ", 8);
[40019]2305 memcpy(rsdp->au8OemId, pThis->au8OemId, 6);
[37444]2306 rsdp->u8Revision = ACPI_REVISION;
2307 rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
2308 rsdp->u8Checksum = acpiChecksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
2309
2310 /* ACPI 2.0 part (XSDT) */
2311 rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
2312 rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
2313 rsdp->u8ExtChecksum = acpiChecksum(rsdp, sizeof(ACPITBLRSDP));
2314}
2315
2316/**
2317 * Plant the Multiple APIC Description Table (MADT).
2318 *
2319 * @note APIC without IO-APIC hangs Windows Vista therefore we setup both.
2320 *
2321 * @todo All hardcoded, should set this up based on the actual VM config!!!!!
2322 */
[37446]2323static void acpiSetupMADT(ACPIState *pThis, RTGCPHYS32 addr)
[37444]2324{
[37446]2325 uint16_t cpus = pThis->cCpus;
[37444]2326 AcpiTableMADT madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
2327
[40019]2328 acpiPrepareHeader(pThis, madt.header_addr(), "APIC", madt.size(), 2);
[37444]2329
2330 *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
2331 *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
2332
2333 /* LAPICs records */
2334 ACPITBLLAPIC* lapic = madt.LApics_addr();
2335 for (uint16_t i = 0; i < cpus; i++)
2336 {
2337 lapic->u8Type = 0;
2338 lapic->u8Length = sizeof(ACPITBLLAPIC);
2339 lapic->u8ProcId = i;
2340 /** Must match numbering convention in MPTABLES */
2341 lapic->u8ApicId = i;
[37446]2342 lapic->u32Flags = VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
[37444]2343 lapic++;
2344 }
2345
2346 /* IO-APIC record */
2347 ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
2348 ioapic->u8Type = 1;
2349 ioapic->u8Length = sizeof(ACPITBLIOAPIC);
2350 /** Must match MP tables ID */
2351 ioapic->u8IOApicId = cpus;
2352 ioapic->u8Reserved = 0;
2353 ioapic->u32Address = RT_H2LE_U32(0xfec00000);
2354 ioapic->u32GSIB = RT_H2LE_U32(0);
2355
2356 /* Interrupt Source Overrides */
2357 /* Flags:
2358 bits[3:2]:
2359 00 conforms to the bus
2360 01 edge-triggered
2361 10 reserved
2362 11 level-triggered
2363 bits[1:0]
2364 00 conforms to the bus
2365 01 active-high
2366 10 reserved
2367 11 active-low */
2368 /* If changing, also update PDMIsaSetIrq() and MPS */
2369 ACPITBLISO* isos = madt.ISO_addr();
2370 /* Timer interrupt rule IRQ0 to GSI2 */
2371 isos[0].u8Type = 2;
2372 isos[0].u8Length = sizeof(ACPITBLISO);
2373 isos[0].u8Bus = 0; /* Must be 0 */
2374 isos[0].u8Source = 0; /* IRQ0 */
2375 isos[0].u32GSI = 2; /* connected to pin 2 */
2376 isos[0].u16Flags = 0; /* conform to the bus */
2377
2378 /* ACPI interrupt rule - IRQ9 to GSI9 */
2379 isos[1].u8Type = 2;
2380 isos[1].u8Length = sizeof(ACPITBLISO);
2381 isos[1].u8Bus = 0; /* Must be 0 */
2382 isos[1].u8Source = 9; /* IRQ9 */
2383 isos[1].u32GSI = 9; /* connected to pin 9 */
2384 isos[1].u16Flags = 0xd; /* active high, level triggered */
2385 Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
2386
2387 madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
[37446]2388 acpiPhyscpy(pThis, addr, madt.data(), madt.size());
[37444]2389}
2390
2391/**
2392 * Plant the High Performance Event Timer (HPET) descriptor.
2393 */
[37446]2394static void acpiSetupHPET(ACPIState *pThis, RTGCPHYS32 addr)
[37444]2395{
2396 ACPITBLHPET hpet;
2397
2398 memset(&hpet, 0, sizeof(hpet));
2399
[40019]2400 acpiPrepareHeader(pThis, &hpet.aHeader, "HPET", sizeof(hpet), 1);
[37444]2401 /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
2402 acpiWriteGenericAddr(&hpet.HpetAddr,
2403 0 /* Memory address space */,
2404 64 /* Register bit width */,
2405 0 /* Bit offset */,
2406 0, /* Register access size, is it correct? */
2407 0xfed00000 /* Address */);
2408
2409 hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
2410 hpet.u32Number = 0;
2411 hpet.u32MinTick = 4096;
2412 hpet.u8Attributes = 0;
2413
2414 hpet.aHeader.u8Checksum = acpiChecksum(&hpet, sizeof(hpet));
2415
[37446]2416 acpiPhyscpy(pThis, addr, (const uint8_t *)&hpet, sizeof(hpet));
[37444]2417}
2418
2419
[40019]2420/** Custom Description Table */
2421static void acpiSetupCUST(ACPIState *pThis, RTGCPHYS32 addr)
2422{
2423 ACPITBLCUST cust;
2424
2425 /* First the ACPI version 1 version of the structure. */
2426 memset(&cust, 0, sizeof(cust));
2427 acpiPrepareHeader(pThis, &cust.header, "CUST", sizeof(cust), 1);
2428
2429 memcpy(cust.header.au8OemTabId, pThis->au8OemTabId, 8);
2430 cust.header.u32OemRevision = RT_H2LE_U32(pThis->u32OemRevision);
2431 cust.header.u8Checksum = acpiChecksum((uint8_t *)&cust, sizeof(cust));
2432
2433 acpiPhyscpy(pThis, addr, pThis->pu8CustBin, pThis->cbCustBin);
2434}
2435
[37444]2436/**
2437 * Used by acpiPlantTables to plant a MMCONFIG PCI config space access (MCFG)
2438 * descriptor.
2439 *
2440 * @param pThis The ACPI instance.
2441 * @param GCPhysDst Where to plant it.
2442 */
2443static void acpiSetupMCFG(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
2444{
2445 struct
2446 {
2447 ACPITBLMCFG hdr;
2448 ACPITBLMCFGENTRY entry;
2449 } tbl;
2450 uint8_t u8StartBus = 0;
2451 uint8_t u8EndBus = (pThis->u64PciConfigMMioLength >> 20) - 1;
2452
2453 RT_ZERO(tbl);
2454
[40019]2455 acpiPrepareHeader(pThis, &tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
[37444]2456 tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
2457 tbl.entry.u8StartBus = u8StartBus;
2458 tbl.entry.u8EndBus = u8EndBus;
2459 // u16PciSegmentGroup must match _SEG in ACPI table
2460
2461 tbl.hdr.aHeader.u8Checksum = acpiChecksum(&tbl, sizeof(tbl));
2462
2463 acpiPhyscpy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
2464}
2465
2466/**
2467 * Used by acpiPlantTables and acpiConstruct.
2468 *
2469 * @returns Guest memory address.
2470 */
2471static uint32_t find_rsdp_space(void)
2472{
2473 return 0xe0000;
2474}
2475
2476/**
2477 * Create the ACPI tables in guest memory.
2478 */
[37446]2479static int acpiPlantTables(ACPIState *pThis)
[1]2480{
[7072]2481 int rc;
[26057]2482 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
[37444]2483 RTGCPHYS32 GCPhysHpet = 0;
2484 RTGCPHYS32 GCPhysApic = 0;
2485 RTGCPHYS32 GCPhysSsdt = 0;
2486 RTGCPHYS32 GCPhysMcfg = 0;
[40019]2487 RTGCPHYS32 GCPhysCust = 0;
[7072]2488 uint32_t addend = 0;
[34425]2489 RTGCPHYS32 aGCPhysRsdt[8];
2490 RTGCPHYS32 aGCPhysXsdt[8];
[37444]2491 uint32_t cAddr;
2492 uint32_t iMadt = 0;
2493 uint32_t iHpet = 0;
2494 uint32_t iSsdt = 0;
2495 uint32_t iMcfg = 0;
[40019]2496 uint32_t iCust = 0;
[26057]2497 size_t cbRsdt = sizeof(ACPITBLHEADER);
2498 size_t cbXsdt = sizeof(ACPITBLHEADER);
[1]2499
[26057]2500 cAddr = 1; /* FADT */
[37446]2501 if (pThis->u8UseIOApic)
[26057]2502 iMadt = cAddr++; /* MADT */
[1]2503
[37446]2504 if (pThis->fUseHpet)
[26057]2505 iHpet = cAddr++; /* HPET */
[25928]2506
[37446]2507 if (pThis->fUseMcfg)
[32591]2508 iMcfg = cAddr++; /* MCFG */
2509
[40019]2510 if (pThis->fUseCust)
2511 iCust = cAddr++; /* CUST */
2512
[26183]2513 iSsdt = cAddr++; /* SSDT */
2514
[34425]2515 Assert(cAddr < RT_ELEMENTS(aGCPhysRsdt));
2516 Assert(cAddr < RT_ELEMENTS(aGCPhysXsdt));
2517
[26057]2518 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
2519 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
[1]2520
[37446]2521 rc = CFGMR3QueryU64(pThis->pDevIns->pCfg, "RamSize", &pThis->u64RamSize);
[17572]2522 if (RT_FAILURE(rc))
[37446]2523 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
[26057]2524 N_("Configuration error: Querying \"RamSize\" as integer failed"));
[1]2525
[17542]2526 uint32_t cbRamHole;
[37446]2527 rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
[17572]2528 if (RT_FAILURE(rc))
[37446]2529 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
[17572]2530 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
[17590]2531
2532 /*
[26057]2533 * Calculate the sizes for the high and low regions.
[17590]2534 */
[17542]2535 const uint64_t offRamHole = _4G - cbRamHole;
[37446]2536 pThis->cbRamHigh = offRamHole < pThis->u64RamSize ? pThis->u64RamSize - offRamHole : 0;
2537 uint64_t cbRamLow = offRamHole < pThis->u64RamSize ? offRamHole : pThis->u64RamSize;
[17590]2538 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
2539 {
[17597]2540 /* Note: This is also enforced by DevPcBios.cpp. */
[17590]2541 LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
2542 cbRamLow = UINT32_C(0xffe00000);
2543 }
[37446]2544 pThis->cbRamLow = (uint32_t)cbRamLow;
[17542]2545
[26057]2546 GCPhysCur = 0;
2547 GCPhysRsdt = GCPhysCur;
[25928]2548
[26057]2549 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
2550 GCPhysXsdt = GCPhysCur;
[25928]2551
[26057]2552 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
2553 GCPhysFadtAcpi1 = GCPhysCur;
[25928]2554
[26057]2555 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
2556 GCPhysFadtAcpi2 = GCPhysCur;
[25928]2557
[26057]2558 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
2559 GCPhysFacs = GCPhysCur;
[25928]2560
[26057]2561 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
[37446]2562 if (pThis->u8UseIOApic)
[1]2563 {
[26057]2564 GCPhysApic = GCPhysCur;
[37446]2565 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
[1]2566 }
[37446]2567 if (pThis->fUseHpet)
[1]2568 {
[26057]2569 GCPhysHpet = GCPhysCur;
2570 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
[1]2571 }
[37446]2572 if (pThis->fUseMcfg)
[32591]2573 {
2574 GCPhysMcfg = GCPhysCur;
2575 /* Assume one entry */
2576 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
2577 }
[40019]2578 if (pThis->fUseCust)
2579 {
2580 GCPhysCust = GCPhysCur;
2581 GCPhysCur = RT_ALIGN_32(GCPhysCur + pThis->cbCustBin, 16);
2582 }
[26183]2583
[37444]2584 void *pvSsdtCode = NULL;
[26183]2585 size_t cbSsdtSize = 0;
[37446]2586 rc = acpiPrepareSsdt(pThis->pDevIns, &pvSsdtCode, &cbSsdtSize);
[26183]2587 if (RT_FAILURE(rc))
2588 return rc;
2589
2590 GCPhysSsdt = GCPhysCur;
2591 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdtSize, 16);
2592
[26057]2593 GCPhysDsdt = GCPhysCur;
[1]2594
[37444]2595 void *pvDsdtCode = NULL;
[26057]2596 size_t cbDsdtSize = 0;
[37446]2597 rc = acpiPrepareDsdt(pThis->pDevIns, &pvDsdtCode, &cbDsdtSize);
[20400]2598 if (RT_FAILURE(rc))
2599 return rc;
2600
[26057]2601 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
[26183]2602
[26057]2603 if (GCPhysCur > 0x10000)
[37446]2604 return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_TOO_MUCH_DATA,
[26057]2605 N_("Error: ACPI tables bigger than 64KB"));
[1]2606
2607 Log(("RSDP 0x%08X\n", find_rsdp_space()));
[37446]2608 addend = pThis->cbRamLow - 0x10000;
[26057]2609 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
2610 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
2611 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
[37446]2612 if (pThis->u8UseIOApic)
[26057]2613 Log((" MADT 0x%08X", GCPhysApic + addend));
[37446]2614 if (pThis->fUseHpet)
[26057]2615 Log((" HPET 0x%08X", GCPhysHpet + addend));
[37446]2616 if (pThis->fUseMcfg)
[32591]2617 Log((" MCFG 0x%08X", GCPhysMcfg + addend));
[40019]2618 if (pThis->fUseCust)
2619 Log((" CUST 0x%08X", GCPhysCust + addend));
[26183]2620 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
[26057]2621 Log(("\n"));
2622
[40019]2623 acpiSetupRSDP(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
[37446]2624 acpiSetupDSDT(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdtSize);
2625 acpiCleanupDsdt(pThis->pDevIns, pvDsdtCode);
2626 acpiSetupFACS(pThis, GCPhysFacs + addend);
2627 acpiSetupFADT(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
[1]2628
[26057]2629 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
2630 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
[37446]2631 if (pThis->u8UseIOApic)
[1]2632 {
[37446]2633 acpiSetupMADT(pThis, GCPhysApic + addend);
[26057]2634 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
2635 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
[1]2636 }
[37446]2637 if (pThis->fUseHpet)
[25928]2638 {
[37446]2639 acpiSetupHPET(pThis, GCPhysHpet + addend);
[26057]2640 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
2641 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
[25928]2642 }
[37446]2643 if (pThis->fUseMcfg)
[32591]2644 {
[37446]2645 acpiSetupMCFG(pThis, GCPhysMcfg + addend);
[32591]2646 aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
2647 aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
2648 }
[40019]2649 if (pThis->fUseCust)
2650 {
2651 acpiSetupCUST(pThis, GCPhysCust + addend);
2652 aGCPhysRsdt[iCust] = GCPhysCust + addend;
2653 aGCPhysXsdt[iCust] = GCPhysCust + addend;
2654 }
[32591]2655
[37446]2656 acpiSetupSSDT(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdtSize);
2657 acpiCleanupSsdt(pThis->pDevIns, pvSsdtCode);
[26183]2658 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
2659 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
[1]2660
[37446]2661 rc = acpiSetupRSDT(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
[11208]2662 if (RT_FAILURE(rc))
[1]2663 return rc;
[37446]2664 return acpiSetupXSDT(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
[1]2665}
2666
[37444]2667/**
2668 * @callback_method_impl{FNPCICONFIGREAD}
2669 */
2670static DECLCALLBACK(uint32_t) acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
[21855]2671{
[21820]2672 PPDMDEVINS pDevIns = pPciDev->pDevIns;
[37444]2673 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
[21820]2674
[21855]2675 Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
[21820]2676 return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
2677}
2678
[37444]2679/**
2680 * @callback_method_impl{FNPCICONFIGWRITE}
2681 */
2682static DECLCALLBACK(void) acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
[21820]2683{
[21829]2684 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2685 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
[21820]2686
[21855]2687 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
[37444]2688 DEVACPI_LOCK_R3(pThis);
[34035]2689
[34494]2690 if (Address == VBOX_PCI_INTERRUPT_LINE)
[34035]2691 {
[34494]2692 Log(("acpi: ignore interrupt line settings: %d, we'll use hardcoded value %d\n", u32Value, SCI_INT));
2693 u32Value = SCI_INT;
[34035]2694 }
2695
[21837]2696 pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
[21820]2697
[21837]2698 /* PMREGMISC written */
[21820]2699 if (Address == 0x80)
2700 {
[21837]2701 /* Check Power Management IO Space Enable (PMIOSE) bit */
2702 if (pPciDev->config[0x80] & 0x1)
[21820]2703 {
[37444]2704 RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
2705 NewIoPortBase &= 0xffc0;
[21820]2706
[37444]2707 int rc = acpiUpdatePmHandlers(pThis, NewIoPortBase);
[25226]2708 AssertRC(rc);
[21820]2709 }
2710 }
[37444]2711
2712 DEVACPI_UNLOCK(pThis);
[21820]2713}
2714
[25817]2715/**
2716 * Attach a new CPU.
2717 *
2718 * @returns VBox status code.
2719 * @param pDevIns The device instance.
2720 * @param iLUN The logical unit which is being attached.
2721 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2722 *
2723 * @remarks This code path is not used during construction.
2724 */
2725static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2726{
[37446]2727 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
[25817]2728 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2729
[25845]2730 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2731 ("Hot-plug flag is not set\n"),
2732 VERR_NOT_SUPPORTED);
[25855]2733 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
[25845]2734
[25817]2735 /* Check if it was already attached */
[37444]2736 int rc = VINF_SUCCESS;
[37446]2737 DEVACPI_LOCK_R3(pThis);
2738 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
[37444]2739 {
2740 PPDMIBASE IBaseTmp;
[37446]2741 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
[37444]2742 if (RT_SUCCESS(rc))
2743 {
2744 /* Enable the CPU */
[37446]2745 VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
[25817]2746
[37444]2747 /*
2748 * Lock the CPU because we don't know if the guest will use it or not.
2749 * Prevents ejection while the CPU is still used
2750 */
[37446]2751 VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
2752 pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
2753 pThis->u32CpuEvent = iLUN;
[25817]2754
[37444]2755 /* Notify the guest */
[37446]2756 update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
[37444]2757 }
[25817]2758 }
[37446]2759 DEVACPI_UNLOCK(pThis);
[25817]2760 return rc;
2761}
2762
2763/**
2764 * Detach notification.
2765 *
2766 * @param pDevIns The device instance.
2767 * @param iLUN The logical unit which is being detached.
2768 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2769 */
2770static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2771{
[37446]2772 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
[25817]2773
2774 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2775
[25845]2776 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2777 ("Hot-plug flag is not set\n"));
2778
[25817]2779 /* Check if it was already detached */
[37446]2780 DEVACPI_LOCK_R3(pThis);
2781 if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
[25817]2782 {
[37446]2783 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
[37444]2784 {
2785 /* Disable the CPU */
[37446]2786 VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
2787 pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
2788 pThis->u32CpuEvent = iLUN;
[25838]2789
[37444]2790 /* Notify the guest */
[37446]2791 update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
[37444]2792 }
2793 else
2794 AssertMsgFailed(("CPU is still locked by the guest\n"));
[25817]2795 }
[37446]2796 DEVACPI_UNLOCK(pThis);
[25817]2797}
2798
[32189]2799/**
2800 * @interface_method_impl{PDMDEVREG,pfnResume}
2801 */
2802static DECLCALLBACK(void) acpiResume(PPDMDEVINS pDevIns)
2803{
2804 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2805 if (pThis->fSetWakeupOnResume)
2806 {
2807 Log(("acpiResume: setting WAK_STS\n"));
2808 pThis->fSetWakeupOnResume = false;
2809 pThis->pm1a_sts |= WAK_STS;
2810 }
2811}
2812
2813/**
2814 * @interface_method_impl{PDMDEVREG,pfnReset}
2815 */
[24078]2816static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
2817{
[37444]2818 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
[24078]2819
[37526]2820 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
[37444]2821 pThis->pm1a_en = 0;
2822 pThis->pm1a_sts = 0;
2823 pThis->pm1a_ctl = 0;
2824 pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
2825 acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
2826 pThis->uBatteryIndex = 0;
2827 pThis->uSystemInfoIndex = 0;
2828 pThis->gpe0_en = 0;
2829 pThis->gpe0_sts = 0;
2830 pThis->uSleepState = 0;
[37526]2831 TMTimerUnlock(pThis->pPmTimerR3);
[24078]2832
2833 /** @todo Should we really reset PM base? */
[37444]2834 acpiUpdatePmHandlers(pThis, PM_PORT_BASE);
[24078]2835
[37444]2836 acpiPlantTables(pThis);
[24078]2837}
2838
[1]2839/**
[32189]2840 * @interface_method_impl{PDMDEVREG,pfnRelocate}
[24078]2841 */
2842static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2843{
[37444]2844 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2845 pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
[39091]2846 NOREF(offDelta);
[24078]2847}
2848
2849/**
[40019]2850 * @interface_methid_impl{PDMDEVREG,pfnDestruct}
2851 */
2852static DECLCALLBACK(int) acpiDestruct(PPDMDEVINS pDevIns)
2853{
2854 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2855 if (pThis->pu8CustBin)
2856 {
2857 MMR3HeapFree(pThis->pu8CustBin);
2858 pThis->pu8CustBin = NULL;
2859 }
2860 return VINF_SUCCESS;
2861}
2862
2863/**
[26160]2864 * @interface_method_impl{PDMDEVREG,pfnConstruct}
[1]2865 */
[26173]2866static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
[1]2867{
[37446]2868 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
[26001]2869 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
[1]2870
[37444]2871 /*
2872 * Init data and set defaults.
2873 */
2874 /** @todo move more of the code up! */
2875
[37446]2876 pThis->pDevIns = pDevIns;
2877 VMCPUSET_EMPTY(&pThis->CpuSetAttached);
2878 VMCPUSET_EMPTY(&pThis->CpuSetLocked);
2879 pThis->idCpuLockCheck = UINT32_C(0xffffffff);
2880 pThis->u32CpuEventType = 0;
2881 pThis->u32CpuEvent = UINT32_C(0xffffffff);
2882
2883 /* The first CPU can't be attached/detached */
2884 VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
2885 VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
2886
2887 /* IBase */
2888 pThis->IBase.pfnQueryInterface = acpiQueryInterface;
2889 /* IACPIPort */
2890 pThis->IACPIPort.pfnSleepButtonPress = acpiPort_SleepButtonPress;
2891 pThis->IACPIPort.pfnPowerButtonPress = acpiPort_PowerButtonPress;
2892 pThis->IACPIPort.pfnGetPowerButtonHandled = acpiPort_GetPowerButtonHandled;
2893 pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiPort_GetGuestEnteredACPIMode;
2894 pThis->IACPIPort.pfnGetCpuStatus = acpiPort_GetCpuStatus;
2895
2896 /* Set the default critical section to NOP (related to the PM timer). */
[37466]2897 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
[37444]2898 AssertRCReturn(rc, rc);
2899
[37466]2900 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi%u", iInstance);
2901 AssertRCReturn(rc, rc);
2902
[37444]2903 /*
2904 * Validate and read the configuration.
2905 */
[26173]2906 if (!CFGMR3AreValuesValid(pCfg,
[17572]2907 "RamSize\0"
2908 "RamHoleSize\0"
2909 "IOAPIC\0"
2910 "NumCPUs\0"
2911 "GCEnabled\0"
2912 "R0Enabled\0"
2913 "HpetEnabled\0"
[32591]2914 "McfgEnabled\0"
[32637]2915 "McfgBase\0"
2916 "McfgLength\0"
[17572]2917 "SmcEnabled\0"
2918 "FdcEnabled\0"
[19007]2919 "ShowRtc\0"
2920 "ShowCpu\0"
[28487]2921 "NicPciAddress\0"
[31519]2922 "AudioPciAddress\0"
[32471]2923 "IocPciAddress\0"
[32477]2924 "HostBusPciAddress\0"
[31963]2925 "EnableSuspendToDisk\0"
2926 "PowerS1Enabled\0"
2927 "PowerS4Enabled\0"
[25838]2928 "CpuHotPlug\0"
2929 "AmlFilePath\0"
[35746]2930 "Serial0IoPortBase\0"
2931 "Serial1IoPortBase\0"
2932 "Serial0Irq\0"
2933 "Serial1Irq\0"
[40019]2934 "AcpiOemId\0"
2935 "AcpiCreatorId\0"
2936 "AcpiCreatorRev\0"
2937 "CustomTable\0"
2938 "SLICTable\0"
[17572]2939 ))
[1]2940 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2941 N_("Configuration error: Invalid config key for ACPI device"));
2942
2943 /* query whether we are supposed to present an IOAPIC */
[37446]2944 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
[17572]2945 if (RT_FAILURE(rc))
[1]2946 return PDMDEV_SET_ERROR(pDevIns, rc,
[6300]2947 N_("Configuration error: Failed to read \"IOAPIC\""));
[1]2948
[37446]2949 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
[12311]2950 if (RT_FAILURE(rc))
2951 return PDMDEV_SET_ERROR(pDevIns, rc,
2952 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
2953
[10372]2954 /* query whether we are supposed to present an FDC controller */
[37446]2955 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
[17572]2956 if (RT_FAILURE(rc))
[10372]2957 return PDMDEV_SET_ERROR(pDevIns, rc,
2958 N_("Configuration error: Failed to read \"FdcEnabled\""));
2959
[16170]2960 /* query whether we are supposed to present HPET */
[37446]2961 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
[16170]2962 if (RT_FAILURE(rc))
2963 return PDMDEV_SET_ERROR(pDevIns, rc,
2964 N_("Configuration error: Failed to read \"HpetEnabled\""));
[33540]2965 /* query MCFG configuration */
[37446]2966 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
[32591]2967 if (RT_FAILURE(rc))
2968 return PDMDEV_SET_ERROR(pDevIns, rc,
2969 N_("Configuration error: Failed to read \"McfgBase\""));
[37446]2970 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
[32637]2971 if (RT_FAILURE(rc))
2972 return PDMDEV_SET_ERROR(pDevIns, rc,
2973 N_("Configuration error: Failed to read \"McfgLength\""));
[37446]2974 pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
[32591]2975
[40019]2976 /* query whether we are supposed to present custom table */
2977 pThis->fUseCust = false;
2978
[16170]2979 /* query whether we are supposed to present SMC */
[37446]2980 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
[16170]2981 if (RT_FAILURE(rc))
2982 return PDMDEV_SET_ERROR(pDevIns, rc,
2983 N_("Configuration error: Failed to read \"SmcEnabled\""));
2984
[19007]2985 /* query whether we are supposed to present RTC object */
[37446]2986 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
[19007]2987 if (RT_FAILURE(rc))
2988 return PDMDEV_SET_ERROR(pDevIns, rc,
2989 N_("Configuration error: Failed to read \"ShowRtc\""));
2990
2991 /* query whether we are supposed to present CPU objects */
[37446]2992 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
[19007]2993 if (RT_FAILURE(rc))
2994 return PDMDEV_SET_ERROR(pDevIns, rc,
[21829]2995 N_("Configuration error: Failed to read \"ShowCpu\""));
[19007]2996
[28487]2997 /* query primary NIC PCI address */
[37446]2998 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
[28487]2999 if (RT_FAILURE(rc))
3000 return PDMDEV_SET_ERROR(pDevIns, rc,
3001 N_("Configuration error: Failed to read \"NicPciAddress\""));
3002
[31519]3003 /* query primary NIC PCI address */
[37446]3004 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
[31519]3005 if (RT_FAILURE(rc))
3006 return PDMDEV_SET_ERROR(pDevIns, rc,
3007 N_("Configuration error: Failed to read \"AudioPciAddress\""));
3008
[32471]3009 /* query IO controller (southbridge) PCI address */
[37446]3010 rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
[32471]3011 if (RT_FAILURE(rc))
3012 return PDMDEV_SET_ERROR(pDevIns, rc,
3013 N_("Configuration error: Failed to read \"IocPciAddress\""));
3014
[32477]3015 /* query host bus controller PCI address */
[37446]3016 rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
[32477]3017 if (RT_FAILURE(rc))
3018 return PDMDEV_SET_ERROR(pDevIns, rc,
3019 N_("Configuration error: Failed to read \"HostBusPciAddress\""));
3020
[31963]3021 /* query whether S1 power state should be exposed */
[37446]3022 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
[31963]3023 if (RT_FAILURE(rc))
3024 return PDMDEV_SET_ERROR(pDevIns, rc,
3025 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
3026
3027 /* query whether S4 power state should be exposed */
[37446]3028 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
[31963]3029 if (RT_FAILURE(rc))
3030 return PDMDEV_SET_ERROR(pDevIns, rc,
[35546]3031 N_("Configuration error: Failed to read \"PowerS4Enabled\""));
[31963]3032
3033 /* query whether S1 power state should save the VM state */
[37446]3034 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
[31963]3035 if (RT_FAILURE(rc))
3036 return PDMDEV_SET_ERROR(pDevIns, rc,
3037 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
3038
[25825]3039 /* query whether we are allow CPU hot plugging */
[37446]3040 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
[25817]3041 if (RT_FAILURE(rc))
3042 return PDMDEV_SET_ERROR(pDevIns, rc,
[25838]3043 N_("Configuration error: Failed to read \"CpuHotPlug\""));
[25817]3044
[40019]3045 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
3046 if (RT_FAILURE(rc))
[1]3047 return PDMDEV_SET_ERROR(pDevIns, rc,
[6300]3048 N_("Configuration error: Failed to read \"GCEnabled\""));
[1]3049
[40019]3050 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
3051 if (RT_FAILURE(rc))
[1]3052 return PDMDEV_SET_ERROR(pDevIns, rc,
[40019]3053 N_("configuration error: failed to read \"R0Enabled\""));
[1]3054
[35746]3055 /* query serial info */
[37446]3056 rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
[35746]3057 if (RT_FAILURE(rc))
3058 return PDMDEV_SET_ERROR(pDevIns, rc,
3059 N_("Configuration error: Failed to read \"Serial0Irq\""));
3060
[37446]3061 rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
[35746]3062 if (RT_FAILURE(rc))
3063 return PDMDEV_SET_ERROR(pDevIns, rc,
3064 N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
3065
3066 /* Serial 1 is enabled, get config data */
[37446]3067 rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
[35746]3068 if (RT_FAILURE(rc))
3069 return PDMDEV_SET_ERROR(pDevIns, rc,
3070 N_("Configuration error: Failed to read \"Serial1Irq\""));
3071
[37446]3072 rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
[35746]3073 if (RT_FAILURE(rc))
3074 return PDMDEV_SET_ERROR(pDevIns, rc,
3075 N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
3076
[25817]3077 /* Try to attach the other CPUs */
[37446]3078 for (unsigned i = 1; i < pThis->cCpus; i++)
[25817]3079 {
[37446]3080 if (pThis->fCpuHotPlug)
[25820]3081 {
3082 PPDMIBASE IBaseTmp;
[37446]3083 rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
[25817]3084
[25820]3085 if (RT_SUCCESS(rc))
3086 {
[37446]3087 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3088 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
[25820]3089 Log(("acpi: Attached CPU %u\n", i));
3090 }
3091 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3092 Log(("acpi: CPU %u not attached yet\n", i));
3093 else
3094 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
3095 }
3096 else
[25817]3097 {
[25825]3098 /* CPU is always attached if hot-plug is not enabled. */
[37446]3099 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3100 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
[25817]3101 }
3102 }
3103
[40019]3104 char *pszOemId = NULL;
3105 rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiOemId", &pszOemId, "VBOX ");
3106 if (RT_FAILURE(rc))
3107 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3108 N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
3109 size_t cbOemId = strlen(pszOemId);
3110 if (cbOemId > 6)
3111 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3112 N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
3113 memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
3114 memcpy(pThis->au8OemId, pszOemId, cbOemId);
3115 MMR3HeapFree(pszOemId);
[25817]3116
[40019]3117 char *pszCreatorId = NULL;
3118 rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
3119 if (RT_FAILURE(rc))
3120 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3121 N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
3122 size_t cbCreatorId = strlen(pszCreatorId);
3123 if (cbCreatorId > 4)
3124 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3125 N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
3126 memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
3127 memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
3128 MMR3HeapFree(pszCreatorId);
3129
3130 rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
3131 if (RT_FAILURE(rc))
3132 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3133 N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
3134 pThis->u32OemRevision = RT_H2LE_U32(0x1);
3135
3136 /*
3137 * Get the custom table binary file name.
3138 */
3139 char *pszCustBinFile;
3140 rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "CustomTable", &pszCustBinFile);
3141 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3142 rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "SLICTable", &pszCustBinFile);
3143 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3144 {
3145 pszCustBinFile = NULL;
3146 rc = VINF_SUCCESS;
3147 }
3148 else if (RT_FAILURE(rc))
3149 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3150 N_("Configuration error: Querying \"CustomTable\" as a string failed"));
3151 else if (!*pszCustBinFile)
3152 {
3153 MMR3HeapFree(pszCustBinFile);
3154 pszCustBinFile = NULL;
3155 }
3156
3157 /*
3158 * Determine the custom table binary size, open specified ROM file in the process.
3159 */
3160 if (pszCustBinFile)
3161 {
3162 RTFILE FileCUSTBin;
3163 rc = RTFileOpen(&FileCUSTBin, pszCustBinFile,
3164 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
3165 if (RT_SUCCESS(rc))
3166 {
3167 rc = RTFileGetSize(FileCUSTBin, &pThis->cbCustBin);
3168 if (RT_SUCCESS(rc))
3169 {
3170 /* The following checks should be in sync the AssertReleaseMsg's below. */
3171 if ( pThis->cbCustBin > 3072
3172 || pThis->cbCustBin < sizeof(ACPITBLHEADER))
3173 rc = VERR_TOO_MUCH_DATA;
3174
3175 /*
3176 * Allocate buffer for the custom table binary data.
3177 */
3178 pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, pThis->cbCustBin);
3179 if (pThis->pu8CustBin)
3180 {
3181 rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
3182 if (RT_FAILURE(rc))
3183 {
3184 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbCustBin, rc));
3185 MMR3HeapFree(pThis->pu8CustBin);
3186 pThis->pu8CustBin = NULL;
3187 }
3188 else
3189 {
3190 pThis->fUseCust = true;
3191 memcpy(&pThis->au8OemId[0], &pThis->pu8CustBin[10], 6);
3192 memcpy(&pThis->au8OemTabId[0], &pThis->pu8CustBin[16], 8);
3193 memcpy(&pThis->u32OemRevision, &pThis->pu8CustBin[24], 4);
3194 memcpy(&pThis->au8CreatorId[0], &pThis->pu8CustBin[28], 4);
3195 memcpy(&pThis->u32CreatorRev, &pThis->pu8CustBin[32], 4);
3196 LogRel(("Reading custom ACPI table from file '%s' (%d bytes)\n", pszCustBinFile, pThis->cbCustBin));
3197 }
3198 }
3199 else
3200 rc = VERR_NO_MEMORY;
3201
3202 RTFileClose(FileCUSTBin);
3203 }
3204 }
3205 MMR3HeapFree(pszCustBinFile);
3206 if (RT_FAILURE(rc))
3207 return PDMDEV_SET_ERROR(pDevIns, rc,
3208 N_("Error reading custom ACPI table"));
3209 }
3210
[21820]3211 /* Set default port base */
[37446]3212 pThis->uPmIoPortBase = PM_PORT_BASE;
[21820]3213
[26001]3214 /*
3215 * FDC and SMC try to use the same non-shareable interrupt (6),
[25987]3216 * enable only one device.
3217 */
[37446]3218 if (pThis->fUseSmc)
3219 pThis->fUseFdc = false;
[25987]3220
[37446]3221 /*
3222 * Plant ACPI tables.
3223 */
[26057]3224 RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
3225 if (!GCPhysRsdp)
[1]3226 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
[6300]3227 N_("Can not find space for RSDP. ACPI is disabled"));
[1]3228
[37446]3229 rc = acpiPlantTables(pThis);
[17572]3230 if (RT_FAILURE(rc))
[1]3231 return rc;
3232
[37446]3233 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
[18143]3234 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
[17572]3235 if (RT_FAILURE(rc))
[1]3236 return rc;
3237
[37446]3238 /*
3239 * Register I/O ports.
3240 */
3241 rc = acpiRegisterPmHandlers(pThis);
[21820]3242 if (RT_FAILURE(rc))
3243 return rc;
3244
3245#define R(addr, cnt, writer, reader, description) \
[17572]3246 do { \
[37446]3247 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
[17572]3248 NULL, NULL, description); \
3249 if (RT_FAILURE(rc)) \
3250 return rc; \
[1]3251 } while (0)
[17572]3252 R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
[1]3253#ifdef DEBUG_ACPI
[17572]3254 R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
3255 R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
[1]3256#endif
[17572]3257 R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
3258 R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
3259 R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
3260 R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
3261 R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
[1]3262#undef R
3263
[37446]3264 /*
3265 * Create the PM timer.
3266 */
[37526]3267 PTMTIMER pTimer;
[37446]3268 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiPmTimer, &pThis->dev,
[37526]3269 TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
3270 AssertRCReturn(rc, rc);
3271 pThis->pPmTimerR3 = pTimer;
3272 pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
3273 pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
[1]3274
[37526]3275 rc = TMTimerLock(pTimer, VERR_IGNORED);
3276 AssertRCReturn(rc, rc);
3277 pThis->u64PmTimerInitial = TMTimerGet(pTimer);
[37446]3278 acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
[37526]3279 TMTimerUnlock(pTimer);
[1]3280
[37446]3281 /*
3282 * Set up the PCI device.
3283 */
3284 PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
3285 PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
[1]3286
[21820]3287 /* See p. 50 of PIIX4 manual */
[37446]3288 PCIDevSetCommand(&pThis->dev, 0x01);
3289 PCIDevSetStatus(&pThis->dev, 0x0280);
[1]3290
[37446]3291 PCIDevSetRevisionId(&pThis->dev, 0x08);
[1]3292
[37446]3293 PCIDevSetClassProg(&pThis->dev, 0x00);
3294 PCIDevSetClassSub(&pThis->dev, 0x80);
3295 PCIDevSetClassBase(&pThis->dev, 0x06);
[21820]3296
[37446]3297 PCIDevSetHeaderType(&pThis->dev, 0x80);
[1]3298
[37446]3299 PCIDevSetBIST(&pThis->dev, 0x00);
[1]3300
[37446]3301 PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
3302 PCIDevSetInterruptPin (&pThis->dev, 0x01);
[21820]3303
[37446]3304 pThis->dev.config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
[21820]3305
[25968]3306#if 0
3307 int smb_io_base = 0xb100;
3308 dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
3309 dev->config[0x90] = smb_io_base >> 8;
3310#endif
3311
[37446]3312 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
[17572]3313 if (RT_FAILURE(rc))
[1]3314 return rc;
3315
[37446]3316 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
3317 acpiPciConfigRead, &pThis->pfnAcpiPciConfigRead,
3318 acpiPciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
[21820]3319
[37446]3320 /*
3321 * Register the saved state.
3322 */
3323 rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*pThis), acpiSaveState, acpiLoadState);
[11208]3324 if (RT_FAILURE(rc))
[1]3325 return rc;
3326
3327 /*
3328 * Get the corresponding connector interface
3329 */
[37446]3330 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
[17572]3331 if (RT_SUCCESS(rc))
[1]3332 {
[37446]3333 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
3334 if (!pThis->pDrv)
[1]3335 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
[6300]3336 N_("LUN #0 doesn't have an ACPI connector interface"));
[1]3337 }
3338 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3339 {
[17572]3340 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
[26165]3341 pDevIns->pReg->szName, pDevIns->iInstance));
[1]3342 rc = VINF_SUCCESS;
3343 }
3344 else
[17572]3345 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
[1]3346
3347 return rc;
3348}
3349
3350/**
3351 * The device registration structure.
3352 */
3353const PDMDEVREG g_DeviceACPI =
3354{
3355 /* u32Version */
3356 PDM_DEVREG_VERSION,
[26165]3357 /* szName */
[1]3358 "acpi",
[12977]3359 /* szRCMod */
[1]3360 "VBoxDDGC.gc",
3361 /* szR0Mod */
3362 "VBoxDDR0.r0",
3363 /* pszDescription */
3364 "Advanced Configuration and Power Interface",
3365 /* fFlags */
[12978]3366 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
[1]3367 /* fClass */
3368 PDM_DEVREG_CLASS_ACPI,
3369 /* cMaxInstances */
[40282]3370 ~0U,
[1]3371 /* cbInstance */
3372 sizeof(ACPIState),
3373 /* pfnConstruct */
3374 acpiConstruct,
3375 /* pfnDestruct */
[40019]3376 acpiDestruct,
[1]3377 /* pfnRelocate */
3378 acpiRelocate,
3379 /* pfnIOCtl */
3380 NULL,
3381 /* pfnPowerOn */
3382 NULL,
3383 /* pfnReset */
3384 acpiReset,
3385 /* pfnSuspend */
3386 NULL,
3387 /* pfnResume */
[32189]3388 acpiResume,
[1]3389 /* pfnAttach */
[25817]3390 acpiAttach,
[1]3391 /* pfnDetach */
[25817]3392 acpiDetach,
[1]3393 /* pfnQueryInterface. */
[12977]3394 NULL,
3395 /* pfnInitComplete */
3396 NULL,
3397 /* pfnPowerOff */
3398 NULL,
3399 /* pfnSoftReset */
3400 NULL,
3401 /* u32VersionEnd */
3402 PDM_DEVREG_VERSION
[1]3403};
3404
3405#endif /* IN_RING3 */
[491]3406#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use