VirtualBox

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

Last change on this file since 31768 was 31519, checked in by vboxsync, 14 years ago

Audio: provide ACPI info for audio card to Mac guests

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