VirtualBox

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

Last change on this file since 54266 was 53528, checked in by vboxsync, 10 years ago

Devices/Graphics, Devices/PC/DevACPI, Main: add support for sending video mode hints through the VGA device.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 124.7 KB
Line 
1/* $Id: DevACPI.cpp 53528 2014-12-12 20:22:39Z 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 * Send an ACPI monitor hot-plug event.
857 *
858 * @returns VBox status code
859 * @param pInterface Pointer to the interface structure containing the
860 * called function pointer.
861 */
862static DECLCALLBACK(int) acpiR3Port_MonitorHotPlugEvent(PPDMIACPIPORT pInterface)
863{
864 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
865 DEVACPI_LOCK_R3(pThis);
866
867 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x4, pThis->gpe0_en);
868
869 DEVACPI_UNLOCK(pThis);
870 return VINF_SUCCESS;
871}
872
873/**
874 * Used by acpiR3PmTimer to re-arm the PM timer.
875 *
876 * The caller is expected to either hold the clock lock or to have made sure
877 * the VM is resetting or loading state.
878 *
879 * @param pThis The ACPI instance.
880 * @param uNow The current time.
881 */
882static void acpiR3PmTimerReset(ACPIState *pThis, uint64_t uNow)
883{
884 uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
885 uint32_t uPmTmrCyclesToRollover = TMR_VAL_MSB - (pThis->uPmTimerVal & (TMR_VAL_MSB - 1));
886 uint64_t uInterval = ASMMultU64ByU32DivByU32(uPmTmrCyclesToRollover, uTimerFreq, PM_TMR_FREQ);
887 TMTimerSet(pThis->pPmTimerR3, uNow + uInterval + 1);
888 Log(("acpi: uInterval = %RU64\n", uInterval));
889}
890
891#endif
892
893/**
894 * Used by acpiR3PMTimer & acpiPmTmrRead to update TMR_VAL and update TMR_STS
895 *
896 * The caller is expected to either hold the clock lock or to have made sure
897 * the VM is resetting or loading state.
898 *
899 * @param pThis The ACPI instance
900 * @param uNow The current time
901 */
902
903static void acpiPmTimerUpdate(ACPIState *pThis, uint64_t u64Now)
904{
905 uint32_t msb = pThis->uPmTimerVal & TMR_VAL_MSB;
906 uint64_t u64Elapsed = u64Now - pThis->u64PmTimerInitial;
907 Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPmTimer)));
908
909 pThis->uPmTimerVal = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer))) & TMR_VAL_MASK;
910
911 if ( (pThis->uPmTimerVal & TMR_VAL_MSB) != msb)
912 {
913 apicUpdatePm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
914 }
915}
916
917#ifdef IN_RING3
918
919/**
920 * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
921 */
922static DECLCALLBACK(void) acpiR3PmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
923{
924 ACPIState *pThis = (ACPIState *)pvUser;
925 Assert(TMTimerIsLockOwner(pTimer));
926 NOREF(pDevIns);
927
928 DEVACPI_LOCK_R3(pThis);
929 Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
930 pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
931 pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
932 uint64_t u64Now = TMTimerGet(pTimer);
933 acpiPmTimerUpdate(pThis, u64Now);
934 DEVACPI_UNLOCK(pThis);
935
936 acpiR3PmTimerReset(pThis, u64Now);
937}
938
939/**
940 * _BST method - used by acpiR3BatDataRead to implement BAT_STATUS_STATE and
941 * acpiR3LoadState.
942 *
943 * @returns VINF_SUCCESS.
944 * @param pThis The ACPI instance.
945 */
946static int acpiR3FetchBatteryStatus(ACPIState *pThis)
947{
948 uint32_t *p = pThis->au8BatteryInfo;
949 bool fPresent; /* battery present? */
950 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
951 PDMACPIBATSTATE hostBatteryState; /* bitfield */
952 uint32_t hostPresentRate; /* 0..1000 */
953 int rc;
954
955 if (!pThis->pDrv)
956 return VINF_SUCCESS;
957 rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
958 &hostBatteryState, &hostPresentRate);
959 AssertRC(rc);
960
961 /* default values */
962 p[BAT_STATUS_STATE] = hostBatteryState;
963 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
964 : hostPresentRate * 50; /* mW */
965 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
966 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
967
968 /* did we get a valid battery state? */
969 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
970 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
971 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
972 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
973
974 return VINF_SUCCESS;
975}
976
977/**
978 * _BIF method - used by acpiR3BatDataRead to implement BAT_INFO_UNITS and
979 * acpiR3LoadState.
980 *
981 * @returns VINF_SUCCESS.
982 * @param pThis The ACPI instance.
983 */
984static int acpiR3FetchBatteryInfo(ACPIState *pThis)
985{
986 uint32_t *p = pThis->au8BatteryInfo;
987
988 p[BAT_INFO_UNITS] = 0; /* mWh */
989 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
990 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
991 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
992 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
993 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
994 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
995 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
996 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
997
998 return VINF_SUCCESS;
999}
1000
1001/**
1002 * The _STA method - used by acpiR3BatDataRead to implement BAT_DEVICE_STATUS.
1003 *
1004 * @returns status mask or 0.
1005 * @param pThis The ACPI instance.
1006 */
1007static uint32_t acpiR3GetBatteryDeviceStatus(ACPIState *pThis)
1008{
1009 bool fPresent; /* battery present? */
1010 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1011 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1012 uint32_t hostPresentRate; /* 0..1000 */
1013 int rc;
1014
1015 if (!pThis->pDrv)
1016 return 0;
1017 rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
1018 &hostBatteryState, &hostPresentRate);
1019 AssertRC(rc);
1020
1021 return fPresent
1022 ? STA_DEVICE_PRESENT_MASK /* present */
1023 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1024 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1025 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1026 | STA_BATTERY_PRESENT_MASK /* battery is present */
1027 : 0; /* device not present */
1028}
1029
1030/**
1031 * Used by acpiR3BatDataRead to implement BAT_POWER_SOURCE.
1032 *
1033 * @returns status.
1034 * @param pThis The ACPI instance.
1035 */
1036static uint32_t acpiR3GetPowerSource(ACPIState *pThis)
1037{
1038 /* query the current power source from the host driver */
1039 if (!pThis->pDrv)
1040 return AC_ONLINE;
1041
1042 PDMACPIPOWERSOURCE ps;
1043 int rc = pThis->pDrv->pfnQueryPowerSource(pThis->pDrv, &ps);
1044 AssertRC(rc);
1045 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1046}
1047
1048/**
1049 * @callback_method_impl{FNIOMIOPORTOUT, Battery status index}
1050 */
1051PDMBOTHCBDECL(int) acpiR3BatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1052{
1053 Log(("acpiR3BatIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
1054 if (cb != 4)
1055 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1056
1057 ACPIState *pThis = (ACPIState *)pvUser;
1058 DEVACPI_LOCK_R3(pThis);
1059
1060 u32 >>= pThis->u8IndexShift;
1061 /* see comment at the declaration of u8IndexShift */
1062 if (pThis->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
1063 {
1064 pThis->u8IndexShift = 2;
1065 u32 >>= 2;
1066 }
1067 Assert(u32 < BAT_INDEX_LAST);
1068 pThis->uBatteryIndex = u32;
1069
1070 DEVACPI_UNLOCK(pThis);
1071 return VINF_SUCCESS;
1072}
1073
1074/**
1075 * @callback_method_impl{FNIOMIOPORTIN, Battery status data}
1076 */
1077PDMBOTHCBDECL(int) acpiR3BatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1078{
1079 if (cb != 4)
1080 return VERR_IOM_IOPORT_UNUSED;
1081
1082 ACPIState *pThis = (ACPIState *)pvUser;
1083 DEVACPI_LOCK_R3(pThis);
1084
1085 int rc = VINF_SUCCESS;
1086 switch (pThis->uBatteryIndex)
1087 {
1088 case BAT_STATUS_STATE:
1089 acpiR3FetchBatteryStatus(pThis);
1090 /* fall thru */
1091 case BAT_STATUS_PRESENT_RATE:
1092 case BAT_STATUS_REMAINING_CAPACITY:
1093 case BAT_STATUS_PRESENT_VOLTAGE:
1094 *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
1095 break;
1096
1097 case BAT_INFO_UNITS:
1098 acpiR3FetchBatteryInfo(pThis);
1099 /* fall thru */
1100 case BAT_INFO_DESIGN_CAPACITY:
1101 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1102 case BAT_INFO_TECHNOLOGY:
1103 case BAT_INFO_DESIGN_VOLTAGE:
1104 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1105 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1106 case BAT_INFO_CAPACITY_GRANULARITY_1:
1107 case BAT_INFO_CAPACITY_GRANULARITY_2:
1108 *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
1109 break;
1110
1111 case BAT_DEVICE_STATUS:
1112 *pu32 = acpiR3GetBatteryDeviceStatus(pThis);
1113 break;
1114
1115 case BAT_POWER_SOURCE:
1116 *pu32 = acpiR3GetPowerSource(pThis);
1117 break;
1118
1119 default:
1120 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
1121 *pu32 = UINT32_MAX;
1122 break;
1123 }
1124
1125 DEVACPI_UNLOCK(pThis);
1126 return rc;
1127}
1128
1129/**
1130 * @callback_method_impl{FNIOMIOPORTOUT, System info index}
1131 */
1132PDMBOTHCBDECL(int) acpiR3SysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1133{
1134 Log(("acpiR3SysInfoIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
1135 if (cb != 4)
1136 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1137
1138 ACPIState *pThis = (ACPIState *)pvUser;
1139 DEVACPI_LOCK_R3(pThis);
1140
1141 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1142 pThis->uSystemInfoIndex = u32;
1143 else
1144 {
1145 /* see comment at the declaration of u8IndexShift */
1146 if (u32 > SYSTEM_INFO_INDEX_END && pThis->u8IndexShift == 0)
1147 {
1148 if ((u32 >> 2) < SYSTEM_INFO_INDEX_END && (u32 & 0x3) == 0)
1149 pThis->u8IndexShift = 2;
1150 }
1151
1152 u32 >>= pThis->u8IndexShift;
1153 Assert(u32 < SYSTEM_INFO_INDEX_END);
1154 pThis->uSystemInfoIndex = u32;
1155 }
1156
1157 DEVACPI_UNLOCK(pThis);
1158 return VINF_SUCCESS;
1159}
1160
1161/**
1162 * @callback_method_impl{FNIOMIOPORTIN, System info data}
1163 */
1164PDMBOTHCBDECL(int) acpiR3SysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1165{
1166 if (cb != 4)
1167 return VERR_IOM_IOPORT_UNUSED;
1168
1169 ACPIState *pThis = (ACPIState *)pvUser;
1170 DEVACPI_LOCK_R3(pThis);
1171
1172 int rc = VINF_SUCCESS;
1173 uint32_t const uSystemInfoIndex = pThis->uSystemInfoIndex;
1174 switch (uSystemInfoIndex)
1175 {
1176 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
1177 *pu32 = pThis->cbRamLow;
1178 break;
1179
1180 case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
1181 *pu32 = pThis->cbRamHigh >> 16; /* 64KB units */
1182 Assert(((uint64_t)*pu32 << 16) == pThis->cbRamHigh);
1183 break;
1184
1185 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1186 *pu32 = pThis->u8UseIOApic;
1187 break;
1188
1189 case SYSTEM_INFO_INDEX_HPET_STATUS:
1190 *pu32 = pThis->fUseHpet
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_SMC_STATUS:
1199 *pu32 = pThis->fUseSmc
1200 ? ( STA_DEVICE_PRESENT_MASK
1201 | STA_DEVICE_ENABLED_MASK
1202 /* no need to show this device in the UI */
1203 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1204 : 0;
1205 break;
1206
1207 case SYSTEM_INFO_INDEX_FDC_STATUS:
1208 *pu32 = pThis->fUseFdc
1209 ? ( STA_DEVICE_PRESENT_MASK
1210 | STA_DEVICE_ENABLED_MASK
1211 | STA_DEVICE_SHOW_IN_UI_MASK
1212 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1213 : 0;
1214 break;
1215
1216 case SYSTEM_INFO_INDEX_NIC_ADDRESS:
1217 *pu32 = pThis->u32NicPciAddress;
1218 break;
1219
1220 case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
1221 *pu32 = pThis->u32AudioPciAddress;
1222 break;
1223
1224 case SYSTEM_INFO_INDEX_POWER_STATES:
1225 *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
1226 if (pThis->fS1Enabled) /* Optionally expose S1 and S4 */
1227 *pu32 |= RT_BIT(1);
1228 if (pThis->fS4Enabled)
1229 *pu32 |= RT_BIT(4);
1230 break;
1231
1232 case SYSTEM_INFO_INDEX_IOC_ADDRESS:
1233 *pu32 = pThis->u32IocPciAddress;
1234 break;
1235
1236 case SYSTEM_INFO_INDEX_HBC_ADDRESS:
1237 *pu32 = pThis->u32HbcPciAddress;
1238 break;
1239
1240 case SYSTEM_INFO_INDEX_PCI_BASE:
1241 /** @todo couldn't MCFG be in 64-bit range? */
1242 Assert(pThis->u64PciConfigMMioAddress < 0xffffffff);
1243 *pu32 = (uint32_t)pThis->u64PciConfigMMioAddress;
1244 break;
1245
1246 case SYSTEM_INFO_INDEX_PCI_LENGTH:
1247 /** @todo couldn't MCFG be in 64-bit range? */
1248 Assert(pThis->u64PciConfigMMioLength< 0xffffffff);
1249 *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
1250 break;
1251
1252 /* This is only for compatibility with older saved states that
1253 may include ACPI code that read these values. Legacy is
1254 a wonderful thing, isn't it? :-) */
1255 case SYSTEM_INFO_INDEX_CPU0_STATUS:
1256 case SYSTEM_INFO_INDEX_CPU1_STATUS:
1257 case SYSTEM_INFO_INDEX_CPU2_STATUS:
1258 case SYSTEM_INFO_INDEX_CPU3_STATUS:
1259 *pu32 = ( pThis->fShowCpu
1260 && pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < pThis->cCpus
1261 && VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached,
1262 pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS) )
1263 ? ( STA_DEVICE_PRESENT_MASK
1264 | STA_DEVICE_ENABLED_MASK
1265 | STA_DEVICE_SHOW_IN_UI_MASK
1266 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1267 : 0;
1268 break;
1269
1270 case SYSTEM_INFO_INDEX_RTC_STATUS:
1271 *pu32 = pThis->fShowRtc
1272 ? ( STA_DEVICE_PRESENT_MASK
1273 | STA_DEVICE_ENABLED_MASK
1274 | STA_DEVICE_SHOW_IN_UI_MASK
1275 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1276 : 0;
1277 break;
1278
1279 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1280 if (pThis->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1281 {
1282 *pu32 = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, pThis->idCpuLockCheck);
1283 pThis->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1284 }
1285 else
1286 {
1287 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "CPU lock check protocol violation (idCpuLockCheck=%#x)\n",
1288 pThis->idCpuLockCheck);
1289 /* Always return locked status just to be safe */
1290 *pu32 = 1;
1291 }
1292 break;
1293
1294 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1295 *pu32 = pThis->u32CpuEventType;
1296 break;
1297
1298 case SYSTEM_INFO_INDEX_CPU_EVENT:
1299 *pu32 = pThis->u32CpuEvent;
1300 break;
1301
1302 case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
1303 *pu32 = pThis->uSerial0IoPortBase;
1304 break;
1305
1306 case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
1307 *pu32 = pThis->uSerial0Irq;
1308 break;
1309
1310 case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
1311 *pu32 = pThis->uSerial1IoPortBase;
1312 break;
1313
1314 case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
1315 *pu32 = pThis->uSerial1Irq;
1316 break;
1317
1318 case SYSTEM_INFO_INDEX_END:
1319 /** @todo why isn't this setting any output value? */
1320 break;
1321
1322 /* Solaris 9 tries to read from this index */
1323 case SYSTEM_INFO_INDEX_INVALID:
1324 *pu32 = 0;
1325 break;
1326
1327 default:
1328 *pu32 = UINT32_MAX;
1329 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
1330 break;
1331 }
1332
1333 DEVACPI_UNLOCK(pThis);
1334 Log(("acpiR3SysInfoDataRead: idx=%d val=%#x (%d) rc=%Rrc\n", uSystemInfoIndex, *pu32, *pu32, rc));
1335 return rc;
1336}
1337
1338/**
1339 * @callback_method_impl{FNIOMIOPORTOUT, System info data}
1340 */
1341PDMBOTHCBDECL(int) acpiR3SysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1342{
1343 ACPIState *pThis = (ACPIState *)pvUser;
1344 if (cb != 4)
1345 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
1346
1347 DEVACPI_LOCK_R3(pThis);
1348 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, pThis->uSystemInfoIndex));
1349
1350 int rc = VINF_SUCCESS;
1351 switch (pThis->uSystemInfoIndex)
1352 {
1353 case SYSTEM_INFO_INDEX_INVALID:
1354 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1355 pThis->u8IndexShift = 0;
1356 break;
1357
1358 case SYSTEM_INFO_INDEX_VALID:
1359 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1360 pThis->u8IndexShift = 2;
1361 break;
1362
1363 case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
1364 pThis->idCpuLockCheck = u32;
1365 break;
1366
1367 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1368 if (u32 < pThis->cCpus)
1369 VMCPUSET_DEL(&pThis->CpuSetLocked, u32); /* Unlock the CPU */
1370 else
1371 LogRel(("ACPI: CPU %u does not exist\n", u32));
1372 break;
1373
1374 default:
1375 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
1376 break;
1377 }
1378
1379 DEVACPI_UNLOCK(pThis);
1380 return rc;
1381}
1382
1383/**
1384 * @callback_method_impl{FNIOMIOPORTIN, PM1a Enable}
1385 */
1386PDMBOTHCBDECL(int) acpiR3Pm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1387{
1388 NOREF(pDevIns); NOREF(Port);
1389 if (cb != 2)
1390 return VERR_IOM_IOPORT_UNUSED;
1391
1392 ACPIState *pThis = (ACPIState *)pvUser;
1393 DEVACPI_LOCK_R3(pThis);
1394
1395 *pu32 = pThis->pm1a_en;
1396
1397 DEVACPI_UNLOCK(pThis);
1398 Log(("acpiR3Pm1aEnRead -> %#x\n", *pu32));
1399 return VINF_SUCCESS;
1400}
1401
1402/**
1403 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Enable}
1404 */
1405PDMBOTHCBDECL(int) acpiR3PM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1406{
1407 if (cb != 2 && cb != 4)
1408 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1409
1410 ACPIState *pThis = (ACPIState *)pvUser;
1411 DEVACPI_LOCK_R3(pThis);
1412
1413 Log(("acpiR3PM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
1414 u32 &= ~(RSR_EN | IGN_EN);
1415 u32 &= 0xffff;
1416 apicUpdatePm1a(pThis, pThis->pm1a_sts, u32);
1417
1418 DEVACPI_UNLOCK(pThis);
1419 return VINF_SUCCESS;
1420}
1421
1422/**
1423 * @callback_method_impl{FNIOMIOPORTIN, PM1a Status}
1424 */
1425PDMBOTHCBDECL(int) acpiR3Pm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1426{
1427 if (cb != 2)
1428 {
1429 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1430 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1431 }
1432
1433 ACPIState *pThis = (ACPIState *)pvUser;
1434 DEVACPI_LOCK_R3(pThis);
1435
1436 *pu32 = pThis->pm1a_sts;
1437
1438 DEVACPI_UNLOCK(pThis);
1439 Log(("acpiR3Pm1aStsRead: %#x\n", *pu32));
1440 return VINF_SUCCESS;
1441}
1442
1443/**
1444 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Status}
1445 */
1446PDMBOTHCBDECL(int) acpiR3PM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1447{
1448 if (cb != 2 && cb != 4)
1449 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1450
1451 ACPIState *pThis = (ACPIState *)pvUser;
1452 DEVACPI_LOCK_R3(pThis);
1453
1454 Log(("acpiR3PM1aStsWrite: %#x (%#x)\n", u32, u32 & ~(RSR_STS | IGN_STS) & 0xffff));
1455 u32 &= 0xffff;
1456 if (u32 & PWRBTN_STS)
1457 pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
1458 u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
1459 apicUpdatePm1a(pThis, u32, pThis->pm1a_en);
1460
1461 DEVACPI_UNLOCK(pThis);
1462 return VINF_SUCCESS;
1463}
1464
1465/**
1466 * @callback_method_impl{FNIOMIOPORTIN, PM1a Control}
1467 */
1468PDMBOTHCBDECL(int) acpiR3Pm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1469{
1470 if (cb != 2)
1471 {
1472 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1473 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1474 }
1475
1476 ACPIState *pThis = (ACPIState *)pvUser;
1477 DEVACPI_LOCK_R3(pThis);
1478
1479 *pu32 = pThis->pm1a_ctl;
1480
1481 DEVACPI_UNLOCK(pThis);
1482 Log(("acpiR3Pm1aCtlRead: %#x\n", *pu32));
1483 return VINF_SUCCESS;
1484}
1485
1486/**
1487 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Control}
1488 */
1489PDMBOTHCBDECL(int) acpiR3PM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1490{
1491 if (cb != 2 && cb != 4)
1492 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1493
1494 ACPIState *pThis = (ACPIState *)pvUser;
1495 DEVACPI_LOCK_R3(pThis);
1496
1497 Log(("acpiR3PM1aCtlWrite: %#x (%#x)\n", u32, u32 & ~(RSR_CNT | IGN_CNT) & 0xffff));
1498 u32 &= 0xffff;
1499 pThis->pm1a_ctl = u32 & ~(RSR_CNT | IGN_CNT);
1500
1501 int rc = VINF_SUCCESS;
1502 uint32_t const uSleepState = (pThis->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
1503 if (uSleepState != pThis->uSleepState)
1504 {
1505 pThis->uSleepState = uSleepState;
1506 switch (uSleepState)
1507 {
1508 case 0x00: /* S0 */
1509 break;
1510
1511 case 0x01: /* S1 */
1512 if (pThis->fS1Enabled)
1513 {
1514 LogRel(("Entering S1 power state (powered-on suspend)\n"));
1515 rc = acpiR3DoSleep(pThis);
1516 break;
1517 }
1518 LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
1519 /* fall thru */
1520
1521 case 0x04: /* S4 */
1522 if (pThis->fS4Enabled)
1523 {
1524 LogRel(("Entering S4 power state (suspend to disk)\n"));
1525 rc = acpiR3DoPowerOff(pThis);/* Same behavior as S5 */
1526 break;
1527 }
1528 LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
1529 /* fall thru */
1530
1531 case 0x05: /* S5 */
1532 LogRel(("Entering S5 power state (power down)\n"));
1533 rc = acpiR3DoPowerOff(pThis);
1534 break;
1535
1536 default:
1537 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Unknown sleep state %#x (u32=%#x)\n", uSleepState, u32);
1538 break;
1539 }
1540 }
1541
1542 DEVACPI_UNLOCK(pThis);
1543 Log(("acpiR3PM1aCtlWrite: rc=%Rrc\n", rc));
1544 return rc;
1545}
1546
1547#endif /* IN_RING3 */
1548
1549/**
1550 * @callback_method_impl{FNIOMIOPORTIN, PMTMR}
1551 *
1552 * @remarks Only I/O port currently implemented in all contexts.
1553 */
1554PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1555{
1556 if (cb != 4)
1557 return VERR_IOM_IOPORT_UNUSED;
1558
1559 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
1560
1561 /*
1562 * We use the clock lock to serialize access to u64PmTimerInitial and to
1563 * make sure we get a reliable time from the clock
1564 * as well as and to prevent uPmTimerVal from being updated during read.
1565 */
1566
1567 int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_R3_IOPORT_READ);
1568 if (rc != VINF_SUCCESS)
1569 return rc;
1570
1571 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
1572 if (rc != VINF_SUCCESS)
1573 {
1574 TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
1575 return rc;
1576 }
1577
1578 uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
1579 acpiPmTimerUpdate(pThis, u64Now);
1580 *pu32 = pThis->uPmTimerVal;
1581
1582 DEVACPI_UNLOCK(pThis);
1583 TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
1584
1585 DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
1586 Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
1587
1588 NOREF(pvUser); NOREF(Port);
1589 return rc;
1590}
1591
1592#ifdef IN_RING3
1593
1594/**
1595 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Status}
1596 */
1597PDMBOTHCBDECL(int) acpiR3Gpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1598{
1599 if (cb != 1)
1600 {
1601 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1602 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1603 }
1604
1605 ACPIState *pThis = (ACPIState *)pvUser;
1606 DEVACPI_LOCK_R3(pThis);
1607
1608 *pu32 = pThis->gpe0_sts & 0xff;
1609
1610 DEVACPI_UNLOCK(pThis);
1611 Log(("acpiR3Gpe0StsRead: %#x\n", *pu32));
1612 return VINF_SUCCESS;
1613}
1614
1615/**
1616 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Status}
1617 */
1618PDMBOTHCBDECL(int) acpiR3Gpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1619{
1620 if (cb != 1)
1621 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1622
1623 ACPIState *pThis = (ACPIState *)pvUser;
1624 DEVACPI_LOCK_R3(pThis);
1625
1626 Log(("acpiR3Gpe0StsWrite: %#x (%#x)\n", u32, pThis->gpe0_sts & ~u32));
1627 u32 = pThis->gpe0_sts & ~u32;
1628 apicR3UpdateGpe0(pThis, u32, pThis->gpe0_en);
1629
1630 DEVACPI_UNLOCK(pThis);
1631 return VINF_SUCCESS;
1632}
1633
1634/**
1635 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Enable}
1636 */
1637PDMBOTHCBDECL(int) acpiR3Gpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1638{
1639 if (cb != 1)
1640 {
1641 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1642 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1643 }
1644
1645 ACPIState *pThis = (ACPIState *)pvUser;
1646 DEVACPI_LOCK_R3(pThis);
1647
1648 *pu32 = pThis->gpe0_en & 0xff;
1649
1650 DEVACPI_UNLOCK(pThis);
1651 Log(("acpiR3Gpe0EnRead: %#x\n", *pu32));
1652 return VINF_SUCCESS;
1653}
1654
1655/**
1656 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Enable}
1657 */
1658PDMBOTHCBDECL(int) acpiR3Gpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1659{
1660 if (cb != 1)
1661 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1662
1663 ACPIState *pThis = (ACPIState *)pvUser;
1664 DEVACPI_LOCK_R3(pThis);
1665
1666 Log(("acpiR3Gpe0EnWrite: %#x\n", u32));
1667 apicR3UpdateGpe0(pThis, pThis->gpe0_sts, u32);
1668
1669 DEVACPI_UNLOCK(pThis);
1670 return VINF_SUCCESS;
1671}
1672
1673/**
1674 * @callback_method_impl{FNIOMIOPORTOUT, SMI_CMD}
1675 */
1676PDMBOTHCBDECL(int) acpiR3SmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1677{
1678 Log(("acpiR3SmiWrite %#x\n", u32));
1679 if (cb != 1)
1680 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1681
1682 ACPIState *pThis = (ACPIState *)pvUser;
1683 DEVACPI_LOCK_R3(pThis);
1684
1685 if (u32 == ACPI_ENABLE)
1686 pThis->pm1a_ctl |= SCI_EN;
1687 else if (u32 == ACPI_DISABLE)
1688 pThis->pm1a_ctl &= ~SCI_EN;
1689 else
1690 Log(("acpiR3SmiWrite: %#x <- unknown value\n", u32));
1691
1692 DEVACPI_UNLOCK(pThis);
1693 return VINF_SUCCESS;
1694}
1695
1696/**
1697 * @{FNIOMIOPORTOUT, ACPI_RESET_BLK}
1698 */
1699PDMBOTHCBDECL(int) acpiR3ResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1700{
1701 Log(("acpiR3ResetWrite: %#x\n", u32));
1702 NOREF(pvUser);
1703 if (cb != 1)
1704 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1705
1706 /* No state locking required. */
1707 int rc = VINF_SUCCESS;
1708 if (u32 == ACPI_RESET_REG_VAL)
1709 {
1710 LogRel(("Reset initiated by ACPI\n"));
1711 rc = PDMDevHlpVMReset(pDevIns);
1712 }
1713 else
1714 Log(("acpiR3ResetWrite: %#x <- unknown value\n", u32));
1715
1716 return rc;
1717}
1718
1719# ifdef DEBUG_ACPI
1720
1721/**
1722 * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
1723 */
1724PDMBOTHCBDECL(int) acpiR3DhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1725{
1726 NOREF(pvUser);
1727 switch (cb)
1728 {
1729 case 1:
1730 Log(("%#x\n", u32 & 0xff));
1731 break;
1732 case 2:
1733 Log(("%#6x\n", u32 & 0xffff));
1734 case 4:
1735 Log(("%#10x\n", u32));
1736 break;
1737 default:
1738 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1739 }
1740 return VINF_SUCCESS;
1741}
1742
1743/**
1744 * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
1745 */
1746PDMBOTHCBDECL(int) acpiR3DchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1747{
1748 NOREF(pvUser);
1749 switch (cb)
1750 {
1751 case 1:
1752 Log(("%c", u32 & 0xff));
1753 break;
1754 default:
1755 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1756 }
1757 return VINF_SUCCESS;
1758}
1759
1760# endif /* DEBUG_ACPI */
1761
1762/**
1763 * Used to calculate the value of a PM I/O port.
1764 *
1765 * @returns The actual I/O port value.
1766 * @param pThis The ACPI instance.
1767 * @param offset The offset into the I/O space, or -1 if invalid.
1768 */
1769static RTIOPORT acpiR3CalcPmPort(ACPIState *pThis, int32_t offset)
1770{
1771 Assert(pThis->uPmIoPortBase != 0);
1772
1773 if (offset == -1)
1774 return 0;
1775
1776 return (RTIOPORT)(pThis->uPmIoPortBase + offset);
1777}
1778
1779/**
1780 * Called by acpiR3LoadState and acpiR3UpdatePmHandlers to register the PM1a, PM
1781 * timer and GPE0 I/O ports.
1782 *
1783 * @returns VBox status code.
1784 * @param pThis The ACPI instance.
1785 */
1786static int acpiR3RegisterPmHandlers(ACPIState *pThis)
1787{
1788 int rc = VINF_SUCCESS;
1789
1790#define R(offset, cnt, writer, reader, description) \
1791 do { \
1792 rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
1793 NULL, NULL, description); \
1794 if (RT_FAILURE(rc)) \
1795 return rc; \
1796 } while (0)
1797#define L (GPE0_BLK_LEN / 2)
1798
1799 R(PM1a_EVT_OFFSET+2, 1, acpiR3PM1aEnWrite, acpiR3Pm1aEnRead, "ACPI PM1a Enable");
1800 R(PM1a_EVT_OFFSET, 1, acpiR3PM1aStsWrite, acpiR3Pm1aStsRead, "ACPI PM1a Status");
1801 R(PM1a_CTL_OFFSET, 1, acpiR3PM1aCtlWrite, acpiR3Pm1aCtlRead, "ACPI PM1a Control");
1802 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
1803 R(GPE0_OFFSET + L, L, acpiR3Gpe0EnWrite, acpiR3Gpe0EnRead, "ACPI GPE0 Enable");
1804 R(GPE0_OFFSET, L, acpiR3Gpe0StsWrite, acpiR3Gpe0StsRead, "ACPI GPE0 Status");
1805#undef L
1806#undef R
1807
1808 /* register RC stuff */
1809 if (pThis->fGCEnabled)
1810 {
1811 rc = PDMDevHlpIOPortRegisterRC(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
1812 1, 0, NULL, "acpiPMTmrRead",
1813 NULL, NULL, "ACPI PM Timer");
1814 AssertRCReturn(rc, rc);
1815 }
1816
1817 /* register R0 stuff */
1818 if (pThis->fR0Enabled)
1819 {
1820 rc = PDMDevHlpIOPortRegisterR0(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
1821 1, 0, NULL, "acpiPMTmrRead",
1822 NULL, NULL, "ACPI PM Timer");
1823 AssertRCReturn(rc, rc);
1824 }
1825
1826 return rc;
1827}
1828
1829/**
1830 * Called by acpiR3LoadState and acpiR3UpdatePmHandlers to unregister the PM1a, PM
1831 * timer and GPE0 I/O ports.
1832 *
1833 * @returns VBox status code.
1834 * @param pThis The ACPI instance.
1835 */
1836static int acpiR3UnregisterPmHandlers(ACPIState *pThis)
1837{
1838#define U(offset, cnt) \
1839 do { \
1840 int rc = PDMDevHlpIOPortDeregister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt); \
1841 AssertRCReturn(rc, rc); \
1842 } while (0)
1843#define L (GPE0_BLK_LEN / 2)
1844
1845 U(PM1a_EVT_OFFSET+2, 1);
1846 U(PM1a_EVT_OFFSET, 1);
1847 U(PM1a_CTL_OFFSET, 1);
1848 U(PM_TMR_OFFSET, 1);
1849 U(GPE0_OFFSET + L, L);
1850 U(GPE0_OFFSET, L);
1851#undef L
1852#undef U
1853
1854 return VINF_SUCCESS;
1855}
1856
1857/**
1858 * Called by acpiR3PciConfigWrite and acpiReset to change the location of the
1859 * PM1a, PM timer and GPE0 ports.
1860 *
1861 * @returns VBox status code.
1862 *
1863 * @param pThis The ACPI instance.
1864 * @param NewIoPortBase The new base address of the I/O ports.
1865 */
1866static int acpiR3UpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
1867{
1868 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
1869 if (NewIoPortBase != pThis->uPmIoPortBase)
1870 {
1871 int rc = acpiR3UnregisterPmHandlers(pThis);
1872 if (RT_FAILURE(rc))
1873 return rc;
1874
1875 pThis->uPmIoPortBase = NewIoPortBase;
1876
1877 rc = acpiR3RegisterPmHandlers(pThis);
1878 if (RT_FAILURE(rc))
1879 return rc;
1880
1881 /* We have to update FADT table acccording to the new base */
1882 rc = acpiR3PlantTables(pThis);
1883 AssertRC(rc);
1884 if (RT_FAILURE(rc))
1885 return rc;
1886 }
1887
1888 return VINF_SUCCESS;
1889}
1890
1891
1892/**
1893 * Saved state structure description, version 4.
1894 */
1895static const SSMFIELD g_AcpiSavedStateFields4[] =
1896{
1897 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1898 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1899 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1900 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1901 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1902 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1903 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1904 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1905 SSMFIELD_ENTRY(ACPIState, u64RamSize),
1906 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1907 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
1908 SSMFIELD_ENTRY(ACPIState, uSleepState),
1909 SSMFIELD_ENTRY_TERM()
1910};
1911
1912/**
1913 * Saved state structure description, version 5.
1914 */
1915static const SSMFIELD g_AcpiSavedStateFields5[] =
1916{
1917 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1918 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1919 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1920 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1921 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1922 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1923 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1924 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1925 SSMFIELD_ENTRY(ACPIState, uSleepState),
1926 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1927 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1928 SSMFIELD_ENTRY_TERM()
1929};
1930
1931/**
1932 * Saved state structure description, version 6.
1933 */
1934static const SSMFIELD g_AcpiSavedStateFields6[] =
1935{
1936 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1937 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1938 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1939 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1940 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1941 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1942 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1943 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1944 SSMFIELD_ENTRY(ACPIState, uSleepState),
1945 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1946 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1947 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
1948 SSMFIELD_ENTRY_TERM()
1949};
1950
1951/**
1952 * Saved state structure description, version 7.
1953 */
1954static const SSMFIELD g_AcpiSavedStateFields7[] =
1955{
1956 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1957 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1958 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1959 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1960 SSMFIELD_ENTRY(ACPIState, uPmTimerVal),
1961 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1962 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1963 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1964 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1965 SSMFIELD_ENTRY(ACPIState, uSleepState),
1966 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1967 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1968 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
1969 SSMFIELD_ENTRY_TERM()
1970};
1971
1972/**
1973 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1974 */
1975static DECLCALLBACK(int) acpiR3SaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1976{
1977 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
1978 return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields7[0]);
1979}
1980
1981/**
1982 * @callback_method_impl{FNSSMDEVLOADEXEC}
1983 */
1984static DECLCALLBACK(int) acpiR3LoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
1985{
1986 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
1987 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1988
1989 /*
1990 * Unregister PM handlers, will register with actual base after state
1991 * successfully loaded.
1992 */
1993 int rc = acpiR3UnregisterPmHandlers(pThis);
1994 if (RT_FAILURE(rc))
1995 return rc;
1996
1997 switch (uVersion)
1998 {
1999 case 4:
2000 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
2001 break;
2002 case 5:
2003 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
2004 break;
2005 case 6:
2006 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2007 break;
2008 case 7:
2009 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields7[0]);
2010 break;
2011 default:
2012 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2013 break;
2014 }
2015 if (RT_SUCCESS(rc))
2016 {
2017 rc = acpiR3RegisterPmHandlers(pThis);
2018 if (RT_FAILURE(rc))
2019 return rc;
2020 rc = acpiR3FetchBatteryStatus(pThis);
2021 if (RT_FAILURE(rc))
2022 return rc;
2023 rc = acpiR3FetchBatteryInfo(pThis);
2024 if (RT_FAILURE(rc))
2025 return rc;
2026 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
2027 DEVACPI_LOCK_R3(pThis);
2028 uint64_t u64Now = TMTimerGet(pThis->pPmTimerR3);
2029 /* The interrupt may be incorrectly re-generated
2030 * if the state is restored from versions < 7
2031 */
2032 acpiPmTimerUpdate(pThis, u64Now);
2033 acpiR3PmTimerReset(pThis, u64Now);
2034 DEVACPI_UNLOCK(pThis);
2035 TMTimerUnlock(pThis->pPmTimerR3);
2036 }
2037 return rc;
2038}
2039
2040/**
2041 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2042 */
2043static DECLCALLBACK(void *) acpiR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2044{
2045 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
2046 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2047 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
2048 return NULL;
2049}
2050
2051/**
2052 * Calculate the check sum for some ACPI data before planting it.
2053 *
2054 * All the bytes must add up to 0.
2055 *
2056 * @returns check sum.
2057 * @param pvSrc What to check sum.
2058 * @param cbData The amount of data to checksum.
2059 */
2060static uint8_t acpiR3Checksum(const void * const pvSrc, size_t cbData)
2061{
2062 uint8_t const *pbSrc = (uint8_t const *)pvSrc;
2063 uint8_t uSum = 0;
2064 for (size_t i = 0; i < cbData; ++i)
2065 uSum += pbSrc[i];
2066 return -uSum;
2067}
2068
2069/**
2070 * Prepare a ACPI table header.
2071 */
2072static void acpiR3PrepareHeader(ACPIState *pThis, ACPITBLHEADER *header,
2073 const char au8Signature[4],
2074 uint32_t u32Length, uint8_t u8Revision)
2075{
2076 memcpy(header->au8Signature, au8Signature, 4);
2077 header->u32Length = RT_H2LE_U32(u32Length);
2078 header->u8Revision = u8Revision;
2079 memcpy(header->au8OemId, pThis->au8OemId, 6);
2080 memcpy(header->au8OemTabId, "VBOX", 4);
2081 memcpy(header->au8OemTabId+4, au8Signature, 4);
2082 header->u32OemRevision = RT_H2LE_U32(1);
2083 memcpy(header->au8CreatorId, pThis->au8CreatorId, 4);
2084 header->u32CreatorRev = pThis->u32CreatorRev;
2085}
2086
2087/**
2088 * Initialize a generic address structure (ACPIGENADDR).
2089 */
2090static void acpiR3WriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
2091 uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
2092 uint8_t u8AccessSize, uint64_t u64Address)
2093{
2094 g->u8AddressSpaceId = u8AddressSpaceId;
2095 g->u8RegisterBitWidth = u8RegisterBitWidth;
2096 g->u8RegisterBitOffset = u8RegisterBitOffset;
2097 g->u8AccessSize = u8AccessSize;
2098 g->u64Address = RT_H2LE_U64(u64Address);
2099}
2100
2101/**
2102 * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
2103 */
2104DECLINLINE(void) acpiR3PhysCopy(ACPIState *pThis, RTGCPHYS32 GCPhys32Dst, const void *pvSrc, size_t cbToCopy)
2105{
2106 PDMDevHlpPhysWrite(pThis->pDevInsR3, GCPhys32Dst, pvSrc, cbToCopy);
2107}
2108
2109/**
2110 * Plant the Differentiated System Description Table (DSDT).
2111 */
2112static void acpiR3SetupDsdt(ACPIState *pThis, RTGCPHYS32 GCPhys32, void *pvPtr, size_t cbDsdt)
2113{
2114 acpiR3PhysCopy(pThis, GCPhys32, pvPtr, cbDsdt);
2115}
2116
2117/**
2118 * Plan the Secondary System Description Table (SSDT).
2119 */
2120static void acpiR3SetupSsdt(ACPIState *pThis, RTGCPHYS32 addr,
2121 void* pPtr, size_t uSsdtLen)
2122{
2123 acpiR3PhysCopy(pThis, addr, pPtr, uSsdtLen);
2124}
2125
2126/**
2127 * Plant the Firmware ACPI Control Structure (FACS).
2128 */
2129static void acpiR3SetupFacs(ACPIState *pThis, RTGCPHYS32 addr)
2130{
2131 ACPITBLFACS facs;
2132
2133 memset(&facs, 0, sizeof(facs));
2134 memcpy(facs.au8Signature, "FACS", 4);
2135 facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
2136 facs.u32HWSignature = RT_H2LE_U32(0);
2137 facs.u32FWVector = RT_H2LE_U32(0);
2138 facs.u32GlobalLock = RT_H2LE_U32(0);
2139 facs.u32Flags = RT_H2LE_U32(0);
2140 facs.u64X_FWVector = RT_H2LE_U64(0);
2141 facs.u8Version = 1;
2142
2143 acpiR3PhysCopy(pThis, addr, (const uint8_t *)&facs, sizeof(facs));
2144}
2145
2146/**
2147 * Plant the Fixed ACPI Description Table (FADT aka FACP).
2148 */
2149static void acpiR3SetupFadt(ACPIState *pThis, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2,
2150 RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
2151{
2152 ACPITBLFADT fadt;
2153
2154 /* First the ACPI version 2+ version of the structure. */
2155 memset(&fadt, 0, sizeof(fadt));
2156 acpiR3PrepareHeader(pThis, &fadt.header, "FACP", sizeof(fadt), 4);
2157 fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
2158 fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
2159 fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
2160 fadt.u8PreferredPMProfile = 0; /* unspecified */
2161 fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
2162 fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
2163 fadt.u8AcpiEnable = ACPI_ENABLE;
2164 fadt.u8AcpiDisable = ACPI_DISABLE;
2165 fadt.u8S4BIOSReq = 0;
2166 fadt.u8PStateCnt = 0;
2167 fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1a_EVT_OFFSET));
2168 fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1b_EVT_OFFSET));
2169 fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1a_CTL_OFFSET));
2170 fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1b_CTL_OFFSET));
2171 fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM2_CTL_OFFSET));
2172 fadt.u32PMTMRBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM_TMR_OFFSET));
2173 fadt.u32GPE0BLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, GPE0_OFFSET));
2174 fadt.u32GPE1BLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, GPE1_OFFSET));
2175 fadt.u8PM1EVTLEN = 4;
2176 fadt.u8PM1CTLLEN = 2;
2177 fadt.u8PM2CTLLEN = 0;
2178 fadt.u8PMTMLEN = 4;
2179 fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
2180 fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
2181 fadt.u8GPE1BASE = GPE1_BASE;
2182 fadt.u8CSTCNT = 0;
2183 fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
2184 fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
2185 fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
2186 fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
2187 fadt.u8DutyOffset = 0;
2188 fadt.u8DutyWidth = 0;
2189 fadt.u8DayAlarm = 0;
2190 fadt.u8MonAlarm = 0;
2191 fadt.u8Century = 0;
2192 fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
2193 /** @note WBINVD is required for ACPI versions newer than 1.0 */
2194 fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
2195 | FADT_FL_FIX_RTC
2196 | FADT_FL_TMR_VAL_EXT
2197 | FADT_FL_RESET_REG_SUP);
2198
2199 /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
2200 if (pThis->fCpuHotPlug)
2201 fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
2202
2203 acpiR3WriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
2204 fadt.u8ResetVal = ACPI_RESET_REG_VAL;
2205 fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
2206 fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
2207 acpiR3WriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiR3CalcPmPort(pThis, PM1a_EVT_OFFSET));
2208 acpiR3WriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, PM1b_EVT_OFFSET));
2209 acpiR3WriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiR3CalcPmPort(pThis, PM1a_CTL_OFFSET));
2210 acpiR3WriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, PM1b_CTL_OFFSET));
2211 acpiR3WriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, PM2_CTL_OFFSET));
2212 acpiR3WriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET));
2213 acpiR3WriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiR3CalcPmPort(pThis, GPE0_OFFSET));
2214 acpiR3WriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, GPE1_OFFSET));
2215 fadt.header.u8Checksum = acpiR3Checksum(&fadt, sizeof(fadt));
2216 acpiR3PhysCopy(pThis, GCPhysAcpi2, &fadt, sizeof(fadt));
2217
2218 /* Now the ACPI 1.0 version. */
2219 fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
2220 fadt.u8IntModel = INT_MODEL_DUAL_PIC;
2221 fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
2222 fadt.header.u8Checksum = acpiR3Checksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
2223 acpiR3PhysCopy(pThis, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
2224}
2225
2226/**
2227 * Plant the root System Description Table.
2228 *
2229 * The RSDT and XSDT tables are basically identical. The only difference is 32
2230 * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
2231 * ACPI 2.0 and up.
2232 */
2233static int acpiR3SetupRsdt(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
2234{
2235 ACPITBLRSDT *rsdt;
2236 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
2237
2238 rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
2239 if (!rsdt)
2240 return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
2241
2242 acpiR3PrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
2243 for (unsigned int i = 0; i < nb_entries; ++i)
2244 {
2245 rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
2246 Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
2247 }
2248 rsdt->header.u8Checksum = acpiR3Checksum(rsdt, size);
2249 acpiR3PhysCopy(pThis, addr, rsdt, size);
2250 RTMemFree(rsdt);
2251 return VINF_SUCCESS;
2252}
2253
2254/**
2255 * Plant the Extended System Description Table.
2256 */
2257static int acpiR3SetupXsdt(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
2258{
2259 ACPITBLXSDT *xsdt;
2260 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
2261
2262 xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
2263 if (!xsdt)
2264 return VERR_NO_TMP_MEMORY;
2265
2266 acpiR3PrepareHeader(pThis, &xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
2267
2268 if (pThis->fUseCust)
2269 memcpy(xsdt->header.au8OemTabId, pThis->au8OemTabId, 8);
2270
2271 for (unsigned int i = 0; i < nb_entries; ++i)
2272 {
2273 xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
2274 Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
2275 }
2276 xsdt->header.u8Checksum = acpiR3Checksum(xsdt, size);
2277 acpiR3PhysCopy(pThis, addr, xsdt, size);
2278 RTMemFree(xsdt);
2279 return VINF_SUCCESS;
2280}
2281
2282/**
2283 * Plant the Root System Description Pointer (RSDP).
2284 */
2285static void acpiR3SetupRsdp(ACPIState *pThis, ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
2286{
2287 memset(rsdp, 0, sizeof(*rsdp));
2288
2289 /* ACPI 1.0 part (RSDT) */
2290 memcpy(rsdp->au8Signature, "RSD PTR ", 8);
2291 memcpy(rsdp->au8OemId, pThis->au8OemId, 6);
2292 rsdp->u8Revision = ACPI_REVISION;
2293 rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
2294 rsdp->u8Checksum = acpiR3Checksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
2295
2296 /* ACPI 2.0 part (XSDT) */
2297 rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
2298 rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
2299 rsdp->u8ExtChecksum = acpiR3Checksum(rsdp, sizeof(ACPITBLRSDP));
2300}
2301
2302/**
2303 * Multiple APIC Description Table.
2304 *
2305 * This structure looks somewhat convoluted due layout of MADT table in MP case.
2306 * There extpected to be multiple LAPIC records for each CPU, thus we cannot
2307 * use regular C structure and proxy to raw memory instead.
2308 */
2309class AcpiTableMadt
2310{
2311 /**
2312 * All actual data stored in dynamically allocated memory pointed by this field.
2313 */
2314 uint8_t *m_pbData;
2315 /**
2316 * Number of CPU entries in this MADT.
2317 */
2318 uint32_t m_cCpus;
2319
2320 /**
2321 * Number of interrupt overrides.
2322 */
2323 uint32_t m_cIsos;
2324
2325public:
2326 /**
2327 * Address of ACPI header
2328 */
2329 inline ACPITBLHEADER *header_addr(void) const
2330 {
2331 return (ACPITBLHEADER *)m_pbData;
2332 }
2333
2334 /**
2335 * Address of local APIC for each CPU. Note that different CPUs address different LAPICs,
2336 * although address is the same for all of them.
2337 */
2338 inline uint32_t *u32LAPIC_addr(void) const
2339 {
2340 return (uint32_t *)(header_addr() + 1);
2341 }
2342
2343 /**
2344 * Address of APIC flags
2345 */
2346 inline uint32_t *u32Flags_addr(void) const
2347 {
2348 return (uint32_t *)(u32LAPIC_addr() + 1);
2349 }
2350
2351 /**
2352 * Address of ISO description
2353 */
2354 inline ACPITBLISO *ISO_addr(void) const
2355 {
2356 return (ACPITBLISO *)(u32Flags_addr() + 1);
2357 }
2358
2359 /**
2360 * Address of per-CPU LAPIC descriptions
2361 */
2362 inline ACPITBLLAPIC *LApics_addr(void) const
2363 {
2364 return (ACPITBLLAPIC *)(ISO_addr() + m_cIsos);
2365 }
2366
2367 /**
2368 * Address of IO APIC description
2369 */
2370 inline ACPITBLIOAPIC *IOApic_addr(void) const
2371 {
2372 return (ACPITBLIOAPIC *)(LApics_addr() + m_cCpus);
2373 }
2374
2375 /**
2376 * Size of MADT.
2377 * Note that this function assumes IOApic to be the last field in structure.
2378 */
2379 inline uint32_t size(void) const
2380 {
2381 return (uint8_t *)(IOApic_addr() + 1) - (uint8_t *)header_addr();
2382 }
2383
2384 /**
2385 * Raw data of MADT.
2386 */
2387 inline const uint8_t *data(void) const
2388 {
2389 return m_pbData;
2390 }
2391
2392 /**
2393 * Size of MADT for given ACPI config, useful to compute layout.
2394 */
2395 static uint32_t sizeFor(ACPIState *pThis, uint32_t cIsos)
2396 {
2397 return AcpiTableMadt(pThis->cCpus, cIsos).size();
2398 }
2399
2400 /*
2401 * Constructor, only works in Ring 3, doesn't look like a big deal.
2402 */
2403 AcpiTableMadt(uint32_t cCpus, uint32_t cIsos)
2404 {
2405 m_cCpus = cCpus;
2406 m_cIsos = cIsos;
2407 m_pbData = NULL; /* size() uses this and gcc will complain if not initialized. */
2408 uint32_t cb = size();
2409 m_pbData = (uint8_t *)RTMemAllocZ(cb);
2410 }
2411
2412 ~AcpiTableMadt()
2413 {
2414 RTMemFree(m_pbData);
2415 }
2416};
2417
2418
2419/**
2420 * Plant the Multiple APIC Description Table (MADT).
2421 *
2422 * @note APIC without IO-APIC hangs Windows Vista therefore we setup both.
2423 *
2424 * @todo All hardcoded, should set this up based on the actual VM config!!!!!
2425 */
2426static void acpiR3SetupMadt(ACPIState *pThis, RTGCPHYS32 addr)
2427{
2428 uint16_t cpus = pThis->cCpus;
2429 AcpiTableMadt madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
2430
2431 acpiR3PrepareHeader(pThis, madt.header_addr(), "APIC", madt.size(), 2);
2432
2433 *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
2434 *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
2435
2436 /* LAPICs records */
2437 ACPITBLLAPIC* lapic = madt.LApics_addr();
2438 for (uint16_t i = 0; i < cpus; i++)
2439 {
2440 lapic->u8Type = 0;
2441 lapic->u8Length = sizeof(ACPITBLLAPIC);
2442 lapic->u8ProcId = i;
2443 /** Must match numbering convention in MPTABLES */
2444 lapic->u8ApicId = i;
2445 lapic->u32Flags = VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
2446 lapic++;
2447 }
2448
2449 /* IO-APIC record */
2450 ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
2451 ioapic->u8Type = 1;
2452 ioapic->u8Length = sizeof(ACPITBLIOAPIC);
2453 /** Must match MP tables ID */
2454 ioapic->u8IOApicId = cpus;
2455 ioapic->u8Reserved = 0;
2456 ioapic->u32Address = RT_H2LE_U32(0xfec00000);
2457 ioapic->u32GSIB = RT_H2LE_U32(0);
2458
2459 /* Interrupt Source Overrides */
2460 /* Flags:
2461 bits[3:2]:
2462 00 conforms to the bus
2463 01 edge-triggered
2464 10 reserved
2465 11 level-triggered
2466 bits[1:0]
2467 00 conforms to the bus
2468 01 active-high
2469 10 reserved
2470 11 active-low */
2471 /* If changing, also update PDMIsaSetIrq() and MPS */
2472 ACPITBLISO* isos = madt.ISO_addr();
2473 /* Timer interrupt rule IRQ0 to GSI2 */
2474 isos[0].u8Type = 2;
2475 isos[0].u8Length = sizeof(ACPITBLISO);
2476 isos[0].u8Bus = 0; /* Must be 0 */
2477 isos[0].u8Source = 0; /* IRQ0 */
2478 isos[0].u32GSI = 2; /* connected to pin 2 */
2479 isos[0].u16Flags = 0; /* conform to the bus */
2480
2481 /* ACPI interrupt rule - IRQ9 to GSI9 */
2482 isos[1].u8Type = 2;
2483 isos[1].u8Length = sizeof(ACPITBLISO);
2484 isos[1].u8Bus = 0; /* Must be 0 */
2485 isos[1].u8Source = 9; /* IRQ9 */
2486 isos[1].u32GSI = 9; /* connected to pin 9 */
2487 isos[1].u16Flags = 0xd; /* active high, level triggered */
2488 Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
2489
2490 madt.header_addr()->u8Checksum = acpiR3Checksum(madt.data(), madt.size());
2491 acpiR3PhysCopy(pThis, addr, madt.data(), madt.size());
2492}
2493
2494/**
2495 * Plant the High Performance Event Timer (HPET) descriptor.
2496 */
2497static void acpiR3SetupHpet(ACPIState *pThis, RTGCPHYS32 addr)
2498{
2499 ACPITBLHPET hpet;
2500
2501 memset(&hpet, 0, sizeof(hpet));
2502
2503 acpiR3PrepareHeader(pThis, &hpet.aHeader, "HPET", sizeof(hpet), 1);
2504 /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
2505 acpiR3WriteGenericAddr(&hpet.HpetAddr,
2506 0 /* Memory address space */,
2507 64 /* Register bit width */,
2508 0 /* Bit offset */,
2509 0, /* Register access size, is it correct? */
2510 0xfed00000 /* Address */);
2511
2512 hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
2513 hpet.u32Number = 0;
2514 hpet.u32MinTick = 4096;
2515 hpet.u8Attributes = 0;
2516
2517 hpet.aHeader.u8Checksum = acpiR3Checksum(&hpet, sizeof(hpet));
2518
2519 acpiR3PhysCopy(pThis, addr, (const uint8_t *)&hpet, sizeof(hpet));
2520}
2521
2522
2523/** Custom Description Table */
2524static void acpiR3SetupCust(ACPIState *pThis, RTGCPHYS32 addr)
2525{
2526 ACPITBLCUST cust;
2527
2528 /* First the ACPI version 1 version of the structure. */
2529 memset(&cust, 0, sizeof(cust));
2530 acpiR3PrepareHeader(pThis, &cust.header, "CUST", sizeof(cust), 1);
2531
2532 memcpy(cust.header.au8OemTabId, pThis->au8OemTabId, 8);
2533 cust.header.u32OemRevision = RT_H2LE_U32(pThis->u32OemRevision);
2534 cust.header.u8Checksum = acpiR3Checksum((uint8_t *)&cust, sizeof(cust));
2535
2536 acpiR3PhysCopy(pThis, addr, pThis->pu8CustBin, pThis->cbCustBin);
2537}
2538
2539/**
2540 * Used by acpiR3PlantTables to plant a MMCONFIG PCI config space access (MCFG)
2541 * descriptor.
2542 *
2543 * @param pThis The ACPI instance.
2544 * @param GCPhysDst Where to plant it.
2545 */
2546static void acpiR3SetupMcfg(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
2547{
2548 struct
2549 {
2550 ACPITBLMCFG hdr;
2551 ACPITBLMCFGENTRY entry;
2552 } tbl;
2553 uint8_t u8StartBus = 0;
2554 uint8_t u8EndBus = (pThis->u64PciConfigMMioLength >> 20) - 1;
2555
2556 RT_ZERO(tbl);
2557
2558 acpiR3PrepareHeader(pThis, &tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
2559 tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
2560 tbl.entry.u8StartBus = u8StartBus;
2561 tbl.entry.u8EndBus = u8EndBus;
2562 // u16PciSegmentGroup must match _SEG in ACPI table
2563
2564 tbl.hdr.aHeader.u8Checksum = acpiR3Checksum(&tbl, sizeof(tbl));
2565
2566 acpiR3PhysCopy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
2567}
2568
2569/**
2570 * Used by acpiR3PlantTables and acpiConstruct.
2571 *
2572 * @returns Guest memory address.
2573 */
2574static uint32_t apicR3FindRsdpSpace(void)
2575{
2576 return 0xe0000;
2577}
2578
2579/**
2580 * Create the ACPI tables in guest memory.
2581 */
2582static int acpiR3PlantTables(ACPIState *pThis)
2583{
2584 int rc;
2585 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
2586 RTGCPHYS32 GCPhysHpet = 0;
2587 RTGCPHYS32 GCPhysApic = 0;
2588 RTGCPHYS32 GCPhysSsdt = 0;
2589 RTGCPHYS32 GCPhysMcfg = 0;
2590 RTGCPHYS32 GCPhysCust = 0;
2591 uint32_t addend = 0;
2592 RTGCPHYS32 aGCPhysRsdt[8];
2593 RTGCPHYS32 aGCPhysXsdt[8];
2594 uint32_t cAddr;
2595 uint32_t iMadt = 0;
2596 uint32_t iHpet = 0;
2597 uint32_t iSsdt = 0;
2598 uint32_t iMcfg = 0;
2599 uint32_t iCust = 0;
2600 size_t cbRsdt = sizeof(ACPITBLHEADER);
2601 size_t cbXsdt = sizeof(ACPITBLHEADER);
2602
2603 cAddr = 1; /* FADT */
2604 if (pThis->u8UseIOApic)
2605 iMadt = cAddr++; /* MADT */
2606
2607 if (pThis->fUseHpet)
2608 iHpet = cAddr++; /* HPET */
2609
2610 if (pThis->fUseMcfg)
2611 iMcfg = cAddr++; /* MCFG */
2612
2613 if (pThis->fUseCust)
2614 iCust = cAddr++; /* CUST */
2615
2616 iSsdt = cAddr++; /* SSDT */
2617
2618 Assert(cAddr < RT_ELEMENTS(aGCPhysRsdt));
2619 Assert(cAddr < RT_ELEMENTS(aGCPhysXsdt));
2620
2621 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
2622 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
2623
2624 rc = CFGMR3QueryU64(pThis->pDevInsR3->pCfg, "RamSize", &pThis->u64RamSize);
2625 if (RT_FAILURE(rc))
2626 return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
2627 N_("Configuration error: Querying \"RamSize\" as integer failed"));
2628
2629 uint32_t cbRamHole;
2630 rc = CFGMR3QueryU32Def(pThis->pDevInsR3->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
2631 if (RT_FAILURE(rc))
2632 return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
2633 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
2634
2635 /*
2636 * Calculate the sizes for the high and low regions.
2637 */
2638 const uint64_t offRamHole = _4G - cbRamHole;
2639 pThis->cbRamHigh = offRamHole < pThis->u64RamSize ? pThis->u64RamSize - offRamHole : 0;
2640 uint64_t cbRamLow = offRamHole < pThis->u64RamSize ? offRamHole : pThis->u64RamSize;
2641 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
2642 {
2643 /* Note: This is also enforced by DevPcBios.cpp. */
2644 LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
2645 cbRamLow = UINT32_C(0xffe00000);
2646 }
2647 pThis->cbRamLow = (uint32_t)cbRamLow;
2648
2649 GCPhysCur = 0;
2650 GCPhysRsdt = GCPhysCur;
2651
2652 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
2653 GCPhysXsdt = GCPhysCur;
2654
2655 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
2656 GCPhysFadtAcpi1 = GCPhysCur;
2657
2658 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
2659 GCPhysFadtAcpi2 = GCPhysCur;
2660
2661 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
2662 GCPhysFacs = GCPhysCur;
2663
2664 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
2665 if (pThis->u8UseIOApic)
2666 {
2667 GCPhysApic = GCPhysCur;
2668 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMadt::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
2669 }
2670 if (pThis->fUseHpet)
2671 {
2672 GCPhysHpet = GCPhysCur;
2673 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
2674 }
2675 if (pThis->fUseMcfg)
2676 {
2677 GCPhysMcfg = GCPhysCur;
2678 /* Assume one entry */
2679 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
2680 }
2681 if (pThis->fUseCust)
2682 {
2683 GCPhysCust = GCPhysCur;
2684 GCPhysCur = RT_ALIGN_32(GCPhysCur + pThis->cbCustBin, 16);
2685 }
2686
2687 void *pvSsdtCode = NULL;
2688 size_t cbSsdt = 0;
2689 rc = acpiPrepareSsdt(pThis->pDevInsR3, &pvSsdtCode, &cbSsdt);
2690 if (RT_FAILURE(rc))
2691 return rc;
2692
2693 GCPhysSsdt = GCPhysCur;
2694 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdt, 16);
2695
2696 GCPhysDsdt = GCPhysCur;
2697
2698 void *pvDsdtCode = NULL;
2699 size_t cbDsdt = 0;
2700 rc = acpiPrepareDsdt(pThis->pDevInsR3, &pvDsdtCode, &cbDsdt);
2701 if (RT_FAILURE(rc))
2702 return rc;
2703
2704 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdt, 16);
2705
2706 if (GCPhysCur > 0x10000)
2707 return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_TOO_MUCH_DATA,
2708 N_("Error: ACPI tables bigger than 64KB"));
2709
2710 Log(("RSDP 0x%08X\n", apicR3FindRsdpSpace()));
2711 addend = pThis->cbRamLow - 0x10000;
2712 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
2713 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
2714 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
2715 if (pThis->u8UseIOApic)
2716 Log((" MADT 0x%08X", GCPhysApic + addend));
2717 if (pThis->fUseHpet)
2718 Log((" HPET 0x%08X", GCPhysHpet + addend));
2719 if (pThis->fUseMcfg)
2720 Log((" MCFG 0x%08X", GCPhysMcfg + addend));
2721 if (pThis->fUseCust)
2722 Log((" CUST 0x%08X", GCPhysCust + addend));
2723 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
2724 Log(("\n"));
2725
2726 acpiR3SetupRsdp(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
2727 acpiR3SetupDsdt(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdt);
2728 acpiCleanupDsdt(pThis->pDevInsR3, pvDsdtCode);
2729 acpiR3SetupFacs(pThis, GCPhysFacs + addend);
2730 acpiR3SetupFadt(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
2731
2732 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
2733 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
2734 if (pThis->u8UseIOApic)
2735 {
2736 acpiR3SetupMadt(pThis, GCPhysApic + addend);
2737 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
2738 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
2739 }
2740 if (pThis->fUseHpet)
2741 {
2742 acpiR3SetupHpet(pThis, GCPhysHpet + addend);
2743 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
2744 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
2745 }
2746 if (pThis->fUseMcfg)
2747 {
2748 acpiR3SetupMcfg(pThis, GCPhysMcfg + addend);
2749 aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
2750 aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
2751 }
2752 if (pThis->fUseCust)
2753 {
2754 acpiR3SetupCust(pThis, GCPhysCust + addend);
2755 aGCPhysRsdt[iCust] = GCPhysCust + addend;
2756 aGCPhysXsdt[iCust] = GCPhysCust + addend;
2757 }
2758
2759 acpiR3SetupSsdt(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdt);
2760 acpiCleanupSsdt(pThis->pDevInsR3, pvSsdtCode);
2761 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
2762 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
2763
2764 rc = acpiR3SetupRsdt(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
2765 if (RT_FAILURE(rc))
2766 return rc;
2767 return acpiR3SetupXsdt(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
2768}
2769
2770/**
2771 * @callback_method_impl{FNPCICONFIGREAD}
2772 */
2773static DECLCALLBACK(uint32_t) acpiR3PciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
2774{
2775 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2776 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2777
2778 Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
2779 return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
2780}
2781
2782/**
2783 * @callback_method_impl{FNPCICONFIGWRITE}
2784 */
2785static DECLCALLBACK(void) acpiR3PciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
2786{
2787 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2788 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2789
2790 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
2791 DEVACPI_LOCK_R3(pThis);
2792
2793 if (Address == VBOX_PCI_INTERRUPT_LINE)
2794 {
2795 Log(("acpi: ignore interrupt line settings: %d, we'll use hardcoded value %d\n", u32Value, SCI_INT));
2796 u32Value = SCI_INT;
2797 }
2798
2799 pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
2800
2801 /* PMREGMISC written */
2802 if (Address == 0x80)
2803 {
2804 /* Check Power Management IO Space Enable (PMIOSE) bit */
2805 if (pPciDev->config[0x80] & 0x1)
2806 {
2807 RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
2808 NewIoPortBase &= 0xffc0;
2809
2810 int rc = acpiR3UpdatePmHandlers(pThis, NewIoPortBase);
2811 AssertRC(rc);
2812 }
2813 }
2814
2815 DEVACPI_UNLOCK(pThis);
2816}
2817
2818/**
2819 * Attach a new CPU.
2820 *
2821 * @returns VBox status code.
2822 * @param pDevIns The device instance.
2823 * @param iLUN The logical unit which is being attached.
2824 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2825 *
2826 * @remarks This code path is not used during construction.
2827 */
2828static DECLCALLBACK(int) acpiR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2829{
2830 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2831 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2832
2833 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2834 ("Hot-plug flag is not set\n"),
2835 VERR_NOT_SUPPORTED);
2836 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
2837
2838 /* Check if it was already attached */
2839 int rc = VINF_SUCCESS;
2840 DEVACPI_LOCK_R3(pThis);
2841 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
2842 {
2843 PPDMIBASE IBaseTmp;
2844 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
2845 if (RT_SUCCESS(rc))
2846 {
2847 /* Enable the CPU */
2848 VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
2849
2850 /*
2851 * Lock the CPU because we don't know if the guest will use it or not.
2852 * Prevents ejection while the CPU is still used
2853 */
2854 VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
2855 pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
2856 pThis->u32CpuEvent = iLUN;
2857
2858 /* Notify the guest */
2859 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
2860 }
2861 }
2862 DEVACPI_UNLOCK(pThis);
2863 return rc;
2864}
2865
2866/**
2867 * Detach notification.
2868 *
2869 * @param pDevIns The device instance.
2870 * @param iLUN The logical unit which is being detached.
2871 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2872 */
2873static DECLCALLBACK(void) acpiR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2874{
2875 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2876
2877 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2878
2879 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2880 ("Hot-plug flag is not set\n"));
2881
2882 /* Check if it was already detached */
2883 DEVACPI_LOCK_R3(pThis);
2884 if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
2885 {
2886 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
2887 {
2888 /* Disable the CPU */
2889 VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
2890 pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
2891 pThis->u32CpuEvent = iLUN;
2892
2893 /* Notify the guest */
2894 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
2895 }
2896 else
2897 AssertMsgFailed(("CPU is still locked by the guest\n"));
2898 }
2899 DEVACPI_UNLOCK(pThis);
2900}
2901
2902/**
2903 * @interface_method_impl{PDMDEVREG,pfnResume}
2904 */
2905static DECLCALLBACK(void) acpiR3Resume(PPDMDEVINS pDevIns)
2906{
2907 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2908 if (pThis->fSetWakeupOnResume)
2909 {
2910 Log(("acpiResume: setting WAK_STS\n"));
2911 pThis->fSetWakeupOnResume = false;
2912 pThis->pm1a_sts |= WAK_STS;
2913 }
2914}
2915
2916/**
2917 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
2918 */
2919static DECLCALLBACK(void) acpiR3MemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
2920{
2921 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2922 acpiR3PlantTables(pThis);
2923}
2924
2925/**
2926 * @interface_method_impl{PDMDEVREG,pfnReset}
2927 */
2928static DECLCALLBACK(void) acpiR3Reset(PPDMDEVINS pDevIns)
2929{
2930 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2931
2932 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
2933 pThis->pm1a_en = 0;
2934 pThis->pm1a_sts = 0;
2935 pThis->pm1a_ctl = 0;
2936 pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
2937 pThis->uPmTimerVal = 0;
2938 acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
2939 pThis->uBatteryIndex = 0;
2940 pThis->uSystemInfoIndex = 0;
2941 pThis->gpe0_en = 0;
2942 pThis->gpe0_sts = 0;
2943 pThis->uSleepState = 0;
2944 TMTimerUnlock(pThis->pPmTimerR3);
2945
2946 /** @todo Should we really reset PM base? */
2947 acpiR3UpdatePmHandlers(pThis, PM_PORT_BASE);
2948}
2949
2950/**
2951 * @interface_method_impl{PDMDEVREG,pfnRelocate}
2952 */
2953static DECLCALLBACK(void) acpiR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2954{
2955 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2956 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2957 pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
2958 NOREF(offDelta);
2959}
2960
2961/**
2962 * @interface_methid_impl{PDMDEVREG,pfnDestruct}
2963 */
2964static DECLCALLBACK(int) acpiR3Destruct(PPDMDEVINS pDevIns)
2965{
2966 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2967 if (pThis->pu8CustBin)
2968 {
2969 MMR3HeapFree(pThis->pu8CustBin);
2970 pThis->pu8CustBin = NULL;
2971 }
2972 return VINF_SUCCESS;
2973}
2974
2975/**
2976 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2977 */
2978static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2979{
2980 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2981 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2982
2983 /*
2984 * Init data and set defaults.
2985 */
2986 /** @todo move more of the code up! */
2987
2988 pThis->pDevInsR3 = pDevIns;
2989 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2990 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2991 VMCPUSET_EMPTY(&pThis->CpuSetAttached);
2992 VMCPUSET_EMPTY(&pThis->CpuSetLocked);
2993 pThis->idCpuLockCheck = UINT32_C(0xffffffff);
2994 pThis->u32CpuEventType = 0;
2995 pThis->u32CpuEvent = UINT32_C(0xffffffff);
2996
2997 /* The first CPU can't be attached/detached */
2998 VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
2999 VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
3000
3001 /* IBase */
3002 pThis->IBase.pfnQueryInterface = acpiR3QueryInterface;
3003 /* IACPIPort */
3004 pThis->IACPIPort.pfnSleepButtonPress = acpiR3Port_SleepButtonPress;
3005 pThis->IACPIPort.pfnPowerButtonPress = acpiR3Port_PowerButtonPress;
3006 pThis->IACPIPort.pfnGetPowerButtonHandled = acpiR3Port_GetPowerButtonHandled;
3007 pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiR3Port_GetGuestEnteredACPIMode;
3008 pThis->IACPIPort.pfnGetCpuStatus = acpiR3Port_GetCpuStatus;
3009 pThis->IACPIPort.pfnMonitorHotPlugEvent = acpiR3Port_MonitorHotPlugEvent;
3010
3011 /*
3012 * Set the default critical section to NOP (related to the PM timer).
3013 */
3014 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3015 AssertRCReturn(rc, rc);
3016
3017 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi#%u", iInstance);
3018 AssertRCReturn(rc, rc);
3019
3020 /*
3021 * Validate and read the configuration.
3022 */
3023 if (!CFGMR3AreValuesValid(pCfg,
3024 "RamSize\0"
3025 "RamHoleSize\0"
3026 "IOAPIC\0"
3027 "NumCPUs\0"
3028 "GCEnabled\0"
3029 "R0Enabled\0"
3030 "HpetEnabled\0"
3031 "McfgEnabled\0"
3032 "McfgBase\0"
3033 "McfgLength\0"
3034 "SmcEnabled\0"
3035 "FdcEnabled\0"
3036 "ShowRtc\0"
3037 "ShowCpu\0"
3038 "NicPciAddress\0"
3039 "AudioPciAddress\0"
3040 "IocPciAddress\0"
3041 "HostBusPciAddress\0"
3042 "EnableSuspendToDisk\0"
3043 "PowerS1Enabled\0"
3044 "PowerS4Enabled\0"
3045 "CpuHotPlug\0"
3046 "AmlFilePath\0"
3047 "Serial0IoPortBase\0"
3048 "Serial1IoPortBase\0"
3049 "Serial0Irq\0"
3050 "Serial1Irq\0"
3051 "AcpiOemId\0"
3052 "AcpiCreatorId\0"
3053 "AcpiCreatorRev\0"
3054 "CustomTable\0"
3055 "SLICTable\0"
3056 ))
3057 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
3058 N_("Configuration error: Invalid config key for ACPI device"));
3059
3060 /* query whether we are supposed to present an IOAPIC */
3061 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
3062 if (RT_FAILURE(rc))
3063 return PDMDEV_SET_ERROR(pDevIns, rc,
3064 N_("Configuration error: Failed to read \"IOAPIC\""));
3065
3066 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
3067 if (RT_FAILURE(rc))
3068 return PDMDEV_SET_ERROR(pDevIns, rc,
3069 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
3070
3071 /* query whether we are supposed to present an FDC controller */
3072 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
3073 if (RT_FAILURE(rc))
3074 return PDMDEV_SET_ERROR(pDevIns, rc,
3075 N_("Configuration error: Failed to read \"FdcEnabled\""));
3076
3077 /* query whether we are supposed to present HPET */
3078 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
3079 if (RT_FAILURE(rc))
3080 return PDMDEV_SET_ERROR(pDevIns, rc,
3081 N_("Configuration error: Failed to read \"HpetEnabled\""));
3082 /* query MCFG configuration */
3083 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
3084 if (RT_FAILURE(rc))
3085 return PDMDEV_SET_ERROR(pDevIns, rc,
3086 N_("Configuration error: Failed to read \"McfgBase\""));
3087 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
3088 if (RT_FAILURE(rc))
3089 return PDMDEV_SET_ERROR(pDevIns, rc,
3090 N_("Configuration error: Failed to read \"McfgLength\""));
3091 pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
3092
3093 /* query whether we are supposed to present custom table */
3094 pThis->fUseCust = false;
3095
3096 /* query whether we are supposed to present SMC */
3097 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
3098 if (RT_FAILURE(rc))
3099 return PDMDEV_SET_ERROR(pDevIns, rc,
3100 N_("Configuration error: Failed to read \"SmcEnabled\""));
3101
3102 /* query whether we are supposed to present RTC object */
3103 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
3104 if (RT_FAILURE(rc))
3105 return PDMDEV_SET_ERROR(pDevIns, rc,
3106 N_("Configuration error: Failed to read \"ShowRtc\""));
3107
3108 /* query whether we are supposed to present CPU objects */
3109 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
3110 if (RT_FAILURE(rc))
3111 return PDMDEV_SET_ERROR(pDevIns, rc,
3112 N_("Configuration error: Failed to read \"ShowCpu\""));
3113
3114 /* query primary NIC PCI address */
3115 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
3116 if (RT_FAILURE(rc))
3117 return PDMDEV_SET_ERROR(pDevIns, rc,
3118 N_("Configuration error: Failed to read \"NicPciAddress\""));
3119
3120 /* query primary NIC PCI address */
3121 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
3122 if (RT_FAILURE(rc))
3123 return PDMDEV_SET_ERROR(pDevIns, rc,
3124 N_("Configuration error: Failed to read \"AudioPciAddress\""));
3125
3126 /* query IO controller (southbridge) PCI address */
3127 rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
3128 if (RT_FAILURE(rc))
3129 return PDMDEV_SET_ERROR(pDevIns, rc,
3130 N_("Configuration error: Failed to read \"IocPciAddress\""));
3131
3132 /* query host bus controller PCI address */
3133 rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
3134 if (RT_FAILURE(rc))
3135 return PDMDEV_SET_ERROR(pDevIns, rc,
3136 N_("Configuration error: Failed to read \"HostBusPciAddress\""));
3137
3138 /* query whether S1 power state should be exposed */
3139 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
3140 if (RT_FAILURE(rc))
3141 return PDMDEV_SET_ERROR(pDevIns, rc,
3142 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
3143
3144 /* query whether S4 power state should be exposed */
3145 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
3146 if (RT_FAILURE(rc))
3147 return PDMDEV_SET_ERROR(pDevIns, rc,
3148 N_("Configuration error: Failed to read \"PowerS4Enabled\""));
3149
3150 /* query whether S1 power state should save the VM state */
3151 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
3152 if (RT_FAILURE(rc))
3153 return PDMDEV_SET_ERROR(pDevIns, rc,
3154 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
3155
3156 /* query whether we are allow CPU hot plugging */
3157 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
3158 if (RT_FAILURE(rc))
3159 return PDMDEV_SET_ERROR(pDevIns, rc,
3160 N_("Configuration error: Failed to read \"CpuHotPlug\""));
3161
3162 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
3163 if (RT_FAILURE(rc))
3164 return PDMDEV_SET_ERROR(pDevIns, rc,
3165 N_("Configuration error: Failed to read \"GCEnabled\""));
3166
3167 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
3168 if (RT_FAILURE(rc))
3169 return PDMDEV_SET_ERROR(pDevIns, rc,
3170 N_("configuration error: failed to read \"R0Enabled\""));
3171
3172 /* query serial info */
3173 rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
3174 if (RT_FAILURE(rc))
3175 return PDMDEV_SET_ERROR(pDevIns, rc,
3176 N_("Configuration error: Failed to read \"Serial0Irq\""));
3177
3178 rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
3179 if (RT_FAILURE(rc))
3180 return PDMDEV_SET_ERROR(pDevIns, rc,
3181 N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
3182
3183 /* Serial 1 is enabled, get config data */
3184 rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
3185 if (RT_FAILURE(rc))
3186 return PDMDEV_SET_ERROR(pDevIns, rc,
3187 N_("Configuration error: Failed to read \"Serial1Irq\""));
3188
3189 rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
3190 if (RT_FAILURE(rc))
3191 return PDMDEV_SET_ERROR(pDevIns, rc,
3192 N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
3193
3194 /* Try to attach the other CPUs */
3195 for (unsigned i = 1; i < pThis->cCpus; i++)
3196 {
3197 if (pThis->fCpuHotPlug)
3198 {
3199 PPDMIBASE IBaseTmp;
3200 rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
3201
3202 if (RT_SUCCESS(rc))
3203 {
3204 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3205 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3206 Log(("acpi: Attached CPU %u\n", i));
3207 }
3208 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3209 Log(("acpi: CPU %u not attached yet\n", i));
3210 else
3211 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
3212 }
3213 else
3214 {
3215 /* CPU is always attached if hot-plug is not enabled. */
3216 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3217 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3218 }
3219 }
3220
3221 char *pszOemId = NULL;
3222 rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiOemId", &pszOemId, "VBOX ");
3223 if (RT_FAILURE(rc))
3224 return PDMDEV_SET_ERROR(pDevIns, rc,
3225 N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
3226 size_t cbOemId = strlen(pszOemId);
3227 if (cbOemId > 6)
3228 return PDMDEV_SET_ERROR(pDevIns, rc,
3229 N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
3230 memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
3231 memcpy(pThis->au8OemId, pszOemId, cbOemId);
3232 MMR3HeapFree(pszOemId);
3233
3234 char *pszCreatorId = NULL;
3235 rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
3236 if (RT_FAILURE(rc))
3237 return PDMDEV_SET_ERROR(pDevIns, rc,
3238 N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
3239 size_t cbCreatorId = strlen(pszCreatorId);
3240 if (cbCreatorId > 4)
3241 return PDMDEV_SET_ERROR(pDevIns, rc,
3242 N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
3243 memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
3244 memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
3245 MMR3HeapFree(pszCreatorId);
3246
3247 rc = CFGMR3QueryU32Def(pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
3248 if (RT_FAILURE(rc))
3249 return PDMDEV_SET_ERROR(pDevIns, rc,
3250 N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
3251 pThis->u32OemRevision = RT_H2LE_U32(0x1);
3252
3253 /*
3254 * Get the custom table binary file name.
3255 */
3256 char *pszCustBinFile;
3257 rc = CFGMR3QueryStringAlloc(pCfg, "CustomTable", &pszCustBinFile);
3258 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3259 rc = CFGMR3QueryStringAlloc(pCfg, "SLICTable", &pszCustBinFile);
3260 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3261 {
3262 pszCustBinFile = NULL;
3263 rc = VINF_SUCCESS;
3264 }
3265 else if (RT_FAILURE(rc))
3266 return PDMDEV_SET_ERROR(pDevIns, rc,
3267 N_("Configuration error: Querying \"CustomTable\" as a string failed"));
3268 else if (!*pszCustBinFile)
3269 {
3270 MMR3HeapFree(pszCustBinFile);
3271 pszCustBinFile = NULL;
3272 }
3273
3274 /*
3275 * Determine the custom table binary size, open specified ROM file in the process.
3276 */
3277 if (pszCustBinFile)
3278 {
3279 RTFILE FileCUSTBin;
3280 rc = RTFileOpen(&FileCUSTBin, pszCustBinFile,
3281 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
3282 if (RT_SUCCESS(rc))
3283 {
3284 rc = RTFileGetSize(FileCUSTBin, &pThis->cbCustBin);
3285 if (RT_SUCCESS(rc))
3286 {
3287 /* The following checks should be in sync the AssertReleaseMsg's below. */
3288 if ( pThis->cbCustBin > 3072
3289 || pThis->cbCustBin < sizeof(ACPITBLHEADER))
3290 rc = VERR_TOO_MUCH_DATA;
3291
3292 /*
3293 * Allocate buffer for the custom table binary data.
3294 */
3295 pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbCustBin);
3296 if (pThis->pu8CustBin)
3297 {
3298 rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
3299 if (RT_FAILURE(rc))
3300 {
3301 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbCustBin, rc));
3302 MMR3HeapFree(pThis->pu8CustBin);
3303 pThis->pu8CustBin = NULL;
3304 }
3305 else
3306 {
3307 pThis->fUseCust = true;
3308 memcpy(&pThis->au8OemId[0], &pThis->pu8CustBin[10], 6);
3309 memcpy(&pThis->au8OemTabId[0], &pThis->pu8CustBin[16], 8);
3310 memcpy(&pThis->u32OemRevision, &pThis->pu8CustBin[24], 4);
3311 memcpy(&pThis->au8CreatorId[0], &pThis->pu8CustBin[28], 4);
3312 memcpy(&pThis->u32CreatorRev, &pThis->pu8CustBin[32], 4);
3313 LogRel(("Reading custom ACPI table from file '%s' (%d bytes)\n", pszCustBinFile, pThis->cbCustBin));
3314 }
3315 }
3316 else
3317 rc = VERR_NO_MEMORY;
3318
3319 RTFileClose(FileCUSTBin);
3320 }
3321 }
3322 MMR3HeapFree(pszCustBinFile);
3323 if (RT_FAILURE(rc))
3324 return PDMDEV_SET_ERROR(pDevIns, rc,
3325 N_("Error reading custom ACPI table"));
3326 }
3327
3328 /* Set default port base */
3329 pThis->uPmIoPortBase = PM_PORT_BASE;
3330
3331 /*
3332 * FDC and SMC try to use the same non-shareable interrupt (6),
3333 * enable only one device.
3334 */
3335 if (pThis->fUseSmc)
3336 pThis->fUseFdc = false;
3337
3338 /*
3339 * Plant ACPI tables.
3340 */
3341 /** @todo Part of this is redone by acpiR3MemSetup, we only need to init the
3342 * au8RSDPPage here. However, there should be no harm in doing it
3343 * twice, so the lazy bird is taking the quick way out for now. */
3344 RTGCPHYS32 GCPhysRsdp = apicR3FindRsdpSpace();
3345 if (!GCPhysRsdp)
3346 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
3347 N_("Can not find space for RSDP. ACPI is disabled"));
3348
3349 rc = acpiR3PlantTables(pThis);
3350 if (RT_FAILURE(rc))
3351 return rc;
3352
3353 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
3354 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
3355 if (RT_FAILURE(rc))
3356 return rc;
3357
3358 /*
3359 * Register I/O ports.
3360 */
3361 rc = acpiR3RegisterPmHandlers(pThis);
3362 if (RT_FAILURE(rc))
3363 return rc;
3364
3365#define R(addr, cnt, writer, reader, description) \
3366 do { \
3367 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
3368 NULL, NULL, description); \
3369 if (RT_FAILURE(rc)) \
3370 return rc; \
3371 } while (0)
3372 R(SMI_CMD, 1, acpiR3SmiWrite, NULL, "ACPI SMI");
3373#ifdef DEBUG_ACPI
3374 R(DEBUG_HEX, 1, acpiR3DhexWrite, NULL, "ACPI Debug hex");
3375 R(DEBUG_CHR, 1, acpiR3DchrWrite, NULL, "ACPI Debug char");
3376#endif
3377 R(BAT_INDEX, 1, acpiR3BatIndexWrite, NULL, "ACPI Battery status index");
3378 R(BAT_DATA, 1, NULL, acpiR3BatDataRead, "ACPI Battery status data");
3379 R(SYSI_INDEX, 1, acpiR3SysInfoIndexWrite, NULL, "ACPI system info index");
3380 R(SYSI_DATA, 1, acpiR3SysInfoDataWrite, acpiR3SysInfoDataRead, "ACPI system info data");
3381 R(ACPI_RESET_BLK, 1, acpiR3ResetWrite, NULL, "ACPI Reset");
3382#undef R
3383
3384 /*
3385 * Create the PM timer.
3386 */
3387 PTMTIMER pTimer;
3388 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiR3PmTimer, &pThis->dev,
3389 TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
3390 AssertRCReturn(rc, rc);
3391 pThis->pPmTimerR3 = pTimer;
3392 pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
3393 pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
3394
3395 rc = TMTimerLock(pTimer, VERR_IGNORED);
3396 AssertRCReturn(rc, rc);
3397 pThis->u64PmTimerInitial = TMTimerGet(pTimer);
3398 acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
3399 TMTimerUnlock(pTimer);
3400
3401 /*
3402 * Set up the PCI device.
3403 */
3404 PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
3405 PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
3406
3407 /* See p. 50 of PIIX4 manual */
3408 PCIDevSetCommand(&pThis->dev, 0x01);
3409 PCIDevSetStatus(&pThis->dev, 0x0280);
3410
3411 PCIDevSetRevisionId(&pThis->dev, 0x08);
3412
3413 PCIDevSetClassProg(&pThis->dev, 0x00);
3414 PCIDevSetClassSub(&pThis->dev, 0x80);
3415 PCIDevSetClassBase(&pThis->dev, 0x06);
3416
3417 PCIDevSetHeaderType(&pThis->dev, 0x80);
3418
3419 PCIDevSetBIST(&pThis->dev, 0x00);
3420
3421 PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
3422 PCIDevSetInterruptPin (&pThis->dev, 0x01);
3423
3424 pThis->dev.config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
3425
3426#if 0
3427 int smb_io_base = 0xb100;
3428 dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
3429 dev->config[0x90] = smb_io_base >> 8;
3430#endif
3431
3432 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
3433 if (RT_FAILURE(rc))
3434 return rc;
3435
3436 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
3437 acpiR3PciConfigRead, &pThis->pfnAcpiPciConfigRead,
3438 acpiR3PciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
3439
3440 /*
3441 * Register the saved state.
3442 */
3443 rc = PDMDevHlpSSMRegister(pDevIns, 7, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
3444 if (RT_FAILURE(rc))
3445 return rc;
3446
3447 /*
3448 * Get the corresponding connector interface
3449 */
3450 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
3451 if (RT_SUCCESS(rc))
3452 {
3453 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
3454 if (!pThis->pDrv)
3455 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
3456 N_("LUN #0 doesn't have an ACPI connector interface"));
3457 }
3458 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3459 {
3460 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
3461 pDevIns->pReg->szName, pDevIns->iInstance));
3462 rc = VINF_SUCCESS;
3463 }
3464 else
3465 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
3466
3467 return rc;
3468}
3469
3470/**
3471 * The device registration structure.
3472 */
3473const PDMDEVREG g_DeviceACPI =
3474{
3475 /* u32Version */
3476 PDM_DEVREG_VERSION,
3477 /* szName */
3478 "acpi",
3479 /* szRCMod */
3480 "VBoxDDGC.gc",
3481 /* szR0Mod */
3482 "VBoxDDR0.r0",
3483 /* pszDescription */
3484 "Advanced Configuration and Power Interface",
3485 /* fFlags */
3486 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
3487 /* fClass */
3488 PDM_DEVREG_CLASS_ACPI,
3489 /* cMaxInstances */
3490 ~0U,
3491 /* cbInstance */
3492 sizeof(ACPIState),
3493 /* pfnConstruct */
3494 acpiR3Construct,
3495 /* pfnDestruct */
3496 acpiR3Destruct,
3497 /* pfnRelocate */
3498 acpiR3Relocate,
3499 /* pfnMemSetup */
3500 acpiR3MemSetup,
3501 /* pfnPowerOn */
3502 NULL,
3503 /* pfnReset */
3504 acpiR3Reset,
3505 /* pfnSuspend */
3506 NULL,
3507 /* pfnResume */
3508 acpiR3Resume,
3509 /* pfnAttach */
3510 acpiR3Attach,
3511 /* pfnDetach */
3512 acpiR3Detach,
3513 /* pfnQueryInterface. */
3514 NULL,
3515 /* pfnInitComplete */
3516 NULL,
3517 /* pfnPowerOff */
3518 NULL,
3519 /* pfnSoftReset */
3520 NULL,
3521 /* u32VersionEnd */
3522 PDM_DEVREG_VERSION
3523};
3524
3525#endif /* IN_RING3 */
3526#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