VirtualBox

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

Last change on this file since 31993 was 31963, checked in by vboxsync, 15 years ago

ACPI: Hook S1 power state.

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

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