VirtualBox

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

最後變更 在這個檔案從27765是 27666,由 vboxsync 提交於 15 年 前

DevACPI.cpp: Restored code removed in r58897 as it is techincally still required for some really (?) odd restore scenarios.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 95.3 KB
 
1/* $Id: DevACPI.cpp 27666 2010-03-24 13:15:14Z 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.alldomusa.eu.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
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 /* This is only for compatability with older saved states that
1506 may include ACPI code that read these values. Legacy is
1507 a wonderful thing, isn't it? :-) */
1508 case SYSTEM_INFO_INDEX_CPU0_STATUS:
1509 case SYSTEM_INFO_INDEX_CPU1_STATUS:
1510 case SYSTEM_INFO_INDEX_CPU2_STATUS:
1511 case SYSTEM_INFO_INDEX_CPU3_STATUS:
1512 *pu32 = ( s->fShowCpu
1513 && s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < s->cCpus
1514 && VMCPUSET_IS_PRESENT(&s->CpuSetAttached,
1515 s->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS))
1516 ? ( STA_DEVICE_PRESENT_MASK
1517 | STA_DEVICE_ENABLED_MASK
1518 | STA_DEVICE_SHOW_IN_UI_MASK
1519 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1520 : 0;
1521 break;
1522
1523 case SYSTEM_INFO_INDEX_RTC_STATUS:
1524 *pu32 = s->fShowRtc ? ( STA_DEVICE_PRESENT_MASK
1525 | STA_DEVICE_ENABLED_MASK
1526 | STA_DEVICE_SHOW_IN_UI_MASK
1527 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1528 : 0;
1529 break;
1530
1531 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1532 {
1533 if (s->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1534 {
1535 *pu32 = VMCPUSET_IS_PRESENT(&s->CpuSetLocked, s->idCpuLockCheck);
1536 s->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1537 }
1538 else
1539 {
1540 AssertMsgFailed(("ACPI: CPU lock check protocol violation\n"));
1541 /* Always return locked status just to be safe */
1542 *pu32 = 1;
1543 }
1544 break;
1545 }
1546
1547 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1548 *pu32 = s->u32CpuEventType;
1549 break;
1550
1551 case SYSTEM_INFO_INDEX_CPU_EVENT:
1552 *pu32 = s->u32CpuEvent;
1553 break;
1554
1555 /* Solaris 9 tries to read from this index */
1556 case SYSTEM_INFO_INDEX_INVALID:
1557 *pu32 = 0;
1558 break;
1559
1560 default:
1561 AssertMsgFailed(("Invalid system info index %d\n", s->uSystemInfoIndex));
1562 break;
1563 }
1564 break;
1565
1566 default:
1567 return VERR_IOM_IOPORT_UNUSED;
1568 }
1569
1570 Log(("index %d val %d\n", s->uSystemInfoIndex, *pu32));
1571 return VINF_SUCCESS;
1572}
1573
1574PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1575{
1576 ACPIState *s = (ACPIState *)pvUser;
1577
1578 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, s->uSystemInfoIndex));
1579
1580 if (cb == 4)
1581 {
1582 switch (s->uSystemInfoIndex)
1583 {
1584 case SYSTEM_INFO_INDEX_INVALID:
1585 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1586 s->u8IndexShift = 0;
1587 break;
1588
1589 case SYSTEM_INFO_INDEX_VALID:
1590 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1591 s->u8IndexShift = 2;
1592 break;
1593
1594 case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
1595 s->idCpuLockCheck = u32;
1596 break;
1597
1598 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1599 if (u32 < s->cCpus)
1600 VMCPUSET_DEL(&s->CpuSetLocked, u32); /* Unlock the CPU */
1601 else
1602 LogRel(("ACPI: CPU %u does not exist\n", u32));
1603 break;
1604
1605 default:
1606 AssertMsgFailed(("Port=%#x cb=%d u32=%#x system_index=%#x\n",
1607 Port, cb, u32, s->uSystemInfoIndex));
1608 break;
1609 }
1610 }
1611 else
1612 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1613 return VINF_SUCCESS;
1614}
1615
1616/** @todo Don't call functions, but do the job in the read/write handlers
1617 * here! */
1618
1619/* IO Helpers */
1620PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1621{
1622 switch (cb)
1623 {
1624 case 2:
1625 *pu32 = acpiPm1aEnReadw((ACPIState*)pvUser, Port);
1626 break;
1627 default:
1628 return VERR_IOM_IOPORT_UNUSED;
1629 }
1630 return VINF_SUCCESS;
1631}
1632
1633PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1634{
1635 switch (cb)
1636 {
1637 case 2:
1638 *pu32 = acpiPm1aStsReadw((ACPIState*)pvUser, Port);
1639 break;
1640 default:
1641 return VERR_IOM_IOPORT_UNUSED;
1642 }
1643 return VINF_SUCCESS;
1644}
1645
1646PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1647{
1648 switch (cb)
1649 {
1650 case 2:
1651 *pu32 = acpiPm1aCtlReadw((ACPIState*)pvUser, Port);
1652 break;
1653 default:
1654 return VERR_IOM_IOPORT_UNUSED;
1655 }
1656 return VINF_SUCCESS;
1657}
1658
1659PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1660{
1661 switch (cb)
1662 {
1663 case 2:
1664 acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32);
1665 break;
1666 case 4:
1667 acpiPM1aEnWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1668 break;
1669 default:
1670 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1671 break;
1672 }
1673 return VINF_SUCCESS;
1674}
1675
1676PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1677{
1678 switch (cb)
1679 {
1680 case 2:
1681 acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32);
1682 break;
1683 case 4:
1684 acpiPM1aStsWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1685 break;
1686 default:
1687 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1688 break;
1689 }
1690 return VINF_SUCCESS;
1691}
1692
1693PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1694{
1695 switch (cb)
1696 {
1697 case 2:
1698 return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32);
1699 case 4:
1700 return acpiPM1aCtlWritew((ACPIState*)pvUser, Port, u32 & 0xffff);
1701 default:
1702 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1703 break;
1704 }
1705 return VINF_SUCCESS;
1706}
1707
1708#endif /* IN_RING3 */
1709
1710/**
1711 * PMTMR readable from host/guest.
1712 */
1713PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1714{
1715 if (cb == 4)
1716 {
1717 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
1718 int64_t now = TMTimerGet(s->CTX_SUFF(ts));
1719 int64_t elapsed = now - s->pm_timer_initial;
1720
1721 *pu32 = ASMMultU64ByU32DivByU32(elapsed, PM_TMR_FREQ, TMTimerGetFreq(s->CTX_SUFF(ts)));
1722 Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
1723 return VINF_SUCCESS;
1724 }
1725 return VERR_IOM_IOPORT_UNUSED;
1726}
1727
1728#ifdef IN_RING3
1729
1730PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1731{
1732 switch (cb)
1733 {
1734 case 1:
1735 *pu32 = acpiGpe0StsReadb((ACPIState*)pvUser, Port);
1736 break;
1737 default:
1738 return VERR_IOM_IOPORT_UNUSED;
1739 }
1740 return VINF_SUCCESS;
1741}
1742
1743PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1744{
1745 switch (cb)
1746 {
1747 case 1:
1748 *pu32 = acpiGpe0EnReadb((ACPIState*)pvUser, Port);
1749 break;
1750 default:
1751 return VERR_IOM_IOPORT_UNUSED;
1752 }
1753 return VINF_SUCCESS;
1754}
1755
1756PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1757{
1758 switch (cb)
1759 {
1760 case 1:
1761 acpiGpe0StsWriteb((ACPIState*)pvUser, Port, u32);
1762 break;
1763 default:
1764 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1765 break;
1766 }
1767 return VINF_SUCCESS;
1768}
1769
1770PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1771{
1772 switch (cb)
1773 {
1774 case 1:
1775 acpiGpe0EnWriteb((ACPIState*)pvUser, Port, u32);
1776 break;
1777 default:
1778 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1779 break;
1780 }
1781 return VINF_SUCCESS;
1782}
1783
1784PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1785{
1786 switch (cb)
1787 {
1788 case 1:
1789 acpiSmiWriteU8((ACPIState*)pvUser, Port, u32);
1790 break;
1791 default:
1792 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1793 break;
1794 }
1795 return VINF_SUCCESS;
1796}
1797
1798PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1799{
1800 switch (cb)
1801 {
1802 case 1:
1803 return acpiResetWriteU8((ACPIState*)pvUser, Port, u32);
1804 default:
1805 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1806 break;
1807 }
1808 return VINF_SUCCESS;
1809}
1810
1811#ifdef DEBUG_ACPI
1812
1813PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1814{
1815 switch (cb)
1816 {
1817 case 1:
1818 Log(("%#x\n", u32 & 0xff));
1819 break;
1820 case 2:
1821 Log(("%#6x\n", u32 & 0xffff));
1822 case 4:
1823 Log(("%#10x\n", u32));
1824 break;
1825 default:
1826 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1827 break;
1828 }
1829 return VINF_SUCCESS;
1830}
1831
1832PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1833{
1834 switch (cb)
1835 {
1836 case 1:
1837 Log(("%c", u32 & 0xff));
1838 break;
1839 default:
1840 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1841 break;
1842 }
1843 return VINF_SUCCESS;
1844}
1845
1846#endif /* DEBUG_ACPI */
1847
1848static int acpiRegisterPmHandlers(ACPIState* pThis)
1849{
1850 int rc = VINF_SUCCESS;
1851
1852#define R(offset, cnt, writer, reader, description) \
1853 do { \
1854 rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt, pThis, writer, reader, \
1855 NULL, NULL, description); \
1856 if (RT_FAILURE(rc)) \
1857 return rc; \
1858 } while (0)
1859#define L (GPE0_BLK_LEN / 2)
1860
1861 R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
1862 R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
1863 R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
1864 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
1865 R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
1866 R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
1867#undef L
1868#undef R
1869
1870 /* register RC stuff */
1871 if (pThis->fGCEnabled)
1872 {
1873 rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
1874 1, 0, NULL, "acpiPMTmrRead",
1875 NULL, NULL, "ACPI PM Timer");
1876 AssertRCReturn(rc, rc);
1877 }
1878
1879 /* register R0 stuff */
1880 if (pThis->fR0Enabled)
1881 {
1882 rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiPmPort(pThis, PM_TMR_OFFSET),
1883 1, 0, NULL, "acpiPMTmrRead",
1884 NULL, NULL, "ACPI PM Timer");
1885 AssertRCReturn(rc, rc);
1886 }
1887
1888 return rc;
1889}
1890
1891static int acpiUnregisterPmHandlers(ACPIState *pThis)
1892{
1893#define U(offset, cnt) \
1894 do { \
1895 int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiPmPort(pThis, offset), cnt); \
1896 AssertRCReturn(rc, rc); \
1897 } while (0)
1898#define L (GPE0_BLK_LEN / 2)
1899
1900 U(PM1a_EVT_OFFSET+2, 1);
1901 U(PM1a_EVT_OFFSET, 1);
1902 U(PM1a_CTL_OFFSET, 1);
1903 U(PM_TMR_OFFSET, 1);
1904 U(GPE0_OFFSET + L, L);
1905 U(GPE0_OFFSET, L);
1906#undef L
1907#undef U
1908
1909 return VINF_SUCCESS;
1910}
1911
1912/**
1913 * Saved state structure description, version 4.
1914 */
1915static const SSMFIELD g_AcpiSavedStateFields4[] =
1916{
1917 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1918 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1919 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1920 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
1921 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1922 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1923 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1924 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1925 SSMFIELD_ENTRY(ACPIState, u64RamSize),
1926 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1927 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
1928 SSMFIELD_ENTRY(ACPIState, uSleepState),
1929 SSMFIELD_ENTRY_TERM()
1930};
1931
1932/**
1933 * Saved state structure description, version 5.
1934 */
1935static const SSMFIELD g_AcpiSavedStateFields5[] =
1936{
1937 SSMFIELD_ENTRY(ACPIState, pm1a_en),
1938 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
1939 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
1940 SSMFIELD_ENTRY(ACPIState, pm_timer_initial),
1941 SSMFIELD_ENTRY(ACPIState, gpe0_en),
1942 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
1943 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
1944 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
1945 SSMFIELD_ENTRY(ACPIState, uSleepState),
1946 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
1947 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
1948 SSMFIELD_ENTRY_TERM()
1949};
1950
1951
1952static DECLCALLBACK(int) acpi_save_state(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1953{
1954 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
1955 return SSMR3PutStruct(pSSMHandle, s, &g_AcpiSavedStateFields5[0]);
1956}
1957
1958static DECLCALLBACK(int) acpi_load_state(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
1959 uint32_t uVersion, uint32_t uPass)
1960{
1961 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
1962
1963 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1964 /*
1965 * Unregister PM handlers, will register with actual base
1966 * after state successfully loaded.
1967 */
1968 int rc = acpiUnregisterPmHandlers(s);
1969 if (RT_FAILURE(rc))
1970 return rc;
1971
1972 switch (uVersion)
1973 {
1974 case 4:
1975 rc = SSMR3GetStruct(pSSMHandle, s, &g_AcpiSavedStateFields4[0]);
1976 /** @todo Provide saner defaults for fields not found in saved state. */
1977 break;
1978 case 5:
1979 rc = SSMR3GetStruct(pSSMHandle, s, &g_AcpiSavedStateFields5[0]);
1980 break;
1981 default:
1982 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1983 }
1984 if (RT_SUCCESS(rc))
1985 {
1986 rc = acpiRegisterPmHandlers(s);
1987 if (RT_FAILURE(rc))
1988 return rc;
1989 rc = acpiFetchBatteryStatus(s);
1990 if (RT_FAILURE(rc))
1991 return rc;
1992 rc = acpiFetchBatteryInfo(s);
1993 if (RT_FAILURE(rc))
1994 return rc;
1995 rc = acpiPMTimerReset(s);
1996 if (RT_FAILURE(rc))
1997 return rc;
1998 }
1999 return rc;
2000}
2001
2002/**
2003 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2004 */
2005static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2006{
2007 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
2008 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2009 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
2010 return NULL;
2011}
2012
2013/**
2014 * Create the ACPI tables.
2015 */
2016static int acpiPlantTables(ACPIState *s)
2017{
2018 int rc;
2019 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
2020 RTGCPHYS32 GCPhysHpet = 0, GCPhysApic = 0, GCPhysSsdt = 0;
2021 uint32_t addend = 0;
2022 RTGCPHYS32 aGCPhysRsdt[4];
2023 RTGCPHYS32 aGCPhysXsdt[4];
2024 uint32_t cAddr, iMadt = 0, iHpet = 0, iSsdt = 0;
2025 size_t cbRsdt = sizeof(ACPITBLHEADER);
2026 size_t cbXsdt = sizeof(ACPITBLHEADER);
2027
2028 cAddr = 1; /* FADT */
2029 if (s->u8UseIOApic)
2030 iMadt = cAddr++; /* MADT */
2031
2032 if (s->fUseHpet)
2033 iHpet = cAddr++; /* HPET */
2034
2035 iSsdt = cAddr++; /* SSDT */
2036
2037 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
2038 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
2039
2040 rc = CFGMR3QueryU64(s->pDevIns->pCfg, "RamSize", &s->u64RamSize);
2041 if (RT_FAILURE(rc))
2042 return PDMDEV_SET_ERROR(s->pDevIns, rc,
2043 N_("Configuration error: Querying \"RamSize\" as integer failed"));
2044
2045 uint32_t cbRamHole;
2046 rc = CFGMR3QueryU32Def(s->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
2047 if (RT_FAILURE(rc))
2048 return PDMDEV_SET_ERROR(s->pDevIns, rc,
2049 N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
2050
2051 /*
2052 * Calculate the sizes for the high and low regions.
2053 */
2054 const uint64_t offRamHole = _4G - cbRamHole;
2055 s->cbRamHigh = offRamHole < s->u64RamSize ? s->u64RamSize - offRamHole : 0;
2056 uint64_t cbRamLow = offRamHole < s->u64RamSize ? offRamHole : s->u64RamSize;
2057 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
2058 {
2059 /* Note: This is also enforced by DevPcBios.cpp. */
2060 LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
2061 cbRamLow = UINT32_C(0xffe00000);
2062 }
2063 s->cbRamLow = (uint32_t)cbRamLow;
2064
2065 GCPhysCur = 0;
2066 GCPhysRsdt = GCPhysCur;
2067
2068 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
2069 GCPhysXsdt = GCPhysCur;
2070
2071 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
2072 GCPhysFadtAcpi1 = GCPhysCur;
2073
2074 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
2075 GCPhysFadtAcpi2 = GCPhysCur;
2076
2077 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
2078 GCPhysFacs = GCPhysCur;
2079
2080 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
2081 if (s->u8UseIOApic)
2082 {
2083 GCPhysApic = GCPhysCur;
2084 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(s, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
2085 }
2086 if (s->fUseHpet)
2087 {
2088 GCPhysHpet = GCPhysCur;
2089 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
2090 }
2091
2092 void* pSsdtCode = NULL;
2093 size_t cbSsdtSize = 0;
2094 rc = acpiPrepareSsdt(s->pDevIns, &pSsdtCode, &cbSsdtSize);
2095 if (RT_FAILURE(rc))
2096 return rc;
2097
2098 GCPhysSsdt = GCPhysCur;
2099 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdtSize, 16);
2100
2101 GCPhysDsdt = GCPhysCur;
2102
2103 void* pDsdtCode = NULL;
2104 size_t cbDsdtSize = 0;
2105 rc = acpiPrepareDsdt(s->pDevIns, &pDsdtCode, &cbDsdtSize);
2106 if (RT_FAILURE(rc))
2107 return rc;
2108
2109 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
2110
2111 if (GCPhysCur > 0x10000)
2112 return PDMDEV_SET_ERROR(s->pDevIns, VERR_TOO_MUCH_DATA,
2113 N_("Error: ACPI tables bigger than 64KB"));
2114
2115 Log(("RSDP 0x%08X\n", find_rsdp_space()));
2116 addend = s->cbRamLow - 0x10000;
2117 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
2118 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
2119 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
2120 if (s->u8UseIOApic)
2121 Log((" MADT 0x%08X", GCPhysApic + addend));
2122 if (s->fUseHpet)
2123 Log((" HPET 0x%08X", GCPhysHpet + addend));
2124 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
2125 Log(("\n"));
2126
2127 acpiSetupRSDP((ACPITBLRSDP*)s->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
2128 acpiSetupDSDT(s, GCPhysDsdt + addend, pDsdtCode, cbDsdtSize);
2129 acpiCleanupDsdt(s->pDevIns, pDsdtCode);
2130 acpiSetupFACS(s, GCPhysFacs + addend);
2131 acpiSetupFADT(s, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
2132
2133 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
2134 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
2135 if (s->u8UseIOApic)
2136 {
2137 acpiSetupMADT(s, GCPhysApic + addend);
2138 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
2139 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
2140 }
2141 if (s->fUseHpet)
2142 {
2143 acpiSetupHPET(s, GCPhysHpet + addend);
2144 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
2145 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
2146 }
2147 acpiSetupSSDT(s, GCPhysSsdt + addend, pSsdtCode, cbSsdtSize);
2148 acpiCleanupSsdt(s->pDevIns, pSsdtCode);
2149 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
2150 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
2151
2152 rc = acpiSetupRSDT(s, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
2153 if (RT_FAILURE(rc))
2154 return rc;
2155 return acpiSetupXSDT(s, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
2156}
2157
2158static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT uNewBase)
2159{
2160 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, uNewBase));
2161 if (uNewBase != pThis->uPmIoPortBase)
2162 {
2163 int rc;
2164
2165 rc = acpiUnregisterPmHandlers(pThis);
2166 if (RT_FAILURE(rc))
2167 return rc;
2168
2169 pThis->uPmIoPortBase = uNewBase;
2170
2171 rc = acpiRegisterPmHandlers(pThis);
2172 if (RT_FAILURE(rc))
2173 return rc;
2174
2175 /* We have to update FADT table acccording to the new base */
2176 rc = acpiPlantTables(pThis);
2177 AssertRC(rc);
2178 if (RT_FAILURE(rc))
2179 return rc;
2180 }
2181
2182 return VINF_SUCCESS;
2183}
2184
2185static uint32_t acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
2186{
2187 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2188 ACPIState* pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2189
2190 Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
2191
2192 return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
2193}
2194
2195static void acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
2196{
2197 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2198 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2199
2200 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
2201 pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
2202
2203 /* PMREGMISC written */
2204 if (Address == 0x80)
2205 {
2206 /* Check Power Management IO Space Enable (PMIOSE) bit */
2207 if (pPciDev->config[0x80] & 0x1)
2208 {
2209 int rc;
2210
2211 RTIOPORT uNewBase =
2212 RTIOPORT(RT_LE2H_U32(*(uint32_t*)&pPciDev->config[0x40]));
2213 uNewBase &= 0xffc0;
2214
2215 rc = acpiUpdatePmHandlers(pThis, uNewBase);
2216 AssertRC(rc);
2217 }
2218 }
2219}
2220
2221/**
2222 * Attach a new CPU.
2223 *
2224 * @returns VBox status code.
2225 * @param pDevIns The device instance.
2226 * @param iLUN The logical unit which is being attached.
2227 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2228 *
2229 * @remarks This code path is not used during construction.
2230 */
2231static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2232{
2233 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2234
2235 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2236
2237 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2238 ("Hot-plug flag is not set\n"),
2239 VERR_NOT_SUPPORTED);
2240 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
2241
2242 /* Check if it was already attached */
2243 if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
2244 return VINF_SUCCESS;
2245
2246 PPDMIBASE IBaseTmp;
2247 int rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &s->IBase, &IBaseTmp, "ACPI CPU");
2248
2249 if (RT_SUCCESS(rc))
2250 {
2251 /* Enable the CPU */
2252 VMCPUSET_ADD(&s->CpuSetAttached, iLUN);
2253
2254 /*
2255 * Lock the CPU because we don't know if the guest will use it or not.
2256 * Prevents ejection while the CPU is still used
2257 */
2258 VMCPUSET_ADD(&s->CpuSetLocked, iLUN);
2259 s->u32CpuEventType = CPU_EVENT_TYPE_ADD;
2260 s->u32CpuEvent = iLUN;
2261 /* Notify the guest */
2262 update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
2263 }
2264 return rc;
2265}
2266
2267/**
2268 * Detach notification.
2269 *
2270 * @param pDevIns The device instance.
2271 * @param iLUN The logical unit which is being detached.
2272 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2273 */
2274static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2275{
2276 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2277
2278 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
2279
2280 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
2281 ("Hot-plug flag is not set\n"));
2282
2283 /* Check if it was already detached */
2284 if (VMCPUSET_IS_PRESENT(&s->CpuSetAttached, iLUN))
2285 {
2286 AssertMsgReturnVoid(!(VMCPUSET_IS_PRESENT(&s->CpuSetLocked, iLUN)), ("CPU is still locked by the guest\n"));
2287
2288 /* Disable the CPU */
2289 VMCPUSET_DEL(&s->CpuSetAttached, iLUN);
2290 s->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
2291 s->u32CpuEvent = iLUN;
2292 /* Notify the guest */
2293 update_gpe0(s, s->gpe0_sts | 0x2, s->gpe0_en);
2294 }
2295}
2296
2297static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
2298{
2299 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2300
2301 s->pm1a_en = 0;
2302 s->pm1a_sts = 0;
2303 s->pm1a_ctl = 0;
2304 s->pm_timer_initial = TMTimerGet(s->CTX_SUFF(ts));
2305 acpiPMTimerReset(s);
2306 s->uBatteryIndex = 0;
2307 s->uSystemInfoIndex = 0;
2308 s->gpe0_en = 0;
2309 s->gpe0_sts = 0;
2310 s->uSleepState = 0;
2311
2312 /** @todo Should we really reset PM base? */
2313 acpiUpdatePmHandlers(s, PM_PORT_BASE);
2314
2315 acpiPlantTables(s);
2316}
2317
2318/**
2319 * Relocates the GC pointer members.
2320 */
2321static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2322{
2323 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2324 s->tsRC = TMTimerRCPtr(s->CTX_SUFF(ts));
2325}
2326
2327/**
2328 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2329 */
2330static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2331{
2332 ACPIState *s = PDMINS_2_DATA(pDevIns, ACPIState *);
2333 PCIDevice *dev = &s->dev;
2334 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2335
2336 /* Validate and read the configuration. */
2337 if (!CFGMR3AreValuesValid(pCfg,
2338 "RamSize\0"
2339 "RamHoleSize\0"
2340 "IOAPIC\0"
2341 "NumCPUs\0"
2342 "GCEnabled\0"
2343 "R0Enabled\0"
2344 "HpetEnabled\0"
2345 "SmcEnabled\0"
2346 "FdcEnabled\0"
2347 "ShowRtc\0"
2348 "ShowCpu\0"
2349 "CpuHotPlug\0"
2350 "AmlFilePath\0"
2351 ))
2352 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2353 N_("Configuration error: Invalid config key for ACPI device"));
2354
2355 s->pDevIns = pDevIns;
2356
2357 /* query whether we are supposed to present an IOAPIC */
2358 int rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &s->u8UseIOApic, 1);
2359 if (RT_FAILURE(rc))
2360 return PDMDEV_SET_ERROR(pDevIns, rc,
2361 N_("Configuration error: Failed to read \"IOAPIC\""));
2362
2363 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &s->cCpus, 1);
2364 if (RT_FAILURE(rc))
2365 return PDMDEV_SET_ERROR(pDevIns, rc,
2366 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
2367
2368 /* query whether we are supposed to present an FDC controller */
2369 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &s->fUseFdc, true);
2370 if (RT_FAILURE(rc))
2371 return PDMDEV_SET_ERROR(pDevIns, rc,
2372 N_("Configuration error: Failed to read \"FdcEnabled\""));
2373
2374 /* query whether we are supposed to present HPET */
2375 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &s->fUseHpet, false);
2376 if (RT_FAILURE(rc))
2377 return PDMDEV_SET_ERROR(pDevIns, rc,
2378 N_("Configuration error: Failed to read \"HpetEnabled\""));
2379 /* query whether we are supposed to present SMC */
2380 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &s->fUseSmc, false);
2381 if (RT_FAILURE(rc))
2382 return PDMDEV_SET_ERROR(pDevIns, rc,
2383 N_("Configuration error: Failed to read \"SmcEnabled\""));
2384
2385 /* query whether we are supposed to present RTC object */
2386 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &s->fShowRtc, false);
2387 if (RT_FAILURE(rc))
2388 return PDMDEV_SET_ERROR(pDevIns, rc,
2389 N_("Configuration error: Failed to read \"ShowRtc\""));
2390
2391 /* query whether we are supposed to present CPU objects */
2392 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &s->fShowCpu, false);
2393 if (RT_FAILURE(rc))
2394 return PDMDEV_SET_ERROR(pDevIns, rc,
2395 N_("Configuration error: Failed to read \"ShowCpu\""));
2396
2397 /* query whether we are allow CPU hot plugging */
2398 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &s->fCpuHotPlug, false);
2399 if (RT_FAILURE(rc))
2400 return PDMDEV_SET_ERROR(pDevIns, rc,
2401 N_("Configuration error: Failed to read \"CpuHotPlug\""));
2402
2403 rc = CFGMR3QueryBool(pCfg, "GCEnabled", &s->fGCEnabled);
2404 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2405 s->fGCEnabled = true;
2406 else if (RT_FAILURE(rc))
2407 return PDMDEV_SET_ERROR(pDevIns, rc,
2408 N_("Configuration error: Failed to read \"GCEnabled\""));
2409
2410 rc = CFGMR3QueryBool(pCfg, "R0Enabled", &s->fR0Enabled);
2411 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2412 s->fR0Enabled = true;
2413 else if (RT_FAILURE(rc))
2414 return PDMDEV_SET_ERROR(pDevIns, rc,
2415 N_("configuration error: failed to read R0Enabled as boolean"));
2416
2417 /*
2418 * Interfaces
2419 */
2420 /* IBase */
2421 s->IBase.pfnQueryInterface = acpiQueryInterface;
2422 /* IACPIPort */
2423 s->IACPIPort.pfnSleepButtonPress = acpiSleepButtonPress;
2424 s->IACPIPort.pfnPowerButtonPress = acpiPowerButtonPress;
2425 s->IACPIPort.pfnGetPowerButtonHandled = acpiGetPowerButtonHandled;
2426 s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiGetGuestEnteredACPIMode;
2427 s->IACPIPort.pfnGetCpuStatus = acpiGetCpuStatus;
2428
2429 VMCPUSET_EMPTY(&s->CpuSetAttached);
2430 VMCPUSET_EMPTY(&s->CpuSetLocked);
2431 s->idCpuLockCheck = UINT32_C(0xffffffff);
2432 s->u32CpuEventType = 0;
2433 s->u32CpuEvent = UINT32_C(0xffffffff);
2434
2435 /* The first CPU can't be attached/detached */
2436 VMCPUSET_ADD(&s->CpuSetAttached, 0);
2437 VMCPUSET_ADD(&s->CpuSetLocked, 0);
2438
2439 /* Try to attach the other CPUs */
2440 for (unsigned i = 1; i < s->cCpus; i++)
2441 {
2442 if (s->fCpuHotPlug)
2443 {
2444 PPDMIBASE IBaseTmp;
2445 rc = PDMDevHlpDriverAttach(pDevIns, i, &s->IBase, &IBaseTmp, "ACPI CPU");
2446
2447 if (RT_SUCCESS(rc))
2448 {
2449 VMCPUSET_ADD(&s->CpuSetAttached, i);
2450 VMCPUSET_ADD(&s->CpuSetLocked, i);
2451 Log(("acpi: Attached CPU %u\n", i));
2452 }
2453 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2454 Log(("acpi: CPU %u not attached yet\n", i));
2455 else
2456 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
2457 }
2458 else
2459 {
2460 /* CPU is always attached if hot-plug is not enabled. */
2461 VMCPUSET_ADD(&s->CpuSetAttached, i);
2462 VMCPUSET_ADD(&s->CpuSetLocked, i);
2463 }
2464 }
2465
2466
2467 /* Set default port base */
2468 s->uPmIoPortBase = PM_PORT_BASE;
2469
2470 /*
2471 * FDC and SMC try to use the same non-shareable interrupt (6),
2472 * enable only one device.
2473 */
2474 if (s->fUseSmc)
2475 s->fUseFdc = false;
2476
2477 /* */
2478 RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
2479 if (!GCPhysRsdp)
2480 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
2481 N_("Can not find space for RSDP. ACPI is disabled"));
2482
2483 rc = acpiPlantTables(s);
2484 if (RT_FAILURE(rc))
2485 return rc;
2486
2487 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, s->au8RSDPPage,
2488 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
2489 if (RT_FAILURE(rc))
2490 return rc;
2491
2492 rc = acpiRegisterPmHandlers(s);
2493 if (RT_FAILURE(rc))
2494 return rc;
2495
2496#define R(addr, cnt, writer, reader, description) \
2497 do { \
2498 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, s, writer, reader, \
2499 NULL, NULL, description); \
2500 if (RT_FAILURE(rc)) \
2501 return rc; \
2502 } while (0)
2503 R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
2504#ifdef DEBUG_ACPI
2505 R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
2506 R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
2507#endif
2508 R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
2509 R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
2510 R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
2511 R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
2512 R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
2513#undef R
2514
2515 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiTimer, dev,
2516 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "ACPI Timer", &s->tsR3);
2517 if (RT_FAILURE(rc))
2518 {
2519 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
2520 return rc;
2521 }
2522
2523 s->tsR0 = TMTimerR0Ptr(s->tsR3);
2524 s->tsRC = TMTimerRCPtr(s->tsR3);
2525 s->pm_timer_initial = TMTimerGet(s->tsR3);
2526 acpiPMTimerReset(s);
2527
2528 PCIDevSetVendorId(dev, 0x8086); /* Intel */
2529 PCIDevSetDeviceId(dev, 0x7113); /* 82371AB */
2530
2531 /* See p. 50 of PIIX4 manual */
2532 dev->config[0x04] = 0x01; /* command */
2533 dev->config[0x05] = 0x00;
2534
2535 dev->config[0x06] = 0x80; /* status */
2536 dev->config[0x07] = 0x02;
2537
2538 dev->config[0x08] = 0x08; /* revision number */
2539
2540 dev->config[0x09] = 0x00; /* class code */
2541 dev->config[0x0a] = 0x80;
2542 dev->config[0x0b] = 0x06;
2543
2544 dev->config[0x0e] = 0x80; /* header type */
2545
2546 dev->config[0x0f] = 0x00; /* reserved */
2547
2548 dev->config[0x3c] = SCI_INT; /* interrupt line */
2549
2550#if 0
2551 dev->config[0x3d] = 0x01; /* interrupt pin */
2552#endif
2553
2554 dev->config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
2555
2556#if 0
2557 int smb_io_base = 0xb100;
2558 dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
2559 dev->config[0x90] = smb_io_base >> 8;
2560#endif
2561
2562 rc = PDMDevHlpPCIRegister(pDevIns, dev);
2563 if (RT_FAILURE(rc))
2564 return rc;
2565
2566 PDMDevHlpPCISetConfigCallbacks(pDevIns, dev,
2567 acpiPciConfigRead, &s->pfnAcpiPciConfigRead,
2568 acpiPciConfigWrite, &s->pfnAcpiPciConfigWrite);
2569
2570 rc = PDMDevHlpSSMRegister(pDevIns, 5, sizeof(*s), acpi_save_state, acpi_load_state);
2571 if (RT_FAILURE(rc))
2572 return rc;
2573
2574 /*
2575 * Get the corresponding connector interface
2576 */
2577 rc = PDMDevHlpDriverAttach(pDevIns, 0, &s->IBase, &s->pDrvBase, "ACPI Driver Port");
2578 if (RT_SUCCESS(rc))
2579 {
2580 s->pDrv = PDMIBASE_QUERY_INTERFACE(s->pDrvBase, PDMIACPICONNECTOR);
2581 if (!s->pDrv)
2582 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
2583 N_("LUN #0 doesn't have an ACPI connector interface"));
2584 }
2585 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2586 {
2587 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
2588 pDevIns->pReg->szName, pDevIns->iInstance));
2589 rc = VINF_SUCCESS;
2590 }
2591 else
2592 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
2593
2594 return rc;
2595}
2596
2597/**
2598 * The device registration structure.
2599 */
2600const PDMDEVREG g_DeviceACPI =
2601{
2602 /* u32Version */
2603 PDM_DEVREG_VERSION,
2604 /* szName */
2605 "acpi",
2606 /* szRCMod */
2607 "VBoxDDGC.gc",
2608 /* szR0Mod */
2609 "VBoxDDR0.r0",
2610 /* pszDescription */
2611 "Advanced Configuration and Power Interface",
2612 /* fFlags */
2613 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2614 /* fClass */
2615 PDM_DEVREG_CLASS_ACPI,
2616 /* cMaxInstances */
2617 ~0,
2618 /* cbInstance */
2619 sizeof(ACPIState),
2620 /* pfnConstruct */
2621 acpiConstruct,
2622 /* pfnDestruct */
2623 NULL,
2624 /* pfnRelocate */
2625 acpiRelocate,
2626 /* pfnIOCtl */
2627 NULL,
2628 /* pfnPowerOn */
2629 NULL,
2630 /* pfnReset */
2631 acpiReset,
2632 /* pfnSuspend */
2633 NULL,
2634 /* pfnResume */
2635 NULL,
2636 /* pfnAttach */
2637 acpiAttach,
2638 /* pfnDetach */
2639 acpiDetach,
2640 /* pfnQueryInterface. */
2641 NULL,
2642 /* pfnInitComplete */
2643 NULL,
2644 /* pfnPowerOff */
2645 NULL,
2646 /* pfnSoftReset */
2647 NULL,
2648 /* u32VersionEnd */
2649 PDM_DEVREG_VERSION
2650};
2651
2652#endif /* IN_RING3 */
2653#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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