VirtualBox

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

Last change on this file since 25893 was 25855, checked in by vboxsync, 15 years ago

DevACPI.cpp: more bound checking.

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