VirtualBox

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

Last change on this file since 37423 was 37391, checked in by vboxsync, 14 years ago

DevACPI: d'oh!

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

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