VirtualBox

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

Last change on this file since 27159 was 26939, checked in by vboxsync, 15 years ago

ACPI, APIC, HPET: emulate typical configuration wrt ISA interrupt routing

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 94.7 KB
Line 
1/* $Id: DevACPI.cpp 26939 2010-03-02 12:13:40Z 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,
156 SYSTEM_INFO_INDEX_CPU1_STATUS = 6,
157 SYSTEM_INFO_INDEX_CPU2_STATUS = 7,
158 SYSTEM_INFO_INDEX_CPU3_STATUS = 8,
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
800 /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
801 if (s->fCpuHotPlug)
802 fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
803
804 acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
805 fadt.u8ResetVal = ACPI_RESET_REG_VAL;
806 fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
807 fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
808 acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiPmPort(s, PM1a_EVT_OFFSET));
809 acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiPmPort(s, PM1b_EVT_OFFSET));
810 acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiPmPort(s, PM1a_CTL_OFFSET));
811 acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiPmPort(s, PM1b_CTL_OFFSET));
812 acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiPmPort(s, PM2_CTL_OFFSET));
813 acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiPmPort(s, PM_TMR_OFFSET));
814 acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiPmPort(s, GPE0_OFFSET));
815 acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiPmPort(s, GPE1_OFFSET));
816 fadt.header.u8Checksum = acpiChecksum((uint8_t *)&fadt, sizeof(fadt));
817 acpiPhyscpy(s, GCPhysAcpi2, &fadt, sizeof(fadt));
818
819 /* Now the ACPI 1.0 version. */
820 fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
821 fadt.u8IntModel = INT_MODEL_DUAL_PIC;
822 fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
823 fadt.header.u8Checksum = acpiChecksum((uint8_t *)&fadt, ACPITBLFADT_VERSION1_SIZE);
824 acpiPhyscpy(s, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
825}
826
827/**
828 * Root System Description Table.
829 * The RSDT and XSDT tables are basically identical. The only difference is 32 vs 64 bits
830 * addresses for description headers. RSDT is for ACPI 1.0. XSDT for ACPI 2.0 and up.
831 */
832static int acpiSetupRSDT(ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
833{
834 ACPITBLRSDT *rsdt;
835 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
836
837 rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
838 if (!rsdt)
839 return PDMDEV_SET_ERROR(s->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
840
841 acpiPrepareHeader(&rsdt->header, "RSDT", (uint32_t)size, 1);
842 for (unsigned int i = 0; i < nb_entries; ++i)
843 {
844 rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
845 Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
846 }
847 rsdt->header.u8Checksum = acpiChecksum((uint8_t*)rsdt, size);
848 acpiPhyscpy(s, addr, rsdt, size);
849 RTMemFree(rsdt);
850 return VINF_SUCCESS;
851}
852
853/** Extended System Description Table. */
854static int acpiSetupXSDT(ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
855{
856 ACPITBLXSDT *xsdt;
857 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
858
859 xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
860 if (!xsdt)
861 return VERR_NO_TMP_MEMORY;
862
863 acpiPrepareHeader(&xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
864 for (unsigned int i = 0; i < nb_entries; ++i)
865 {
866 xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
867 Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
868 }
869 xsdt->header.u8Checksum = acpiChecksum((uint8_t*)xsdt, size);
870 acpiPhyscpy(s, addr, xsdt, size);
871 RTMemFree(xsdt);
872 return VINF_SUCCESS;
873}
874
875/** Root System Description Pointer (RSDP) */
876static void acpiSetupRSDP(ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
877{
878 memset(rsdp, 0, sizeof(*rsdp));
879
880 /* ACPI 1.0 part (RSDT */
881 memcpy(rsdp->au8Signature, "RSD PTR ", 8);
882 memcpy(rsdp->au8OemId, "VBOX ", 6);
883 rsdp->u8Revision = ACPI_REVISION;
884 rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
885 rsdp->u8Checksum = acpiChecksum((uint8_t*)rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
886
887 /* ACPI 2.0 part (XSDT) */
888 rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
889 rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
890 rsdp->u8ExtChecksum = acpiChecksum((uint8_t*)rsdp, sizeof(ACPITBLRSDP));
891}
892
893/**
894 * Multiple APIC Description Table.
895 *
896 * @note APIC without IO-APIC hangs Windows Vista therefore we setup both
897 *
898 * @todo All hardcoded, should set this up based on the actual VM config!!!!!
899 */
900static void acpiSetupMADT(ACPIState *s, RTGCPHYS32 addr)
901{
902 uint16_t cpus = s->cCpus;
903 AcpiTableMADT madt(cpus, 1 /* one source override */ );
904
905 acpiPrepareHeader(madt.header_addr(), "APIC", madt.size(), 2);
906
907 *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
908 *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
909
910 /* LAPICs records */
911 ACPITBLLAPIC* lapic = madt.LApics_addr();
912 for (uint16_t i = 0; i < cpus; i++)
913 {
914 lapic->u8Type = 0;
915 lapic->u8Length = sizeof(ACPITBLLAPIC);
916 lapic->u8ProcId = i;
917 /** Must match numbering convention in MPTABLES */
918 lapic->u8ApicId = i;
919 lapic->u32Flags = VMCPUSET_IS_PRESENT(&s->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
920 lapic++;
921 }
922
923 /* IO-APIC record */
924 ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
925 ioapic->u8Type = 1;
926 ioapic->u8Length = sizeof(ACPITBLIOAPIC);
927 /** Must match MP tables ID */
928 ioapic->u8IOApicId = cpus;
929 ioapic->u8Reserved = 0;
930 ioapic->u32Address = RT_H2LE_U32(0xfec00000);
931 ioapic->u32GSIB = RT_H2LE_U32(0);
932
933 /* Interrupt Source Overrides */
934 /* If changing, also update PDMIsaSetIrq() and MPS */
935 ACPITBLISO* isos = madt.ISO_addr();
936 isos[0].u8Type = 2;
937 isos[0].u8Length = sizeof(ACPITBLISO);
938 isos[0].u8Bus = 0; /* Must be 0 */
939 isos[0].u8Source = 0; /* IRQ0 */
940 isos[0].u32GSI = 2; /* connected to pin 2 */
941 isos[0].u16Flags = 0; /* conform to the bus */
942 Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 1);
943
944 madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
945 acpiPhyscpy(s, addr, madt.data(), madt.size());
946}
947
948
949/** High Performance Event Timer (HPET) descriptor */
950static void acpiSetupHPET(ACPIState *s, RTGCPHYS32 addr)
951{
952 ACPITBLHPET hpet;
953
954 memset(&hpet, 0, sizeof(hpet));
955
956 acpiPrepareHeader(&hpet.aHeader, "HPET", sizeof(hpet), 1);
957 /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
958 acpiWriteGenericAddr(&hpet.HpetAddr,
959 0 /* Memory address space */,
960 64 /* Register bit width */,
961 0 /* Bit offset */,
962 0, /* Register access size, is it correct? */
963 0xfed00000 /* Address */);
964
965 hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
966 hpet.u32Number = 0;
967 hpet.u32MinTick = 4096;
968 hpet.u8Attributes = 0;
969
970 hpet.aHeader.u8Checksum = acpiChecksum((uint8_t *)&hpet, sizeof(hpet));
971
972 acpiPhyscpy(s, addr, (const uint8_t *)&hpet, sizeof(hpet));
973}
974
975/* SCI IRQ */
976DECLINLINE(void) acpiSetIrq(ACPIState *s, int level)
977{
978 if (s->pm1a_ctl & SCI_EN)
979 PDMDevHlpPCISetIrq(s->pDevIns, -1, level);
980}
981
982DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
983{
984 return en & ~(RSR_EN | IGN_EN);
985}
986
987DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
988{
989 return sts & ~(RSR_STS | IGN_STS);
990}
991
992DECLINLINE(int) pm1a_level(ACPIState *s)
993{
994 return (pm1a_pure_en(s->pm1a_en) & pm1a_pure_sts(s->pm1a_sts)) != 0;
995}
996
997DECLINLINE(int) gpe0_level(ACPIState *s)
998{
999 return (s->gpe0_en & s->gpe0_sts) != 0;
1000}
1001
1002static void update_pm1a(ACPIState *s, uint32_t sts, uint32_t en)
1003{
1004 int old_level, new_level;
1005
1006 if (gpe0_level(s))
1007 return;
1008
1009 old_level = pm1a_level(s);
1010 new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
1011
1012 s->pm1a_en = en;
1013 s->pm1a_sts = sts;
1014
1015 if (new_level != old_level)
1016 acpiSetIrq(s, new_level);
1017}
1018
1019static void update_gpe0(ACPIState *s, uint32_t sts, uint32_t en)
1020{
1021 int old_level, new_level;
1022
1023 if (pm1a_level(s))
1024 return;
1025
1026 old_level = (s->gpe0_en & s->gpe0_sts) != 0;
1027 new_level = (en & sts) != 0;
1028
1029 s->gpe0_en = en;
1030 s->gpe0_sts = sts;
1031
1032 if (new_level != old_level)
1033 acpiSetIrq(s, new_level);
1034}
1035
1036static int acpiPowerDown(ACPIState *s)
1037{
1038 int rc = PDMDevHlpVMPowerOff(s->pDevIns);
1039 if (RT_FAILURE(rc))
1040 AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
1041 return rc;
1042}
1043
1044/** Converts a ACPI port interface pointer to an ACPI state pointer. */
1045#define IACPIPORT_2_ACPISTATE(pInterface) ( (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IACPIPort)) )
1046
1047/**
1048 * Send an ACPI power off event.
1049 *
1050 * @returns VBox status code
1051 * @param pInterface Pointer to the interface structure containing the called function pointer.
1052 */
1053static DECLCALLBACK(int) acpiPowerButtonPress(PPDMIACPIPORT pInterface)
1054{
1055 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1056 s->fPowerButtonHandled = false;
1057 update_pm1a(s, s->pm1a_sts | PWRBTN_STS, s->pm1a_en);
1058 return VINF_SUCCESS;
1059}
1060
1061/**
1062 * Check if the ACPI power button event was handled.
1063 *
1064 * @returns VBox status code
1065 * @param pInterface Pointer to the interface structure containing the called function pointer.
1066 * @param pfHandled Return true if the power button event was handled by the guest.
1067 */
1068static DECLCALLBACK(int) acpiGetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
1069{
1070 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1071 *pfHandled = s->fPowerButtonHandled;
1072 return VINF_SUCCESS;
1073}
1074
1075/**
1076 * Check if the Guest entered into G0 (working) or G1 (sleeping).
1077 *
1078 * @returns VBox status code
1079 * @param pInterface Pointer to the interface structure containing the called function pointer.
1080 * @param pfEntered Return true if the guest entered the ACPI mode.
1081 */
1082static DECLCALLBACK(int) acpiGetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
1083{
1084 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1085 *pfEntered = (s->pm1a_ctl & SCI_EN) != 0;
1086 return VINF_SUCCESS;
1087}
1088
1089static DECLCALLBACK(int) acpiGetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
1090{
1091 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1092 *pfLocked = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, uCpu);
1093 return VINF_SUCCESS;
1094}
1095
1096/**
1097 * Send an ACPI sleep button event.
1098 *
1099 * @returns VBox status code
1100 * @param pInterface Pointer to the interface structure containing the called function pointer.
1101 */
1102static DECLCALLBACK(int) acpiSleepButtonPress(PPDMIACPIPORT pInterface)
1103{
1104 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
1105 update_pm1a(s, s->pm1a_sts | SLPBTN_STS, s->pm1a_en);
1106 return VINF_SUCCESS;
1107}
1108
1109/* PM1a_EVT_BLK enable */
1110static uint32_t acpiPm1aEnReadw(ACPIState *s, uint32_t addr)
1111{
1112 uint16_t val = s->pm1a_en;
1113 Log(("acpi: acpiPm1aEnReadw -> %#x\n", val));
1114 return val;
1115}
1116
1117static void acpiPM1aEnWritew(ACPIState *s, uint32_t addr, uint32_t val)
1118{
1119 Log(("acpi: acpiPM1aEnWritew <- %#x (%#x)\n", val, val & ~(RSR_EN | IGN_EN)));
1120 val &= ~(RSR_EN | IGN_EN);
1121 update_pm1a(s, s->pm1a_sts, val);
1122}
1123
1124/* PM1a_EVT_BLK status */
1125static uint32_t acpiPm1aStsReadw(ACPIState *s, uint32_t addr)
1126{
1127 uint16_t val = s->pm1a_sts;
1128 Log(("acpi: acpiPm1aStsReadw -> %#x\n", val));
1129 return val;
1130}
1131
1132static void acpiPM1aStsWritew(ACPIState *s, uint32_t addr, uint32_t val)
1133{
1134 Log(("acpi: acpiPM1aStsWritew <- %#x (%#x)\n", val, val & ~(RSR_STS | IGN_STS)));
1135 if (val & PWRBTN_STS)
1136 s->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
1137 val = s->pm1a_sts & ~(val & ~(RSR_STS | IGN_STS));
1138 update_pm1a(s, val, s->pm1a_en);
1139}
1140
1141/* PM1a_CTL_BLK */
1142static uint32_t acpiPm1aCtlReadw(ACPIState *s, uint32_t addr)
1143{
1144 uint16_t val = s->pm1a_ctl;
1145 Log(("acpi: acpiPm1aCtlReadw -> %#x\n", val));
1146 return val;
1147}
1148
1149static int acpiPM1aCtlWritew(ACPIState *s, uint32_t addr, uint32_t val)
1150{
1151 uint32_t uSleepState;
1152
1153 Log(("acpi: acpiPM1aCtlWritew <- %#x (%#x)\n", val, val & ~(RSR_CNT | IGN_CNT)));
1154 s->pm1a_ctl = val & ~(RSR_CNT | IGN_CNT);
1155
1156 uSleepState = (s->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
1157 if (uSleepState != s->uSleepState)
1158 {
1159 s->uSleepState = uSleepState;
1160 switch (uSleepState)
1161 {
1162 case 0x00: /* S0 */
1163 break;
1164 case 0x05: /* S5 */
1165 LogRel(("Entering S5 (power down)\n"));
1166 return acpiPowerDown(s);
1167 default:
1168 AssertMsgFailed(("Unknown sleep state %#x\n", uSleepState));
1169 break;
1170 }
1171 }
1172 return VINF_SUCCESS;
1173}
1174
1175/* GPE0_BLK */
1176static uint32_t acpiGpe0EnReadb(ACPIState *s, uint32_t addr)
1177{
1178 uint8_t val = s->gpe0_en;
1179 Log(("acpi: acpiGpe0EnReadl -> %#x\n", val));
1180 return val;
1181}
1182
1183static void acpiGpe0EnWriteb(ACPIState *s, uint32_t addr, uint32_t val)
1184{
1185 Log(("acpi: acpiGpe0EnWritel <- %#x\n", val));
1186 update_gpe0(s, s->gpe0_sts, val);
1187}
1188
1189static uint32_t acpiGpe0StsReadb(ACPIState *s, uint32_t addr)
1190{
1191 uint8_t val = s->gpe0_sts;
1192 Log(("acpi: acpiGpe0StsReadl -> %#x\n", val));
1193 return val;
1194}
1195
1196static void acpiGpe0StsWriteb(ACPIState *s, uint32_t addr, uint32_t val)
1197{
1198 val = s->gpe0_sts & ~val;
1199 update_gpe0(s, val, s->gpe0_en);
1200 Log(("acpi: acpiGpe0StsWritel <- %#x\n", val));
1201}
1202
1203static int acpiResetWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1204{
1205 int rc = VINF_SUCCESS;
1206
1207 Log(("ACPI: acpiResetWriteU8: %x %x\n", addr, val));
1208 if (val == ACPI_RESET_REG_VAL)
1209 {
1210# ifndef IN_RING3
1211 rc = VINF_IOM_HC_IOPORT_WRITE;
1212# else /* IN_RING3 */
1213 rc = PDMDevHlpVMReset(s->pDevIns);
1214# endif /* !IN_RING3 */
1215 }
1216 return rc;
1217}
1218
1219/* SMI */
1220static void acpiSmiWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1221{
1222 Log(("acpi: acpiSmiWriteU8 %#x\n", val));
1223 if (val == ACPI_ENABLE)
1224 s->pm1a_ctl |= SCI_EN;
1225 else if (val == ACPI_DISABLE)
1226 s->pm1a_ctl &= ~SCI_EN;
1227 else
1228 Log(("acpi: acpiSmiWriteU8 %#x <- unknown value\n", val));
1229}
1230
1231static uint32_t find_rsdp_space(void)
1232{
1233 return 0xe0000;
1234}
1235
1236static int acpiPMTimerReset(ACPIState *s)
1237{
1238 uint64_t interval, freq;
1239
1240 freq = TMTimerGetFreq(s->CTX_SUFF(ts));
1241 interval = ASMMultU64ByU32DivByU32(0xffffffff, freq, PM_TMR_FREQ);
1242 Log(("interval = %RU64\n", interval));
1243 TMTimerSet(s->CTX_SUFF(ts), TMTimerGet(s->CTX_SUFF(ts)) + interval);
1244
1245 return VINF_SUCCESS;
1246}
1247
1248static DECLCALLBACK(void) acpiTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1249{
1250 ACPIState *s = (ACPIState *)pvUser;
1251
1252 Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
1253 s->pm1a_sts, (s->pm1a_sts & TMR_STS) != 0,
1254 s->pm1a_en, (s->pm1a_en & TMR_EN) != 0));
1255
1256 update_pm1a(s, s->pm1a_sts | TMR_STS, s->pm1a_en);
1257 acpiPMTimerReset(s);
1258}
1259
1260/**
1261 * _BST method.
1262 */
1263static int acpiFetchBatteryStatus(ACPIState *s)
1264{
1265 uint32_t *p = s->au8BatteryInfo;
1266 bool fPresent; /* battery present? */
1267 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1268 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1269 uint32_t hostPresentRate; /* 0..1000 */
1270 int rc;
1271
1272 if (!s->pDrv)
1273 return VINF_SUCCESS;
1274 rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
1275 &hostBatteryState, &hostPresentRate);
1276 AssertRC(rc);
1277
1278 /* default values */
1279 p[BAT_STATUS_STATE] = hostBatteryState;
1280 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
1281 : hostPresentRate * 50; /* mW */
1282 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
1283 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
1284
1285 /* did we get a valid battery state? */
1286 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
1287 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
1288 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
1289 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
1290
1291 return VINF_SUCCESS;
1292}
1293
1294/**
1295 * _BIF method.
1296 */
1297static int acpiFetchBatteryInfo(ACPIState *s)
1298{
1299 uint32_t *p = s->au8BatteryInfo;
1300
1301 p[BAT_INFO_UNITS] = 0; /* mWh */
1302 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
1303 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
1304 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
1305 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
1306 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
1307 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
1308 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
1309 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
1310
1311 return VINF_SUCCESS;
1312}
1313
1314/**
1315 * _STA method.
1316 */
1317static uint32_t acpiGetBatteryDeviceStatus(ACPIState *s)
1318{
1319 bool fPresent; /* battery present? */
1320 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1321 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1322 uint32_t hostPresentRate; /* 0..1000 */
1323 int rc;
1324
1325 if (!s->pDrv)
1326 return 0;
1327 rc = s->pDrv->pfnQueryBatteryStatus(s->pDrv, &fPresent, &hostRemainingCapacity,
1328 &hostBatteryState, &hostPresentRate);
1329 AssertRC(rc);
1330
1331 return fPresent
1332 ? STA_DEVICE_PRESENT_MASK /* present */
1333 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1334 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1335 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1336 | STA_BATTERY_PRESENT_MASK /* battery is present */
1337 : 0; /* device not present */
1338}
1339
1340static uint32_t acpiGetPowerSource(ACPIState *s)
1341{
1342 PDMACPIPOWERSOURCE ps;
1343
1344 /* query the current power source from the host driver */
1345 if (!s->pDrv)
1346 return AC_ONLINE;
1347 int rc = s->pDrv->pfnQueryPowerSource(s->pDrv, &ps);
1348 AssertRC(rc);
1349 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1350}
1351
1352PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1353{
1354 ACPIState *s = (ACPIState *)pvUser;
1355
1356 switch (cb)
1357 {
1358 case 4:
1359 u32 >>= s->u8IndexShift;
1360 /* see comment at the declaration of u8IndexShift */
1361 if (s->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
1362 {
1363 s->u8IndexShift = 2;
1364 u32 >>= 2;
1365 }
1366 Assert(u32 < BAT_INDEX_LAST);
1367 s->uBatteryIndex = u32;
1368 break;
1369 default:
1370 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1371 break;
1372 }
1373 return VINF_SUCCESS;
1374}
1375
1376PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1377{
1378 ACPIState *s = (ACPIState *)pvUser;
1379
1380 switch (cb)
1381 {
1382 case 4:
1383 switch (s->uBatteryIndex)
1384 {
1385 case BAT_STATUS_STATE:
1386 acpiFetchBatteryStatus(s);
1387 case BAT_STATUS_PRESENT_RATE:
1388 case BAT_STATUS_REMAINING_CAPACITY:
1389 case BAT_STATUS_PRESENT_VOLTAGE:
1390 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1391 break;
1392
1393 case BAT_INFO_UNITS:
1394 acpiFetchBatteryInfo(s);
1395 case BAT_INFO_DESIGN_CAPACITY:
1396 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1397 case BAT_INFO_TECHNOLOGY:
1398 case BAT_INFO_DESIGN_VOLTAGE:
1399 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1400 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1401 case BAT_INFO_CAPACITY_GRANULARITY_1:
1402 case BAT_INFO_CAPACITY_GRANULARITY_2:
1403 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1404 break;
1405
1406 case BAT_DEVICE_STATUS:
1407 *pu32 = acpiGetBatteryDeviceStatus(s);
1408 break;
1409
1410 case BAT_POWER_SOURCE:
1411 *pu32 = acpiGetPowerSource(s);
1412 break;
1413
1414 default:
1415 AssertMsgFailed(("Invalid battery index %d\n", s->uBatteryIndex));
1416 break;
1417 }
1418 break;
1419 default:
1420 return VERR_IOM_IOPORT_UNUSED;
1421 }
1422 return VINF_SUCCESS;
1423}
1424
1425PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1426{
1427 ACPIState *s = (ACPIState *)pvUser;
1428
1429 Log(("system_index = %d, %d\n", u32, u32 >> 2));
1430 switch (cb)
1431 {
1432 case 4:
1433 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1434 s->uSystemInfoIndex = u32;
1435 else
1436 {
1437 /* see comment at the declaration of u8IndexShift */
1438 if (s->u8IndexShift == 0)
1439 {
1440 if (((u32 >> 2) < SYSTEM_INFO_INDEX_END) && ((u32 & 0x3)) == 0)
1441 {
1442 s->u8IndexShift = 2;
1443 }
1444 }
1445
1446 u32 >>= s->u8IndexShift;
1447 Assert(u32 < SYSTEM_INFO_INDEX_END);
1448 s->uSystemInfoIndex = u32;
1449 }
1450 break;
1451
1452 default:
1453 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1454 break;
1455 }
1456 return VINF_SUCCESS;
1457}
1458
1459PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1460{
1461 ACPIState *s = (ACPIState *)pvUser;
1462
1463 switch (cb)
1464 {
1465 case 4:
1466 switch (s->uSystemInfoIndex)
1467 {
1468 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
1469 *pu32 = s->cbRamLow;
1470 break;
1471
1472 case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
1473 *pu32 = s->cbRamHigh >> 16; /* 64KB units */
1474 Assert(((uint64_t)*pu32 << 16) == s->cbRamHigh);
1475 break;
1476
1477 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1478 *pu32 = s->u8UseIOApic;
1479 break;
1480
1481 case SYSTEM_INFO_INDEX_HPET_STATUS:
1482 *pu32 = s->fUseHpet ? ( STA_DEVICE_PRESENT_MASK
1483 | STA_DEVICE_ENABLED_MASK
1484 | STA_DEVICE_SHOW_IN_UI_MASK
1485 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1486 : 0;
1487 break;
1488
1489 case SYSTEM_INFO_INDEX_SMC_STATUS:
1490 *pu32 = s->fUseSmc ? ( STA_DEVICE_PRESENT_MASK
1491 | STA_DEVICE_ENABLED_MASK
1492 /* no need to show this device in the UI */
1493 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1494 : 0;
1495 break;
1496
1497 case SYSTEM_INFO_INDEX_FDC_STATUS:
1498 *pu32 = s->fUseFdc ? ( STA_DEVICE_PRESENT_MASK
1499 | STA_DEVICE_ENABLED_MASK
1500 | STA_DEVICE_SHOW_IN_UI_MASK
1501 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1502 : 0;
1503 break;
1504
1505
1506 case SYSTEM_INFO_INDEX_CPU0_STATUS:
1507 case SYSTEM_INFO_INDEX_CPU1_STATUS:
1508 case SYSTEM_INFO_INDEX_CPU2_STATUS:
1509 case SYSTEM_INFO_INDEX_CPU3_STATUS:
1510 *pu32 = s->fShowCpu
1511 && s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < s->cCpus
1512 && VMCPUSET_IS_PRESENT(&s->CpuSetAttached, s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS)
1513 ?
1514 STA_DEVICE_PRESENT_MASK
1515 | STA_DEVICE_ENABLED_MASK
1516 | STA_DEVICE_SHOW_IN_UI_MASK
1517 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK
1518 : 0;
1519
1520 case SYSTEM_INFO_INDEX_RTC_STATUS:
1521 *pu32 = s->fShowRtc ? ( STA_DEVICE_PRESENT_MASK
1522 | STA_DEVICE_ENABLED_MASK
1523 | STA_DEVICE_SHOW_IN_UI_MASK
1524 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1525 : 0;
1526 break;
1527
1528 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1529 {
1530 if (s->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1531 {
1532 *pu32 = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, s->idCpuLockCheck);
1533 s->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1534 }
1535 else
1536 {
1537 AssertMsgFailed(("ACPI: CPU lock check protocol violation\n"));
1538 /* Always return locked status just to be safe */
1539 *pu32 = 1;
1540 }
1541 break;
1542 }
1543
1544 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1545 {
1546 *pu32 = s->u32CpuEventType;
1547 break;
1548 }
1549
1550 case SYSTEM_INFO_INDEX_CPU_EVENT:
1551 {
1552 *pu32 = s->u32CpuEvent;
1553 break;
1554 }
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