VirtualBox

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

Last change on this file since 30714 was 29250, checked in by vboxsync, 15 years ago

iprt/asm*.h: split out asm-math.h, don't include asm-*.h from asm.h, don't include asm.h from sup.h. Fixed a couple file headers.

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