VirtualBox

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

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

More parameter warning fixes; made PciIch9 check the saved state version.

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