VirtualBox

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

Last change on this file since 33000 was 32825, checked in by vboxsync, 14 years ago

DevACPI.cpp: warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 105.2 KB
Line 
1/* $Id: DevACPI.cpp 32825 2010-09-29 17:00:22Z vboxsync $ */
2/** @file
3 * DevACPI - Advanced Configuration and Power Interface (ACPI) Device.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_ACPI
22#include <VBox/pdmdev.h>
23#include <VBox/pgm.h>
24#include <VBox/log.h>
25#include <VBox/param.h>
26#include <iprt/assert.h>
27#include <iprt/asm.h>
28#include <iprt/asm-math.h>
29#ifdef IN_RING3
30# include <iprt/alloc.h>
31# include <iprt/string.h>
32# include <iprt/uuid.h>
33#endif /* IN_RING3 */
34
35#include "../Builtins.h"
36
37#ifdef LOG_ENABLED
38# define DEBUG_ACPI
39#endif
40
41#if defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
42int acpiPrepareDsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puDsdtLen);
43int acpiCleanupDsdt(PPDMDEVINS pDevIns, void* pPtr);
44
45int acpiPrepareSsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puSsdtLen);
46int acpiCleanupSsdt(PPDMDEVINS pDevIns, void* pPtr);
47#endif /* !IN_RING3 */
48
49
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54#define DEBUG_HEX 0x3000
55#define DEBUG_CHR 0x3001
56
57#define PM_TMR_FREQ 3579545
58/* Default base for PM PIIX4 device */
59#define PM_PORT_BASE 0x4000
60/* Port offsets in PM device */
61enum
62{
63 PM1a_EVT_OFFSET = 0x00,
64 PM1b_EVT_OFFSET = -1, /**< not supported */
65 PM1a_CTL_OFFSET = 0x04,
66 PM1b_CTL_OFFSET = -1, /**< not supported */
67 PM2_CTL_OFFSET = -1, /**< not supported */
68 PM_TMR_OFFSET = 0x08,
69 GPE0_OFFSET = 0x20,
70 GPE1_OFFSET = -1 /**< not supported */
71};
72
73#define BAT_INDEX 0x00004040
74#define BAT_DATA 0x00004044
75#define SYSI_INDEX 0x00004048
76#define SYSI_DATA 0x0000404c
77#define ACPI_RESET_BLK 0x00004050
78
79/* PM1x status register bits */
80#define TMR_STS RT_BIT(0)
81#define RSR1_STS (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
82#define BM_STS RT_BIT(4)
83#define GBL_STS RT_BIT(5)
84#define RSR2_STS (RT_BIT(6) | RT_BIT(7))
85#define PWRBTN_STS RT_BIT(8)
86#define SLPBTN_STS RT_BIT(9)
87#define RTC_STS RT_BIT(10)
88#define IGN_STS RT_BIT(11)
89#define RSR3_STS (RT_BIT(12) | RT_BIT(13) | RT_BIT(14))
90#define WAK_STS RT_BIT(15)
91#define RSR_STS (RSR1_STS | RSR2_STS | RSR3_STS)
92
93/* PM1x enable register bits */
94#define TMR_EN RT_BIT(0)
95#define RSR1_EN (RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
96#define GBL_EN RT_BIT(5)
97#define RSR2_EN (RT_BIT(6) | RT_BIT(7))
98#define PWRBTN_EN RT_BIT(8)
99#define SLPBTN_EN RT_BIT(9)
100#define RTC_EN RT_BIT(10)
101#define RSR3_EN (RT_BIT(11) | RT_BIT(12) | RT_BIT(13) | RT_BIT(14) | RT_BIT(15))
102#define RSR_EN (RSR1_EN | RSR2_EN | RSR3_EN)
103#define IGN_EN 0
104
105/* PM1x control register bits */
106#define SCI_EN RT_BIT(0)
107#define BM_RLD RT_BIT(1)
108#define GBL_RLS RT_BIT(2)
109#define RSR1_CNT (RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7) | RT_BIT(8))
110#define IGN_CNT RT_BIT(9)
111#define SLP_TYPx_SHIFT 10
112#define SLP_TYPx_MASK 7
113#define SLP_EN RT_BIT(13)
114#define RSR2_CNT (RT_BIT(14) | RT_BIT(15))
115#define RSR_CNT (RSR1_CNT | RSR2_CNT)
116
117#define GPE0_BATTERY_INFO_CHANGED RT_BIT(0)
118
119enum
120{
121 BAT_STATUS_STATE = 0x00, /**< BST battery state */
122 BAT_STATUS_PRESENT_RATE = 0x01, /**< BST battery present rate */
123 BAT_STATUS_REMAINING_CAPACITY = 0x02, /**< BST battery remaining capacity */
124 BAT_STATUS_PRESENT_VOLTAGE = 0x03, /**< BST battery present voltage */
125 BAT_INFO_UNITS = 0x04, /**< BIF power unit */
126 BAT_INFO_DESIGN_CAPACITY = 0x05, /**< BIF design capacity */
127 BAT_INFO_LAST_FULL_CHARGE_CAPACITY = 0x06, /**< BIF last full charge capacity */
128 BAT_INFO_TECHNOLOGY = 0x07, /**< BIF battery technology */
129 BAT_INFO_DESIGN_VOLTAGE = 0x08, /**< BIF design voltage */
130 BAT_INFO_DESIGN_CAPACITY_OF_WARNING = 0x09, /**< BIF design capacity of warning */
131 BAT_INFO_DESIGN_CAPACITY_OF_LOW = 0x0A, /**< BIF design capacity of low */
132 BAT_INFO_CAPACITY_GRANULARITY_1 = 0x0B, /**< BIF battery capacity granularity 1 */
133 BAT_INFO_CAPACITY_GRANULARITY_2 = 0x0C, /**< BIF battery capacity granularity 2 */
134 BAT_DEVICE_STATUS = 0x0D, /**< STA device status */
135 BAT_POWER_SOURCE = 0x0E, /**< PSR power source */
136 BAT_INDEX_LAST
137};
138
139enum
140{
141 CPU_EVENT_TYPE_ADD = 0x01, /**< Event type add */
142 CPU_EVENT_TYPE_REMOVE = 0x03 /**< Event type remove */
143};
144
145enum
146{
147 SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH = 0,
148 SYSTEM_INFO_INDEX_USE_IOAPIC = 1,
149 SYSTEM_INFO_INDEX_HPET_STATUS = 2,
150 SYSTEM_INFO_INDEX_SMC_STATUS = 3,
151 SYSTEM_INFO_INDEX_FDC_STATUS = 4,
152 SYSTEM_INFO_INDEX_CPU0_STATUS = 5, /**< For compatability with older saved states. */
153 SYSTEM_INFO_INDEX_CPU1_STATUS = 6, /**< For compatability with older saved states. */
154 SYSTEM_INFO_INDEX_CPU2_STATUS = 7, /**< For compatability with older saved states. */
155 SYSTEM_INFO_INDEX_CPU3_STATUS = 8, /**< For compatability with older saved states. */
156 SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH= 9,
157 SYSTEM_INFO_INDEX_RTC_STATUS = 10,
158 SYSTEM_INFO_INDEX_CPU_LOCKED = 11, /**< Contains a flag indicating whether the CPU is locked or not */
159 SYSTEM_INFO_INDEX_CPU_LOCK_CHECK = 12, /**< For which CPU the lock status should be checked */
160 SYSTEM_INFO_INDEX_CPU_EVENT_TYPE = 13, /**< Type of the CPU hot-plug event */
161 SYSTEM_INFO_INDEX_CPU_EVENT = 14, /**< The CPU id the event is for */
162 SYSTEM_INFO_INDEX_NIC_ADDRESS = 15, /**< NIC PCI address, or 0 */
163 SYSTEM_INFO_INDEX_AUDIO_ADDRESS = 16, /**< Audio card PCI address, or 0 */
164 SYSTEM_INFO_INDEX_POWER_STATES = 17,
165 SYSTEM_INFO_INDEX_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 ownship of ACPIregs */
377#define ACPI_ENABLE 0xa1
378 uint8_t u8AcpiDisable; /**< SMICmd val to re-enable ownship 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 1
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 protextion 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 initilized. */
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, 1 /* one source override */ );
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 /* If changing, also update PDMIsaSetIrq() and MPS */
979 ACPITBLISO* isos = madt.ISO_addr();
980 isos[0].u8Type = 2;
981 isos[0].u8Length = sizeof(ACPITBLISO);
982 isos[0].u8Bus = 0; /* Must be 0 */
983 isos[0].u8Source = 0; /* IRQ0 */
984 isos[0].u32GSI = 2; /* connected to pin 2 */
985 isos[0].u16Flags = 0; /* conform to the bus */
986 Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 1);
987
988 madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
989 acpiPhyscpy(s, addr, madt.data(), madt.size());
990}
991
992
993/** High Performance Event Timer (HPET) descriptor */
994static void acpiSetupHPET(ACPIState *s, RTGCPHYS32 addr)
995{
996 ACPITBLHPET hpet;
997
998 memset(&hpet, 0, sizeof(hpet));
999
1000 acpiPrepareHeader(&hpet.aHeader, "HPET", sizeof(hpet), 1);
1001 /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
1002 acpiWriteGenericAddr(&hpet.HpetAddr,
1003 0 /* Memory address space */,
1004 64 /* Register bit width */,
1005 0 /* Bit offset */,
1006 0, /* Register access size, is it correct? */
1007 0xfed00000 /* Address */);
1008
1009 hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
1010 hpet.u32Number = 0;
1011 hpet.u32MinTick = 4096;
1012 hpet.u8Attributes = 0;
1013
1014 hpet.aHeader.u8Checksum = acpiChecksum((uint8_t *)&hpet, sizeof(hpet));
1015
1016 acpiPhyscpy(s, addr, (const uint8_t *)&hpet, sizeof(hpet));
1017}
1018
1019/** MMCONFIG PCI config space access (MCFG) descriptor */
1020static void acpiSetupMCFG(ACPIState *s, RTGCPHYS32 addr)
1021{
1022 struct {
1023 ACPITBLMCFG hdr;
1024 ACPITBLMCFGENTRY entry;
1025 } tbl;
1026
1027 uint8_t u8StartBus = 0;
1028 uint8_t u8EndBus = (s->u64PciConfigMMioLength >> 20) - 1;
1029
1030 memset(&tbl, 0, sizeof(tbl));
1031
1032 acpiPrepareHeader(&tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
1033 tbl.entry.u64BaseAddress = s->u64PciConfigMMioAddress;
1034 tbl.entry.u8StartBus = u8StartBus;
1035 tbl.entry.u8EndBus = u8EndBus;
1036 // u16PciSegmentGroup must match _SEG in ACPI table
1037
1038 tbl.hdr.aHeader.u8Checksum = acpiChecksum((uint8_t *)&tbl, sizeof(tbl));
1039
1040 acpiPhyscpy(s, addr, (const uint8_t *)&tbl, sizeof(tbl));
1041}
1042
1043/* SCI IRQ */
1044DECLINLINE(void) acpiSetIrq(ACPIState *s, int level)
1045{
1046 if (s->pm1a_ctl & SCI_EN)
1047 PDMDevHlpPCISetIrq(s->pDevIns, -1, level);
1048}
1049
1050DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
1051{
1052 return en & ~(RSR_EN | IGN_EN);
1053}
1054
1055DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
1056{
1057 return sts & ~(RSR_STS | IGN_STS);
1058}
1059
1060DECLINLINE(int) pm1a_level(ACPIState *s)
1061{
1062 return (pm1a_pure_en(s->pm1a_en) & pm1a_pure_sts(s->pm1a_sts)) != 0;
1063}
1064
1065DECLINLINE(int) gpe0_level(ACPIState *s)
1066{
1067 return (s->gpe0_en & s->gpe0_sts) != 0;
1068}
1069
1070static void update_pm1a(ACPIState *s, uint32_t sts, uint32_t en)
1071{
1072 int old_level, new_level;
1073
1074 if (gpe0_level(s))
1075 return;
1076
1077 old_level = pm1a_level(s);
1078 new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
1079
1080 s->pm1a_en = en;
1081 s->pm1a_sts = sts;
1082
1083 if (new_level != old_level)
1084 acpiSetIrq(s, new_level);
1085}
1086
1087static void update_gpe0(ACPIState *s, uint32_t sts, uint32_t en)
1088{
1089 int old_level, new_level;
1090
1091 if (pm1a_level(s))
1092 return;
1093
1094 old_level = (s->gpe0_en & s->gpe0_sts) != 0;
1095 new_level = (en & sts) != 0;
1096
1097 s->gpe0_en = en;
1098 s->gpe0_sts = sts;
1099
1100 if (new_level != old_level)
1101 acpiSetIrq(s, new_level);
1102}
1103
1104static int acpiPowerDown(ACPIState *s)
1105{
1106 int rc = PDMDevHlpVMPowerOff(s->pDevIns);
1107 if (RT_FAILURE(rc))
1108 AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
1109 return rc;
1110}
1111
1112static int acpiSleep(ACPIState *pThis)
1113{
1114 int rc;
1115
1116 /* We must set WAK_STS on resume (includes restore) so the guest knows that
1117 we've woken up and can continue executing code. The guest is probably
1118 reading the PMSTS register in a loop to check this. */
1119 pThis->fSetWakeupOnResume = true;
1120 if (pThis->fSuspendToSavedState)
1121 {
1122 rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
1123 if (rc != VERR_NOT_SUPPORTED)
1124 AssertRC(rc);
1125 else
1126 {
1127 LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
1128 rc = PDMDevHlpVMSuspend(pThis->pDevIns);
1129 AssertRC(rc);
1130 }
1131 }
1132 else
1133 {
1134 rc = PDMDevHlpVMSuspend(pThis->pDevIns);
1135 AssertRC(rc);
1136 }
1137 return rc;
1138}
1139
1140/** Converts a ACPI port interface pointer to an ACPI state pointer. */
1141#define IACPIPORT_2_ACPISTATE(pInterface) ( (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IACPIPort)) )
1142
1143/**
1144 * Send an ACPI power off event.
1145 *
1146 * @returns VBox status code
1147 * @param pInterface Pointer to the interface structure containing the called function pointer.
1148 */
1149static DECLCALLBACK(int) acpiPowerButtonPress(PPDMIACPIPORT pInterface)
1150{
1151 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1152 s->fPowerButtonHandled = false;
1153 update_pm1a(s, s->pm1a_sts | PWRBTN_STS, s->pm1a_en);
1154 return VINF_SUCCESS;
1155}
1156
1157/**
1158 * Check if the ACPI power button event was handled.
1159 *
1160 * @returns VBox status code
1161 * @param pInterface Pointer to the interface structure containing the called function pointer.
1162 * @param pfHandled Return true if the power button event was handled by the guest.
1163 */
1164static DECLCALLBACK(int) acpiGetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
1165{
1166 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1167 *pfHandled = s->fPowerButtonHandled;
1168 return VINF_SUCCESS;
1169}
1170
1171/**
1172 * Check if the Guest entered into G0 (working) or G1 (sleeping).
1173 *
1174 * @returns VBox status code
1175 * @param pInterface Pointer to the interface structure containing the called function pointer.
1176 * @param pfEntered Return true if the guest entered the ACPI mode.
1177 */
1178static DECLCALLBACK(int) acpiGetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
1179{
1180 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1181 *pfEntered = (s->pm1a_ctl & SCI_EN) != 0;
1182 return VINF_SUCCESS;
1183}
1184
1185static DECLCALLBACK(int) acpiGetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
1186{
1187 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1188 *pfLocked = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, uCpu);
1189 return VINF_SUCCESS;
1190}
1191
1192/**
1193 * Send an ACPI sleep button event.
1194 *
1195 * @returns VBox status code
1196 * @param pInterface Pointer to the interface structure containing the called function pointer.
1197 */
1198static DECLCALLBACK(int) acpiSleepButtonPress(PPDMIACPIPORT pInterface)
1199{
1200 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1201 update_pm1a(s, s->pm1a_sts | SLPBTN_STS, s->pm1a_en);
1202 return VINF_SUCCESS;
1203}
1204
1205/* PM1a_EVT_BLK enable */
1206static uint32_t acpiPm1aEnReadw(ACPIState *s, uint32_t addr)
1207{
1208 uint16_t val = s->pm1a_en;
1209 Log(("acpi: acpiPm1aEnReadw -> %#x\n", val));
1210 return val;
1211}
1212
1213static void acpiPM1aEnWritew(ACPIState *s, uint32_t addr, uint32_t val)
1214{
1215 Log(("acpi: acpiPM1aEnWritew <- %#x (%#x)\n", val, val & ~(RSR_EN | IGN_EN)));
1216 val &= ~(RSR_EN | IGN_EN);
1217 update_pm1a(s, s->pm1a_sts, val);
1218}
1219
1220/* PM1a_EVT_BLK status */
1221static uint32_t acpiPm1aStsReadw(ACPIState *s, uint32_t addr)
1222{
1223 uint16_t val = s->pm1a_sts;
1224 Log(("acpi: acpiPm1aStsReadw -> %#x\n", val));
1225 return val;
1226}
1227
1228static void acpiPM1aStsWritew(ACPIState *s, uint32_t addr, uint32_t val)
1229{
1230 Log(("acpi: acpiPM1aStsWritew <- %#x (%#x)\n", val, val & ~(RSR_STS | IGN_STS)));
1231 if (val & PWRBTN_STS)
1232 s->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
1233 val = s->pm1a_sts & ~(val & ~(RSR_STS | IGN_STS));
1234 update_pm1a(s, val, s->pm1a_en);
1235}
1236
1237/* PM1a_CTL_BLK */
1238static uint32_t acpiPm1aCtlReadw(ACPIState *s, uint32_t addr)
1239{
1240 uint16_t val = s->pm1a_ctl;
1241 Log(("acpi: acpiPm1aCtlReadw -> %#x\n", val));
1242 return val;
1243}
1244
1245static int acpiPM1aCtlWritew(ACPIState *s, uint32_t addr, uint32_t val)
1246{
1247 uint32_t uSleepState;
1248
1249 Log(("acpi: acpiPM1aCtlWritew <- %#x (%#x)\n", val, val & ~(RSR_CNT | IGN_CNT)));
1250 s->pm1a_ctl = val & ~(RSR_CNT | IGN_CNT);
1251
1252 uSleepState = (s->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
1253 if (uSleepState != s->uSleepState)
1254 {
1255 s->uSleepState = uSleepState;
1256 switch (uSleepState)
1257 {
1258 case 0x00: /* S0 */
1259 break;
1260 case 0x01: /* S1 */
1261 LogRel(("Entering S1 power state (powered-on suspend)\n"));
1262 return acpiSleep(s);
1263 case 0x04: /* S4 */
1264 LogRel(("Entering S4 power state (suspend to disk)\n"));
1265 return acpiPowerDown(s);/* Same behavior as S5 */
1266 case 0x05: /* S5 */
1267 LogRel(("Entering S5 power state (power down)\n"));
1268 return acpiPowerDown(s);
1269 default:
1270 AssertMsgFailed(("Unknown sleep state %#x\n", uSleepState));
1271 break;
1272 }
1273 }
1274 return VINF_SUCCESS;
1275}
1276
1277/* GPE0_BLK */
1278static uint32_t acpiGpe0EnReadb(ACPIState *s, uint32_t addr)
1279{
1280 uint8_t val = s->gpe0_en;
1281 Log(("acpi: acpiGpe0EnReadl -> %#x\n", val));
1282 return val;
1283}
1284
1285static void acpiGpe0EnWriteb(ACPIState *s, uint32_t addr, uint32_t val)
1286{
1287 Log(("acpi: acpiGpe0EnWritel <- %#x\n", val));
1288 update_gpe0(s, s->gpe0_sts, val);
1289}
1290
1291static uint32_t acpiGpe0StsReadb(ACPIState *s, uint32_t addr)
1292{
1293 uint8_t val = s->gpe0_sts;
1294 Log(("acpi: acpiGpe0StsReadl -> %#x\n", val));
1295 return val;
1296}
1297
1298static void acpiGpe0StsWriteb(ACPIState *s, uint32_t addr, uint32_t val)
1299{
1300 val = s->gpe0_sts & ~val;
1301 update_gpe0(s, val, s->gpe0_en);
1302 Log(("acpi: acpiGpe0StsWritel <- %#x\n", val));
1303}
1304
1305static int acpiResetWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1306{
1307 int rc = VINF_SUCCESS;
1308
1309 Log(("ACPI: acpiResetWriteU8: %x %x\n", addr, val));
1310 if (val == ACPI_RESET_REG_VAL)
1311 {
1312# ifndef IN_RING3
1313 rc = VINF_IOM_HC_IOPORT_WRITE;
1314# else /* IN_RING3 */
1315 rc = PDMDevHlpVMReset(s->pDevIns);
1316# endif /* !IN_RING3 */
1317 }
1318 return rc;
1319}
1320
1321/* SMI */
1322static void acpiSmiWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1323{
1324 Log(("acpi: acpiSmiWriteU8 %#x\n", val));
1325 if (val == ACPI_ENABLE)
1326 s->pm1a_ctl |= SCI_EN;
1327 else if (val == ACPI_DISABLE)
1328 s->pm1a_ctl &= ~SCI_EN;
1329 else
1330 Log(("acpi: acpiSmiWriteU8 %#x <- unknown value\n", val));
1331}
1332
1333static uint32_t find_rsdp_space(void)
1334{
1335 return 0xe0000;
1336}
1337
1338static int acpiPMTimerReset(ACPIState *s)
1339{
1340 uint64_t interval, freq;
1341
1342 freq = TMTimerGetFreq(s->CTX_SUFF(ts));
1343 interval = ASMMultU64ByU32DivByU32(0xffffffff, freq, PM_TMR_FREQ);
1344 Log(("interval = %RU64\n", interval));
1345 TMTimerSet(s->CTX_SUFF(ts), TMTimerGet(s->CTX_SUFF(ts)) + interval);
1346
1347 return VINF_SUCCESS;
1348}
1349
1350static DECLCALLBACK(void) acpiTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1351{
1352 ACPIState *s = (ACPIState *)pvUser;
1353
1354 Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
1355 s->pm1a_sts, (s->pm1a_sts & TMR_STS) != 0,
1356 s->pm1a_en, (s->pm1a_en & TMR_EN) != 0));
1357
1358 update_pm1a(s, s->pm1a_sts | TMR_STS, s->pm1a_en);
1359 acpiPMTimerReset(s);
1360}
1361
1362/**
1363 * _BST method.
1364 */
1365static int acpiFetchBatteryStatus(ACPIState *s)
1366{
1367 uint32_t *p = s->au8BatteryInfo;
1368 bool fPresent; /* battery present? */
1369 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1370 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1371 uint32_t hostPresentRate; /* 0..1000 */
1372 int rc;
1373
1374 if (!s->pDrv)
1375 return VINF_SUCCESS;
1376 rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
1377 &hostBatteryState, &hostPresentRate);
1378 AssertRC(rc);
1379
1380 /* default values */
1381 p[BAT_STATUS_STATE] = hostBatteryState;
1382 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
1383 : hostPresentRate * 50; /* mW */
1384 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
1385 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
1386
1387 /* did we get a valid battery state? */
1388 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
1389 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
1390 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
1391 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
1392
1393 return VINF_SUCCESS;
1394}
1395
1396/**
1397 * _BIF method.
1398 */
1399static int acpiFetchBatteryInfo(ACPIState *s)
1400{
1401 uint32_t *p = s->au8BatteryInfo;
1402
1403 p[BAT_INFO_UNITS] = 0; /* mWh */
1404 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
1405 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
1406 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
1407 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
1408 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
1409 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
1410 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
1411 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
1412
1413 return VINF_SUCCESS;
1414}
1415
1416/**
1417 * _STA method.
1418 */
1419static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
1420{
1421 bool fPresent; /* battery present? */
1422 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1423 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1424 uint32_t hostPresentRate; /* 0..1000 */
1425 int rc;
1426
1427 if (!s->pDrv)
1428 return 0;
1429 rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
1430 &hostBatteryState, &hostPresentRate);
1431 AssertRC(rc);
1432
1433 return fPresent
1434 ? STA_DEVICE_PRESENT_MASK /* present */
1435 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1436 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1437 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1438 | STA_BATTERY_PRESENT_MASK /* battery is present */
1439 : 0; /* device not present */
1440}
1441
1442static uint32_t acpiGetPowerSource(ACPIState *s)
1443{
1444 PDMACPIPOWERSOURCE ps;
1445
1446 /* query the current power source from the host driver */
1447 if (!s->pDrv)
1448 return AC_ONLINE;
1449 int rc = s->pDrv->pfnQueryPowerSource(s->pDrv, &ps);
1450 AssertRC(rc);
1451 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1452}
1453
1454PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1455{
1456 ACPIState *s = (ACPIState *)pvUser;
1457
1458 switch (cb)
1459 {
1460 case 4:
1461 u32 >>= s->u8IndexShift;
1462 /* see comment at the declaration of u8IndexShift */
1463 if (s->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
1464 {
1465 s->u8IndexShift = 2;
1466 u32 >>= 2;
1467 }
1468 Assert(u32 < BAT_INDEX_LAST);
1469 s->uBatteryIndex = u32;
1470 break;
1471 default:
1472 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1473 break;
1474 }
1475 return VINF_SUCCESS;
1476}
1477
1478PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1479{
1480 ACPIState *s = (ACPIState *)pvUser;
1481
1482 switch (cb)
1483 {
1484 case 4:
1485 switch (s->uBatteryIndex)
1486 {
1487 case BAT_STATUS_STATE:
1488 acpiFetchBatteryStatus(s);
1489 case BAT_STATUS_PRESENT_RATE:
1490 case BAT_STATUS_REMAINING_CAPACITY:
1491 case BAT_STATUS_PRESENT_VOLTAGE:
1492 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1493 break;
1494
1495 case BAT_INFO_UNITS:
1496 acpiFetchBatteryInfo(s);
1497 case BAT_INFO_DESIGN_CAPACITY:
1498 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1499 case BAT_INFO_TECHNOLOGY:
1500 case BAT_INFO_DESIGN_VOLTAGE:
1501 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1502 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1503 case BAT_INFO_CAPACITY_GRANULARITY_1:
1504 case BAT_INFO_CAPACITY_GRANULARITY_2:
1505 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1506 break;
1507
1508 case BAT_DEVICE_STATUS:
1509 *pu32 = acpiGetBatteryDeviceStatus(s);
1510 break;
1511
1512 case BAT_POWER_SOURCE:
1513 *pu32 = acpiGetPowerSource(s);
1514 break;
1515
1516 default:
1517 AssertMsgFailed(("Invalid battery index %d\n", s->uBatteryIndex));
1518 break;
1519 }
1520 break;
1521 default:
1522 return VERR_IOM_IOPORT_UNUSED;
1523 }
1524 return VINF_SUCCESS;
1525}
1526
1527PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1528{
1529 ACPIState *s = (ACPIState *)pvUser;
1530
1531 Log(("system_index = %d, %d\n", u32, u32 >> 2));
1532 switch (cb)
1533 {
1534 case 4:
1535 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1536 s->uSystemInfoIndex = u32;
1537 else
1538 {
1539 /* see comment at the declaration of u8IndexShift */
1540 if (s->u8IndexShift == 0)
1541 {
1542 if (((u32 >> 2) < SYSTEM_INFO_INDEX_END) && ((u32 & 0x3)) == 0)
1543 {
1544 s->u8IndexShift = 2;
1545 }
1546 }
1547
1548 u32 >>= s->u8IndexShift;
1549 Assert(u32 < SYSTEM_INFO_INDEX_END);
1550 s->uSystemInfoIndex = u32;
1551 }
1552 break;
1553
1554 default:
1555 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1556 break;
1557 }
1558 return VINF_SUCCESS;
1559}
1560
1561PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1562{
1563 ACPIState *s = (ACPIState *)pvUser;
1564
1565 switch (cb)
1566 {
1567 case 4:
1568 switch (s->uSystemInfoIndex)
1569 {
1570 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
1571 *pu32 = s->cbRamLow;
1572 break;
1573
1574 case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
1575 *pu32 = s->cbRamHigh >> 16; /* 64KB units */
1576 Assert(((uint64_t)*pu32 << 16) == s->cbRamHigh);
1577 break;
1578
1579 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1580 *pu32 = s->u8UseIOApic;
1581 break;
1582
1583 case SYSTEM_INFO_INDEX_HPET_STATUS:
1584 *pu32 = s->fUseHpet ? ( STA_DEVICE_PRESENT_MASK
1585 | STA_DEVICE_ENABLED_MASK
1586 | STA_DEVICE_SHOW_IN_UI_MASK
1587 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1588 : 0;
1589 break;
1590
1591 case SYSTEM_INFO_INDEX_SMC_STATUS:
1592 *pu32 = s->fUseSmc ? ( STA_DEVICE_PRESENT_MASK
1593 | STA_DEVICE_ENABLED_MASK
1594 /* no need to show this device in the UI */
1595 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1596 : 0;
1597 break;
1598
1599 case SYSTEM_INFO_INDEX_FDC_STATUS:
1600 *pu32 = s->fUseFdc ? ( STA_DEVICE_PRESENT_MASK
1601 | STA_DEVICE_ENABLED_MASK
1602 | STA_DEVICE_SHOW_IN_UI_MASK
1603 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1604 : 0;
1605 break;
1606
1607 case SYSTEM_INFO_INDEX_NIC_ADDRESS:
1608 *pu32 = s->u32NicPciAddress;
1609 break;
1610
1611 case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
1612 *pu32 = s->u32AudioPciAddress;
1613 break;
1614
1615 case SYSTEM_INFO_INDEX_POWER_STATES:
1616 *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
1617 if (s->fS1Enabled) /* Optionally expose S1 and S4 */
1618 *pu32 |= RT_BIT(1);
1619 if (s->fS4Enabled)
1620 *pu32 |= RT_BIT(4);
1621 break;
1622
1623 case SYSTEM_INFO_INDEX_IOC_ADDRESS:
1624 *pu32 = s->u32IocPciAddress;
1625 break;
1626
1627 case SYSTEM_INFO_INDEX_HBC_ADDRESS:
1628 *pu32 = s->u32HbcPciAddress;
1629 break;
1630
1631 case SYSTEM_INFO_INDEX_PCI_BASE:
1632 /** @todo: couldn't MCFG be in 64-bit range? */
1633 Assert(s->u64PciConfigMMioAddress< 0xffffffff);
1634 *pu32 = (uint32_t)s->u64PciConfigMMioAddress;
1635 break;
1636
1637 case SYSTEM_INFO_INDEX_PCI_LENGTH:
1638 /** @todo: couldn't MCFG be in 64-bit range? */
1639 Assert(s->u64PciConfigMMioLength< 0xffffffff);
1640 *pu32 = (uint32_t)s->u64PciConfigMMioLength;
1641 break;
1642
1643 /* This is only for compatability with older saved states that
1644 may include ACPI code that read these values. Legacy is
1645 a wonderful thing, isn't it? :-) */
1646 case SYSTEM_INFO_INDEX_CPU0_STATUS:
1647 case SYSTEM_INFO_INDEX_CPU1_STATUS:
1648 case SYSTEM_INFO_INDEX_CPU2_STATUS:
1649 case SYSTEM_INFO_INDEX_CPU3_STATUS:
1650 *pu32 = ( s->fShowCpu
1651 && s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < s->cCpus
1652 && VMCPUSET_IS_PRESENT(&s->CpuSetAttached,
1653 s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS))
1654 ? ( STA_DEVICE_PRESENT_MASK
1655 | STA_DEVICE_ENABLED_MASK
1656 | STA_DEVICE_SHOW_IN_UI_MASK
1657 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1658 : 0;
1659 break;
1660
1661 case SYSTEM_INFO_INDEX_RTC_STATUS:
1662 *pu32 = s->fShowRtc ? ( STA_DEVICE_PRESENT_MASK
1663 | STA_DEVICE_ENABLED_MASK
1664 | STA_DEVICE_SHOW_IN_UI_MASK
1665 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1666 : 0;
1667 break;
1668
1669 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1670 {
1671 if (s->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1672 {
1673 *pu32 = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, s->idCpuLockCheck);
1674 s->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1675 }
1676 else
1677 {
1678 AssertMsgFailed(("ACPI: CPU lock check protocol violation\n"));
1679 /* Always return locked status just to be safe */
1680 *pu32 = 1;
1681 }
1682 break;
1683 }
1684
1685 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1686 *pu32 = s->u32CpuEventType;
1687 break;
1688
1689 case SYSTEM_INFO_INDEX_CPU_EVENT:
1690 *pu32 = s->u32CpuEvent;
1691 break;
1692
1693 /* Solaris 9 tries to read from this index */
1694 case SYSTEM_INFO_INDEX_INVALID:
1695 *pu32 = 0;
1696 break;
1697
1698 default:
1699 AssertMsgFailed(("Invalid system info index %d\n", s->uSystemInfoIndex));
1700 break;
1701 }
1702 break;
1703
1704 default:
1705 return VERR_IOM_IOPORT_UNUSED;
1706 }
1707
1708 Log(("index %d val %d\n", s->uSystemInfoIndex, *pu32));
1709 return VINF_SUCCESS;
1710}
1711
1712PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1713{
1714 ACPIState *s = (ACPIState *)pvUser;
1715
1716 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, s->uSystemInfoIndex));
1717
1718 if (cb == 4)
1719 {
1720 switch (s->uSystemInfoIndex)
1721 {
1722 case SYSTEM_INFO_INDEX_INVALID:
1723 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1724 s->u8IndexShift = 0;
1725 break;
1726
1727 case SYSTEM_INFO_INDEX_VALID:
1728 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1729 s->u8IndexShift = 2;
1730 break;
1731
1732 case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
1733 s->idCpuLockCheck = u32;
1734 break;
1735
1736 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1737 if (u32 < s->cCpus)
1738 VMCPUSET_DEL(&s->CpuSetLocked, u32); /* Unlock the CPU */
1739 else
1740 LogRel(("ACPI: CPU %u does not exist\n", u32));
1741 break;
1742
1743 default:
1744 AssertMsgFailed(("Port=%#x cb=%d u32=%#x system_index=%#x\n",
1745 Port, cb, u32, s->uSystemInfoIndex));
1746 break;
1747 }
1748 }
1749 else
1750 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1751 return VINF_SUCCESS;
1752}
1753
1754/** @todo Don't call functions, but do the job in the read/write handlers
1755 * here! */
1756
1757/* IO Helpers */
1758PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1759{
1760 switch (cb)
1761 {
1762 case 2:
1763 *pu32 = acpiPm1aEnReadw((ACPIState*)pvUser, Port);
1764 break;
1765 default:
1766 return VERR_IOM_IOPORT_UNUSED;
1767 }
1768 return VINF_SUCCESS;
1769}
1770
1771PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1772{
1773 switch (cb)
1774 {
1775 case 2:
1776 *pu32 = acpiPm1aStsReadw((ACPIState*)pvUser, Port);
1777 break;
1778 default:
1779 return VERR_IOM_IOPORT_UNUSED;
1780 }
1781 return VINF_SUCCESS;
1782}
1783
1784PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1785{
1786 switch (cb)
1787 {
1788 case 2:
1789 *pu32 = acpiPm1aCtlReadw((ACPIState*)pvUser, Port);
1790 break;
1791 default:
1792 return VERR_IOM_IOPORT_UNUSED;
1793 }
1794 return VINF_SUCCESS;
1795}
1796
1797PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1798{
1799 switch (cb)
1800 {
1801 case 2:
1802 acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32);
1803 break;
1804 case 4:
1805 acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1806 break;
1807 default:
1808 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1809 break;
1810 }
1811 return VINF_SUCCESS;
1812}
1813
1814PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1815{
1816 switch (cb)
1817 {
1818 case 2:
1819 acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32);
1820 break;
1821 case 4:
1822 acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1823 break;
1824 default:
1825 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1826 break;
1827 }
1828 return VINF_SUCCESS;
1829}
1830
1831PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1832{
1833 switch (cb)
1834 {
1835 case 2:
1836 return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32);
1837 case 4:
1838 return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1839 default:
1840 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1841 break;
1842 }
1843 return VINF_SUCCESS;
1844}
1845
1846#endif /* IN_RING3 */
1847
1848/**
1849 * PMTMR readable from host/guest.
1850 */
1851PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1852{
1853 if (cb == 4)
1854 {
1855 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
1856 int64_t now = TMTimerGet(s->CTX_SUFF(ts));
1857 int64_t elapsed = now - s->pm_timer_initial;
1858
1859 *pu32 = ASMMultU64ByU32DivByU32(elapsed, PM_TMR_FREQ, TMTimerGetFreq(s->CTX_SUFF(ts)));
1860 Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
1861 return VINF_SUCCESS;
1862 }
1863 return VERR_IOM_IOPORT_UNUSED;
1864}
1865
1866#ifdef IN_RING3
1867
1868PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1869{
1870 switch (cb)
1871 {
1872 case 1:
1873 *pu32 = acpiGpe0StsReadb((ACPIState*)pvUser, Port);
1874 break;
1875 default:
1876 return VERR_IOM_IOPORT_UNUSED;
1877 }
1878 return VINF_SUCCESS;
1879}
1880
1881PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1882{
1883 switch (cb)
1884 {
1885 case 1:
1886 *pu32 = acpiGpe0EnReadb((ACPIState*)pvUser, Port);
1887 break;
1888 default:
1889 return VERR_IOM_IOPORT_UNUSED;
1890 }
1891 return VINF_SUCCESS;
1892}
1893
1894PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1895{
1896 switch (cb)
1897 {
1898 case 1:
1899 acpiGpe0StsWriteb((ACPIState*)pvUser, Port, u32);
1900 break;
1901 default:
1902 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1903 break;
1904 }
1905 return VINF_SUCCESS;
1906}
1907
1908PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1909{
1910 switch (cb)
1911 {
1912 case 1:
1913 acpiGpe0EnWriteb((ACPIState*)pvUser, Port, u32);
1914 break;
1915 default:
1916 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1917 break;
1918 }
1919 return VINF_SUCCESS;
1920}
1921
1922PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1923{
1924 switch (cb)
1925 {
1926 case 1:
1927 acpiSmiWriteU8((ACPIState*)pvUser, Port, u32);
1928 break;
1929 default:
1930 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1931 break;
1932 }
1933 return VINF_SUCCESS;
1934}
1935
1936PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1937{
1938 switch (cb)
1939 {
1940 case 1:
1941 return acpiResetWriteU8((ACPIState*)pvUser, Port, u32);
1942 default:
1943 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1944 break;
1945 }
1946 return VINF_SUCCESS;
1947}
1948
1949#ifdef DEBUG_ACPI
1950
1951PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1952{
1953 switch (cb)
1954 {
1955 case 1:
1956 Log(("%#x\n", u32 & 0xff));
1957 break;
1958 case 2:
1959 Log(("%#6x\n", u32 & 0xffff));
1960 case 4:
1961 Log(("%#10x\n", u32));
1962 break;
1963 default:
1964 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1965 break;
1966 }
1967 return VINF_SUCCESS;
1968}
1969
1970PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1971{
1972 switch (cb)
1973 {
1974 case 1:
1975 Log(("%c", u32 & 0xff));
1976 break;
1977 default:
1978 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1979 break;
1980 }
1981 return VINF_SUCCESS;
1982}
1983
1984#endif /* DEBUG_ACPI */
1985
1986static int acpiRegisterPmHandlers(ACPIState* pThis)
1987{
1988 int rc = VINF_SUCCESS;
1989
1990#define R(offset, cnt, writer, reader, description) \
1991 do { \
1992 rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt, pThis, writer, reader, \
1993 NULL, NULL, description); \
1994 if (RT_FAILURE(rc)) \
1995 return rc; \
1996 } while (0)
1997#define L (GPE0_BLK_LEN / 2)
1998
1999 R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
2000 R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
2001 R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
2002 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
2003 R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
2004 R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
2005#undef L
2006#undef R
2007
2008 /* register RC stuff */
2009 if (pThis->fGCEnabled)
2010 {
2011 rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
2012 1, 0, NULL, "acpiPMTmrRead",
2013 NULL, NULL, "ACPI PM Timer");
2014 AssertRCReturn(rc, rc);
2015 }
2016
2017 /* register R0 stuff */
2018 if (pThis->fR0Enabled)
2019 {
2020 rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
2021 1, 0, NULL, "acpiPMTmrRead",
2022 NULL, NULL, "ACPI PM Timer");
2023 AssertRCReturn(rc, rc);
2024 }
2025
2026 return rc;
2027}
2028
2029static int acpiUnregisterPmHandlers(ACPIState *pThis)
2030{
2031#define U(offset, cnt) \
2032 do { \
2033 int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt); \
2034 AssertRCReturn(rc, rc); \
2035 } while (0)
2036#define L (GPE0_BLK_LEN / 2)
2037
2038 U(PM1a_EVT_OFFSET+2, 1);
2039 U(PM1a_EVT_OFFSET, 1);
2040 U(PM1a_CTL_OFFSET, 1);
2041 U(PM_TMR_OFFSET, 1);
2042 U(GPE0_OFFSET + L, L);
2043 U(GPE0_OFFSET, L);
2044#undef L
2045#undef U
2046
2047 return VINF_SUCCESS;
2048}
2049
2050/**
2051 * Saved state structure description, version 4.
2052 */
2053static const SSMFIELD g_AcpiSavedStateFields4[] =
2054{
2055 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2056 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2057 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2058 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
2059 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2060 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2061 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2062 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2063 SSMFIELD_ENTRY(ACPIState, u64RamSize),
2064 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2065 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
2066 SSMFIELD_ENTRY(ACPIState, uSleepState),
2067 SSMFIELD_ENTRY_TERM()
2068};
2069
2070/**
2071 * Saved state structure description, version 5.
2072 */
2073static const SSMFIELD g_AcpiSavedStateFields5[] =
2074{
2075 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2076 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2077 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2078 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
2079 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2080 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2081 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2082 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2083 SSMFIELD_ENTRY(ACPIState, uSleepState),
2084 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2085 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2086 SSMFIELD_ENTRY_TERM()
2087};
2088
2089/**
2090 * Saved state structure description, version 6.
2091 */
2092static const SSMFIELD g_AcpiSavedStateFields6[] =
2093{
2094 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2095 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2096 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2097 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
2098 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2099 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2100 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2101 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2102 SSMFIELD_ENTRY(ACPIState, uSleepState),
2103 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2104 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2105 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
2106 SSMFIELD_ENTRY_TERM()
2107};
2108
2109
2110/**
2111 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2112 */
2113static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2114{
2115 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2116 return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2117}
2118
2119/**
2120 * @callback_method_impl{FNSSMDEVLOADEXEC}
2121 */
2122static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
2123 uint32_t uVersion, uint32_t uPass)
2124{
2125 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2126 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2127
2128 /*
2129 * Unregister PM handlers, will register with actual base after state
2130 * successfully loaded.
2131 */
2132 int rc = acpiUnregisterPmHandlers(pThis);
2133 if (RT_FAILURE(rc))
2134 return rc;
2135
2136 switch (uVersion)
2137 {
2138 case 4:
2139 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
2140 break;
2141 case 5:
2142 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
2143 break;
2144 case 6:
2145 rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
2146 break;
2147 default:
2148 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2149 break;
2150 }
2151 if (RT_SUCCESS(rc))
2152 {
2153 rc = acpiRegisterPmHandlers(pThis);
2154 if (RT_FAILURE(rc))
2155 return rc;
2156 rc = acpiFetchBatteryStatus(pThis);
2157 if (RT_FAILURE(rc))
2158 return rc;
2159 rc = acpiFetchBatteryInfo(pThis);
2160 if (RT_FAILURE(rc))
2161 return rc;
2162 rc = acpiPMTimerReset(pThis);
2163 if (RT_FAILURE(rc))
2164 return rc;
2165 }
2166 return rc;
2167}
2168
2169/**
2170 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2171 */
2172static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2173{
2174 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
2175 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2176 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
2177 return NULL;
2178}
2179
2180/**
2181 * Create the ACPI tables.
2182 */
2183static int acpiPlantTables(ACPIState *s)
2184{
2185 int rc;
2186 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
2187 RTGCPHYS32 GCPhysHpet = 0, GCPhysApic = 0, GCPhysSsdt = 0, GCPhysMcfg = 0;
2188 uint32_t addend = 0;
2189 RTGCPHYS32 aGCPhysRsdt[4];
2190 RTGCPHYS32 aGCPhysXsdt[4];
2191 uint32_t cAddr, iMadt = 0, iHpet = 0, iSsdt = 0, iMcfg = 0;
2192 size_t cbRsdt = sizeof(ACPITBLHEADER);
2193 size_t cbXsdt = sizeof(ACPITBLHEADER);
2194
2195 cAddr = 1; /* FADT */
2196 if (s->u8UseIOApic)
2197 iMadt = cAddr++; /* MADT */
2198
2199 if (s->fUseHpet)
2200 iHpet = cAddr++; /* HPET */
2201
2202 if (s->fUseMcfg)
2203 iMcfg = cAddr++; /* MCFG */
2204
2205 iSsdt = cAddr++; /* SSDT */
2206
2207 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
2208 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
2209
2210 rc = CFGMR3QueryU64(s->pDevIns->pCfg, "RamSize", &s->u64RamSize);
2211 if (RT_FAILURE(rc))
2212 return PDMDEV_SET_ERROR(s->pDevIns, rc,
2213 N_("Configuration error: Querying \"RamSize\" as integer failed"));
2214
2215 uint32_t cbRamHole;
2216 rc = CFGMR3QueryU32Def(s->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
2217 if (RT_FAILURE(rc))
2218 return PDMDEV_SET_ERROR(s->pDevIns, rc,
2219 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
2220
2221 /*
2222 * Calculate the sizes for the high and low regions.
2223 */
2224 const uint64_t offRamHole = _4G - cbRamHole;
2225 s->cbRamHigh = offRamHole < s->u64RamSize ? s->u64RamSize - offRamHole : 0;
2226 uint64_t cbRamLow = offRamHole < s->u64RamSize ? offRamHole : s->u64RamSize;
2227 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
2228 {
2229 /* Note: This is also enforced by DevPcBios.cpp. */
2230 LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
2231 cbRamLow = UINT32_C(0xffe00000);
2232 }
2233 s->cbRamLow = (uint32_t)cbRamLow;
2234
2235 GCPhysCur = 0;
2236 GCPhysRsdt = GCPhysCur;
2237
2238 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
2239 GCPhysXsdt = GCPhysCur;
2240
2241 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
2242 GCPhysFadtAcpi1 = GCPhysCur;
2243
2244 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
2245 GCPhysFadtAcpi2 = GCPhysCur;
2246
2247 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
2248 GCPhysFacs = GCPhysCur;
2249
2250 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
2251 if (s->u8UseIOApic)
2252 {
2253 GCPhysApic = GCPhysCur;
2254 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(s, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
2255 }
2256 if (s->fUseHpet)
2257 {
2258 GCPhysHpet = GCPhysCur;
2259 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
2260 }
2261 if (s->fUseMcfg)
2262 {
2263 GCPhysMcfg = GCPhysCur;
2264 /* Assume one entry */
2265 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
2266 }
2267
2268 void* pSsdtCode = NULL;
2269 size_t cbSsdtSize = 0;
2270 rc = acpiPrepareSsdt(s->pDevIns, &pSsdtCode, &cbSsdtSize);
2271 if (RT_FAILURE(rc))
2272 return rc;
2273
2274 GCPhysSsdt = GCPhysCur;
2275 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdtSize, 16);
2276
2277 GCPhysDsdt = GCPhysCur;
2278
2279 void* pDsdtCode = NULL;
2280 size_t cbDsdtSize = 0;
2281 rc = acpiPrepareDsdt(s->pDevIns, &pDsdtCode, &cbDsdtSize);
2282 if (RT_FAILURE(rc))
2283 return rc;
2284
2285 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
2286
2287 if (GCPhysCur > 0x10000)
2288 return PDMDEV_SET_ERROR(s->pDevIns, VERR_TOO_MUCH_DATA,
2289 N_("Error: ACPI tables bigger than 64KB"));
2290
2291 Log(("RSDP 0x%08X\n", find_rsdp_space()));
2292 addend = s->cbRamLow - 0x10000;
2293 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
2294 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
2295 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
2296 if (s->u8UseIOApic)
2297 Log((" MADT 0x%08X", GCPhysApic + addend));
2298 if (s->fUseHpet)
2299 Log((" HPET 0x%08X", GCPhysHpet + addend));
2300 if (s->fUseMcfg)
2301 Log((" MCFG 0x%08X", GCPhysMcfg + addend));
2302 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
2303 Log(("\n"));
2304
2305 acpiSetupRSDP((ACPITBLRSDP*)s->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
2306 acpiSetupDSDT(s, GCPhysDsdt + addend, pDsdtCode, cbDsdtSize);
2307 acpiCleanupDsdt(s->pDevIns, pDsdtCode);
2308 acpiSetupFACS(s, GCPhysFacs + addend);
2309 acpiSetupFADT(s, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
2310
2311 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
2312 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
2313 if (s->u8UseIOApic)
2314 {
2315 acpiSetupMADT(s, GCPhysApic + addend);
2316 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
2317 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
2318 }
2319 if (s->fUseHpet)
2320 {
2321 acpiSetupHPET(s, GCPhysHpet + addend);
2322 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
2323 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
2324 }
2325 if (s->fUseMcfg)
2326 {
2327 acpiSetupMCFG(s, GCPhysMcfg + addend);
2328 aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
2329 aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
2330 }
2331
2332 acpiSetupSSDT(s, GCPhysSsdt + addend, pSsdtCode, cbSsdtSize);
2333 acpiCleanupSsdt(s->pDevIns, pSsdtCode);
2334 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
2335 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
2336
2337 rc = acpiSetupRSDT(s, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
2338 if (RT_FAILURE(rc))
2339 return rc;
2340 return acpiSetupXSDT(s, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
2341}
2342
2343static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT uNewBase)
2344{
2345 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, uNewBase));
2346 if (uNewBase != pThis->uPmIoPortBase)
2347 {
2348 int rc;
2349
2350 rc = acpiUnregisterPmHandlers(pThis);
2351 if (RT_FAILURE(rc))
2352 return rc;
2353
2354 pThis->uPmIoPortBase = uNewBase;
2355
2356 rc = acpiRegisterPmHandlers(pThis);
2357 if (RT_FAILURE(rc))
2358 return rc;
2359
2360 /* We have to update FADT table acccording to the new base */
2361 rc = acpiPlantTables(pThis);
2362 AssertRC(rc);
2363 if (RT_FAILURE(rc))
2364 return rc;
2365 }
2366
2367 return VINF_SUCCESS;
2368}
2369
2370static uint32_t acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
2371{
2372 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2373 ACPIState* pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2374
2375 Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
2376
2377 return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
2378}
2379
2380static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
2381{
2382 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2383 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2384
2385 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
2386 pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
2387
2388 /* PMREGMISC written */
2389 if (Address == 0x80)
2390 {
2391 /* Check Power Management IO Space Enable (PMIOSE) bit */
2392 if (pPciDev->config[0x80] & 0x1)
2393 {
2394 int rc;
2395
2396 RTIOPORT uNewBase =
2397 RTIOPORT(RT_LE2H_U32(*(uint32_t*)&pPciDev->config[0x40]));
2398 uNewBase &= 0xffc0;
2399
2400 rc = acpiUpdatePmHandlers(pThis, uNewBase);
2401 AssertRC(rc);
2402 }
2403 }
2404}
2405
2406/**
2407 * Attach a new CPU.
2408 *
2409 * @returns VBox status code.
2410 * @param pDevIns The device instance.
2411 * @param iLUN The logical unit which is being attached.
2412 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2413 *
2414 * @remarks This code path is not used during construction.
2415 */
2416static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2417{
2418 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2419
2420 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2421
2422 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2423 ("Hot-plug flag is not set\n"),
2424 VERR_NOT_SUPPORTED);
2425 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
2426
2427 /* Check if it was already attached */
2428 if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
2429 return VINF_SUCCESS;
2430
2431 PPDMIBASE IBaseTmp;
2432 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &s->IBase, &IBaseTmp, "ACPI CPU");
2433
2434 if (RT_SUCCESS(rc))
2435 {
2436 /* Enable the CPU */
2437 VMCPUSET_ADD(&s->CpuSetAttached, iLUN);
2438
2439 /*
2440 * Lock the CPU because we don't know if the guest will use it or not.
2441 * Prevents ejection while the CPU is still used
2442 */
2443 VMCPUSET_ADD(&s->CpuSetLocked, iLUN);
2444 s->u32CpuEventType = CPU_EVENT_TYPE_ADD;
2445 s->u32CpuEvent = iLUN;
2446 /* Notify the guest */
2447 update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
2448 }
2449 return rc;
2450}
2451
2452/**
2453 * Detach notification.
2454 *
2455 * @param pDevIns The device instance.
2456 * @param iLUN The logical unit which is being detached.
2457 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2458 */
2459static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2460{
2461 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2462
2463 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2464
2465 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2466 ("Hot-plug flag is not set\n"));
2467
2468 /* Check if it was already detached */
2469 if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
2470 {
2471 AssertMsgReturnVoid(!(VMCPUSET_IS_PRESENT(&s->CpuSetLocked, iLUN)), ("CPU is still locked by the guest\n"));
2472
2473 /* Disable the CPU */
2474 VMCPUSET_DEL(&s->CpuSetAttached, iLUN);
2475 s->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
2476 s->u32CpuEvent = iLUN;
2477 /* Notify the guest */
2478 update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
2479 }
2480}
2481
2482/**
2483 * @interface_method_impl{PDMDEVREG,pfnResume}
2484 */
2485static DECLCALLBACK(void) acpiResume(PPDMDEVINS pDevIns)
2486{
2487 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2488 if (pThis->fSetWakeupOnResume)
2489 {
2490 Log(("acpiResume: setting WAK_STS\n"));
2491 pThis->fSetWakeupOnResume = false;
2492 pThis->pm1a_sts |= WAK_STS;
2493 }
2494}
2495
2496/**
2497 * @interface_method_impl{PDMDEVREG,pfnReset}
2498 */
2499static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
2500{
2501 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2502
2503 s->pm1a_en = 0;
2504 s->pm1a_sts = 0;
2505 s->pm1a_ctl = 0;
2506 s->pm_timer_initial = TMTimerGet(s->CTX_SUFF(ts));
2507 acpiPMTimerReset(s);
2508 s->uBatteryIndex = 0;
2509 s->uSystemInfoIndex = 0;
2510 s->gpe0_en = 0;
2511 s->gpe0_sts = 0;
2512 s->uSleepState = 0;
2513
2514 /** @todo Should we really reset PM base? */
2515 acpiUpdatePmHandlers(s, PM_PORT_BASE);
2516
2517 acpiPlantTables(s);
2518}
2519
2520/**
2521 * @interface_method_impl{PDMDEVREG,pfnRelocate}
2522 */
2523static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2524{
2525 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2526 s->tsRC = TMTimerRCPtr(s->CTX_SUFF(ts));
2527}
2528
2529/**
2530 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2531 */
2532static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2533{
2534 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2535 PCIDevice *dev = &s->dev;
2536 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2537
2538 /* Validate and read the configuration. */
2539 if (!CFGMR3AreValuesValid(pCfg,
2540 "RamSize\0"
2541 "RamHoleSize\0"
2542 "IOAPIC\0"
2543 "NumCPUs\0"
2544 "GCEnabled\0"
2545 "R0Enabled\0"
2546 "HpetEnabled\0"
2547 "McfgEnabled\0"
2548 "McfgBase\0"
2549 "McfgLength\0"
2550 "SmcEnabled\0"
2551 "FdcEnabled\0"
2552 "ShowRtc\0"
2553 "ShowCpu\0"
2554 "NicPciAddress\0"
2555 "AudioPciAddress\0"
2556 "IocPciAddress\0"
2557 "HostBusPciAddress\0"
2558 "EnableSuspendToDisk\0"
2559 "PowerS1Enabled\0"
2560 "PowerS4Enabled\0"
2561 "CpuHotPlug\0"
2562 "AmlFilePath\0"
2563 ))
2564 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2565 N_("Configuration error: Invalid config key for ACPI device"));
2566
2567 s->pDevIns = pDevIns;
2568
2569 /* query whether we are supposed to present an IOAPIC */
2570 int rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &s->u8UseIOApic, 1);
2571 if (RT_FAILURE(rc))
2572 return PDMDEV_SET_ERROR(pDevIns, rc,
2573 N_("Configuration error: Failed to read \"IOAPIC\""));
2574
2575 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &s->cCpus, 1);
2576 if (RT_FAILURE(rc))
2577 return PDMDEV_SET_ERROR(pDevIns, rc,
2578 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
2579
2580 /* query whether we are supposed to present an FDC controller */
2581 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &s->fUseFdc, true);
2582 if (RT_FAILURE(rc))
2583 return PDMDEV_SET_ERROR(pDevIns, rc,
2584 N_("Configuration error: Failed to read \"FdcEnabled\""));
2585
2586 /* query whether we are supposed to present HPET */
2587 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &s->fUseHpet, false);
2588 if (RT_FAILURE(rc))
2589 return PDMDEV_SET_ERROR(pDevIns, rc,
2590 N_("Configuration error: Failed to read \"HpetEnabled\""));
2591 /* query MCFG configuartion */
2592 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &s->u64PciConfigMMioAddress, 0);
2593 if (RT_FAILURE(rc))
2594 return PDMDEV_SET_ERROR(pDevIns, rc,
2595 N_("Configuration error: Failed to read \"McfgBase\""));
2596 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &s->u64PciConfigMMioLength, 0);
2597 if (RT_FAILURE(rc))
2598 return PDMDEV_SET_ERROR(pDevIns, rc,
2599 N_("Configuration error: Failed to read \"McfgLength\""));
2600 s->fUseMcfg = (s->u64PciConfigMMioAddress != 0) && (s->u64PciConfigMMioLength != 0);
2601
2602 /* query whether we are supposed to present SMC */
2603 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &s->fUseSmc, false);
2604 if (RT_FAILURE(rc))
2605 return PDMDEV_SET_ERROR(pDevIns, rc,
2606 N_("Configuration error: Failed to read \"SmcEnabled\""));
2607
2608 /* query whether we are supposed to present RTC object */
2609 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &s->fShowRtc, false);
2610 if (RT_FAILURE(rc))
2611 return PDMDEV_SET_ERROR(pDevIns, rc,
2612 N_("Configuration error: Failed to read \"ShowRtc\""));
2613
2614 /* query whether we are supposed to present CPU objects */
2615 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &s->fShowCpu, false);
2616 if (RT_FAILURE(rc))
2617 return PDMDEV_SET_ERROR(pDevIns, rc,
2618 N_("Configuration error: Failed to read \"ShowCpu\""));
2619
2620 /* query primary NIC PCI address */
2621 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &s->u32NicPciAddress, 0);
2622 if (RT_FAILURE(rc))
2623 return PDMDEV_SET_ERROR(pDevIns, rc,
2624 N_("Configuration error: Failed to read \"NicPciAddress\""));
2625
2626 /* query primary NIC PCI address */
2627 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &s->u32AudioPciAddress, 0);
2628 if (RT_FAILURE(rc))
2629 return PDMDEV_SET_ERROR(pDevIns, rc,
2630 N_("Configuration error: Failed to read \"AudioPciAddress\""));
2631
2632 /* query IO controller (southbridge) PCI address */
2633 rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &s->u32IocPciAddress, 0);
2634 if (RT_FAILURE(rc))
2635 return PDMDEV_SET_ERROR(pDevIns, rc,
2636 N_("Configuration error: Failed to read \"IocPciAddress\""));
2637
2638 /* query host bus controller PCI address */
2639 rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &s->u32HbcPciAddress, 0);
2640 if (RT_FAILURE(rc))
2641 return PDMDEV_SET_ERROR(pDevIns, rc,
2642 N_("Configuration error: Failed to read \"HostBusPciAddress\""));
2643
2644 /* query whether S1 power state should be exposed */
2645 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &s->fS1Enabled, true);
2646 if (RT_FAILURE(rc))
2647 return PDMDEV_SET_ERROR(pDevIns, rc,
2648 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
2649
2650 /* query whether S4 power state should be exposed */
2651 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &s->fS4Enabled, true);
2652 if (RT_FAILURE(rc))
2653 return PDMDEV_SET_ERROR(pDevIns, rc,
2654 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
2655
2656 /* query whether S1 power state should save the VM state */
2657 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &s->fSuspendToSavedState, false);
2658 if (RT_FAILURE(rc))
2659 return PDMDEV_SET_ERROR(pDevIns, rc,
2660 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
2661
2662 /* query whether we are allow CPU hot plugging */
2663 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &s->fCpuHotPlug, false);
2664 if (RT_FAILURE(rc))
2665 return PDMDEV_SET_ERROR(pDevIns, rc,
2666 N_("Configuration error: Failed to read \"CpuHotPlug\""));
2667
2668 rc = CFGMR3QueryBool(pCfg, "GCEnabled", &s->fGCEnabled);
2669 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2670 s->fGCEnabled = true;
2671 else if (RT_FAILURE(rc))
2672 return PDMDEV_SET_ERROR(pDevIns, rc,
2673 N_("Configuration error: Failed to read \"GCEnabled\""));
2674
2675 rc = CFGMR3QueryBool(pCfg, "R0Enabled", &s->fR0Enabled);
2676 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2677 s->fR0Enabled = true;
2678 else if (RT_FAILURE(rc))
2679 return PDMDEV_SET_ERROR(pDevIns, rc,
2680 N_("configuration error: failed to read R0Enabled as boolean"));
2681
2682 /*
2683 * Interfaces
2684 */
2685 /* IBase */
2686 s->IBase.pfnQueryInterface = acpiQueryInterface;
2687 /* IACPIPort */
2688 s->IACPIPort.pfnSleepButtonPress = acpiSleepButtonPress;
2689 s->IACPIPort.pfnPowerButtonPress = acpiPowerButtonPress;
2690 s->IACPIPort.pfnGetPowerButtonHandled = acpiGetPowerButtonHandled;
2691 s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiGetGuestEnteredACPIMode;
2692 s->IACPIPort.pfnGetCpuStatus = acpiGetCpuStatus;
2693
2694 VMCPUSET_EMPTY(&s->CpuSetAttached);
2695 VMCPUSET_EMPTY(&s->CpuSetLocked);
2696 s->idCpuLockCheck = UINT32_C(0xffffffff);
2697 s->u32CpuEventType = 0;
2698 s->u32CpuEvent = UINT32_C(0xffffffff);
2699
2700 /* The first CPU can't be attached/detached */
2701 VMCPUSET_ADD(&s->CpuSetAttached, 0);
2702 VMCPUSET_ADD(&s->CpuSetLocked, 0);
2703
2704 /* Try to attach the other CPUs */
2705 for (unsigned i = 1; i < s->cCpus; i++)
2706 {
2707 if (s->fCpuHotPlug)
2708 {
2709 PPDMIBASE IBaseTmp;
2710 rc = PDMDevHlpDriverAttach(pDevIns, i, &s->IBase, &IBaseTmp, "ACPI CPU");
2711
2712 if (RT_SUCCESS(rc))
2713 {
2714 VMCPUSET_ADD(&s->CpuSetAttached, i);
2715 VMCPUSET_ADD(&s->CpuSetLocked, i);
2716 Log(("acpi: Attached CPU %u\n", i));
2717 }
2718 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2719 Log(("acpi: CPU %u not attached yet\n", i));
2720 else
2721 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
2722 }
2723 else
2724 {
2725 /* CPU is always attached if hot-plug is not enabled. */
2726 VMCPUSET_ADD(&s->CpuSetAttached, i);
2727 VMCPUSET_ADD(&s->CpuSetLocked, i);
2728 }
2729 }
2730
2731
2732 /* Set default port base */
2733 s->uPmIoPortBase = PM_PORT_BASE;
2734
2735 /*
2736 * FDC and SMC try to use the same non-shareable interrupt (6),
2737 * enable only one device.
2738 */
2739 if (s->fUseSmc)
2740 s->fUseFdc = false;
2741
2742 /* */
2743 RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
2744 if (!GCPhysRsdp)
2745 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
2746 N_("Can not find space for RSDP. ACPI is disabled"));
2747
2748 rc = acpiPlantTables(s);
2749 if (RT_FAILURE(rc))
2750 return rc;
2751
2752 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, s->au8RSDPPage,
2753 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
2754 if (RT_FAILURE(rc))
2755 return rc;
2756
2757 rc = acpiRegisterPmHandlers(s);
2758 if (RT_FAILURE(rc))
2759 return rc;
2760
2761#define R(addr, cnt, writer, reader, description) \
2762 do { \
2763 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, s, writer, reader, \
2764 NULL, NULL, description); \
2765 if (RT_FAILURE(rc)) \
2766 return rc; \
2767 } while (0)
2768 R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
2769#ifdef DEBUG_ACPI
2770 R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
2771 R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
2772#endif
2773 R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
2774 R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
2775 R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
2776 R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
2777 R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
2778#undef R
2779
2780 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiTimer, dev,
2781 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "ACPI Timer", &s->tsR3);
2782 if (RT_FAILURE(rc))
2783 {
2784 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
2785 return rc;
2786 }
2787
2788 s->tsR0 = TMTimerR0Ptr(s->tsR3);
2789 s->tsRC = TMTimerRCPtr(s->tsR3);
2790 s->pm_timer_initial = TMTimerGet(s->tsR3);
2791 acpiPMTimerReset(s);
2792
2793 PCIDevSetVendorId(dev, 0x8086); /* Intel */
2794 PCIDevSetDeviceId(dev, 0x7113); /* 82371AB */
2795
2796 /* See p. 50 of PIIX4 manual */
2797 PCIDevSetCommand(dev, 0x01);
2798 PCIDevSetStatus(dev, 0x0280);
2799
2800 PCIDevSetRevisionId(dev, 0x08);
2801
2802 PCIDevSetClassProg(dev, 0x00);
2803 PCIDevSetClassSub(dev, 0x80);
2804 PCIDevSetClassBase(dev, 0x06);
2805
2806 PCIDevSetHeaderType(dev, 0x80);
2807
2808 PCIDevSetBIST(dev, 0x00);
2809
2810 PCIDevSetInterruptLine(dev, SCI_INT);
2811
2812#if 0
2813 dev->config[0x3d] = 0x01; /* interrupt pin */
2814#endif
2815
2816 dev->config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
2817
2818#if 0
2819 int smb_io_base = 0xb100;
2820 dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
2821 dev->config[0x90] = smb_io_base >> 8;
2822#endif
2823
2824 rc = PDMDevHlpPCIRegister(pDevIns, dev);
2825 if (RT_FAILURE(rc))
2826 return rc;
2827
2828 PDMDevHlpPCISetConfigCallbacks(pDevIns, dev,
2829 acpiPciConfigRead, &s->pfnAcpiPciConfigRead,
2830 acpiPciConfigWrite, &s->pfnAcpiPciConfigWrite);
2831
2832 rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*s), acpiSaveState, acpiLoadState);
2833 if (RT_FAILURE(rc))
2834 return rc;
2835
2836 /*
2837 * Get the corresponding connector interface
2838 */
2839 rc = PDMDevHlpDriverAttach(pDevIns, 0, &s->IBase, &s->pDrvBase, "ACPI Driver Port");
2840 if (RT_SUCCESS(rc))
2841 {
2842 s->pDrv = PDMIBASE_QUERY_INTERFACE(s->pDrvBase, PDMIACPICONNECTOR);
2843 if (!s->pDrv)
2844 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
2845 N_("LUN #0 doesn't have an ACPI connector interface"));
2846 }
2847 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2848 {
2849 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
2850 pDevIns->pReg->szName, pDevIns->iInstance));
2851 rc = VINF_SUCCESS;
2852 }
2853 else
2854 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
2855
2856 return rc;
2857}
2858
2859/**
2860 * The device registration structure.
2861 */
2862const PDMDEVREG g_DeviceACPI =
2863{
2864 /* u32Version */
2865 PDM_DEVREG_VERSION,
2866 /* szName */
2867 "acpi",
2868 /* szRCMod */
2869 "VBoxDDGC.gc",
2870 /* szR0Mod */
2871 "VBoxDDR0.r0",
2872 /* pszDescription */
2873 "Advanced Configuration and Power Interface",
2874 /* fFlags */
2875 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2876 /* fClass */
2877 PDM_DEVREG_CLASS_ACPI,
2878 /* cMaxInstances */
2879 ~0,
2880 /* cbInstance */
2881 sizeof(ACPIState),
2882 /* pfnConstruct */
2883 acpiConstruct,
2884 /* pfnDestruct */
2885 NULL,
2886 /* pfnRelocate */
2887 acpiRelocate,
2888 /* pfnIOCtl */
2889 NULL,
2890 /* pfnPowerOn */
2891 NULL,
2892 /* pfnReset */
2893 acpiReset,
2894 /* pfnSuspend */
2895 NULL,
2896 /* pfnResume */
2897 acpiResume,
2898 /* pfnAttach */
2899 acpiAttach,
2900 /* pfnDetach */
2901 acpiDetach,
2902 /* pfnQueryInterface. */
2903 NULL,
2904 /* pfnInitComplete */
2905 NULL,
2906 /* pfnPowerOff */
2907 NULL,
2908 /* pfnSoftReset */
2909 NULL,
2910 /* u32VersionEnd */
2911 PDM_DEVREG_VERSION
2912};
2913
2914#endif /* IN_RING3 */
2915#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use