VirtualBox

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

Last change on this file since 43030 was 41560, checked in by vboxsync, 13 years ago

Log which device triggered a reset.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 120.6 KB
Line 
1/* $Id: DevACPI.cpp 41560 2012-06-04 12:07:32Z 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, 0, 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 {
1756 LogRel(("Reset initiated by ACPI\n"));
1757 rc = PDMDevHlpVMReset(pDevIns);
1758 }
1759 else
1760 Log(("acpiResetWrite: %#x <- unknown value\n", u32));
1761
1762 return rc;
1763}
1764
1765# ifdef DEBUG_ACPI
1766
1767/**
1768 * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
1769 */
1770PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1771{
1772 NOREF(pvUser);
1773 switch (cb)
1774 {
1775 case 1:
1776 Log(("%#x\n", u32 & 0xff));
1777 break;
1778 case 2:
1779 Log(("%#6x\n", u32 & 0xffff));
1780 case 4:
1781 Log(("%#10x\n", u32));
1782 break;
1783 default:
1784 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1785 }
1786 return VINF_SUCCESS;
1787}
1788
1789/**
1790 * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
1791 */
1792PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1793{
1794 NOREF(pvUser);
1795 switch (cb)
1796 {
1797 case 1:
1798 Log(("%c", u32 & 0xff));
1799 break;
1800 default:
1801 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1802 }
1803 return VINF_SUCCESS;
1804}
1805
1806# endif /* DEBUG_ACPI */
1807
1808/**
1809 * Used to calculate the value of a PM I/O port.
1810 *
1811 * @returns The actual I/O port value.
1812 * @param pThis The ACPI instance.
1813 * @param offset The offset into the I/O space, or -1 if invalid.
1814 */
1815static RTIOPORT acpiCalcPmPort(ACPIState *pThis, int32_t offset)
1816{
1817 Assert(pThis->uPmIoPortBase != 0);
1818
1819 if (offset == -1)
1820 return 0;
1821
1822 return (RTIOPORT)(pThis->uPmIoPortBase + offset);
1823}
1824
1825/**
1826 * Called by acpiLoadState and acpiUpdatePmHandlers to register the PM1a, PM
1827 * timer and GPE0 I/O ports.
1828 *
1829 * @returns VBox status code.
1830 * @param pThis The ACPI instance.
1831 */
1832static int acpiRegisterPmHandlers(ACPIState *pThis)
1833{
1834 int rc = VINF_SUCCESS;
1835
1836#define R(offset, cnt, writer, reader, description) \
1837 do { \
1838 rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
1839 NULL, NULL, description); \
1840 if (RT_FAILURE(rc)) \
1841 return rc; \
1842 } while (0)
1843#define L (GPE0_BLK_LEN / 2)
1844
1845 R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
1846 R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
1847 R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
1848 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
1849 R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
1850 R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
1851#undef L
1852#undef R
1853
1854 /* register RC stuff */
1855 if (pThis->fGCEnabled)
1856 {
1857 rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
1858 1, 0, NULL, "acpiPMTmrRead",
1859 NULL, NULL, "ACPI PM Timer");
1860 AssertRCReturn(rc, rc);
1861 }
1862
1863 /* register R0 stuff */
1864 if (pThis->fR0Enabled)
1865 {
1866 rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
1867 1, 0, NULL, "acpiPMTmrRead",
1868 NULL, NULL, "ACPI PM Timer");
1869 AssertRCReturn(rc, rc);
1870 }
1871
1872 return rc;
1873}
1874
1875/**
1876 * Called by acpiLoadState and acpiUpdatePmHandlers to unregister the PM1a, PM
1877 * timer and GPE0 I/O ports.
1878 *
1879 * @returns VBox status code.
1880 * @param pThis The ACPI instance.
1881 */
1882static int acpiUnregisterPmHandlers(ACPIState *pThis)
1883{
1884#define U(offset, cnt) \
1885 do { \
1886 int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt); \
1887 AssertRCReturn(rc, rc); \
1888 } while (0)
1889#define L (GPE0_BLK_LEN / 2)
1890
1891 U(PM1a_EVT_OFFSET+2, 1);
1892 U(PM1a_EVT_OFFSET, 1);
1893 U(PM1a_CTL_OFFSET, 1);
1894 U(PM_TMR_OFFSET, 1);
1895 U(GPE0_OFFSET + L, L);
1896 U(GPE0_OFFSET, L);
1897#undef L
1898#undef U
1899
1900 return VINF_SUCCESS;
1901}
1902
1903/**
1904 * Called by acpiPciConfigWrite and acpiReset to change the location of the
1905 * PM1a, PM timer and GPE0 ports.
1906 *
1907 * @returns VBox status code.
1908 *
1909 * @param pThis The ACPI instance.
1910 * @param NewIoPortBase The new base address of the I/O ports.
1911 */
1912static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
1913{
1914 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
1915 if (NewIoPortBase != pThis->uPmIoPortBase)
1916 {
1917 int rc = acpiUnregisterPmHandlers(pThis);
1918 if (RT_FAILURE(rc))
1919 return rc;
1920
1921 pThis->uPmIoPortBase = NewIoPortBase;
1922
1923 rc = acpiRegisterPmHandlers(pThis);
1924 if (RT_FAILURE(rc))
1925 return rc;
1926
1927 /* We have to update FADT table acccording to the new base */
1928 rc = acpiPlantTables(pThis);
1929 AssertRC(rc);
1930 if (RT_FAILURE(rc))
1931 return rc;
1932 }
1933
1934 return VINF_SUCCESS;
1935}
1936
1937
1938/**
1939 * Saved state structure description, version 4.
1940 */
1941static const SSMFIELD g_AcpiSavedStateFields4[] =
1942{
1943 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1944 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1945 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1946 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1947 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1948 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1949 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1950 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1951 SSMFIELD_ENTRY(ACPIState, u64RamSize),
1952 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1953 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
1954 SSMFIELD_ENTRY(ACPIState, uSleepState),
1955 SSMFIELD_ENTRY_TERM()
1956};
1957
1958/**
1959 * Saved state structure description, version 5.
1960 */
1961static const SSMFIELD g_AcpiSavedStateFields5[] =
1962{
1963 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1964 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1965 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1966 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1967 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1968 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1969 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1970 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1971 SSMFIELD_ENTRY(ACPIState, uSleepState),
1972 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1973 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1974 SSMFIELD_ENTRY_TERM()
1975};
1976
1977/**
1978 * Saved state structure description, version 6.
1979 */
1980static const SSMFIELD g_AcpiSavedStateFields6[] =
1981{
1982 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1983 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1984 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1985 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
1986 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1987 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1988 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1989 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1990 SSMFIELD_ENTRY(ACPIState, uSleepState),
1991 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1992 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1993 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
1994 SSMFIELD_ENTRY_TERM()
1995};
1996
1997
1998/**
1999 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2000 */
2001static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2002{
2003 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2004 return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2005}
2006
2007/**
2008 * @callback_method_impl{FNSSMDEVLOADEXEC}
2009 */
2010static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
2011 uint32_t uVersion, uint32_t uPass)
2012{
2013 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2014 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2015
2016 /*
2017 * Unregister PM handlers, will register with actual base after state
2018 * successfully loaded.
2019 */
2020 int rc = acpiUnregisterPmHandlers(pThis);
2021 if (RT_FAILURE(rc))
2022 return rc;
2023
2024 switch (uVersion)
2025 {
2026 case 4:
2027 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
2028 break;
2029 case 5:
2030 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
2031 break;
2032 case 6:
2033 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2034 break;
2035 default:
2036 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2037 break;
2038 }
2039 if (RT_SUCCESS(rc))
2040 {
2041 rc = acpiRegisterPmHandlers(pThis);
2042 if (RT_FAILURE(rc))
2043 return rc;
2044 rc = acpiFetchBatteryStatus(pThis);
2045 if (RT_FAILURE(rc))
2046 return rc;
2047 rc = acpiFetchBatteryInfo(pThis);
2048 if (RT_FAILURE(rc))
2049 return rc;
2050 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
2051 acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
2052 TMTimerUnlock(pThis->pPmTimerR3);
2053 }
2054 return rc;
2055}
2056
2057/**
2058 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2059 */
2060static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2061{
2062 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
2063 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2064 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
2065 return NULL;
2066}
2067
2068/**
2069 * Calculate the check sum for some ACPI data before planting it.
2070 *
2071 * All the bytes must add up to 0.
2072 *
2073 * @returns check sum.
2074 * @param pvSrc What to check sum.
2075 * @param cbData The amount of data to checksum.
2076 */
2077static uint8_t acpiChecksum(const void * const pvSrc, size_t cbData)
2078{
2079 uint8_t const *pbSrc = (uint8_t const *)pvSrc;
2080 uint8_t uSum = 0;
2081 for (size_t i = 0; i < cbData; ++i)
2082 uSum += pbSrc[i];
2083 return -uSum;
2084}
2085
2086/**
2087 * Prepare a ACPI table header.
2088 */
2089static void acpiPrepareHeader(ACPIState *pThis, ACPITBLHEADER *header,
2090 const char au8Signature[4],
2091 uint32_t u32Length, uint8_t u8Revision)
2092{
2093 memcpy(header->au8Signature, au8Signature, 4);
2094 header->u32Length = RT_H2LE_U32(u32Length);
2095 header->u8Revision = u8Revision;
2096 memcpy(header->au8OemId, pThis->au8OemId, 6);
2097 memcpy(header->au8OemTabId, "VBOX", 4);
2098 memcpy(header->au8OemTabId+4, au8Signature, 4);
2099 header->u32OemRevision = RT_H2LE_U32(1);
2100 memcpy(header->au8CreatorId, pThis->au8CreatorId, 4);
2101 header->u32CreatorRev = pThis->u32CreatorRev;
2102}
2103
2104/**
2105 * Initialize a generic address structure (ACPIGENADDR).
2106 */
2107static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
2108 uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
2109 uint8_t u8AccessSize, uint64_t u64Address)
2110{
2111 g->u8AddressSpaceId = u8AddressSpaceId;
2112 g->u8RegisterBitWidth = u8RegisterBitWidth;
2113 g->u8RegisterBitOffset = u8RegisterBitOffset;
2114 g->u8AccessSize = u8AccessSize;
2115 g->u64Address = RT_H2LE_U64(u64Address);
2116}
2117
2118/**
2119 * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
2120 */
2121static void acpiPhyscpy(ACPIState *pThis, RTGCPHYS32 dst, const void * const src, size_t size)
2122{
2123 PDMDevHlpPhysWrite(pThis->pDevIns, dst, src, size);
2124}
2125
2126/**
2127 * Plant the Differentiated System Description Table (DSDT).
2128 */
2129static void acpiSetupDSDT(ACPIState *pThis, RTGCPHYS32 addr,
2130 void* pPtr, size_t uDsdtLen)
2131{
2132 acpiPhyscpy(pThis, addr, pPtr, uDsdtLen);
2133}
2134
2135/**
2136 * Plan the Secondary System Description Table (SSDT).
2137 */
2138static void acpiSetupSSDT(ACPIState *pThis, RTGCPHYS32 addr,
2139 void* pPtr, size_t uSsdtLen)
2140{
2141 acpiPhyscpy(pThis, addr, pPtr, uSsdtLen);
2142}
2143
2144/**
2145 * Plant the Firmware ACPI Control Structure (FACS).
2146 */
2147static void acpiSetupFACS(ACPIState *pThis, RTGCPHYS32 addr)
2148{
2149 ACPITBLFACS facs;
2150
2151 memset(&facs, 0, sizeof(facs));
2152 memcpy(facs.au8Signature, "FACS", 4);
2153 facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
2154 facs.u32HWSignature = RT_H2LE_U32(0);
2155 facs.u32FWVector = RT_H2LE_U32(0);
2156 facs.u32GlobalLock = RT_H2LE_U32(0);
2157 facs.u32Flags = RT_H2LE_U32(0);
2158 facs.u64X_FWVector = RT_H2LE_U64(0);
2159 facs.u8Version = 1;
2160
2161 acpiPhyscpy(pThis, addr, (const uint8_t *)&facs, sizeof(facs));
2162}
2163
2164/**
2165 * Plant the Fixed ACPI Description Table (FADT aka FACP).
2166 */
2167static void acpiSetupFADT(ACPIState *pThis, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2, RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
2168{
2169 ACPITBLFADT fadt;
2170
2171 /* First the ACPI version 2+ version of the structure. */
2172 memset(&fadt, 0, sizeof(fadt));
2173 acpiPrepareHeader(pThis, &fadt.header, "FACP", sizeof(fadt), 4);
2174 fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
2175 fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
2176 fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
2177 fadt.u8PreferredPMProfile = 0; /* unspecified */
2178 fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
2179 fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
2180 fadt.u8AcpiEnable = ACPI_ENABLE;
2181 fadt.u8AcpiDisable = ACPI_DISABLE;
2182 fadt.u8S4BIOSReq = 0;
2183 fadt.u8PStateCnt = 0;
2184 fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
2185 fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
2186 fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
2187 fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
2188 fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
2189 fadt.u32PMTMRBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM_TMR_OFFSET));
2190 fadt.u32GPE0BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE0_OFFSET));
2191 fadt.u32GPE1BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE1_OFFSET));
2192 fadt.u8PM1EVTLEN = 4;
2193 fadt.u8PM1CTLLEN = 2;
2194 fadt.u8PM2CTLLEN = 0;
2195 fadt.u8PMTMLEN = 4;
2196 fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
2197 fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
2198 fadt.u8GPE1BASE = GPE1_BASE;
2199 fadt.u8CSTCNT = 0;
2200 fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
2201 fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
2202 fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
2203 fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
2204 fadt.u8DutyOffset = 0;
2205 fadt.u8DutyWidth = 0;
2206 fadt.u8DayAlarm = 0;
2207 fadt.u8MonAlarm = 0;
2208 fadt.u8Century = 0;
2209 fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
2210 /** @note WBINVD is required for ACPI versions newer than 1.0 */
2211 fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
2212 | FADT_FL_FIX_RTC
2213 | FADT_FL_TMR_VAL_EXT
2214 | FADT_FL_RESET_REG_SUP);
2215
2216 /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
2217 if (pThis->fCpuHotPlug)
2218 fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
2219
2220 acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
2221 fadt.u8ResetVal = ACPI_RESET_REG_VAL;
2222 fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
2223 fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
2224 acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
2225 acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
2226 acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
2227 acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
2228 acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
2229 acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiCalcPmPort(pThis, PM_TMR_OFFSET));
2230 acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiCalcPmPort(pThis, GPE0_OFFSET));
2231 acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, GPE1_OFFSET));
2232 fadt.header.u8Checksum = acpiChecksum(&fadt, sizeof(fadt));
2233 acpiPhyscpy(pThis, GCPhysAcpi2, &fadt, sizeof(fadt));
2234
2235 /* Now the ACPI 1.0 version. */
2236 fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
2237 fadt.u8IntModel = INT_MODEL_DUAL_PIC;
2238 fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
2239 fadt.header.u8Checksum = acpiChecksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
2240 acpiPhyscpy(pThis, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
2241}
2242
2243/**
2244 * Plant the root System Description Table.
2245 *
2246 * The RSDT and XSDT tables are basically identical. The only difference is 32
2247 * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
2248 * ACPI 2.0 and up.
2249 */
2250static int acpiSetupRSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
2251{
2252 ACPITBLRSDT *rsdt;
2253 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
2254
2255 rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
2256 if (!rsdt)
2257 return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
2258
2259 acpiPrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
2260 for (unsigned int i = 0; i < nb_entries; ++i)
2261 {
2262 rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
2263 Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
2264 }
2265 rsdt->header.u8Checksum = acpiChecksum(rsdt, size);
2266 acpiPhyscpy(pThis, addr, rsdt, size);
2267 RTMemFree(rsdt);
2268 return VINF_SUCCESS;
2269}
2270
2271/**
2272 * Plant the Extended System Description Table.
2273 */
2274static int acpiSetupXSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
2275{
2276 ACPITBLXSDT *xsdt;
2277 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
2278
2279 xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
2280 if (!xsdt)
2281 return VERR_NO_TMP_MEMORY;
2282
2283 acpiPrepareHeader(pThis, &xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
2284
2285 if (pThis->fUseCust)
2286 memcpy(xsdt->header.au8OemTabId, pThis->au8OemTabId, 8);
2287
2288 for (unsigned int i = 0; i < nb_entries; ++i)
2289 {
2290 xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
2291 Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
2292 }
2293 xsdt->header.u8Checksum = acpiChecksum(xsdt, size);
2294 acpiPhyscpy(pThis, addr, xsdt, size);
2295 RTMemFree(xsdt);
2296 return VINF_SUCCESS;
2297}
2298
2299/**
2300 * Plant the Root System Description Pointer (RSDP).
2301 */
2302static void acpiSetupRSDP(ACPIState *pThis, ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
2303{
2304 memset(rsdp, 0, sizeof(*rsdp));
2305
2306 /* ACPI 1.0 part (RSDT */
2307 memcpy(rsdp->au8Signature, "RSD PTR ", 8);
2308 memcpy(rsdp->au8OemId, pThis->au8OemId, 6);
2309 rsdp->u8Revision = ACPI_REVISION;
2310 rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
2311 rsdp->u8Checksum = acpiChecksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
2312
2313 /* ACPI 2.0 part (XSDT) */
2314 rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
2315 rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
2316 rsdp->u8ExtChecksum = acpiChecksum(rsdp, sizeof(ACPITBLRSDP));
2317}
2318
2319/**
2320 * Plant the Multiple APIC Description Table (MADT).
2321 *
2322 * @note APIC without IO-APIC hangs Windows Vista therefore we setup both.
2323 *
2324 * @todo All hardcoded, should set this up based on the actual VM config!!!!!
2325 */
2326static void acpiSetupMADT(ACPIState *pThis, RTGCPHYS32 addr)
2327{
2328 uint16_t cpus = pThis->cCpus;
2329 AcpiTableMADT madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
2330
2331 acpiPrepareHeader(pThis, madt.header_addr(), "APIC", madt.size(), 2);
2332
2333 *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
2334 *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
2335
2336 /* LAPICs records */
2337 ACPITBLLAPIC* lapic = madt.LApics_addr();
2338 for (uint16_t i = 0; i < cpus; i++)
2339 {
2340 lapic->u8Type = 0;
2341 lapic->u8Length = sizeof(ACPITBLLAPIC);
2342 lapic->u8ProcId = i;
2343 /** Must match numbering convention in MPTABLES */
2344 lapic->u8ApicId = i;
2345 lapic->u32Flags = VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
2346 lapic++;
2347 }
2348
2349 /* IO-APIC record */
2350 ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
2351 ioapic->u8Type = 1;
2352 ioapic->u8Length = sizeof(ACPITBLIOAPIC);
2353 /** Must match MP tables ID */
2354 ioapic->u8IOApicId = cpus;
2355 ioapic->u8Reserved = 0;
2356 ioapic->u32Address = RT_H2LE_U32(0xfec00000);
2357 ioapic->u32GSIB = RT_H2LE_U32(0);
2358
2359 /* Interrupt Source Overrides */
2360 /* Flags:
2361 bits[3:2]:
2362 00 conforms to the bus
2363 01 edge-triggered
2364 10 reserved
2365 11 level-triggered
2366 bits[1:0]
2367 00 conforms to the bus
2368 01 active-high
2369 10 reserved
2370 11 active-low */
2371 /* If changing, also update PDMIsaSetIrq() and MPS */
2372 ACPITBLISO* isos = madt.ISO_addr();
2373 /* Timer interrupt rule IRQ0 to GSI2 */
2374 isos[0].u8Type = 2;
2375 isos[0].u8Length = sizeof(ACPITBLISO);
2376 isos[0].u8Bus = 0; /* Must be 0 */
2377 isos[0].u8Source = 0; /* IRQ0 */
2378 isos[0].u32GSI = 2; /* connected to pin 2 */
2379 isos[0].u16Flags = 0; /* conform to the bus */
2380
2381 /* ACPI interrupt rule - IRQ9 to GSI9 */
2382 isos[1].u8Type = 2;
2383 isos[1].u8Length = sizeof(ACPITBLISO);
2384 isos[1].u8Bus = 0; /* Must be 0 */
2385 isos[1].u8Source = 9; /* IRQ9 */
2386 isos[1].u32GSI = 9; /* connected to pin 9 */
2387 isos[1].u16Flags = 0xd; /* active high, level triggered */
2388 Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
2389
2390 madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
2391 acpiPhyscpy(pThis, addr, madt.data(), madt.size());
2392}
2393
2394/**
2395 * Plant the High Performance Event Timer (HPET) descriptor.
2396 */
2397static void acpiSetupHPET(ACPIState *pThis, RTGCPHYS32 addr)
2398{
2399 ACPITBLHPET hpet;
2400
2401 memset(&hpet, 0, sizeof(hpet));
2402
2403 acpiPrepareHeader(pThis, &hpet.aHeader, "HPET", sizeof(hpet), 1);
2404 /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
2405 acpiWriteGenericAddr(&hpet.HpetAddr,
2406 0 /* Memory address space */,
2407 64 /* Register bit width */,
2408 0 /* Bit offset */,
2409 0, /* Register access size, is it correct? */
2410 0xfed00000 /* Address */);
2411
2412 hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
2413 hpet.u32Number = 0;
2414 hpet.u32MinTick = 4096;
2415 hpet.u8Attributes = 0;
2416
2417 hpet.aHeader.u8Checksum = acpiChecksum(&hpet, sizeof(hpet));
2418
2419 acpiPhyscpy(pThis, addr, (const uint8_t *)&hpet, sizeof(hpet));
2420}
2421
2422
2423/** Custom Description Table */
2424static void acpiSetupCUST(ACPIState *pThis, RTGCPHYS32 addr)
2425{
2426 ACPITBLCUST cust;
2427
2428 /* First the ACPI version 1 version of the structure. */
2429 memset(&cust, 0, sizeof(cust));
2430 acpiPrepareHeader(pThis, &cust.header, "CUST", sizeof(cust), 1);
2431
2432 memcpy(cust.header.au8OemTabId, pThis->au8OemTabId, 8);
2433 cust.header.u32OemRevision = RT_H2LE_U32(pThis->u32OemRevision);
2434 cust.header.u8Checksum = acpiChecksum((uint8_t *)&cust, sizeof(cust));
2435
2436 acpiPhyscpy(pThis, addr, pThis->pu8CustBin, pThis->cbCustBin);
2437}
2438
2439/**
2440 * Used by acpiPlantTables to plant a MMCONFIG PCI config space access (MCFG)
2441 * descriptor.
2442 *
2443 * @param pThis The ACPI instance.
2444 * @param GCPhysDst Where to plant it.
2445 */
2446static void acpiSetupMCFG(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
2447{
2448 struct
2449 {
2450 ACPITBLMCFG hdr;
2451 ACPITBLMCFGENTRY entry;
2452 } tbl;
2453 uint8_t u8StartBus = 0;
2454 uint8_t u8EndBus = (pThis->u64PciConfigMMioLength >> 20) - 1;
2455
2456 RT_ZERO(tbl);
2457
2458 acpiPrepareHeader(pThis, &tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
2459 tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
2460 tbl.entry.u8StartBus = u8StartBus;
2461 tbl.entry.u8EndBus = u8EndBus;
2462 // u16PciSegmentGroup must match _SEG in ACPI table
2463
2464 tbl.hdr.aHeader.u8Checksum = acpiChecksum(&tbl, sizeof(tbl));
2465
2466 acpiPhyscpy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
2467}
2468
2469/**
2470 * Used by acpiPlantTables and acpiConstruct.
2471 *
2472 * @returns Guest memory address.
2473 */
2474static uint32_t find_rsdp_space(void)
2475{
2476 return 0xe0000;
2477}
2478
2479/**
2480 * Create the ACPI tables in guest memory.
2481 */
2482static int acpiPlantTables(ACPIState *pThis)
2483{
2484 int rc;
2485 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
2486 RTGCPHYS32 GCPhysHpet = 0;
2487 RTGCPHYS32 GCPhysApic = 0;
2488 RTGCPHYS32 GCPhysSsdt = 0;
2489 RTGCPHYS32 GCPhysMcfg = 0;
2490 RTGCPHYS32 GCPhysCust = 0;
2491 uint32_t addend = 0;
2492 RTGCPHYS32 aGCPhysRsdt[8];
2493 RTGCPHYS32 aGCPhysXsdt[8];
2494 uint32_t cAddr;
2495 uint32_t iMadt = 0;
2496 uint32_t iHpet = 0;
2497 uint32_t iSsdt = 0;
2498 uint32_t iMcfg = 0;
2499 uint32_t iCust = 0;
2500 size_t cbRsdt = sizeof(ACPITBLHEADER);
2501 size_t cbXsdt = sizeof(ACPITBLHEADER);
2502
2503 cAddr = 1; /* FADT */
2504 if (pThis->u8UseIOApic)
2505 iMadt = cAddr++; /* MADT */
2506
2507 if (pThis->fUseHpet)
2508 iHpet = cAddr++; /* HPET */
2509
2510 if (pThis->fUseMcfg)
2511 iMcfg = cAddr++; /* MCFG */
2512
2513 if (pThis->fUseCust)
2514 iCust = cAddr++; /* CUST */
2515
2516 iSsdt = cAddr++; /* SSDT */
2517
2518 Assert(cAddr < RT_ELEMENTS(aGCPhysRsdt));
2519 Assert(cAddr < RT_ELEMENTS(aGCPhysXsdt));
2520
2521 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
2522 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
2523
2524 rc = CFGMR3QueryU64(pThis->pDevIns->pCfg, "RamSize", &pThis->u64RamSize);
2525 if (RT_FAILURE(rc))
2526 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
2527 N_("Configuration error: Querying \"RamSize\" as integer failed"));
2528
2529 uint32_t cbRamHole;
2530 rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
2531 if (RT_FAILURE(rc))
2532 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
2533 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
2534
2535 /*
2536 * Calculate the sizes for the high and low regions.
2537 */
2538 const uint64_t offRamHole = _4G - cbRamHole;
2539 pThis->cbRamHigh = offRamHole < pThis->u64RamSize ? pThis->u64RamSize - offRamHole : 0;
2540 uint64_t cbRamLow = offRamHole < pThis->u64RamSize ? offRamHole : pThis->u64RamSize;
2541 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
2542 {
2543 /* Note: This is also enforced by DevPcBios.cpp. */
2544 LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
2545 cbRamLow = UINT32_C(0xffe00000);
2546 }
2547 pThis->cbRamLow = (uint32_t)cbRamLow;
2548
2549 GCPhysCur = 0;
2550 GCPhysRsdt = GCPhysCur;
2551
2552 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
2553 GCPhysXsdt = GCPhysCur;
2554
2555 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
2556 GCPhysFadtAcpi1 = GCPhysCur;
2557
2558 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
2559 GCPhysFadtAcpi2 = GCPhysCur;
2560
2561 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
2562 GCPhysFacs = GCPhysCur;
2563
2564 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
2565 if (pThis->u8UseIOApic)
2566 {
2567 GCPhysApic = GCPhysCur;
2568 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
2569 }
2570 if (pThis->fUseHpet)
2571 {
2572 GCPhysHpet = GCPhysCur;
2573 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
2574 }
2575 if (pThis->fUseMcfg)
2576 {
2577 GCPhysMcfg = GCPhysCur;
2578 /* Assume one entry */
2579 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
2580 }
2581 if (pThis->fUseCust)
2582 {
2583 GCPhysCust = GCPhysCur;
2584 GCPhysCur = RT_ALIGN_32(GCPhysCur + pThis->cbCustBin, 16);
2585 }
2586
2587 void *pvSsdtCode = NULL;
2588 size_t cbSsdtSize = 0;
2589 rc = acpiPrepareSsdt(pThis->pDevIns, &pvSsdtCode, &cbSsdtSize);
2590 if (RT_FAILURE(rc))
2591 return rc;
2592
2593 GCPhysSsdt = GCPhysCur;
2594 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdtSize, 16);
2595
2596 GCPhysDsdt = GCPhysCur;
2597
2598 void *pvDsdtCode = NULL;
2599 size_t cbDsdtSize = 0;
2600 rc = acpiPrepareDsdt(pThis->pDevIns, &pvDsdtCode, &cbDsdtSize);
2601 if (RT_FAILURE(rc))
2602 return rc;
2603
2604 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
2605
2606 if (GCPhysCur > 0x10000)
2607 return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_TOO_MUCH_DATA,
2608 N_("Error: ACPI tables bigger than 64KB"));
2609
2610 Log(("RSDP 0x%08X\n", find_rsdp_space()));
2611 addend = pThis->cbRamLow - 0x10000;
2612 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
2613 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
2614 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
2615 if (pThis->u8UseIOApic)
2616 Log((" MADT 0x%08X", GCPhysApic + addend));
2617 if (pThis->fUseHpet)
2618 Log((" HPET 0x%08X", GCPhysHpet + addend));
2619 if (pThis->fUseMcfg)
2620 Log((" MCFG 0x%08X", GCPhysMcfg + addend));
2621 if (pThis->fUseCust)
2622 Log((" CUST 0x%08X", GCPhysCust + addend));
2623 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
2624 Log(("\n"));
2625
2626 acpiSetupRSDP(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
2627 acpiSetupDSDT(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdtSize);
2628 acpiCleanupDsdt(pThis->pDevIns, pvDsdtCode);
2629 acpiSetupFACS(pThis, GCPhysFacs + addend);
2630 acpiSetupFADT(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
2631
2632 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
2633 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
2634 if (pThis->u8UseIOApic)
2635 {
2636 acpiSetupMADT(pThis, GCPhysApic + addend);
2637 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
2638 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
2639 }
2640 if (pThis->fUseHpet)
2641 {
2642 acpiSetupHPET(pThis, GCPhysHpet + addend);
2643 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
2644 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
2645 }
2646 if (pThis->fUseMcfg)
2647 {
2648 acpiSetupMCFG(pThis, GCPhysMcfg + addend);
2649 aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
2650 aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
2651 }
2652 if (pThis->fUseCust)
2653 {
2654 acpiSetupCUST(pThis, GCPhysCust + addend);
2655 aGCPhysRsdt[iCust] = GCPhysCust + addend;
2656 aGCPhysXsdt[iCust] = GCPhysCust + addend;
2657 }
2658
2659 acpiSetupSSDT(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdtSize);
2660 acpiCleanupSsdt(pThis->pDevIns, pvSsdtCode);
2661 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
2662 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
2663
2664 rc = acpiSetupRSDT(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
2665 if (RT_FAILURE(rc))
2666 return rc;
2667 return acpiSetupXSDT(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
2668}
2669
2670/**
2671 * @callback_method_impl{FNPCICONFIGREAD}
2672 */
2673static DECLCALLBACK(uint32_t) acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
2674{
2675 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2676 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2677
2678 Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
2679 return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
2680}
2681
2682/**
2683 * @callback_method_impl{FNPCICONFIGWRITE}
2684 */
2685static DECLCALLBACK(void) acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
2686{
2687 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2688 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2689
2690 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
2691 DEVACPI_LOCK_R3(pThis);
2692
2693 if (Address == VBOX_PCI_INTERRUPT_LINE)
2694 {
2695 Log(("acpi: ignore interrupt line settings: %d, we'll use hardcoded value %d\n", u32Value, SCI_INT));
2696 u32Value = SCI_INT;
2697 }
2698
2699 pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
2700
2701 /* PMREGMISC written */
2702 if (Address == 0x80)
2703 {
2704 /* Check Power Management IO Space Enable (PMIOSE) bit */
2705 if (pPciDev->config[0x80] & 0x1)
2706 {
2707 RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
2708 NewIoPortBase &= 0xffc0;
2709
2710 int rc = acpiUpdatePmHandlers(pThis, NewIoPortBase);
2711 AssertRC(rc);
2712 }
2713 }
2714
2715 DEVACPI_UNLOCK(pThis);
2716}
2717
2718/**
2719 * Attach a new CPU.
2720 *
2721 * @returns VBox status code.
2722 * @param pDevIns The device instance.
2723 * @param iLUN The logical unit which is being attached.
2724 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2725 *
2726 * @remarks This code path is not used during construction.
2727 */
2728static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2729{
2730 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2731 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2732
2733 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2734 ("Hot-plug flag is not set\n"),
2735 VERR_NOT_SUPPORTED);
2736 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
2737
2738 /* Check if it was already attached */
2739 int rc = VINF_SUCCESS;
2740 DEVACPI_LOCK_R3(pThis);
2741 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
2742 {
2743 PPDMIBASE IBaseTmp;
2744 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
2745 if (RT_SUCCESS(rc))
2746 {
2747 /* Enable the CPU */
2748 VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
2749
2750 /*
2751 * Lock the CPU because we don't know if the guest will use it or not.
2752 * Prevents ejection while the CPU is still used
2753 */
2754 VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
2755 pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
2756 pThis->u32CpuEvent = iLUN;
2757
2758 /* Notify the guest */
2759 update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
2760 }
2761 }
2762 DEVACPI_UNLOCK(pThis);
2763 return rc;
2764}
2765
2766/**
2767 * Detach notification.
2768 *
2769 * @param pDevIns The device instance.
2770 * @param iLUN The logical unit which is being detached.
2771 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2772 */
2773static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2774{
2775 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2776
2777 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2778
2779 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2780 ("Hot-plug flag is not set\n"));
2781
2782 /* Check if it was already detached */
2783 DEVACPI_LOCK_R3(pThis);
2784 if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
2785 {
2786 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
2787 {
2788 /* Disable the CPU */
2789 VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
2790 pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
2791 pThis->u32CpuEvent = iLUN;
2792
2793 /* Notify the guest */
2794 update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
2795 }
2796 else
2797 AssertMsgFailed(("CPU is still locked by the guest\n"));
2798 }
2799 DEVACPI_UNLOCK(pThis);
2800}
2801
2802/**
2803 * @interface_method_impl{PDMDEVREG,pfnResume}
2804 */
2805static DECLCALLBACK(void) acpiResume(PPDMDEVINS pDevIns)
2806{
2807 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2808 if (pThis->fSetWakeupOnResume)
2809 {
2810 Log(("acpiResume: setting WAK_STS\n"));
2811 pThis->fSetWakeupOnResume = false;
2812 pThis->pm1a_sts |= WAK_STS;
2813 }
2814}
2815
2816/**
2817 * @interface_method_impl{PDMDEVREG,pfnReset}
2818 */
2819static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
2820{
2821 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2822
2823 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
2824 pThis->pm1a_en = 0;
2825 pThis->pm1a_sts = 0;
2826 pThis->pm1a_ctl = 0;
2827 pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
2828 acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
2829 pThis->uBatteryIndex = 0;
2830 pThis->uSystemInfoIndex = 0;
2831 pThis->gpe0_en = 0;
2832 pThis->gpe0_sts = 0;
2833 pThis->uSleepState = 0;
2834 TMTimerUnlock(pThis->pPmTimerR3);
2835
2836 /** @todo Should we really reset PM base? */
2837 acpiUpdatePmHandlers(pThis, PM_PORT_BASE);
2838
2839 acpiPlantTables(pThis);
2840}
2841
2842/**
2843 * @interface_method_impl{PDMDEVREG,pfnRelocate}
2844 */
2845static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2846{
2847 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2848 pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
2849 NOREF(offDelta);
2850}
2851
2852/**
2853 * @interface_methid_impl{PDMDEVREG,pfnDestruct}
2854 */
2855static DECLCALLBACK(int) acpiDestruct(PPDMDEVINS pDevIns)
2856{
2857 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2858 if (pThis->pu8CustBin)
2859 {
2860 MMR3HeapFree(pThis->pu8CustBin);
2861 pThis->pu8CustBin = NULL;
2862 }
2863 return VINF_SUCCESS;
2864}
2865
2866/**
2867 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2868 */
2869static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2870{
2871 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2872 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2873
2874 /*
2875 * Init data and set defaults.
2876 */
2877 /** @todo move more of the code up! */
2878
2879 pThis->pDevIns = pDevIns;
2880 VMCPUSET_EMPTY(&pThis->CpuSetAttached);
2881 VMCPUSET_EMPTY(&pThis->CpuSetLocked);
2882 pThis->idCpuLockCheck = UINT32_C(0xffffffff);
2883 pThis->u32CpuEventType = 0;
2884 pThis->u32CpuEvent = UINT32_C(0xffffffff);
2885
2886 /* The first CPU can't be attached/detached */
2887 VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
2888 VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
2889
2890 /* IBase */
2891 pThis->IBase.pfnQueryInterface = acpiQueryInterface;
2892 /* IACPIPort */
2893 pThis->IACPIPort.pfnSleepButtonPress = acpiPort_SleepButtonPress;
2894 pThis->IACPIPort.pfnPowerButtonPress = acpiPort_PowerButtonPress;
2895 pThis->IACPIPort.pfnGetPowerButtonHandled = acpiPort_GetPowerButtonHandled;
2896 pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiPort_GetGuestEnteredACPIMode;
2897 pThis->IACPIPort.pfnGetCpuStatus = acpiPort_GetCpuStatus;
2898
2899 /* Set the default critical section to NOP (related to the PM timer). */
2900 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2901 AssertRCReturn(rc, rc);
2902
2903 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi%u", iInstance);
2904 AssertRCReturn(rc, rc);
2905
2906 /*
2907 * Validate and read the configuration.
2908 */
2909 if (!CFGMR3AreValuesValid(pCfg,
2910 "RamSize\0"
2911 "RamHoleSize\0"
2912 "IOAPIC\0"
2913 "NumCPUs\0"
2914 "GCEnabled\0"
2915 "R0Enabled\0"
2916 "HpetEnabled\0"
2917 "McfgEnabled\0"
2918 "McfgBase\0"
2919 "McfgLength\0"
2920 "SmcEnabled\0"
2921 "FdcEnabled\0"
2922 "ShowRtc\0"
2923 "ShowCpu\0"
2924 "NicPciAddress\0"
2925 "AudioPciAddress\0"
2926 "IocPciAddress\0"
2927 "HostBusPciAddress\0"
2928 "EnableSuspendToDisk\0"
2929 "PowerS1Enabled\0"
2930 "PowerS4Enabled\0"
2931 "CpuHotPlug\0"
2932 "AmlFilePath\0"
2933 "Serial0IoPortBase\0"
2934 "Serial1IoPortBase\0"
2935 "Serial0Irq\0"
2936 "Serial1Irq\0"
2937 "AcpiOemId\0"
2938 "AcpiCreatorId\0"
2939 "AcpiCreatorRev\0"
2940 "CustomTable\0"
2941 "SLICTable\0"
2942 ))
2943 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2944 N_("Configuration error: Invalid config key for ACPI device"));
2945
2946 /* query whether we are supposed to present an IOAPIC */
2947 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
2948 if (RT_FAILURE(rc))
2949 return PDMDEV_SET_ERROR(pDevIns, rc,
2950 N_("Configuration error: Failed to read \"IOAPIC\""));
2951
2952 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
2953 if (RT_FAILURE(rc))
2954 return PDMDEV_SET_ERROR(pDevIns, rc,
2955 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
2956
2957 /* query whether we are supposed to present an FDC controller */
2958 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
2959 if (RT_FAILURE(rc))
2960 return PDMDEV_SET_ERROR(pDevIns, rc,
2961 N_("Configuration error: Failed to read \"FdcEnabled\""));
2962
2963 /* query whether we are supposed to present HPET */
2964 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
2965 if (RT_FAILURE(rc))
2966 return PDMDEV_SET_ERROR(pDevIns, rc,
2967 N_("Configuration error: Failed to read \"HpetEnabled\""));
2968 /* query MCFG configuration */
2969 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
2970 if (RT_FAILURE(rc))
2971 return PDMDEV_SET_ERROR(pDevIns, rc,
2972 N_("Configuration error: Failed to read \"McfgBase\""));
2973 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
2974 if (RT_FAILURE(rc))
2975 return PDMDEV_SET_ERROR(pDevIns, rc,
2976 N_("Configuration error: Failed to read \"McfgLength\""));
2977 pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
2978
2979 /* query whether we are supposed to present custom table */
2980 pThis->fUseCust = false;
2981
2982 /* query whether we are supposed to present SMC */
2983 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
2984 if (RT_FAILURE(rc))
2985 return PDMDEV_SET_ERROR(pDevIns, rc,
2986 N_("Configuration error: Failed to read \"SmcEnabled\""));
2987
2988 /* query whether we are supposed to present RTC object */
2989 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
2990 if (RT_FAILURE(rc))
2991 return PDMDEV_SET_ERROR(pDevIns, rc,
2992 N_("Configuration error: Failed to read \"ShowRtc\""));
2993
2994 /* query whether we are supposed to present CPU objects */
2995 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
2996 if (RT_FAILURE(rc))
2997 return PDMDEV_SET_ERROR(pDevIns, rc,
2998 N_("Configuration error: Failed to read \"ShowCpu\""));
2999
3000 /* query primary NIC PCI address */
3001 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
3002 if (RT_FAILURE(rc))
3003 return PDMDEV_SET_ERROR(pDevIns, rc,
3004 N_("Configuration error: Failed to read \"NicPciAddress\""));
3005
3006 /* query primary NIC PCI address */
3007 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
3008 if (RT_FAILURE(rc))
3009 return PDMDEV_SET_ERROR(pDevIns, rc,
3010 N_("Configuration error: Failed to read \"AudioPciAddress\""));
3011
3012 /* query IO controller (southbridge) PCI address */
3013 rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
3014 if (RT_FAILURE(rc))
3015 return PDMDEV_SET_ERROR(pDevIns, rc,
3016 N_("Configuration error: Failed to read \"IocPciAddress\""));
3017
3018 /* query host bus controller PCI address */
3019 rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
3020 if (RT_FAILURE(rc))
3021 return PDMDEV_SET_ERROR(pDevIns, rc,
3022 N_("Configuration error: Failed to read \"HostBusPciAddress\""));
3023
3024 /* query whether S1 power state should be exposed */
3025 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
3026 if (RT_FAILURE(rc))
3027 return PDMDEV_SET_ERROR(pDevIns, rc,
3028 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
3029
3030 /* query whether S4 power state should be exposed */
3031 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
3032 if (RT_FAILURE(rc))
3033 return PDMDEV_SET_ERROR(pDevIns, rc,
3034 N_("Configuration error: Failed to read \"PowerS4Enabled\""));
3035
3036 /* query whether S1 power state should save the VM state */
3037 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
3038 if (RT_FAILURE(rc))
3039 return PDMDEV_SET_ERROR(pDevIns, rc,
3040 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
3041
3042 /* query whether we are allow CPU hot plugging */
3043 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
3044 if (RT_FAILURE(rc))
3045 return PDMDEV_SET_ERROR(pDevIns, rc,
3046 N_("Configuration error: Failed to read \"CpuHotPlug\""));
3047
3048 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
3049 if (RT_FAILURE(rc))
3050 return PDMDEV_SET_ERROR(pDevIns, rc,
3051 N_("Configuration error: Failed to read \"GCEnabled\""));
3052
3053 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
3054 if (RT_FAILURE(rc))
3055 return PDMDEV_SET_ERROR(pDevIns, rc,
3056 N_("configuration error: failed to read \"R0Enabled\""));
3057
3058 /* query serial info */
3059 rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
3060 if (RT_FAILURE(rc))
3061 return PDMDEV_SET_ERROR(pDevIns, rc,
3062 N_("Configuration error: Failed to read \"Serial0Irq\""));
3063
3064 rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
3065 if (RT_FAILURE(rc))
3066 return PDMDEV_SET_ERROR(pDevIns, rc,
3067 N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
3068
3069 /* Serial 1 is enabled, get config data */
3070 rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
3071 if (RT_FAILURE(rc))
3072 return PDMDEV_SET_ERROR(pDevIns, rc,
3073 N_("Configuration error: Failed to read \"Serial1Irq\""));
3074
3075 rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
3076 if (RT_FAILURE(rc))
3077 return PDMDEV_SET_ERROR(pDevIns, rc,
3078 N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
3079
3080 /* Try to attach the other CPUs */
3081 for (unsigned i = 1; i < pThis->cCpus; i++)
3082 {
3083 if (pThis->fCpuHotPlug)
3084 {
3085 PPDMIBASE IBaseTmp;
3086 rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
3087
3088 if (RT_SUCCESS(rc))
3089 {
3090 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3091 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3092 Log(("acpi: Attached CPU %u\n", i));
3093 }
3094 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3095 Log(("acpi: CPU %u not attached yet\n", i));
3096 else
3097 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
3098 }
3099 else
3100 {
3101 /* CPU is always attached if hot-plug is not enabled. */
3102 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3103 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3104 }
3105 }
3106
3107 char *pszOemId = NULL;
3108 rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiOemId", &pszOemId, "VBOX ");
3109 if (RT_FAILURE(rc))
3110 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3111 N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
3112 size_t cbOemId = strlen(pszOemId);
3113 if (cbOemId > 6)
3114 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3115 N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
3116 memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
3117 memcpy(pThis->au8OemId, pszOemId, cbOemId);
3118 MMR3HeapFree(pszOemId);
3119
3120 char *pszCreatorId = NULL;
3121 rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
3122 if (RT_FAILURE(rc))
3123 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3124 N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
3125 size_t cbCreatorId = strlen(pszCreatorId);
3126 if (cbCreatorId > 4)
3127 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3128 N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
3129 memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
3130 memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
3131 MMR3HeapFree(pszCreatorId);
3132
3133 rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
3134 if (RT_FAILURE(rc))
3135 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3136 N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
3137 pThis->u32OemRevision = RT_H2LE_U32(0x1);
3138
3139 /*
3140 * Get the custom table binary file name.
3141 */
3142 char *pszCustBinFile;
3143 rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "CustomTable", &pszCustBinFile);
3144 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3145 rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "SLICTable", &pszCustBinFile);
3146 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3147 {
3148 pszCustBinFile = NULL;
3149 rc = VINF_SUCCESS;
3150 }
3151 else if (RT_FAILURE(rc))
3152 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
3153 N_("Configuration error: Querying \"CustomTable\" as a string failed"));
3154 else if (!*pszCustBinFile)
3155 {
3156 MMR3HeapFree(pszCustBinFile);
3157 pszCustBinFile = NULL;
3158 }
3159
3160 /*
3161 * Determine the custom table binary size, open specified ROM file in the process.
3162 */
3163 if (pszCustBinFile)
3164 {
3165 RTFILE FileCUSTBin;
3166 rc = RTFileOpen(&FileCUSTBin, pszCustBinFile,
3167 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
3168 if (RT_SUCCESS(rc))
3169 {
3170 rc = RTFileGetSize(FileCUSTBin, &pThis->cbCustBin);
3171 if (RT_SUCCESS(rc))
3172 {
3173 /* The following checks should be in sync the AssertReleaseMsg's below. */
3174 if ( pThis->cbCustBin > 3072
3175 || pThis->cbCustBin < sizeof(ACPITBLHEADER))
3176 rc = VERR_TOO_MUCH_DATA;
3177
3178 /*
3179 * Allocate buffer for the custom table binary data.
3180 */
3181 pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, pThis->cbCustBin);
3182 if (pThis->pu8CustBin)
3183 {
3184 rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
3185 if (RT_FAILURE(rc))
3186 {
3187 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbCustBin, rc));
3188 MMR3HeapFree(pThis->pu8CustBin);
3189 pThis->pu8CustBin = NULL;
3190 }
3191 else
3192 {
3193 pThis->fUseCust = true;
3194 memcpy(&pThis->au8OemId[0], &pThis->pu8CustBin[10], 6);
3195 memcpy(&pThis->au8OemTabId[0], &pThis->pu8CustBin[16], 8);
3196 memcpy(&pThis->u32OemRevision, &pThis->pu8CustBin[24], 4);
3197 memcpy(&pThis->au8CreatorId[0], &pThis->pu8CustBin[28], 4);
3198 memcpy(&pThis->u32CreatorRev, &pThis->pu8CustBin[32], 4);
3199 LogRel(("Reading custom ACPI table from file '%s' (%d bytes)\n", pszCustBinFile, pThis->cbCustBin));
3200 }
3201 }
3202 else
3203 rc = VERR_NO_MEMORY;
3204
3205 RTFileClose(FileCUSTBin);
3206 }
3207 }
3208 MMR3HeapFree(pszCustBinFile);
3209 if (RT_FAILURE(rc))
3210 return PDMDEV_SET_ERROR(pDevIns, rc,
3211 N_("Error reading custom ACPI table"));
3212 }
3213
3214 /* Set default port base */
3215 pThis->uPmIoPortBase = PM_PORT_BASE;
3216
3217 /*
3218 * FDC and SMC try to use the same non-shareable interrupt (6),
3219 * enable only one device.
3220 */
3221 if (pThis->fUseSmc)
3222 pThis->fUseFdc = false;
3223
3224 /*
3225 * Plant ACPI tables.
3226 */
3227 RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
3228 if (!GCPhysRsdp)
3229 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
3230 N_("Can not find space for RSDP. ACPI is disabled"));
3231
3232 rc = acpiPlantTables(pThis);
3233 if (RT_FAILURE(rc))
3234 return rc;
3235
3236 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
3237 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
3238 if (RT_FAILURE(rc))
3239 return rc;
3240
3241 /*
3242 * Register I/O ports.
3243 */
3244 rc = acpiRegisterPmHandlers(pThis);
3245 if (RT_FAILURE(rc))
3246 return rc;
3247
3248#define R(addr, cnt, writer, reader, description) \
3249 do { \
3250 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
3251 NULL, NULL, description); \
3252 if (RT_FAILURE(rc)) \
3253 return rc; \
3254 } while (0)
3255 R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
3256#ifdef DEBUG_ACPI
3257 R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
3258 R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
3259#endif
3260 R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
3261 R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
3262 R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
3263 R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
3264 R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
3265#undef R
3266
3267 /*
3268 * Create the PM timer.
3269 */
3270 PTMTIMER pTimer;
3271 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiPmTimer, &pThis->dev,
3272 TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
3273 AssertRCReturn(rc, rc);
3274 pThis->pPmTimerR3 = pTimer;
3275 pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
3276 pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
3277
3278 rc = TMTimerLock(pTimer, VERR_IGNORED);
3279 AssertRCReturn(rc, rc);
3280 pThis->u64PmTimerInitial = TMTimerGet(pTimer);
3281 acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
3282 TMTimerUnlock(pTimer);
3283
3284 /*
3285 * Set up the PCI device.
3286 */
3287 PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
3288 PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
3289
3290 /* See p. 50 of PIIX4 manual */
3291 PCIDevSetCommand(&pThis->dev, 0x01);
3292 PCIDevSetStatus(&pThis->dev, 0x0280);
3293
3294 PCIDevSetRevisionId(&pThis->dev, 0x08);
3295
3296 PCIDevSetClassProg(&pThis->dev, 0x00);
3297 PCIDevSetClassSub(&pThis->dev, 0x80);
3298 PCIDevSetClassBase(&pThis->dev, 0x06);
3299
3300 PCIDevSetHeaderType(&pThis->dev, 0x80);
3301
3302 PCIDevSetBIST(&pThis->dev, 0x00);
3303
3304 PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
3305 PCIDevSetInterruptPin (&pThis->dev, 0x01);
3306
3307 pThis->dev.config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
3308
3309#if 0
3310 int smb_io_base = 0xb100;
3311 dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
3312 dev->config[0x90] = smb_io_base >> 8;
3313#endif
3314
3315 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
3316 if (RT_FAILURE(rc))
3317 return rc;
3318
3319 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
3320 acpiPciConfigRead, &pThis->pfnAcpiPciConfigRead,
3321 acpiPciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
3322
3323 /*
3324 * Register the saved state.
3325 */
3326 rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*pThis), acpiSaveState, acpiLoadState);
3327 if (RT_FAILURE(rc))
3328 return rc;
3329
3330 /*
3331 * Get the corresponding connector interface
3332 */
3333 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
3334 if (RT_SUCCESS(rc))
3335 {
3336 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
3337 if (!pThis->pDrv)
3338 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
3339 N_("LUN #0 doesn't have an ACPI connector interface"));
3340 }
3341 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3342 {
3343 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
3344 pDevIns->pReg->szName, pDevIns->iInstance));
3345 rc = VINF_SUCCESS;
3346 }
3347 else
3348 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
3349
3350 return rc;
3351}
3352
3353/**
3354 * The device registration structure.
3355 */
3356const PDMDEVREG g_DeviceACPI =
3357{
3358 /* u32Version */
3359 PDM_DEVREG_VERSION,
3360 /* szName */
3361 "acpi",
3362 /* szRCMod */
3363 "VBoxDDGC.gc",
3364 /* szR0Mod */
3365 "VBoxDDR0.r0",
3366 /* pszDescription */
3367 "Advanced Configuration and Power Interface",
3368 /* fFlags */
3369 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
3370 /* fClass */
3371 PDM_DEVREG_CLASS_ACPI,
3372 /* cMaxInstances */
3373 ~0U,
3374 /* cbInstance */
3375 sizeof(ACPIState),
3376 /* pfnConstruct */
3377 acpiConstruct,
3378 /* pfnDestruct */
3379 acpiDestruct,
3380 /* pfnRelocate */
3381 acpiRelocate,
3382 /* pfnIOCtl */
3383 NULL,
3384 /* pfnPowerOn */
3385 NULL,
3386 /* pfnReset */
3387 acpiReset,
3388 /* pfnSuspend */
3389 NULL,
3390 /* pfnResume */
3391 acpiResume,
3392 /* pfnAttach */
3393 acpiAttach,
3394 /* pfnDetach */
3395 acpiDetach,
3396 /* pfnQueryInterface. */
3397 NULL,
3398 /* pfnInitComplete */
3399 NULL,
3400 /* pfnPowerOff */
3401 NULL,
3402 /* pfnSoftReset */
3403 NULL,
3404 /* u32VersionEnd */
3405 PDM_DEVREG_VERSION
3406};
3407
3408#endif /* IN_RING3 */
3409#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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