VirtualBox

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

Last change on this file since 37519 was 37519, checked in by vboxsync, 14 years ago

DevACPI: Drop the last seen time workaround as the problem should be addressed in TM now.

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

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