VirtualBox

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

Last change on this file since 39518 was 39303, checked in by vboxsync, 13 years ago

VMCPUSET changes.

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