VirtualBox

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

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

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use