VirtualBox

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

最後變更 在這個檔案從32189是 32189,由 vboxsync 提交於 15 年 前

DevACPI/PDMDevHlpVMSuspendSaveAndPowerOff.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 100.3 KB
 
1/* $Id: DevACPI.cpp 32189 2010-09-02 10:10:47Z 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.alldomusa.eu.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 AssertRC(rc);
1067 }
1068 else
1069 {
1070 rc = PDMDevHlpVMSuspend(pThis->pDevIns);
1071 AssertRC(rc);
1072 }
1073 return rc;
1074}
1075
1076/** Converts a ACPI port interface pointer to an ACPI state pointer. */
1077#define IACPIPORT_2_ACPISTATE(pInterface) ( (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IACPIPort)) )
1078
1079/**
1080 * Send an ACPI power off event.
1081 *
1082 * @returns VBox status code
1083 * @param pInterface Pointer to the interface structure containing the called function pointer.
1084 */
1085static DECLCALLBACK(int) acpiPowerButtonPress(PPDMIACPIPORT pInterface)
1086{
1087 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1088 s->fPowerButtonHandled = false;
1089 update_pm1a(s, s->pm1a_sts | PWRBTN_STS, s->pm1a_en);
1090 return VINF_SUCCESS;
1091}
1092
1093/**
1094 * Check if the ACPI power button event was handled.
1095 *
1096 * @returns VBox status code
1097 * @param pInterface Pointer to the interface structure containing the called function pointer.
1098 * @param pfHandled Return true if the power button event was handled by the guest.
1099 */
1100static DECLCALLBACK(int) acpiGetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
1101{
1102 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1103 *pfHandled = s->fPowerButtonHandled;
1104 return VINF_SUCCESS;
1105}
1106
1107/**
1108 * Check if the Guest entered into G0 (working) or G1 (sleeping).
1109 *
1110 * @returns VBox status code
1111 * @param pInterface Pointer to the interface structure containing the called function pointer.
1112 * @param pfEntered Return true if the guest entered the ACPI mode.
1113 */
1114static DECLCALLBACK(int) acpiGetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
1115{
1116 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1117 *pfEntered = (s->pm1a_ctl & SCI_EN) != 0;
1118 return VINF_SUCCESS;
1119}
1120
1121static DECLCALLBACK(int) acpiGetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
1122{
1123 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1124 *pfLocked = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, uCpu);
1125 return VINF_SUCCESS;
1126}
1127
1128/**
1129 * Send an ACPI sleep button event.
1130 *
1131 * @returns VBox status code
1132 * @param pInterface Pointer to the interface structure containing the called function pointer.
1133 */
1134static DECLCALLBACK(int) acpiSleepButtonPress(PPDMIACPIPORT pInterface)
1135{
1136 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1137 update_pm1a(s, s->pm1a_sts | SLPBTN_STS, s->pm1a_en);
1138 return VINF_SUCCESS;
1139}
1140
1141/* PM1a_EVT_BLK enable */
1142static uint32_t acpiPm1aEnReadw(ACPIState *s, uint32_t addr)
1143{
1144 uint16_t val = s->pm1a_en;
1145 Log(("acpi: acpiPm1aEnReadw -> %#x\n", val));
1146 return val;
1147}
1148
1149static void acpiPM1aEnWritew(ACPIState *s, uint32_t addr, uint32_t val)
1150{
1151 Log(("acpi: acpiPM1aEnWritew <- %#x (%#x)\n", val, val & ~(RSR_EN | IGN_EN)));
1152 val &= ~(RSR_EN | IGN_EN);
1153 update_pm1a(s, s->pm1a_sts, val);
1154}
1155
1156/* PM1a_EVT_BLK status */
1157static uint32_t acpiPm1aStsReadw(ACPIState *s, uint32_t addr)
1158{
1159 uint16_t val = s->pm1a_sts;
1160 Log(("acpi: acpiPm1aStsReadw -> %#x\n", val));
1161 return val;
1162}
1163
1164static void acpiPM1aStsWritew(ACPIState *s, uint32_t addr, uint32_t val)
1165{
1166 Log(("acpi: acpiPM1aStsWritew <- %#x (%#x)\n", val, val & ~(RSR_STS | IGN_STS)));
1167 if (val & PWRBTN_STS)
1168 s->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
1169 val = s->pm1a_sts & ~(val & ~(RSR_STS | IGN_STS));
1170 update_pm1a(s, val, s->pm1a_en);
1171}
1172
1173/* PM1a_CTL_BLK */
1174static uint32_t acpiPm1aCtlReadw(ACPIState *s, uint32_t addr)
1175{
1176 uint16_t val = s->pm1a_ctl;
1177 Log(("acpi: acpiPm1aCtlReadw -> %#x\n", val));
1178 return val;
1179}
1180
1181static int acpiPM1aCtlWritew(ACPIState *s, uint32_t addr, uint32_t val)
1182{
1183 uint32_t uSleepState;
1184
1185 Log(("acpi: acpiPM1aCtlWritew <- %#x (%#x)\n", val, val & ~(RSR_CNT | IGN_CNT)));
1186 s->pm1a_ctl = val & ~(RSR_CNT | IGN_CNT);
1187
1188 uSleepState = (s->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
1189 if (uSleepState != s->uSleepState)
1190 {
1191 s->uSleepState = uSleepState;
1192 switch (uSleepState)
1193 {
1194 case 0x00: /* S0 */
1195 break;
1196 case 0x01: /* S1 */
1197 LogRel(("Entering S1 power state (powered-on suspend)\n"));
1198 return acpiSleep(s);
1199 case 0x04: /* S4 */
1200 LogRel(("Entering S4 power state (suspend to disk)\n"));
1201 return acpiPowerDown(s);/* Same behavior as S5 */
1202 case 0x05: /* S5 */
1203 LogRel(("Entering S5 power state (power down)\n"));
1204 return acpiPowerDown(s);
1205 default:
1206 AssertMsgFailed(("Unknown sleep state %#x\n", uSleepState));
1207 break;
1208 }
1209 }
1210 return VINF_SUCCESS;
1211}
1212
1213/* GPE0_BLK */
1214static uint32_t acpiGpe0EnReadb(ACPIState *s, uint32_t addr)
1215{
1216 uint8_t val = s->gpe0_en;
1217 Log(("acpi: acpiGpe0EnReadl -> %#x\n", val));
1218 return val;
1219}
1220
1221static void acpiGpe0EnWriteb(ACPIState *s, uint32_t addr, uint32_t val)
1222{
1223 Log(("acpi: acpiGpe0EnWritel <- %#x\n", val));
1224 update_gpe0(s, s->gpe0_sts, val);
1225}
1226
1227static uint32_t acpiGpe0StsReadb(ACPIState *s, uint32_t addr)
1228{
1229 uint8_t val = s->gpe0_sts;
1230 Log(("acpi: acpiGpe0StsReadl -> %#x\n", val));
1231 return val;
1232}
1233
1234static void acpiGpe0StsWriteb(ACPIState *s, uint32_t addr, uint32_t val)
1235{
1236 val = s->gpe0_sts & ~val;
1237 update_gpe0(s, val, s->gpe0_en);
1238 Log(("acpi: acpiGpe0StsWritel <- %#x\n", val));
1239}
1240
1241static int acpiResetWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1242{
1243 int rc = VINF_SUCCESS;
1244
1245 Log(("ACPI: acpiResetWriteU8: %x %x\n", addr, val));
1246 if (val == ACPI_RESET_REG_VAL)
1247 {
1248# ifndef IN_RING3
1249 rc = VINF_IOM_HC_IOPORT_WRITE;
1250# else /* IN_RING3 */
1251 rc = PDMDevHlpVMReset(s->pDevIns);
1252# endif /* !IN_RING3 */
1253 }
1254 return rc;
1255}
1256
1257/* SMI */
1258static void acpiSmiWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1259{
1260 Log(("acpi: acpiSmiWriteU8 %#x\n", val));
1261 if (val == ACPI_ENABLE)
1262 s->pm1a_ctl |= SCI_EN;
1263 else if (val == ACPI_DISABLE)
1264 s->pm1a_ctl &= ~SCI_EN;
1265 else
1266 Log(("acpi: acpiSmiWriteU8 %#x <- unknown value\n", val));
1267}
1268
1269static uint32_t find_rsdp_space(void)
1270{
1271 return 0xe0000;
1272}
1273
1274static int acpiPMTimerReset(ACPIState *s)
1275{
1276 uint64_t interval, freq;
1277
1278 freq = TMTimerGetFreq(s->CTX_SUFF(ts));
1279 interval = ASMMultU64ByU32DivByU32(0xffffffff, freq, PM_TMR_FREQ);
1280 Log(("interval = %RU64\n", interval));
1281 TMTimerSet(s->CTX_SUFF(ts), TMTimerGet(s->CTX_SUFF(ts)) + interval);
1282
1283 return VINF_SUCCESS;
1284}
1285
1286static DECLCALLBACK(void) acpiTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1287{
1288 ACPIState *s = (ACPIState *)pvUser;
1289
1290 Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
1291 s->pm1a_sts, (s->pm1a_sts & TMR_STS) != 0,
1292 s->pm1a_en, (s->pm1a_en & TMR_EN) != 0));
1293
1294 update_pm1a(s, s->pm1a_sts | TMR_STS, s->pm1a_en);
1295 acpiPMTimerReset(s);
1296}
1297
1298/**
1299 * _BST method.
1300 */
1301static int acpiFetchBatteryStatus(ACPIState *s)
1302{
1303 uint32_t *p = s->au8BatteryInfo;
1304 bool fPresent; /* battery present? */
1305 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1306 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1307 uint32_t hostPresentRate; /* 0..1000 */
1308 int rc;
1309
1310 if (!s->pDrv)
1311 return VINF_SUCCESS;
1312 rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
1313 &hostBatteryState, &hostPresentRate);
1314 AssertRC(rc);
1315
1316 /* default values */
1317 p[BAT_STATUS_STATE] = hostBatteryState;
1318 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
1319 : hostPresentRate * 50; /* mW */
1320 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
1321 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
1322
1323 /* did we get a valid battery state? */
1324 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
1325 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
1326 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
1327 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
1328
1329 return VINF_SUCCESS;
1330}
1331
1332/**
1333 * _BIF method.
1334 */
1335static int acpiFetchBatteryInfo(ACPIState *s)
1336{
1337 uint32_t *p = s->au8BatteryInfo;
1338
1339 p[BAT_INFO_UNITS] = 0; /* mWh */
1340 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
1341 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
1342 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
1343 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
1344 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
1345 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
1346 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
1347 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
1348
1349 return VINF_SUCCESS;
1350}
1351
1352/**
1353 * _STA method.
1354 */
1355static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
1356{
1357 bool fPresent; /* battery present? */
1358 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1359 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1360 uint32_t hostPresentRate; /* 0..1000 */
1361 int rc;
1362
1363 if (!s->pDrv)
1364 return 0;
1365 rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
1366 &hostBatteryState, &hostPresentRate);
1367 AssertRC(rc);
1368
1369 return fPresent
1370 ? STA_DEVICE_PRESENT_MASK /* present */
1371 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1372 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1373 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1374 | STA_BATTERY_PRESENT_MASK /* battery is present */
1375 : 0; /* device not present */
1376}
1377
1378static uint32_t acpiGetPowerSource(ACPIState *s)
1379{
1380 PDMACPIPOWERSOURCE ps;
1381
1382 /* query the current power source from the host driver */
1383 if (!s->pDrv)
1384 return AC_ONLINE;
1385 int rc = s->pDrv->pfnQueryPowerSource(s->pDrv, &ps);
1386 AssertRC(rc);
1387 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1388}
1389
1390PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1391{
1392 ACPIState *s = (ACPIState *)pvUser;
1393
1394 switch (cb)
1395 {
1396 case 4:
1397 u32 >>= s->u8IndexShift;
1398 /* see comment at the declaration of u8IndexShift */
1399 if (s->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
1400 {
1401 s->u8IndexShift = 2;
1402 u32 >>= 2;
1403 }
1404 Assert(u32 < BAT_INDEX_LAST);
1405 s->uBatteryIndex = u32;
1406 break;
1407 default:
1408 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1409 break;
1410 }
1411 return VINF_SUCCESS;
1412}
1413
1414PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1415{
1416 ACPIState *s = (ACPIState *)pvUser;
1417
1418 switch (cb)
1419 {
1420 case 4:
1421 switch (s->uBatteryIndex)
1422 {
1423 case BAT_STATUS_STATE:
1424 acpiFetchBatteryStatus(s);
1425 case BAT_STATUS_PRESENT_RATE:
1426 case BAT_STATUS_REMAINING_CAPACITY:
1427 case BAT_STATUS_PRESENT_VOLTAGE:
1428 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1429 break;
1430
1431 case BAT_INFO_UNITS:
1432 acpiFetchBatteryInfo(s);
1433 case BAT_INFO_DESIGN_CAPACITY:
1434 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1435 case BAT_INFO_TECHNOLOGY:
1436 case BAT_INFO_DESIGN_VOLTAGE:
1437 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1438 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1439 case BAT_INFO_CAPACITY_GRANULARITY_1:
1440 case BAT_INFO_CAPACITY_GRANULARITY_2:
1441 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1442 break;
1443
1444 case BAT_DEVICE_STATUS:
1445 *pu32 = acpiGetBatteryDeviceStatus(s);
1446 break;
1447
1448 case BAT_POWER_SOURCE:
1449 *pu32 = acpiGetPowerSource(s);
1450 break;
1451
1452 default:
1453 AssertMsgFailed(("Invalid battery index %d\n", s->uBatteryIndex));
1454 break;
1455 }
1456 break;
1457 default:
1458 return VERR_IOM_IOPORT_UNUSED;
1459 }
1460 return VINF_SUCCESS;
1461}
1462
1463PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1464{
1465 ACPIState *s = (ACPIState *)pvUser;
1466
1467 Log(("system_index = %d, %d\n", u32, u32 >> 2));
1468 switch (cb)
1469 {
1470 case 4:
1471 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1472 s->uSystemInfoIndex = u32;
1473 else
1474 {
1475 /* see comment at the declaration of u8IndexShift */
1476 if (s->u8IndexShift == 0)
1477 {
1478 if (((u32 >> 2) < SYSTEM_INFO_INDEX_END) && ((u32 & 0x3)) == 0)
1479 {
1480 s->u8IndexShift = 2;
1481 }
1482 }
1483
1484 u32 >>= s->u8IndexShift;
1485 Assert(u32 < SYSTEM_INFO_INDEX_END);
1486 s->uSystemInfoIndex = u32;
1487 }
1488 break;
1489
1490 default:
1491 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1492 break;
1493 }
1494 return VINF_SUCCESS;
1495}
1496
1497PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1498{
1499 ACPIState *s = (ACPIState *)pvUser;
1500
1501 switch (cb)
1502 {
1503 case 4:
1504 switch (s->uSystemInfoIndex)
1505 {
1506 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
1507 *pu32 = s->cbRamLow;
1508 break;
1509
1510 case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
1511 *pu32 = s->cbRamHigh >> 16; /* 64KB units */
1512 Assert(((uint64_t)*pu32 << 16) == s->cbRamHigh);
1513 break;
1514
1515 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1516 *pu32 = s->u8UseIOApic;
1517 break;
1518
1519 case SYSTEM_INFO_INDEX_HPET_STATUS:
1520 *pu32 = s->fUseHpet ? ( STA_DEVICE_PRESENT_MASK
1521 | STA_DEVICE_ENABLED_MASK
1522 | STA_DEVICE_SHOW_IN_UI_MASK
1523 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1524 : 0;
1525 break;
1526
1527 case SYSTEM_INFO_INDEX_SMC_STATUS:
1528 *pu32 = s->fUseSmc ? ( STA_DEVICE_PRESENT_MASK
1529 | STA_DEVICE_ENABLED_MASK
1530 /* no need to show this device in the UI */
1531 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1532 : 0;
1533 break;
1534
1535 case SYSTEM_INFO_INDEX_FDC_STATUS:
1536 *pu32 = s->fUseFdc ? ( STA_DEVICE_PRESENT_MASK
1537 | STA_DEVICE_ENABLED_MASK
1538 | STA_DEVICE_SHOW_IN_UI_MASK
1539 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1540 : 0;
1541 break;
1542
1543 case SYSTEM_INFO_INDEX_NIC_ADDRESS:
1544 *pu32 = s->u32NicPciAddress;
1545 break;
1546
1547 case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
1548 *pu32 = s->u32AudioPciAddress;
1549 break;
1550
1551 case SYSTEM_INFO_INDEX_POWER_STATES:
1552 *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
1553 if (s->fS1Enabled) /* Optionally expose S1 and S4 */
1554 *pu32 |= RT_BIT(1);
1555 if (s->fS4Enabled)
1556 *pu32 |= RT_BIT(4);
1557 break;
1558
1559 /* This is only for compatability with older saved states that
1560 may include ACPI code that read these values. Legacy is
1561 a wonderful thing, isn't it? :-) */
1562 case SYSTEM_INFO_INDEX_CPU0_STATUS:
1563 case SYSTEM_INFO_INDEX_CPU1_STATUS:
1564 case SYSTEM_INFO_INDEX_CPU2_STATUS:
1565 case SYSTEM_INFO_INDEX_CPU3_STATUS:
1566 *pu32 = ( s->fShowCpu
1567 && s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < s->cCpus
1568 && VMCPUSET_IS_PRESENT(&s->CpuSetAttached,
1569 s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS))
1570 ? ( STA_DEVICE_PRESENT_MASK
1571 | STA_DEVICE_ENABLED_MASK
1572 | STA_DEVICE_SHOW_IN_UI_MASK
1573 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1574 : 0;
1575 break;
1576
1577 case SYSTEM_INFO_INDEX_RTC_STATUS:
1578 *pu32 = s->fShowRtc ? ( STA_DEVICE_PRESENT_MASK
1579 | STA_DEVICE_ENABLED_MASK
1580 | STA_DEVICE_SHOW_IN_UI_MASK
1581 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1582 : 0;
1583 break;
1584
1585 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1586 {
1587 if (s->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1588 {
1589 *pu32 = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, s->idCpuLockCheck);
1590 s->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1591 }
1592 else
1593 {
1594 AssertMsgFailed(("ACPI: CPU lock check protocol violation\n"));
1595 /* Always return locked status just to be safe */
1596 *pu32 = 1;
1597 }
1598 break;
1599 }
1600
1601 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1602 *pu32 = s->u32CpuEventType;
1603 break;
1604
1605 case SYSTEM_INFO_INDEX_CPU_EVENT:
1606 *pu32 = s->u32CpuEvent;
1607 break;
1608
1609 /* Solaris 9 tries to read from this index */
1610 case SYSTEM_INFO_INDEX_INVALID:
1611 *pu32 = 0;
1612 break;
1613
1614 default:
1615 AssertMsgFailed(("Invalid system info index %d\n", s->uSystemInfoIndex));
1616 break;
1617 }
1618 break;
1619
1620 default:
1621 return VERR_IOM_IOPORT_UNUSED;
1622 }
1623
1624 Log(("index %d val %d\n", s->uSystemInfoIndex, *pu32));
1625 return VINF_SUCCESS;
1626}
1627
1628PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1629{
1630 ACPIState *s = (ACPIState *)pvUser;
1631
1632 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, s->uSystemInfoIndex));
1633
1634 if (cb == 4)
1635 {
1636 switch (s->uSystemInfoIndex)
1637 {
1638 case SYSTEM_INFO_INDEX_INVALID:
1639 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1640 s->u8IndexShift = 0;
1641 break;
1642
1643 case SYSTEM_INFO_INDEX_VALID:
1644 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1645 s->u8IndexShift = 2;
1646 break;
1647
1648 case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
1649 s->idCpuLockCheck = u32;
1650 break;
1651
1652 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1653 if (u32 < s->cCpus)
1654 VMCPUSET_DEL(&s->CpuSetLocked, u32); /* Unlock the CPU */
1655 else
1656 LogRel(("ACPI: CPU %u does not exist\n", u32));
1657 break;
1658
1659 default:
1660 AssertMsgFailed(("Port=%#x cb=%d u32=%#x system_index=%#x\n",
1661 Port, cb, u32, s->uSystemInfoIndex));
1662 break;
1663 }
1664 }
1665 else
1666 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1667 return VINF_SUCCESS;
1668}
1669
1670/** @todo Don't call functions, but do the job in the read/write handlers
1671 * here! */
1672
1673/* IO Helpers */
1674PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1675{
1676 switch (cb)
1677 {
1678 case 2:
1679 *pu32 = acpiPm1aEnReadw((ACPIState*)pvUser, Port);
1680 break;
1681 default:
1682 return VERR_IOM_IOPORT_UNUSED;
1683 }
1684 return VINF_SUCCESS;
1685}
1686
1687PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1688{
1689 switch (cb)
1690 {
1691 case 2:
1692 *pu32 = acpiPm1aStsReadw((ACPIState*)pvUser, Port);
1693 break;
1694 default:
1695 return VERR_IOM_IOPORT_UNUSED;
1696 }
1697 return VINF_SUCCESS;
1698}
1699
1700PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1701{
1702 switch (cb)
1703 {
1704 case 2:
1705 *pu32 = acpiPm1aCtlReadw((ACPIState*)pvUser, Port);
1706 break;
1707 default:
1708 return VERR_IOM_IOPORT_UNUSED;
1709 }
1710 return VINF_SUCCESS;
1711}
1712
1713PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1714{
1715 switch (cb)
1716 {
1717 case 2:
1718 acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32);
1719 break;
1720 case 4:
1721 acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1722 break;
1723 default:
1724 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1725 break;
1726 }
1727 return VINF_SUCCESS;
1728}
1729
1730PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1731{
1732 switch (cb)
1733 {
1734 case 2:
1735 acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32);
1736 break;
1737 case 4:
1738 acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1739 break;
1740 default:
1741 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1742 break;
1743 }
1744 return VINF_SUCCESS;
1745}
1746
1747PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1748{
1749 switch (cb)
1750 {
1751 case 2:
1752 return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32);
1753 case 4:
1754 return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1755 default:
1756 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1757 break;
1758 }
1759 return VINF_SUCCESS;
1760}
1761
1762#endif /* IN_RING3 */
1763
1764/**
1765 * PMTMR readable from host/guest.
1766 */
1767PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1768{
1769 if (cb == 4)
1770 {
1771 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
1772 int64_t now = TMTimerGet(s->CTX_SUFF(ts));
1773 int64_t elapsed = now - s->pm_timer_initial;
1774
1775 *pu32 = ASMMultU64ByU32DivByU32(elapsed, PM_TMR_FREQ, TMTimerGetFreq(s->CTX_SUFF(ts)));
1776 Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
1777 return VINF_SUCCESS;
1778 }
1779 return VERR_IOM_IOPORT_UNUSED;
1780}
1781
1782#ifdef IN_RING3
1783
1784PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1785{
1786 switch (cb)
1787 {
1788 case 1:
1789 *pu32 = acpiGpe0StsReadb((ACPIState*)pvUser, Port);
1790 break;
1791 default:
1792 return VERR_IOM_IOPORT_UNUSED;
1793 }
1794 return VINF_SUCCESS;
1795}
1796
1797PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1798{
1799 switch (cb)
1800 {
1801 case 1:
1802 *pu32 = acpiGpe0EnReadb((ACPIState*)pvUser, Port);
1803 break;
1804 default:
1805 return VERR_IOM_IOPORT_UNUSED;
1806 }
1807 return VINF_SUCCESS;
1808}
1809
1810PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1811{
1812 switch (cb)
1813 {
1814 case 1:
1815 acpiGpe0StsWriteb((ACPIState*)pvUser, Port, u32);
1816 break;
1817 default:
1818 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1819 break;
1820 }
1821 return VINF_SUCCESS;
1822}
1823
1824PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1825{
1826 switch (cb)
1827 {
1828 case 1:
1829 acpiGpe0EnWriteb((ACPIState*)pvUser, Port, u32);
1830 break;
1831 default:
1832 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1833 break;
1834 }
1835 return VINF_SUCCESS;
1836}
1837
1838PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1839{
1840 switch (cb)
1841 {
1842 case 1:
1843 acpiSmiWriteU8((ACPIState*)pvUser, Port, u32);
1844 break;
1845 default:
1846 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1847 break;
1848 }
1849 return VINF_SUCCESS;
1850}
1851
1852PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1853{
1854 switch (cb)
1855 {
1856 case 1:
1857 return acpiResetWriteU8((ACPIState*)pvUser, Port, u32);
1858 default:
1859 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1860 break;
1861 }
1862 return VINF_SUCCESS;
1863}
1864
1865#ifdef DEBUG_ACPI
1866
1867PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1868{
1869 switch (cb)
1870 {
1871 case 1:
1872 Log(("%#x\n", u32 & 0xff));
1873 break;
1874 case 2:
1875 Log(("%#6x\n", u32 & 0xffff));
1876 case 4:
1877 Log(("%#10x\n", u32));
1878 break;
1879 default:
1880 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1881 break;
1882 }
1883 return VINF_SUCCESS;
1884}
1885
1886PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1887{
1888 switch (cb)
1889 {
1890 case 1:
1891 Log(("%c", u32 & 0xff));
1892 break;
1893 default:
1894 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1895 break;
1896 }
1897 return VINF_SUCCESS;
1898}
1899
1900#endif /* DEBUG_ACPI */
1901
1902static int acpiRegisterPmHandlers(ACPIState* pThis)
1903{
1904 int rc = VINF_SUCCESS;
1905
1906#define R(offset, cnt, writer, reader, description) \
1907 do { \
1908 rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt, pThis, writer, reader, \
1909 NULL, NULL, description); \
1910 if (RT_FAILURE(rc)) \
1911 return rc; \
1912 } while (0)
1913#define L (GPE0_BLK_LEN / 2)
1914
1915 R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
1916 R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
1917 R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
1918 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
1919 R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
1920 R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
1921#undef L
1922#undef R
1923
1924 /* register RC stuff */
1925 if (pThis->fGCEnabled)
1926 {
1927 rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
1928 1, 0, NULL, "acpiPMTmrRead",
1929 NULL, NULL, "ACPI PM Timer");
1930 AssertRCReturn(rc, rc);
1931 }
1932
1933 /* register R0 stuff */
1934 if (pThis->fR0Enabled)
1935 {
1936 rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
1937 1, 0, NULL, "acpiPMTmrRead",
1938 NULL, NULL, "ACPI PM Timer");
1939 AssertRCReturn(rc, rc);
1940 }
1941
1942 return rc;
1943}
1944
1945static int acpiUnregisterPmHandlers(ACPIState *pThis)
1946{
1947#define U(offset, cnt) \
1948 do { \
1949 int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt); \
1950 AssertRCReturn(rc, rc); \
1951 } while (0)
1952#define L (GPE0_BLK_LEN / 2)
1953
1954 U(PM1a_EVT_OFFSET+2, 1);
1955 U(PM1a_EVT_OFFSET, 1);
1956 U(PM1a_CTL_OFFSET, 1);
1957 U(PM_TMR_OFFSET, 1);
1958 U(GPE0_OFFSET + L, L);
1959 U(GPE0_OFFSET, L);
1960#undef L
1961#undef U
1962
1963 return VINF_SUCCESS;
1964}
1965
1966/**
1967 * Saved state structure description, version 4.
1968 */
1969static const SSMFIELD g_AcpiSavedStateFields4[] =
1970{
1971 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1972 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1973 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1974 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
1975 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1976 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1977 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1978 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1979 SSMFIELD_ENTRY(ACPIState, u64RamSize),
1980 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1981 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
1982 SSMFIELD_ENTRY(ACPIState, uSleepState),
1983 SSMFIELD_ENTRY_TERM()
1984};
1985
1986/**
1987 * Saved state structure description, version 5.
1988 */
1989static const SSMFIELD g_AcpiSavedStateFields5[] =
1990{
1991 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1992 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1993 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1994 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
1995 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1996 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1997 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1998 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1999 SSMFIELD_ENTRY(ACPIState, uSleepState),
2000 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2001 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2002 SSMFIELD_ENTRY_TERM()
2003};
2004
2005/**
2006 * Saved state structure description, version 6.
2007 */
2008static const SSMFIELD g_AcpiSavedStateFields6[] =
2009{
2010 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2011 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2012 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2013 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
2014 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2015 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2016 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2017 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2018 SSMFIELD_ENTRY(ACPIState, uSleepState),
2019 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2020 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2021 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
2022 SSMFIELD_ENTRY_TERM()
2023};
2024
2025
2026/**
2027 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2028 */
2029static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2030{
2031 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2032 return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2033}
2034
2035/**
2036 * @callback_method_impl{FNSSMDEVLOADEXEC}
2037 */
2038static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
2039 uint32_t uVersion, uint32_t uPass)
2040{
2041 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2042 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2043
2044 /*
2045 * Unregister PM handlers, will register with actual base after state
2046 * successfully loaded.
2047 */
2048 int rc = acpiUnregisterPmHandlers(pThis);
2049 if (RT_FAILURE(rc))
2050 return rc;
2051
2052 switch (uVersion)
2053 {
2054 case 4:
2055 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
2056 break;
2057 case 5:
2058 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
2059 break;
2060 case 6:
2061 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2062 break;
2063 default:
2064 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2065 break;
2066 }
2067 if (RT_SUCCESS(rc))
2068 {
2069 rc = acpiRegisterPmHandlers(pThis);
2070 if (RT_FAILURE(rc))
2071 return rc;
2072 rc = acpiFetchBatteryStatus(pThis);
2073 if (RT_FAILURE(rc))
2074 return rc;
2075 rc = acpiFetchBatteryInfo(pThis);
2076 if (RT_FAILURE(rc))
2077 return rc;
2078 rc = acpiPMTimerReset(pThis);
2079 if (RT_FAILURE(rc))
2080 return rc;
2081 }
2082 return rc;
2083}
2084
2085/**
2086 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2087 */
2088static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2089{
2090 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
2091 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2092 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
2093 return NULL;
2094}
2095
2096/**
2097 * Create the ACPI tables.
2098 */
2099static int acpiPlantTables(ACPIState *s)
2100{
2101 int rc;
2102 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
2103 RTGCPHYS32 GCPhysHpet = 0, GCPhysApic = 0, GCPhysSsdt = 0;
2104 uint32_t addend = 0;
2105 RTGCPHYS32 aGCPhysRsdt[4];
2106 RTGCPHYS32 aGCPhysXsdt[4];
2107 uint32_t cAddr, iMadt = 0, iHpet = 0, iSsdt = 0;
2108 size_t cbRsdt = sizeof(ACPITBLHEADER);
2109 size_t cbXsdt = sizeof(ACPITBLHEADER);
2110
2111 cAddr = 1; /* FADT */
2112 if (s->u8UseIOApic)
2113 iMadt = cAddr++; /* MADT */
2114
2115 if (s->fUseHpet)
2116 iHpet = cAddr++; /* HPET */
2117
2118 iSsdt = cAddr++; /* SSDT */
2119
2120 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
2121 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
2122
2123 rc = CFGMR3QueryU64(s->pDevIns->pCfg, "RamSize", &s->u64RamSize);
2124 if (RT_FAILURE(rc))
2125 return PDMDEV_SET_ERROR(s->pDevIns, rc,
2126 N_("Configuration error: Querying \"RamSize\" as integer failed"));
2127
2128 uint32_t cbRamHole;
2129 rc = CFGMR3QueryU32Def(s->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
2130 if (RT_FAILURE(rc))
2131 return PDMDEV_SET_ERROR(s->pDevIns, rc,
2132 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
2133
2134 /*
2135 * Calculate the sizes for the high and low regions.
2136 */
2137 const uint64_t offRamHole = _4G - cbRamHole;
2138 s->cbRamHigh = offRamHole < s->u64RamSize ? s->u64RamSize - offRamHole : 0;
2139 uint64_t cbRamLow = offRamHole < s->u64RamSize ? offRamHole : s->u64RamSize;
2140 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
2141 {
2142 /* Note: This is also enforced by DevPcBios.cpp. */
2143 LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
2144 cbRamLow = UINT32_C(0xffe00000);
2145 }
2146 s->cbRamLow = (uint32_t)cbRamLow;
2147
2148 GCPhysCur = 0;
2149 GCPhysRsdt = GCPhysCur;
2150
2151 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
2152 GCPhysXsdt = GCPhysCur;
2153
2154 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
2155 GCPhysFadtAcpi1 = GCPhysCur;
2156
2157 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
2158 GCPhysFadtAcpi2 = GCPhysCur;
2159
2160 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
2161 GCPhysFacs = GCPhysCur;
2162
2163 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
2164 if (s->u8UseIOApic)
2165 {
2166 GCPhysApic = GCPhysCur;
2167 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(s, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
2168 }
2169 if (s->fUseHpet)
2170 {
2171 GCPhysHpet = GCPhysCur;
2172 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
2173 }
2174
2175 void* pSsdtCode = NULL;
2176 size_t cbSsdtSize = 0;
2177 rc = acpiPrepareSsdt(s->pDevIns, &pSsdtCode, &cbSsdtSize);
2178 if (RT_FAILURE(rc))
2179 return rc;
2180
2181 GCPhysSsdt = GCPhysCur;
2182 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdtSize, 16);
2183
2184 GCPhysDsdt = GCPhysCur;
2185
2186 void* pDsdtCode = NULL;
2187 size_t cbDsdtSize = 0;
2188 rc = acpiPrepareDsdt(s->pDevIns, &pDsdtCode, &cbDsdtSize);
2189 if (RT_FAILURE(rc))
2190 return rc;
2191
2192 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
2193
2194 if (GCPhysCur > 0x10000)
2195 return PDMDEV_SET_ERROR(s->pDevIns, VERR_TOO_MUCH_DATA,
2196 N_("Error: ACPI tables bigger than 64KB"));
2197
2198 Log(("RSDP 0x%08X\n", find_rsdp_space()));
2199 addend = s->cbRamLow - 0x10000;
2200 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
2201 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
2202 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
2203 if (s->u8UseIOApic)
2204 Log((" MADT 0x%08X", GCPhysApic + addend));
2205 if (s->fUseHpet)
2206 Log((" HPET 0x%08X", GCPhysHpet + addend));
2207 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
2208 Log(("\n"));
2209
2210 acpiSetupRSDP((ACPITBLRSDP*)s->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
2211 acpiSetupDSDT(s, GCPhysDsdt + addend, pDsdtCode, cbDsdtSize);
2212 acpiCleanupDsdt(s->pDevIns, pDsdtCode);
2213 acpiSetupFACS(s, GCPhysFacs + addend);
2214 acpiSetupFADT(s, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
2215
2216 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
2217 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
2218 if (s->u8UseIOApic)
2219 {
2220 acpiSetupMADT(s, GCPhysApic + addend);
2221 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
2222 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
2223 }
2224 if (s->fUseHpet)
2225 {
2226 acpiSetupHPET(s, GCPhysHpet + addend);
2227 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
2228 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
2229 }
2230 acpiSetupSSDT(s, GCPhysSsdt + addend, pSsdtCode, cbSsdtSize);
2231 acpiCleanupSsdt(s->pDevIns, pSsdtCode);
2232 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
2233 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
2234
2235 rc = acpiSetupRSDT(s, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
2236 if (RT_FAILURE(rc))
2237 return rc;
2238 return acpiSetupXSDT(s, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
2239}
2240
2241static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT uNewBase)
2242{
2243 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, uNewBase));
2244 if (uNewBase != pThis->uPmIoPortBase)
2245 {
2246 int rc;
2247
2248 rc = acpiUnregisterPmHandlers(pThis);
2249 if (RT_FAILURE(rc))
2250 return rc;
2251
2252 pThis->uPmIoPortBase = uNewBase;
2253
2254 rc = acpiRegisterPmHandlers(pThis);
2255 if (RT_FAILURE(rc))
2256 return rc;
2257
2258 /* We have to update FADT table acccording to the new base */
2259 rc = acpiPlantTables(pThis);
2260 AssertRC(rc);
2261 if (RT_FAILURE(rc))
2262 return rc;
2263 }
2264
2265 return VINF_SUCCESS;
2266}
2267
2268static uint32_t acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
2269{
2270 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2271 ACPIState* pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2272
2273 Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
2274
2275 return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
2276}
2277
2278static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
2279{
2280 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2281 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2282
2283 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
2284 pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
2285
2286 /* PMREGMISC written */
2287 if (Address == 0x80)
2288 {
2289 /* Check Power Management IO Space Enable (PMIOSE) bit */
2290 if (pPciDev->config[0x80] & 0x1)
2291 {
2292 int rc;
2293
2294 RTIOPORT uNewBase =
2295 RTIOPORT(RT_LE2H_U32(*(uint32_t*)&pPciDev->config[0x40]));
2296 uNewBase &= 0xffc0;
2297
2298 rc = acpiUpdatePmHandlers(pThis, uNewBase);
2299 AssertRC(rc);
2300 }
2301 }
2302}
2303
2304/**
2305 * Attach a new CPU.
2306 *
2307 * @returns VBox status code.
2308 * @param pDevIns The device instance.
2309 * @param iLUN The logical unit which is being attached.
2310 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2311 *
2312 * @remarks This code path is not used during construction.
2313 */
2314static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2315{
2316 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2317
2318 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2319
2320 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2321 ("Hot-plug flag is not set\n"),
2322 VERR_NOT_SUPPORTED);
2323 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
2324
2325 /* Check if it was already attached */
2326 if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
2327 return VINF_SUCCESS;
2328
2329 PPDMIBASE IBaseTmp;
2330 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &s->IBase, &IBaseTmp, "ACPI CPU");
2331
2332 if (RT_SUCCESS(rc))
2333 {
2334 /* Enable the CPU */
2335 VMCPUSET_ADD(&s->CpuSetAttached, iLUN);
2336
2337 /*
2338 * Lock the CPU because we don't know if the guest will use it or not.
2339 * Prevents ejection while the CPU is still used
2340 */
2341 VMCPUSET_ADD(&s->CpuSetLocked, iLUN);
2342 s->u32CpuEventType = CPU_EVENT_TYPE_ADD;
2343 s->u32CpuEvent = iLUN;
2344 /* Notify the guest */
2345 update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
2346 }
2347 return rc;
2348}
2349
2350/**
2351 * Detach notification.
2352 *
2353 * @param pDevIns The device instance.
2354 * @param iLUN The logical unit which is being detached.
2355 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2356 */
2357static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2358{
2359 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2360
2361 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2362
2363 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2364 ("Hot-plug flag is not set\n"));
2365
2366 /* Check if it was already detached */
2367 if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
2368 {
2369 AssertMsgReturnVoid(!(VMCPUSET_IS_PRESENT(&s->CpuSetLocked, iLUN)), ("CPU is still locked by the guest\n"));
2370
2371 /* Disable the CPU */
2372 VMCPUSET_DEL(&s->CpuSetAttached, iLUN);
2373 s->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
2374 s->u32CpuEvent = iLUN;
2375 /* Notify the guest */
2376 update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
2377 }
2378}
2379
2380/**
2381 * @interface_method_impl{PDMDEVREG,pfnResume}
2382 */
2383static DECLCALLBACK(void) acpiResume(PPDMDEVINS pDevIns)
2384{
2385 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2386 if (pThis->fSetWakeupOnResume)
2387 {
2388 Log(("acpiResume: setting WAK_STS\n"));
2389 pThis->fSetWakeupOnResume = false;
2390 pThis->pm1a_sts |= WAK_STS;
2391 }
2392}
2393
2394/**
2395 * @interface_method_impl{PDMDEVREG,pfnReset}
2396 */
2397static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
2398{
2399 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2400
2401 s->pm1a_en = 0;
2402 s->pm1a_sts = 0;
2403 s->pm1a_ctl = 0;
2404 s->pm_timer_initial = TMTimerGet(s->CTX_SUFF(ts));
2405 acpiPMTimerReset(s);
2406 s->uBatteryIndex = 0;
2407 s->uSystemInfoIndex = 0;
2408 s->gpe0_en = 0;
2409 s->gpe0_sts = 0;
2410 s->uSleepState = 0;
2411
2412 /** @todo Should we really reset PM base? */
2413 acpiUpdatePmHandlers(s, PM_PORT_BASE);
2414
2415 acpiPlantTables(s);
2416}
2417
2418/**
2419 * @interface_method_impl{PDMDEVREG,pfnRelocate}
2420 */
2421static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2422{
2423 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2424 s->tsRC = TMTimerRCPtr(s->CTX_SUFF(ts));
2425}
2426
2427/**
2428 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2429 */
2430static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2431{
2432 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2433 PCIDevice *dev = &s->dev;
2434 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2435
2436 /* Validate and read the configuration. */
2437 if (!CFGMR3AreValuesValid(pCfg,
2438 "RamSize\0"
2439 "RamHoleSize\0"
2440 "IOAPIC\0"
2441 "NumCPUs\0"
2442 "GCEnabled\0"
2443 "R0Enabled\0"
2444 "HpetEnabled\0"
2445 "SmcEnabled\0"
2446 "FdcEnabled\0"
2447 "ShowRtc\0"
2448 "ShowCpu\0"
2449 "NicPciAddress\0"
2450 "AudioPciAddress\0"
2451 "EnableSuspendToDisk\0"
2452 "PowerS1Enabled\0"
2453 "PowerS4Enabled\0"
2454 "CpuHotPlug\0"
2455 "AmlFilePath\0"
2456 ))
2457 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2458 N_("Configuration error: Invalid config key for ACPI device"));
2459
2460 s->pDevIns = pDevIns;
2461
2462 /* query whether we are supposed to present an IOAPIC */
2463 int rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &s->u8UseIOApic, 1);
2464 if (RT_FAILURE(rc))
2465 return PDMDEV_SET_ERROR(pDevIns, rc,
2466 N_("Configuration error: Failed to read \"IOAPIC\""));
2467
2468 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &s->cCpus, 1);
2469 if (RT_FAILURE(rc))
2470 return PDMDEV_SET_ERROR(pDevIns, rc,
2471 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
2472
2473 /* query whether we are supposed to present an FDC controller */
2474 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &s->fUseFdc, true);
2475 if (RT_FAILURE(rc))
2476 return PDMDEV_SET_ERROR(pDevIns, rc,
2477 N_("Configuration error: Failed to read \"FdcEnabled\""));
2478
2479 /* query whether we are supposed to present HPET */
2480 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &s->fUseHpet, false);
2481 if (RT_FAILURE(rc))
2482 return PDMDEV_SET_ERROR(pDevIns, rc,
2483 N_("Configuration error: Failed to read \"HpetEnabled\""));
2484 /* query whether we are supposed to present SMC */
2485 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &s->fUseSmc, false);
2486 if (RT_FAILURE(rc))
2487 return PDMDEV_SET_ERROR(pDevIns, rc,
2488 N_("Configuration error: Failed to read \"SmcEnabled\""));
2489
2490 /* query whether we are supposed to present RTC object */
2491 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &s->fShowRtc, false);
2492 if (RT_FAILURE(rc))
2493 return PDMDEV_SET_ERROR(pDevIns, rc,
2494 N_("Configuration error: Failed to read \"ShowRtc\""));
2495
2496 /* query whether we are supposed to present CPU objects */
2497 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &s->fShowCpu, false);
2498 if (RT_FAILURE(rc))
2499 return PDMDEV_SET_ERROR(pDevIns, rc,
2500 N_("Configuration error: Failed to read \"ShowCpu\""));
2501
2502 /* query primary NIC PCI address */
2503 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &s->u32NicPciAddress, 0);
2504 if (RT_FAILURE(rc))
2505 return PDMDEV_SET_ERROR(pDevIns, rc,
2506 N_("Configuration error: Failed to read \"NicPciAddress\""));
2507
2508 /* query primary NIC PCI address */
2509 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &s->u32AudioPciAddress, 0);
2510 if (RT_FAILURE(rc))
2511 return PDMDEV_SET_ERROR(pDevIns, rc,
2512 N_("Configuration error: Failed to read \"AudioPciAddress\""));
2513
2514 /* query whether S1 power state should be exposed */
2515 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &s->fS1Enabled, true);
2516 if (RT_FAILURE(rc))
2517 return PDMDEV_SET_ERROR(pDevIns, rc,
2518 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
2519
2520 /* query whether S4 power state should be exposed */
2521 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &s->fS4Enabled, true);
2522 if (RT_FAILURE(rc))
2523 return PDMDEV_SET_ERROR(pDevIns, rc,
2524 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
2525
2526 /* query whether S1 power state should save the VM state */
2527 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &s->fSuspendToSavedState, false);
2528 if (RT_FAILURE(rc))
2529 return PDMDEV_SET_ERROR(pDevIns, rc,
2530 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
2531
2532 /* query whether we are allow CPU hot plugging */
2533 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &s->fCpuHotPlug, false);
2534 if (RT_FAILURE(rc))
2535 return PDMDEV_SET_ERROR(pDevIns, rc,
2536 N_("Configuration error: Failed to read \"CpuHotPlug\""));
2537
2538 rc = CFGMR3QueryBool(pCfg, "GCEnabled", &s->fGCEnabled);
2539 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2540 s->fGCEnabled = true;
2541 else if (RT_FAILURE(rc))
2542 return PDMDEV_SET_ERROR(pDevIns, rc,
2543 N_("Configuration error: Failed to read \"GCEnabled\""));
2544
2545 rc = CFGMR3QueryBool(pCfg, "R0Enabled", &s->fR0Enabled);
2546 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2547 s->fR0Enabled = true;
2548 else if (RT_FAILURE(rc))
2549 return PDMDEV_SET_ERROR(pDevIns, rc,
2550 N_("configuration error: failed to read R0Enabled as boolean"));
2551
2552 /*
2553 * Interfaces
2554 */
2555 /* IBase */
2556 s->IBase.pfnQueryInterface = acpiQueryInterface;
2557 /* IACPIPort */
2558 s->IACPIPort.pfnSleepButtonPress = acpiSleepButtonPress;
2559 s->IACPIPort.pfnPowerButtonPress = acpiPowerButtonPress;
2560 s->IACPIPort.pfnGetPowerButtonHandled = acpiGetPowerButtonHandled;
2561 s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiGetGuestEnteredACPIMode;
2562 s->IACPIPort.pfnGetCpuStatus = acpiGetCpuStatus;
2563
2564 VMCPUSET_EMPTY(&s->CpuSetAttached);
2565 VMCPUSET_EMPTY(&s->CpuSetLocked);
2566 s->idCpuLockCheck = UINT32_C(0xffffffff);
2567 s->u32CpuEventType = 0;
2568 s->u32CpuEvent = UINT32_C(0xffffffff);
2569
2570 /* The first CPU can't be attached/detached */
2571 VMCPUSET_ADD(&s->CpuSetAttached, 0);
2572 VMCPUSET_ADD(&s->CpuSetLocked, 0);
2573
2574 /* Try to attach the other CPUs */
2575 for (unsigned i = 1; i < s->cCpus; i++)
2576 {
2577 if (s->fCpuHotPlug)
2578 {
2579 PPDMIBASE IBaseTmp;
2580 rc = PDMDevHlpDriverAttach(pDevIns, i, &s->IBase, &IBaseTmp, "ACPI CPU");
2581
2582 if (RT_SUCCESS(rc))
2583 {
2584 VMCPUSET_ADD(&s->CpuSetAttached, i);
2585 VMCPUSET_ADD(&s->CpuSetLocked, i);
2586 Log(("acpi: Attached CPU %u\n", i));
2587 }
2588 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2589 Log(("acpi: CPU %u not attached yet\n", i));
2590 else
2591 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
2592 }
2593 else
2594 {
2595 /* CPU is always attached if hot-plug is not enabled. */
2596 VMCPUSET_ADD(&s->CpuSetAttached, i);
2597 VMCPUSET_ADD(&s->CpuSetLocked, i);
2598 }
2599 }
2600
2601
2602 /* Set default port base */
2603 s->uPmIoPortBase = PM_PORT_BASE;
2604
2605 /*
2606 * FDC and SMC try to use the same non-shareable interrupt (6),
2607 * enable only one device.
2608 */
2609 if (s->fUseSmc)
2610 s->fUseFdc = false;
2611
2612 /* */
2613 RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
2614 if (!GCPhysRsdp)
2615 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
2616 N_("Can not find space for RSDP. ACPI is disabled"));
2617
2618 rc = acpiPlantTables(s);
2619 if (RT_FAILURE(rc))
2620 return rc;
2621
2622 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, s->au8RSDPPage,
2623 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
2624 if (RT_FAILURE(rc))
2625 return rc;
2626
2627 rc = acpiRegisterPmHandlers(s);
2628 if (RT_FAILURE(rc))
2629 return rc;
2630
2631#define R(addr, cnt, writer, reader, description) \
2632 do { \
2633 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, s, writer, reader, \
2634 NULL, NULL, description); \
2635 if (RT_FAILURE(rc)) \
2636 return rc; \
2637 } while (0)
2638 R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
2639#ifdef DEBUG_ACPI
2640 R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
2641 R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
2642#endif
2643 R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
2644 R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
2645 R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
2646 R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
2647 R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
2648#undef R
2649
2650 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiTimer, dev,
2651 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "ACPI Timer", &s->tsR3);
2652 if (RT_FAILURE(rc))
2653 {
2654 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
2655 return rc;
2656 }
2657
2658 s->tsR0 = TMTimerR0Ptr(s->tsR3);
2659 s->tsRC = TMTimerRCPtr(s->tsR3);
2660 s->pm_timer_initial = TMTimerGet(s->tsR3);
2661 acpiPMTimerReset(s);
2662
2663 PCIDevSetVendorId(dev, 0x8086); /* Intel */
2664 PCIDevSetDeviceId(dev, 0x7113); /* 82371AB */
2665
2666 /* See p. 50 of PIIX4 manual */
2667 dev->config[0x04] = 0x01; /* command */
2668 dev->config[0x05] = 0x00;
2669
2670 dev->config[0x06] = 0x80; /* status */
2671 dev->config[0x07] = 0x02;
2672
2673 dev->config[0x08] = 0x08; /* revision number */
2674
2675 dev->config[0x09] = 0x00; /* class code */
2676 dev->config[0x0a] = 0x80;
2677 dev->config[0x0b] = 0x06;
2678
2679 dev->config[0x0e] = 0x80; /* header type */
2680
2681 dev->config[0x0f] = 0x00; /* reserved */
2682
2683 dev->config[0x3c] = SCI_INT; /* interrupt line */
2684
2685#if 0
2686 dev->config[0x3d] = 0x01; /* interrupt pin */
2687#endif
2688
2689 dev->config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
2690
2691#if 0
2692 int smb_io_base = 0xb100;
2693 dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
2694 dev->config[0x90] = smb_io_base >> 8;
2695#endif
2696
2697 rc = PDMDevHlpPCIRegister(pDevIns, dev);
2698 if (RT_FAILURE(rc))
2699 return rc;
2700
2701 PDMDevHlpPCISetConfigCallbacks(pDevIns, dev,
2702 acpiPciConfigRead, &s->pfnAcpiPciConfigRead,
2703 acpiPciConfigWrite, &s->pfnAcpiPciConfigWrite);
2704
2705 rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*s), acpiSaveState, acpiLoadState);
2706 if (RT_FAILURE(rc))
2707 return rc;
2708
2709 /*
2710 * Get the corresponding connector interface
2711 */
2712 rc = PDMDevHlpDriverAttach(pDevIns, 0, &s->IBase, &s->pDrvBase, "ACPI Driver Port");
2713 if (RT_SUCCESS(rc))
2714 {
2715 s->pDrv = PDMIBASE_QUERY_INTERFACE(s->pDrvBase, PDMIACPICONNECTOR);
2716 if (!s->pDrv)
2717 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
2718 N_("LUN #0 doesn't have an ACPI connector interface"));
2719 }
2720 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2721 {
2722 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
2723 pDevIns->pReg->szName, pDevIns->iInstance));
2724 rc = VINF_SUCCESS;
2725 }
2726 else
2727 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
2728
2729 return rc;
2730}
2731
2732/**
2733 * The device registration structure.
2734 */
2735const PDMDEVREG g_DeviceACPI =
2736{
2737 /* u32Version */
2738 PDM_DEVREG_VERSION,
2739 /* szName */
2740 "acpi",
2741 /* szRCMod */
2742 "VBoxDDGC.gc",
2743 /* szR0Mod */
2744 "VBoxDDR0.r0",
2745 /* pszDescription */
2746 "Advanced Configuration and Power Interface",
2747 /* fFlags */
2748 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2749 /* fClass */
2750 PDM_DEVREG_CLASS_ACPI,
2751 /* cMaxInstances */
2752 ~0,
2753 /* cbInstance */
2754 sizeof(ACPIState),
2755 /* pfnConstruct */
2756 acpiConstruct,
2757 /* pfnDestruct */
2758 NULL,
2759 /* pfnRelocate */
2760 acpiRelocate,
2761 /* pfnIOCtl */
2762 NULL,
2763 /* pfnPowerOn */
2764 NULL,
2765 /* pfnReset */
2766 acpiReset,
2767 /* pfnSuspend */
2768 NULL,
2769 /* pfnResume */
2770 acpiResume,
2771 /* pfnAttach */
2772 acpiAttach,
2773 /* pfnDetach */
2774 acpiDetach,
2775 /* pfnQueryInterface. */
2776 NULL,
2777 /* pfnInitComplete */
2778 NULL,
2779 /* pfnPowerOff */
2780 NULL,
2781 /* pfnSoftReset */
2782 NULL,
2783 /* u32VersionEnd */
2784 PDM_DEVREG_VERSION
2785};
2786
2787#endif /* IN_RING3 */
2788#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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