VirtualBox

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

Last change on this file since 53426 was 53083, checked in by vboxsync, 10 years ago

DevACPI: properly relocate pDevInsRC (should fix occassional crashes in raw mode)

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette