VirtualBox

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

Last change on this file since 27452 was 27422, checked in by vboxsync, 15 years ago

ACPI: cleaned up no longer used CPU entries, made RTC on by default

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