VirtualBox

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

最後變更 在這個檔案從35582是 35546,由 vboxsync 提交於 14 年 前

Devices/DevACPI: enforce disabling of S1/S4 power states

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

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