VirtualBox

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

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

PDMDevHlpVMSuspendSaveAndPowerOff: More code.

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