VirtualBox

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

Last change on this file since 60404 was 60404, checked in by vboxsync, 8 years ago

VMM,Devices,Main: Implemented soft/warm reset for shutdown status codes 05h, 09h and 0Ah.

This is a shot at adjusting our VM reset handling to handle the ancient way of
getting a 286 out of protected mode and back to real mode. Our exiting reset
code (XXXR3Reset, PDMDEVREG::pfnReset, and so on) is doing a cold reset of the
system and then some additional device & memory initialization that the firmware
is usually responsible for doing. When the guest triggers a reset via the
keyboard controller, system control port A, CPU triple fault, and possibly ACPI,
only the CPU is supposed to be reset. The BIOS would then decide whether memory
and devices needed resetting as well, or if the resetter justed wanted to get out
protected mode and resume executing some real mode code pointed to by 467h.

  • New states SOFT_RESETTING and SOFT_RESETTING_LS. The latter returns to RUNNING_LS, not SUSPENDED_LS like for hard reset.
  • Added a firmware interface so the VMM/PDM can ask it whether we're supposed to do a hard reset or a soft(/warm) one.
  • Implemented firmware interface for the PC BIOS (but not EFI). It indicates soft(/warm) reset when CMOS[0xf] is 5, 9 or 10.
  • Moved the CMOS[0xf] resetting from the RTC device to the PC BIOS since it's firmware thing, not RTC.
  • Added a flag parameter to PDMDevHlpVMReset for specifying the source of the reset operation. One class of sources (GIM) will always trigger hard resets, whereas the others will check with the firmware first.
  • Added PDMR3GetResetInfo for query the flags passed to PDMDevHlpVMReset and for asking the firmware whether it's a hard or soft reset. The latter, however, is only done if only CPU 0 is active. Systems with more than one CPU in a state other than EMSTATE_WAIT_SIPI status will always be hard reset.
  • Added internal VMR3ResetFF and VMR3ResetTripleFault APIs for handling the VM_FF_RESET and VINF_EM_TRIPLE_FAULT conditions.
  • Added PMDR3ResetSoft and had it call pfnSoftReset (which is now defined).

Warning! Major PDM_DEVHLPR3_VERSION change, minor PDM_DEVREG_VERSION change.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use