VirtualBox

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

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

Devices: refactoring, further PCI work

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

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