VirtualBox

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

Last change on this file since 27867 was 27851, checked in by vboxsync, 15 years ago

Backed out acpi part of r59458; breaks Windows guests

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