VirtualBox

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

Last change on this file since 61675 was 61675, checked in by vboxsync, 9 years ago

Devices/ACPI: Notify the guest by sending a battery status change event by calling the GPE bit 0 handler. Also tell the guest to re-evaluate _BST (battery dynamic state) and _PSR (AC adapter status). I don't think that the guest needs to re-evaluate _BIF (battery info) at this time. Thanks Dennis Wassenberg / secunet!

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