VirtualBox

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

Last change on this file since 15682 was 14976, checked in by vboxsync, 16 years ago

Solaris 9 reads from invalid ACPI register - let it

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 68.7 KB
Line 
1/* $Id: DevACPI.cpp 14976 2008-12-04 12:50:07Z vboxsync $ */
2/** @file
3 * DevACPI - Advanced Configuration and Power Interface (ACPI) Device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#define LOG_GROUP LOG_GROUP_DEV_ACPI
23#include <VBox/pdmdev.h>
24#include <VBox/log.h>
25#include <iprt/assert.h>
26#include <iprt/asm.h>
27#ifdef IN_RING3
28# include <iprt/alloc.h>
29# include <iprt/string.h>
30#endif /* IN_RING3 */
31
32#include "../Builtins.h"
33
34#ifdef LOG_ENABLED
35# define DEBUG_ACPI
36#endif
37
38/* the compiled DSL */
39#if defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
40#include <vboxaml.hex>
41#endif /* !IN_RING3 */
42
43#define IO_READ_PROTO(name) \
44 PDMBOTHCBDECL(int) name (PPDMDEVINS pDevIns, void *pvUser, \
45 RTIOPORT Port, uint32_t *pu32, unsigned cb)
46
47#define IO_WRITE_PROTO(name) \
48 PDMBOTHCBDECL(int) name (PPDMDEVINS pDevIns, void *pvUser, \
49 RTIOPORT Port, uint32_t u32, unsigned cb)
50
51#define DEBUG_HEX 0x3000
52#define DEBUG_CHR 0x3001
53
54#define PM_TMR_FREQ 3579545
55#define PM1a_EVT_BLK 0x00004000
56#define PM1b_EVT_BLK 0x00000000 /**< not supported */
57#define PM1a_CTL_BLK 0x00004004
58#define PM1b_CTL_BLK 0x00000000 /**< not supported */
59#define PM2_CTL_BLK 0x00000000 /**< not supported */
60#define PM_TMR_BLK 0x00004008
61#define GPE0_BLK 0x00004020
62#define GPE1_BLK 0x00000000 /**< not supported */
63#define BAT_INDEX 0x00004040
64#define BAT_DATA 0x00004044
65#define SYSI_INDEX 0x00004048
66#define SYSI_DATA 0x0000404c
67#define ACPI_RESET_BLK 0x00004050
68#define FDC_STATUS 0x00004054
69
70/* PM1x status register bits */
71#define TMR_STS RT_BIT(0)
72#define RSR1_STS (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
73#define BM_STS RT_BIT(4)
74#define GBL_STS RT_BIT(5)
75#define RSR2_STS (RT_BIT(6) | RT_BIT(7))
76#define PWRBTN_STS RT_BIT(8)
77#define SLPBTN_STS RT_BIT(9)
78#define RTC_STS RT_BIT(10)
79#define IGN_STS RT_BIT(11)
80#define RSR3_STS (RT_BIT(12) | RT_BIT(13) | RT_BIT(14))
81#define WAK_STS RT_BIT(15)
82#define RSR_STS (RSR1_STS | RSR2_STS | RSR3_STS)
83
84/* PM1x enable register bits */
85#define TMR_EN RT_BIT(0)
86#define RSR1_EN (RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
87#define GBL_EN RT_BIT(5)
88#define RSR2_EN (RT_BIT(6) | RT_BIT(7))
89#define PWRBTN_EN RT_BIT(8)
90#define SLPBTN_EN RT_BIT(9)
91#define RTC_EN RT_BIT(10)
92#define RSR3_EN (RT_BIT(11) | RT_BIT(12) | RT_BIT(13) | RT_BIT(14) | RT_BIT(15))
93#define RSR_EN (RSR1_EN | RSR2_EN | RSR3_EN)
94#define IGN_EN 0
95
96/* PM1x control register bits */
97#define SCI_EN RT_BIT(0)
98#define BM_RLD RT_BIT(1)
99#define GBL_RLS RT_BIT(2)
100#define RSR1_CNT (RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7) | RT_BIT(8))
101#define IGN_CNT RT_BIT(9)
102#define SLP_TYPx_SHIFT 10
103#define SLP_TYPx_MASK 7
104#define SLP_EN RT_BIT(13)
105#define RSR2_CNT (RT_BIT(14) | RT_BIT(15))
106#define RSR_CNT (RSR1_CNT | RSR2_CNT)
107
108#define GPE0_BATTERY_INFO_CHANGED RT_BIT(0)
109
110enum
111{
112 BAT_STATUS_STATE = 0x00, /**< BST battery state */
113 BAT_STATUS_PRESENT_RATE = 0x01, /**< BST battery present rate */
114 BAT_STATUS_REMAINING_CAPACITY = 0x02, /**< BST battery remaining capacity */
115 BAT_STATUS_PRESENT_VOLTAGE = 0x03, /**< BST battery present voltage */
116 BAT_INFO_UNITS = 0x04, /**< BIF power unit */
117 BAT_INFO_DESIGN_CAPACITY = 0x05, /**< BIF design capacity */
118 BAT_INFO_LAST_FULL_CHARGE_CAPACITY = 0x06, /**< BIF last full charge capacity */
119 BAT_INFO_TECHNOLOGY = 0x07, /**< BIF battery technology */
120 BAT_INFO_DESIGN_VOLTAGE = 0x08, /**< BIF design voltage */
121 BAT_INFO_DESIGN_CAPACITY_OF_WARNING = 0x09, /**< BIF design capacity of warning */
122 BAT_INFO_DESIGN_CAPACITY_OF_LOW = 0x0A, /**< BIF design capacity of low */
123 BAT_INFO_CAPACITY_GRANULARITY_1 = 0x0B, /**< BIF battery capacity granularity 1 */
124 BAT_INFO_CAPACITY_GRANULARITY_2 = 0x0C, /**< BIF battery capacity granularity 2 */
125 BAT_DEVICE_STATUS = 0x0D, /**< STA device status */
126 BAT_POWER_SOURCE = 0x0E, /**< PSR power source */
127 BAT_INDEX_LAST
128};
129
130enum
131{
132 SYSTEM_INFO_INDEX_MEMORY_LENGTH = 0,
133 SYSTEM_INFO_INDEX_USE_IOAPIC = 1,
134 SYSTEM_INFO_INDEX_LAST = 2,
135 SYSTEM_INFO_INDEX_INVALID = 0x80,
136 SYSTEM_INFO_INDEX_VALID = 0x200
137};
138
139#define AC_OFFLINE 0
140#define AC_ONLINE 1
141
142#define BAT_TECH_PRIMARY 1
143#define BAT_TECH_SECONDARY 2
144
145#define STA_DEVICE_PRESENT_MASK RT_BIT(0)
146#define STA_DEVICE_ENABLED_MASK RT_BIT(1)
147#define STA_DEVICE_SHOW_IN_UI_MASK RT_BIT(2)
148#define STA_DEVICE_FUNCTIONING_PROPERLY_MASK RT_BIT(3)
149#define STA_BATTERY_PRESENT_MASK RT_BIT(4)
150
151struct ACPIState
152{
153 PCIDevice dev;
154 uint16_t pm1a_en;
155 uint16_t pm1a_sts;
156 uint16_t pm1a_ctl;
157 /** Number of logical CPUs in guest */
158 uint16_t cCpus;
159 int64_t pm_timer_initial;
160 PTMTIMERR3 tsR3;
161 PTMTIMERR0 tsR0;
162 PTMTIMERRC tsRC;
163
164 uint32_t gpe0_en;
165 uint32_t gpe0_sts;
166
167 unsigned int uBatteryIndex;
168 uint32_t au8BatteryInfo[13];
169
170 unsigned int uSystemInfoIndex;
171 uint64_t u64RamSize;
172
173 /** Current ACPI S* state. We support S0 and S5 */
174 uint32_t uSleepState;
175 uint8_t au8RSDPPage[0x1000];
176 /** This is a workaround for incorrect index field handling by Intels ACPICA.
177 * The system info _INI method writes to offset 0x200. We either observe a
178 * write request to index 0x80 (in that case we don't change the index) or a
179 * write request to offset 0x200 (in that case we divide the index value by
180 * 4. Note that the _STA method is sometimes called prior to the _INI method
181 * (ACPI spec 6.3.7, _STA). See the special case for BAT_DEVICE_STATUS in
182 * acpiBatIndexWrite() for handling this. */
183 uint8_t u8IndexShift;
184 uint8_t u8UseIOApic;
185 uint8_t u8UseFdc;
186 bool fPowerButtonHandled;
187
188 /** ACPI port base interface. */
189 PDMIBASE IBase;
190 /** ACPI port interface. */
191 PDMIACPIPORT IACPIPort;
192 /** Pointer to the device instance. */
193 PPDMDEVINSR3 pDevIns;
194 /** Pointer to the driver base interface */
195 R3PTRTYPE(PPDMIBASE) pDrvBase;
196 /** Pointer to the driver connector interface */
197 R3PTRTYPE(PPDMIACPICONNECTOR) pDrv;
198};
199
200#pragma pack(1)
201
202/** Generic Address Structure (see ACPIspec 3.0, 5.2.3.1) */
203struct ACPIGENADDR
204{
205 uint8_t u8AddressSpaceId; /**< 0=sys, 1=IO, 2=PCICfg, 3=emb, 4=SMBus */
206 uint8_t u8RegisterBitWidth; /**< size in bits of the given register */
207 uint8_t u8RegisterBitOffset; /**< bit offset of register */
208 uint8_t u8AccessSize; /**< 1=byte, 2=word, 3=dword, 4=qword */
209 uint64_t u64Address; /**< 64-bit address of register */
210};
211AssertCompileSize(ACPIGENADDR, 12);
212
213/** Root System Description Pointer */
214struct ACPITBLRSDP
215{
216 uint8_t au8Signature[8]; /**< 'RSD PTR ' */
217 uint8_t u8Checksum; /**< checksum for the first 20 bytes */
218 uint8_t au8OemId[6]; /**< OEM-supplied identifier */
219 uint8_t u8Revision; /**< revision number, currently 2 */
220#define ACPI_REVISION 2 /**< ACPI 3.0 */
221 uint32_t u32RSDT; /**< phys addr of RSDT */
222 uint32_t u32Length; /**< bytes of this table */
223 uint64_t u64XSDT; /**< 64-bit phys addr of XSDT */
224 uint8_t u8ExtChecksum; /**< checksum of entire table */
225 uint8_t u8Reserved[3]; /**< reserved */
226};
227AssertCompileSize(ACPITBLRSDP, 36);
228
229/** System Description Table Header */
230struct ACPITBLHEADER
231{
232 uint8_t au8Signature[4]; /**< table identifier */
233 uint32_t u32Length; /**< length of the table including header */
234 uint8_t u8Revision; /**< revision number */
235 uint8_t u8Checksum; /**< all fields inclusive this add to zero */
236 uint8_t au8OemId[6]; /**< OEM-supplied string */
237 uint8_t au8OemTabId[8]; /**< to identify the particular data table */
238 uint32_t u32OemRevision; /**< OEM-supplied revision number */
239 uint8_t au8CreatorId[4]; /**< ID for the ASL compiler */
240 uint32_t u32CreatorRev; /**< revision for the ASL compiler */
241};
242AssertCompileSize(ACPITBLHEADER, 36);
243
244/** Root System Description Table */
245struct ACPITBLRSDT
246{
247 ACPITBLHEADER header;
248 uint32_t u32Entry[1]; /**< array of phys. addresses to other tables */
249};
250AssertCompileSize(ACPITBLRSDT, 40);
251
252/** Extended System Description Table */
253struct ACPITBLXSDT
254{
255 ACPITBLHEADER header;
256 uint64_t u64Entry[1]; /**< array of phys. addresses to other tables */
257};
258AssertCompileSize(ACPITBLXSDT, 44);
259
260/** Fixed ACPI Description Table */
261struct ACPITBLFADT
262{
263 ACPITBLHEADER header;
264 uint32_t u32FACS; /**< phys. address of FACS */
265 uint32_t u32DSDT; /**< phys. address of DSDT */
266 uint8_t u8IntModel; /**< was eleminated in ACPI 2.0 */
267#define INT_MODEL_DUAL_PIC 1 /**< for ACPI 2+ */
268#define INT_MODEL_MULTIPLE_APIC 2
269 uint8_t u8PreferredPMProfile; /**< preferred power management profile */
270 uint16_t u16SCIInt; /**< system vector the SCI is wired in 8259 mode */
271#define SCI_INT 9
272 uint32_t u32SMICmd; /**< system port address of SMI command port */
273#define SMI_CMD 0x0000442e
274 uint8_t u8AcpiEnable; /**< SMICmd val to disable ownship of ACPIregs */
275#define ACPI_ENABLE 0xa1
276 uint8_t u8AcpiDisable; /**< SMICmd val to re-enable ownship of ACPIregs */
277#define ACPI_DISABLE 0xa0
278 uint8_t u8S4BIOSReq; /**< SMICmd val to enter S4BIOS state */
279 uint8_t u8PStateCnt; /**< SMICmd val to assume processor performance
280 state control responsibility */
281 uint32_t u32PM1aEVTBLK; /**< port addr of PM1a event regs block */
282 uint32_t u32PM1bEVTBLK; /**< port addr of PM1b event regs block */
283 uint32_t u32PM1aCTLBLK; /**< port addr of PM1a control regs block */
284 uint32_t u32PM1bCTLBLK; /**< port addr of PM1b control regs block */
285 uint32_t u32PM2CTLBLK; /**< port addr of PM2 control regs block */
286 uint32_t u32PMTMRBLK; /**< port addr of PMTMR regs block */
287 uint32_t u32GPE0BLK; /**< port addr of gen-purp event 0 regs block */
288 uint32_t u32GPE1BLK; /**< port addr of gen-purp event 1 regs block */
289 uint8_t u8PM1EVTLEN; /**< bytes decoded by PM1a_EVT_BLK. >= 4 */
290 uint8_t u8PM1CTLLEN; /**< bytes decoded by PM1b_CNT_BLK. >= 2 */
291 uint8_t u8PM2CTLLEN; /**< bytes decoded by PM2_CNT_BLK. >= 1 or 0 */
292 uint8_t u8PMTMLEN; /**< bytes decoded by PM_TMR_BLK. ==4 */
293 uint8_t u8GPE0BLKLEN; /**< bytes decoded by GPE0_BLK. %2==0 */
294#define GPE0_BLK_LEN 2
295 uint8_t u8GPE1BLKLEN; /**< bytes decoded by GPE1_BLK. %2==0 */
296#define GPE1_BLK_LEN 0
297 uint8_t u8GPE1BASE; /**< offset of GPE1 based events */
298#define GPE1_BASE 0
299 uint8_t u8CSTCNT; /**< SMICmd val to indicate OS supp for C states */
300 uint16_t u16PLVL2LAT; /**< us to enter/exit C2. >100 => unsupported */
301#define P_LVL2_LAT 101 /**< C2 state not supported */
302 uint16_t u16PLVL3LAT; /**< us to enter/exit C3. >1000 => unsupported */
303#define P_LVL3_LAT 1001 /**< C3 state not supported */
304 uint16_t u16FlushSize; /**< # of flush strides to read to flush dirty
305 lines from any processors memory caches */
306#define FLUSH_SIZE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
307 uint16_t u16FlushStride; /**< cache line width */
308#define FLUSH_STRIDE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
309 uint8_t u8DutyOffset;
310 uint8_t u8DutyWidth;
311 uint8_t u8DayAlarm; /**< RTC CMOS RAM index of day-of-month alarm */
312 uint8_t u8MonAlarm; /**< RTC CMOS RAM index of month-of-year alarm */
313 uint8_t u8Century; /**< RTC CMOS RAM index of century */
314 uint16_t u16IAPCBOOTARCH; /**< IA-PC boot architecture flags */
315#define IAPC_BOOT_ARCH_LEGACY_DEV RT_BIT(0) /**< legacy devices present such as LPT
316 (COM too?) */
317#define IAPC_BOOT_ARCH_8042 RT_BIT(1) /**< legacy keyboard device present */
318#define IAPC_BOOT_ARCH_NO_VGA RT_BIT(2) /**< VGA not present */
319 uint8_t u8Must0_0; /**< must be 0 */
320 uint32_t u32Flags; /**< fixed feature flags */
321#define FADT_FL_WBINVD RT_BIT(0) /**< emulation of WBINVD available */
322#define FADT_FL_WBINVD_FLUSH RT_BIT(1)
323#define FADT_FL_PROC_C1 RT_BIT(2) /**< 1=C1 supported on all processors */
324#define FADT_FL_P_LVL2_UP RT_BIT(3) /**< 1=C2 works on SMP and UNI systems */
325#define FADT_FL_PWR_BUTTON RT_BIT(4) /**< 1=power button handled as ctrl method dev */
326#define FADT_FL_SLP_BUTTON RT_BIT(5) /**< 1=sleep button handled as ctrl method dev */
327#define FADT_FL_FIX_RTC RT_BIT(6) /**< 0=RTC wake status in fixed register */
328#define FADT_FL_RTC_S4 RT_BIT(7) /**< 1=RTC can wake system from S4 */
329#define FADT_FL_TMR_VAL_EXT RT_BIT(8) /**< 1=TMR_VAL implemented as 32 bit */
330#define FADT_FL_DCK_CAP RT_BIT(9) /**< 0=system cannot support docking */
331#define FADT_FL_RESET_REG_SUP RT_BIT(10) /**< 1=system supports system resets */
332#define FADT_FL_SEALED_CASE RT_BIT(11) /**< 1=case is sealed */
333#define FADT_FL_HEADLESS RT_BIT(12) /**< 1=system cannot detect moni/keyb/mouse */
334#define FADT_FL_CPU_SW_SLP RT_BIT(13)
335#define FADT_FL_PCI_EXT_WAK RT_BIT(14) /**< 1=system supports PCIEXP_WAKE_STS */
336#define FADT_FL_USE_PLATFORM_CLOCK RT_BIT(15) /**< 1=system has ACPI PM timer */
337#define FADT_FL_S4_RTC_STS_VALID RT_BIT(16) /**< 1=RTC_STS flag is valid when waking from S4 */
338#define FADT_FL_REMOVE_POWER_ON_CAPABLE RT_BIT(17) /**< 1=platform can remote power on */
339#define FADT_FL_FORCE_APIC_CLUSTER_MODEL RT_BIT(18)
340#define FADT_FL_FORCE_APIC_PHYS_DEST_MODE RT_BIT(19)
341 ACPIGENADDR ResetReg; /**< ext addr of reset register */
342 uint8_t u8ResetVal; /**< ResetReg value to reset the system */
343#define ACPI_RESET_REG_VAL 0x10
344 uint8_t au8Must0_1[3]; /**< must be 0 */
345 uint64_t u64XFACS; /**< 64-bit phys address of FACS */
346 uint64_t u64XDSDT; /**< 64-bit phys address of DSDT */
347 ACPIGENADDR X_PM1aEVTBLK; /**< ext addr of PM1a event regs block */
348 ACPIGENADDR X_PM1bEVTBLK; /**< ext addr of PM1b event regs block */
349 ACPIGENADDR X_PM1aCTLBLK; /**< ext addr of PM1a control regs block */
350 ACPIGENADDR X_PM1bCTLBLK; /**< ext addr of PM1b control regs block */
351 ACPIGENADDR X_PM2CTLBLK; /**< ext addr of PM2 control regs block */
352 ACPIGENADDR X_PMTMRBLK; /**< ext addr of PMTMR control regs block */
353 ACPIGENADDR X_GPE0BLK; /**< ext addr of GPE1 regs block */
354 ACPIGENADDR X_GPE1BLK; /**< ext addr of GPE1 regs block */
355};
356AssertCompileSize(ACPITBLFADT, 244);
357
358/** Firmware ACPI Control Structure */
359struct ACPITBLFACS
360{
361 uint8_t au8Signature[4]; /**< 'FACS' */
362 uint32_t u32Length; /**< bytes of entire FACS structure >= 64 */
363 uint32_t u32HWSignature; /**< systems HW signature at last boot */
364 uint32_t u32FWVector; /**< address of waking vector */
365 uint32_t u32GlobalLock; /**< global lock to sync HW/SW */
366 uint32_t u32Flags; /**< FACS flags */
367 uint64_t u64X_FWVector; /**< 64-bit waking vector */
368 uint8_t u8Version; /**< version of this table */
369 uint8_t au8Reserved[31]; /**< zero */
370};
371AssertCompileSize(ACPITBLFACS, 64);
372
373/** Processor Local APIC Structure */
374struct ACPITBLLAPIC
375{
376 uint8_t u8Type; /**< 0 = LAPIC */
377 uint8_t u8Length; /**< 8 */
378 uint8_t u8ProcId; /**< processor ID */
379 uint8_t u8ApicId; /**< local APIC ID */
380 uint32_t u32Flags; /**< Flags */
381#define LAPIC_ENABLED 0x1
382};
383AssertCompileSize(ACPITBLLAPIC, 8);
384
385/** I/O APIC Structure */
386struct ACPITBLIOAPIC
387{
388 uint8_t u8Type; /**< 1 == I/O APIC */
389 uint8_t u8Length; /**< 12 */
390 uint8_t u8IOApicId; /**< I/O APIC ID */
391 uint8_t u8Reserved; /**< 0 */
392 uint32_t u32Address; /**< phys address to access I/O APIC */
393 uint32_t u32GSIB; /**< global system interrupt number to start */
394};
395AssertCompileSize(ACPITBLIOAPIC, 12);
396
397#ifdef VBOX_WITH_SMP_GUESTS
398#ifdef IN_RING3 /**@todo r=bird: Move this down to where it's used. */
399
400# define PCAT_COMPAT 0x1 /**< system has also a dual-8259 setup */
401
402/**
403 * Multiple APIC Description Table.
404 *
405 * This structure looks somewhat convoluted due layout of MADT table in MP case.
406 * There extpected to be multiple LAPIC records for each CPU, thus we cannot
407 * use regular C structure and proxy to raw memory instead.
408 */
409class AcpiTableMADT
410{
411 /**
412 * All actual data stored in dynamically allocated memory pointed by this field.
413 */
414 uint8_t* pData;
415 /**
416 * Number of CPU entries in this MADT.
417 */
418 uint32_t cCpus;
419
420 public:
421 /**
422 * Address of ACPI header
423 */
424 inline ACPITBLHEADER* header_addr() const
425 {
426 return (ACPITBLHEADER*)pData;
427 }
428
429 /**
430 * Address of local APIC for each CPU. Note that different CPUs address different LAPICs,
431 * although address is the same for all of them.
432 */
433 inline uint32_t* u32LAPIC_addr() const
434 {
435 return (uint32_t*)(header_addr() + 1);
436 }
437
438 /**
439 * Address of APIC flags
440 */
441 inline uint32_t* u32Flags_addr() const
442 {
443 return (uint32_t*)(u32LAPIC_addr() + 1);
444 }
445
446 /**
447 * Address of per-CPU LAPIC descriptions
448 */
449 inline ACPITBLLAPIC* LApics_addr() const
450 {
451 return (ACPITBLLAPIC*)(u32Flags_addr() + 1);
452 }
453
454 /**
455 * Address of IO APIC description
456 */
457 inline ACPITBLIOAPIC* IOApic_addr() const
458 {
459 return (ACPITBLIOAPIC*)(LApics_addr() + cCpus);
460 }
461
462 /**
463 * Size of MADT.
464 * Note that this function assumes IOApic to be the last field in structure.
465 */
466 inline uint32_t size() const
467 {
468 return (uint8_t*)(IOApic_addr() + 1)-(uint8_t*)header_addr();
469 }
470
471 /**
472 * Raw data of MADT.
473 */
474 inline const uint8_t* data() const
475 {
476 return pData;
477 }
478
479 /**
480 * Size of MADT for given ACPI config, useful to compute layout.
481 */
482 static uint32_t sizeFor(ACPIState *s)
483 {
484 return AcpiTableMADT(s->cCpus).size();
485 }
486
487 /*
488 * Constructor, only works in Ring 3, doesn't look like a big deal.
489 */
490 AcpiTableMADT(uint16_t cpus)
491 {
492 cCpus = cpus;
493 pData = 0;
494 uint32_t sSize = size();
495 pData = (uint8_t*)RTMemAllocZ(sSize);
496 }
497
498 ~AcpiTableMADT()
499 {
500 RTMemFree(pData);
501 }
502};
503#endif /* IN_RING3 */
504
505#else /* !VBOX_WITH_SMP_GUESTS */
506/** Multiple APIC Description Table */
507struct ACPITBLMADT
508{
509 ACPITBLHEADER header;
510 uint32_t u32LAPIC; /**< local APIC address */
511 uint32_t u32Flags; /**< Flags */
512#define PCAT_COMPAT 0x1 /**< system has also a dual-8259 setup */
513 ACPITBLLAPIC LApic;
514 ACPITBLIOAPIC IOApic;
515};
516AssertCompileSize(ACPITBLMADT, 64);
517#endif /* !VBOX_WITH_SMP_GUESTS */
518
519#pragma pack()
520
521
522#ifndef VBOX_DEVICE_STRUCT_TESTCASE
523__BEGIN_DECLS
524IO_READ_PROTO (acpiPMTmrRead);
525#ifdef IN_RING3
526IO_READ_PROTO (acpiPm1aEnRead);
527IO_WRITE_PROTO (acpiPM1aEnWrite);
528IO_READ_PROTO (acpiPm1aStsRead);
529IO_WRITE_PROTO (acpiPM1aStsWrite);
530IO_READ_PROTO (acpiPm1aCtlRead);
531IO_WRITE_PROTO (acpiPM1aCtlWrite);
532IO_WRITE_PROTO (acpiSmiWrite);
533IO_WRITE_PROTO (acpiBatIndexWrite);
534IO_READ_PROTO (acpiBatDataRead);
535IO_READ_PROTO (acpiFdcStatusRead);
536IO_READ_PROTO (acpiSysInfoDataRead);
537IO_WRITE_PROTO (acpiSysInfoDataWrite);
538IO_READ_PROTO (acpiGpe0EnRead);
539IO_WRITE_PROTO (acpiGpe0EnWrite);
540IO_READ_PROTO (acpiGpe0StsRead);
541IO_WRITE_PROTO (acpiGpe0StsWrite);
542IO_WRITE_PROTO (acpiResetWrite);
543# ifdef DEBUG_ACPI
544IO_WRITE_PROTO (acpiDhexWrite);
545IO_WRITE_PROTO (acpiDchrWrite);
546# endif
547#endif
548__END_DECLS
549
550#ifdef IN_RING3
551
552/* Simple acpiChecksum: all the bytes must add up to 0. */
553static uint8_t acpiChecksum (const uint8_t * const data, uint32_t len)
554{
555 uint8_t sum = 0;
556 for (size_t i = 0; i < len; ++i)
557 sum += data[i];
558 return -sum;
559}
560
561static void acpiPrepareHeader (ACPITBLHEADER *header, const char au8Signature[4],
562 uint32_t u32Length, uint8_t u8Revision)
563{
564 memcpy(header->au8Signature, au8Signature, 4);
565 header->u32Length = RT_H2LE_U32(u32Length);
566 header->u8Revision = u8Revision;
567 memcpy(header->au8OemId, "VBOX ", 6);
568 memcpy(header->au8OemTabId, "VBOX", 4);
569 memcpy(header->au8OemTabId+4, au8Signature, 4);
570 header->u32OemRevision = RT_H2LE_U32(1);
571 memcpy(header->au8CreatorId, "ASL ", 4);
572 header->u32CreatorRev = RT_H2LE_U32(0x61);
573}
574
575static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
576 uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
577 uint8_t u8AccessSize, uint64_t u64Address)
578{
579 g->u8AddressSpaceId = u8AddressSpaceId;
580 g->u8RegisterBitWidth = u8RegisterBitWidth;
581 g->u8RegisterBitOffset = u8RegisterBitOffset;
582 g->u8AccessSize = u8AccessSize;
583 g->u64Address = RT_H2LE_U64(u64Address);
584}
585
586static void acpiPhyscpy (ACPIState *s, RTGCPHYS32 dst, const void * const src, size_t size)
587{
588 PDMDevHlpPhysWrite (s->pDevIns, dst, src, size);
589}
590
591/* Differentiated System Description Table (DSDT) */
592static void acpiSetupDSDT (ACPIState *s, RTGCPHYS32 addr)
593{
594 acpiPhyscpy (s, addr, AmlCode, sizeof(AmlCode));
595}
596
597/* Firmware ACPI Control Structure (FACS) */
598static void acpiSetupFACS (ACPIState *s, RTGCPHYS32 addr)
599{
600 ACPITBLFACS facs;
601
602 memset (&facs, 0, sizeof(facs));
603 memcpy (facs.au8Signature, "FACS", 4);
604 facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
605 facs.u32HWSignature = RT_H2LE_U32(0);
606 facs.u32FWVector = RT_H2LE_U32(0);
607 facs.u32GlobalLock = RT_H2LE_U32(0);
608 facs.u32Flags = RT_H2LE_U32(0);
609 facs.u64X_FWVector = RT_H2LE_U64(0);
610 facs.u8Version = 1;
611
612 acpiPhyscpy (s, addr, (const uint8_t*)&facs, sizeof(facs));
613}
614
615/* Fixed ACPI Description Table (FADT aka FACP) */
616static void acpiSetupFADT (ACPIState *s, RTGCPHYS32 addr, uint32_t facs_addr, uint32_t dsdt_addr)
617{
618 ACPITBLFADT fadt;
619
620 memset (&fadt, 0, sizeof(fadt));
621 acpiPrepareHeader (&fadt.header, "FACP", sizeof(fadt), 4);
622 fadt.u32FACS = RT_H2LE_U32(facs_addr);
623 fadt.u32DSDT = RT_H2LE_U32(dsdt_addr);
624 fadt.u8IntModel = INT_MODEL_DUAL_PIC;
625 fadt.u8PreferredPMProfile = 0; /* unspecified */
626 fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
627 fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
628 fadt.u8AcpiEnable = ACPI_ENABLE;
629 fadt.u8AcpiDisable = ACPI_DISABLE;
630 fadt.u8S4BIOSReq = 0;
631 fadt.u8PStateCnt = 0;
632 fadt.u32PM1aEVTBLK = RT_H2LE_U32(PM1a_EVT_BLK);
633 fadt.u32PM1bEVTBLK = RT_H2LE_U32(PM1b_EVT_BLK);
634 fadt.u32PM1aCTLBLK = RT_H2LE_U32(PM1a_CTL_BLK);
635 fadt.u32PM1bCTLBLK = RT_H2LE_U32(PM1b_CTL_BLK);
636 fadt.u32PM2CTLBLK = RT_H2LE_U32(PM2_CTL_BLK);
637 fadt.u32PMTMRBLK = RT_H2LE_U32(PM_TMR_BLK);
638 fadt.u32GPE0BLK = RT_H2LE_U32(GPE0_BLK);
639 fadt.u32GPE1BLK = RT_H2LE_U32(GPE1_BLK);
640 fadt.u8PM1EVTLEN = 4;
641 fadt.u8PM1CTLLEN = 2;
642 fadt.u8PM2CTLLEN = 0;
643 fadt.u8PMTMLEN = 4;
644 fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
645 fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
646 fadt.u8GPE1BASE = GPE1_BASE;
647 fadt.u8CSTCNT = 0;
648 fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
649 fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
650 fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
651 fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
652 fadt.u8DutyOffset = 0;
653 fadt.u8DutyWidth = 0;
654 fadt.u8DayAlarm = 0;
655 fadt.u8MonAlarm = 0;
656 fadt.u8Century = 0;
657 fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
658 /** @note WBINVD is required for ACPI versions newer than 1.0 */
659 fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
660 | FADT_FL_FIX_RTC
661 | FADT_FL_TMR_VAL_EXT);
662 acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
663 fadt.u8ResetVal = ACPI_RESET_REG_VAL;
664 fadt.u64XFACS = RT_H2LE_U64((uint64_t)facs_addr);
665 fadt.u64XDSDT = RT_H2LE_U64((uint64_t)dsdt_addr);
666 acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, PM1a_EVT_BLK);
667 acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, PM1b_EVT_BLK);
668 acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, PM1a_CTL_BLK);
669 acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, PM1b_CTL_BLK);
670 acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, PM2_CTL_BLK);
671 acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, PM_TMR_BLK);
672 acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, GPE0_BLK);
673 acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, GPE1_BLK);
674 fadt.header.u8Checksum = acpiChecksum ((uint8_t*)&fadt, sizeof(fadt));
675 acpiPhyscpy (s, addr, &fadt, sizeof(fadt));
676}
677
678/*
679 * Root System Description Table.
680 * The RSDT and XSDT tables are basically identical. The only difference is 32 vs 64 bits
681 * addresses for description headers. RSDT is for ACPI 1.0. XSDT for ACPI 2.0 and up.
682 */
683static int acpiSetupRSDT (ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
684{
685 ACPITBLRSDT *rsdt;
686 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
687
688 rsdt = (ACPITBLRSDT*)RTMemAllocZ (size);
689 if (!rsdt)
690 return PDMDEV_SET_ERROR(s->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
691
692 acpiPrepareHeader (&rsdt->header, "RSDT", size, 1);
693 for (unsigned int i = 0; i < nb_entries; ++i)
694 {
695 rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
696 Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
697 }
698 rsdt->header.u8Checksum = acpiChecksum ((uint8_t*)rsdt, size);
699 acpiPhyscpy (s, addr, rsdt, size);
700 RTMemFree (rsdt);
701 return VINF_SUCCESS;
702}
703
704/* Extended System Description Table. */
705static int acpiSetupXSDT (ACPIState *s, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
706{
707 ACPITBLXSDT *xsdt;
708 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
709
710 xsdt = (ACPITBLXSDT*)RTMemAllocZ (size);
711 if (!xsdt)
712 return VERR_NO_TMP_MEMORY;
713
714 acpiPrepareHeader (&xsdt->header, "XSDT", size, 1 /* according to ACPI 3.0 specs */);
715 for (unsigned int i = 0; i < nb_entries; ++i)
716 {
717 xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
718 Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
719 }
720 xsdt->header.u8Checksum = acpiChecksum ((uint8_t*)xsdt, size);
721 acpiPhyscpy (s, addr, xsdt, size);
722 RTMemFree (xsdt);
723 return VINF_SUCCESS;
724}
725
726/* Root System Description Pointer (RSDP) */
727static void acpiSetupRSDP (ACPITBLRSDP *rsdp, uint32_t rsdt_addr, uint64_t xsdt_addr)
728{
729 memset(rsdp, 0, sizeof(*rsdp));
730
731 /* ACPI 1.0 part (RSDT */
732 memcpy(rsdp->au8Signature, "RSD PTR ", 8);
733 memcpy(rsdp->au8OemId, "VBOX ", 6);
734 rsdp->u8Revision = ACPI_REVISION;
735 rsdp->u32RSDT = RT_H2LE_U32(rsdt_addr);
736 rsdp->u8Checksum = acpiChecksum((uint8_t*)rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
737
738 /* ACPI 2.0 part (XSDT) */
739 rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
740 rsdp->u64XSDT = RT_H2LE_U64(xsdt_addr);
741 rsdp->u8ExtChecksum = acpiChecksum ((uint8_t*)rsdp, sizeof(ACPITBLRSDP));
742}
743
744/* Multiple APIC Description Table. */
745/** @todo All hardcoded, should set this up based on the actual VM config!!!!! */
746/** @note APIC without IO-APIC hangs Windows Vista therefore we setup both */
747static void acpiSetupMADT (ACPIState *s, RTGCPHYS32 addr)
748{
749#ifdef VBOX_WITH_SMP_GUESTS
750 uint16_t cpus = s->cCpus;
751 AcpiTableMADT madt(cpus);
752
753 acpiPrepareHeader(madt.header_addr(), "APIC", madt.size(), 2);
754
755 *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
756 *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
757
758 ACPITBLLAPIC* lapic = madt.LApics_addr();
759 for (uint16_t i = 0; i < cpus; i++)
760 {
761 lapic->u8Type = 0;
762 lapic->u8Length = sizeof(ACPITBLLAPIC);
763 lapic->u8ProcId = i;
764 lapic->u8ApicId = i;
765 lapic->u32Flags = RT_H2LE_U32(LAPIC_ENABLED);
766 lapic++;
767 }
768
769 ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
770
771 ioapic->u8Type = 1;
772 ioapic->u8Length = sizeof(ACPITBLIOAPIC);
773 ioapic->u8IOApicId = cpus;
774 ioapic->u8Reserved = 0;
775 ioapic->u32Address = RT_H2LE_U32(0xfec00000);
776 ioapic->u32GSIB = RT_H2LE_U32(0);
777
778 madt.header_addr()->u8Checksum = acpiChecksum (madt.data(), madt.size());
779 acpiPhyscpy (s, addr, madt.data(), madt.size());
780
781#else /* !VBOX_WITH_SMP_GUESTS */
782 ACPITBLMADT madt;
783
784 /* Don't call this function if u8UseIOApic==false! */
785 Assert(s->u8UseIOApic);
786
787 memset(&madt, 0, sizeof(madt));
788 acpiPrepareHeader(&madt.header, "APIC", sizeof(madt), 2);
789
790 madt.u32LAPIC = RT_H2LE_U32(0xfee00000);
791 madt.u32Flags = RT_H2LE_U32(PCAT_COMPAT);
792
793 madt.LApic.u8Type = 0;
794 madt.LApic.u8Length = sizeof(ACPITBLLAPIC);
795 madt.LApic.u8ProcId = 0;
796 madt.LApic.u8ApicId = 0;
797 madt.LApic.u32Flags = RT_H2LE_U32(LAPIC_ENABLED);
798
799 madt.IOApic.u8Type = 1;
800 madt.IOApic.u8Length = sizeof(ACPITBLIOAPIC);
801 madt.IOApic.u8IOApicId = 0;
802 madt.IOApic.u8Reserved = 0;
803 madt.IOApic.u32Address = RT_H2LE_U32(0xfec00000);
804 madt.IOApic.u32GSIB = RT_H2LE_U32(0);
805
806 madt.header.u8Checksum = acpiChecksum ((uint8_t*)&madt, sizeof(madt));
807 acpiPhyscpy (s, addr, &madt, sizeof(madt));
808#endif /* !VBOX_WITH_SMP_GUESTS */
809}
810
811/* SCI IRQ */
812DECLINLINE(void) acpiSetIrq (ACPIState *s, int level)
813{
814 if (s->pm1a_ctl & SCI_EN)
815 PDMDevHlpPCISetIrq (s->pDevIns, -1, level);
816}
817
818DECLINLINE(uint32_t) pm1a_pure_en (uint32_t en)
819{
820 return en & ~(RSR_EN | IGN_EN);
821}
822
823DECLINLINE(uint32_t) pm1a_pure_sts (uint32_t sts)
824{
825 return sts & ~(RSR_STS | IGN_STS);
826}
827
828DECLINLINE(int) pm1a_level (ACPIState *s)
829{
830 return (pm1a_pure_en (s->pm1a_en) & pm1a_pure_sts (s->pm1a_sts)) != 0;
831}
832
833DECLINLINE(int) gpe0_level (ACPIState *s)
834{
835 return (s->gpe0_en & s->gpe0_sts) != 0;
836}
837
838static void update_pm1a (ACPIState *s, uint32_t sts, uint32_t en)
839{
840 int old_level, new_level;
841
842 if (gpe0_level (s))
843 return;
844
845 old_level = pm1a_level (s);
846 new_level = (pm1a_pure_en (en) & pm1a_pure_sts (sts)) != 0;
847
848 s->pm1a_en = en;
849 s->pm1a_sts = sts;
850
851 if (new_level != old_level)
852 acpiSetIrq (s, new_level);
853}
854
855static void update_gpe0 (ACPIState *s, uint32_t sts, uint32_t en)
856{
857 int old_level, new_level;
858
859 if (pm1a_level (s))
860 return;
861
862 old_level = (s->gpe0_en & s->gpe0_sts) != 0;
863 new_level = (en & sts) != 0;
864
865 s->gpe0_en = en;
866 s->gpe0_sts = sts;
867
868 if (new_level != old_level)
869 acpiSetIrq (s, new_level);
870}
871
872static int acpiPowerDown (ACPIState *s)
873{
874 int rc = PDMDevHlpVMPowerOff(s->pDevIns);
875 if (RT_FAILURE (rc))
876 AssertMsgFailed (("Could not power down the VM. rc = %Rrc\n", rc));
877 return rc;
878}
879
880/** Converts a ACPI port interface pointer to an ACPI state pointer. */
881#define IACPIPORT_2_ACPISTATE(pInterface) ( (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IACPIPort)) )
882
883/**
884 * Send an ACPI power off event.
885 *
886 * @returns VBox status code
887 * @param pInterface Pointer to the interface structure containing the called function pointer.
888 */
889static DECLCALLBACK(int) acpiPowerButtonPress(PPDMIACPIPORT pInterface)
890{
891 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
892 s->fPowerButtonHandled = false;
893 update_pm1a (s, s->pm1a_sts | PWRBTN_STS, s->pm1a_en);
894 return VINF_SUCCESS;
895}
896
897/**
898 * Check if the ACPI power button event was handled.
899 *
900 * @returns VBox status code
901 * @param pInterface Pointer to the interface structure containing the called function pointer.
902 * @param pfHandled Return true if the power button event was handled by the guest.
903 */
904static DECLCALLBACK(int) acpiGetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
905{
906 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
907 *pfHandled = s->fPowerButtonHandled;
908 return VINF_SUCCESS;
909}
910
911/**
912 * Check if the Guest entered into G0 (working) or G1 (sleeping).
913 *
914 * @returns VBox status code
915 * @param pInterface Pointer to the interface structure containing the called function pointer.
916 * @param pfEntered Return true if the guest entered the ACPI mode.
917 */
918static DECLCALLBACK(int) acpiGetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
919{
920 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
921 *pfEntered = (s->pm1a_ctl & SCI_EN) != 0;
922 return VINF_SUCCESS;
923}
924
925/**
926 * Send an ACPI sleep button event.
927 *
928 * @returns VBox status code
929 * @param pInterface Pointer to the interface structure containing the called function pointer.
930 */
931static DECLCALLBACK(int) acpiSleepButtonPress(PPDMIACPIPORT pInterface)
932{
933 ACPIState *s = IACPIPORT_2_ACPISTATE(pInterface);
934 update_pm1a (s, s->pm1a_sts | SLPBTN_STS, s->pm1a_en);
935 return VINF_SUCCESS;
936}
937
938/* PM1a_EVT_BLK enable */
939static uint32_t acpiPm1aEnReadw (ACPIState *s, uint32_t addr)
940{
941 uint16_t val = s->pm1a_en;
942 Log (("acpi: acpiPm1aEnReadw -> %#x\n", val));
943 return val;
944}
945
946static void acpiPM1aEnWritew (ACPIState *s, uint32_t addr, uint32_t val)
947{
948 Log (("acpi: acpiPM1aEnWritew <- %#x (%#x)\n", val, val & ~(RSR_EN | IGN_EN)));
949 val &= ~(RSR_EN | IGN_EN);
950 update_pm1a (s, s->pm1a_sts, val);
951}
952
953/* PM1a_EVT_BLK status */
954static uint32_t acpiPm1aStsReadw (ACPIState *s, uint32_t addr)
955{
956 uint16_t val = s->pm1a_sts;
957 Log (("acpi: acpiPm1aStsReadw -> %#x\n", val));
958 return val;
959}
960
961static void acpiPM1aStsWritew (ACPIState *s, uint32_t addr, uint32_t val)
962{
963 Log (("acpi: acpiPM1aStsWritew <- %#x (%#x)\n", val, val & ~(RSR_STS | IGN_STS)));
964 if (val & PWRBTN_STS)
965 s->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
966 val = s->pm1a_sts & ~(val & ~(RSR_STS | IGN_STS));
967 update_pm1a (s, val, s->pm1a_en);
968}
969
970/* PM1a_CTL_BLK */
971static uint32_t acpiPm1aCtlReadw (ACPIState *s, uint32_t addr)
972{
973 uint16_t val = s->pm1a_ctl;
974 Log (("acpi: acpiPm1aCtlReadw -> %#x\n", val));
975 return val;
976}
977
978static int acpiPM1aCtlWritew (ACPIState *s, uint32_t addr, uint32_t val)
979{
980 uint32_t uSleepState;
981
982 Log (("acpi: acpiPM1aCtlWritew <- %#x (%#x)\n", val, val & ~(RSR_CNT | IGN_CNT)));
983 s->pm1a_ctl = val & ~(RSR_CNT | IGN_CNT);
984
985 uSleepState = (s->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
986 if (uSleepState != s->uSleepState)
987 {
988 s->uSleepState = uSleepState;
989 switch (uSleepState)
990 {
991 case 0x00: /* S0 */
992 break;
993 case 0x05: /* S5 */
994 LogRel (("Entering S5 (power down)\n"));
995 return acpiPowerDown (s);
996 default:
997 AssertMsgFailed (("Unknown sleep state %#x\n", uSleepState));
998 break;
999 }
1000 }
1001 return VINF_SUCCESS;
1002}
1003
1004/* GPE0_BLK */
1005static uint32_t acpiGpe0EnReadb (ACPIState *s, uint32_t addr)
1006{
1007 uint8_t val = s->gpe0_en;
1008 Log (("acpi: acpiGpe0EnReadl -> %#x\n", val));
1009 return val;
1010}
1011
1012static void acpiGpe0EnWriteb (ACPIState *s, uint32_t addr, uint32_t val)
1013{
1014 Log (("acpi: acpiGpe0EnWritel <- %#x\n", val));
1015 update_gpe0 (s, s->gpe0_sts, val);
1016}
1017
1018static uint32_t acpiGpe0StsReadb (ACPIState *s, uint32_t addr)
1019{
1020 uint8_t val = s->gpe0_sts;
1021 Log (("acpi: acpiGpe0StsReadl -> %#x\n", val));
1022 return val;
1023}
1024
1025static void acpiGpe0StsWriteb (ACPIState *s, uint32_t addr, uint32_t val)
1026{
1027 val = s->gpe0_sts & ~val;
1028 update_gpe0 (s, val, s->gpe0_en);
1029 Log (("acpi: acpiGpe0StsWritel <- %#x\n", val));
1030}
1031
1032static int acpiResetWriteU8(ACPIState *s, uint32_t addr, uint32_t val)
1033{
1034 int rc = VINF_SUCCESS;
1035
1036 Log(("ACPI: acpiResetWriteU8: %x %x\n", addr, val));
1037 if (val == ACPI_RESET_REG_VAL)
1038 {
1039# ifndef IN_RING3
1040 rc = VINF_IOM_HC_IOPORT_WRITE;
1041# else /* IN_RING3 */
1042 rc = PDMDevHlpVMReset(s->pDevIns);
1043# endif /* !IN_RING3 */
1044 }
1045 return rc;
1046}
1047
1048/* SMI */
1049static void acpiSmiWriteU8 (ACPIState *s, uint32_t addr, uint32_t val)
1050{
1051 Log (("acpi: acpiSmiWriteU8 %#x\n", val));
1052 if (val == ACPI_ENABLE)
1053 s->pm1a_ctl |= SCI_EN;
1054 else if (val == ACPI_DISABLE)
1055 s->pm1a_ctl &= ~SCI_EN;
1056 else
1057 Log (("acpi: acpiSmiWriteU8 %#x <- unknown value\n", val));
1058}
1059
1060static uint32_t find_rsdp_space (void)
1061{
1062 return 0xe0000;
1063}
1064
1065static void acpiPMTimerReset (ACPIState *s)
1066{
1067 uint64_t interval, freq;
1068
1069 freq = TMTimerGetFreq (s->CTX_SUFF(ts));
1070 interval = ASMMultU64ByU32DivByU32 (0xffffffff, freq, PM_TMR_FREQ);
1071 Log (("interval = %RU64\n", interval));
1072 TMTimerSet (s->CTX_SUFF(ts), TMTimerGet (s->CTX_SUFF(ts)) + interval);
1073}
1074
1075static DECLCALLBACK(void) acpiTimer (PPDMDEVINS pDevIns, PTMTIMER pTimer)
1076{
1077 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1078
1079 Log (("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
1080 s->pm1a_sts, (s->pm1a_sts & TMR_STS) != 0,
1081 s->pm1a_en, (s->pm1a_en & TMR_EN) != 0));
1082
1083 update_pm1a (s, s->pm1a_sts | TMR_STS, s->pm1a_en);
1084 acpiPMTimerReset (s);
1085}
1086
1087/**
1088 * _BST method.
1089 */
1090static void acpiFetchBatteryStatus (ACPIState *s)
1091{
1092 uint32_t *p = s->au8BatteryInfo;
1093 bool fPresent; /* battery present? */
1094 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1095 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1096 uint32_t hostPresentRate; /* 0..1000 */
1097 int rc;
1098
1099 if (!s->pDrv)
1100 return;
1101 rc = s->pDrv->pfnQueryBatteryStatus (s->pDrv, &fPresent, &hostRemainingCapacity,
1102 &hostBatteryState, &hostPresentRate);
1103 AssertRC (rc);
1104
1105 /* default values */
1106 p[BAT_STATUS_STATE] = hostBatteryState;
1107 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
1108 : hostPresentRate * 50; /* mW */
1109 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
1110 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
1111
1112 /* did we get a valid battery state? */
1113 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
1114 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
1115 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
1116 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
1117}
1118
1119/**
1120 * _BIF method.
1121 */
1122static void acpiFetchBatteryInfo (ACPIState *s)
1123{
1124 uint32_t *p = s->au8BatteryInfo;
1125
1126 p[BAT_INFO_UNITS] = 0; /* mWh */
1127 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
1128 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
1129 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
1130 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
1131 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
1132 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
1133 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
1134 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
1135}
1136
1137/**
1138 * _STA method.
1139 */
1140static uint32_t acpiGetBatteryDeviceStatus (ACPIState *s)
1141{
1142 bool fPresent; /* battery present? */
1143 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1144 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1145 uint32_t hostPresentRate; /* 0..1000 */
1146 int rc;
1147
1148 if (!s->pDrv)
1149 return 0;
1150 rc = s->pDrv->pfnQueryBatteryStatus (s->pDrv, &fPresent, &hostRemainingCapacity,
1151 &hostBatteryState, &hostPresentRate);
1152 AssertRC (rc);
1153
1154 return fPresent
1155 ? STA_DEVICE_PRESENT_MASK /* present */
1156 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1157 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1158 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1159 | STA_BATTERY_PRESENT_MASK /* battery is present */
1160 : 0; /* device not present */
1161}
1162
1163static uint32_t acpiGetPowerSource (ACPIState *s)
1164{
1165 PDMACPIPOWERSOURCE ps;
1166
1167 /* query the current power source from the host driver */
1168 if (!s->pDrv)
1169 return AC_ONLINE;
1170 int rc = s->pDrv->pfnQueryPowerSource (s->pDrv, &ps);
1171 AssertRC (rc);
1172 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1173}
1174
1175IO_WRITE_PROTO (acpiBatIndexWrite)
1176{
1177 ACPIState *s = (ACPIState *)pvUser;
1178
1179 switch (cb)
1180 {
1181 case 4:
1182 u32 >>= s->u8IndexShift;
1183 /* see comment at the declaration of u8IndexShift */
1184 if (s->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
1185 {
1186 s->u8IndexShift = 2;
1187 u32 >>= 2;
1188 }
1189 Assert (u32 < BAT_INDEX_LAST);
1190 s->uBatteryIndex = u32;
1191 break;
1192 default:
1193 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1194 break;
1195 }
1196 return VINF_SUCCESS;
1197}
1198
1199IO_READ_PROTO (acpiBatDataRead)
1200{
1201 ACPIState *s = (ACPIState *)pvUser;
1202
1203 switch (cb)
1204 {
1205 case 4:
1206 switch (s->uBatteryIndex)
1207 {
1208 case BAT_STATUS_STATE:
1209 acpiFetchBatteryStatus(s);
1210 case BAT_STATUS_PRESENT_RATE:
1211 case BAT_STATUS_REMAINING_CAPACITY:
1212 case BAT_STATUS_PRESENT_VOLTAGE:
1213 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1214 break;
1215
1216 case BAT_INFO_UNITS:
1217 acpiFetchBatteryInfo(s);
1218 case BAT_INFO_DESIGN_CAPACITY:
1219 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1220 case BAT_INFO_TECHNOLOGY:
1221 case BAT_INFO_DESIGN_VOLTAGE:
1222 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1223 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1224 case BAT_INFO_CAPACITY_GRANULARITY_1:
1225 case BAT_INFO_CAPACITY_GRANULARITY_2:
1226 *pu32 = s->au8BatteryInfo[s->uBatteryIndex];
1227 break;
1228
1229 case BAT_DEVICE_STATUS:
1230 *pu32 = acpiGetBatteryDeviceStatus(s);
1231 break;
1232
1233 case BAT_POWER_SOURCE:
1234 *pu32 = acpiGetPowerSource(s);
1235 break;
1236
1237 default:
1238 AssertMsgFailed (("Invalid battery index %d\n", s->uBatteryIndex));
1239 break;
1240 }
1241 break;
1242 default:
1243 return VERR_IOM_IOPORT_UNUSED;
1244 }
1245 return VINF_SUCCESS;
1246}
1247
1248IO_READ_PROTO (acpiFdcStatusRead)
1249{
1250 ACPIState *s = (ACPIState *)pvUser;
1251
1252 switch (cb)
1253 {
1254 case 4:
1255 *pu32 = s->u8UseFdc
1256 ? STA_DEVICE_PRESENT_MASK /* present */
1257 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1258 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1259 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1260 : 0; /* device not present */
1261 break;
1262 default:
1263 return VERR_IOM_IOPORT_UNUSED;
1264 }
1265 return VINF_SUCCESS;
1266}
1267
1268IO_WRITE_PROTO (acpiSysInfoIndexWrite)
1269{
1270 ACPIState *s = (ACPIState *)pvUser;
1271
1272 Log(("system_index = %d, %d\n", u32, u32 >> 2));
1273 switch (cb) {
1274 case 4:
1275 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1276 s->uSystemInfoIndex = u32;
1277 else
1278 {
1279 u32 >>= s->u8IndexShift;
1280 Assert (u32 < SYSTEM_INFO_INDEX_LAST);
1281 s->uSystemInfoIndex = u32;
1282 }
1283 break;
1284
1285 default:
1286 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1287 break;
1288 }
1289 return VINF_SUCCESS;
1290}
1291
1292IO_READ_PROTO (acpiSysInfoDataRead)
1293{
1294 ACPIState *s = (ACPIState *)pvUser;
1295
1296 switch (cb)
1297 {
1298 case 4:
1299 switch (s->uSystemInfoIndex)
1300 {
1301 case SYSTEM_INFO_INDEX_MEMORY_LENGTH:
1302 *pu32 = s->u64RamSize;
1303 break;
1304
1305 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1306 *pu32 = s->u8UseIOApic;
1307 break;
1308
1309 /* Solaris 9 tries to read from this index */
1310 case SYSTEM_INFO_INDEX_INVALID:
1311 *pu32 = 0;
1312 break;
1313
1314 default:
1315 AssertMsgFailed (("Invalid system info index %d\n", s->uSystemInfoIndex));
1316 break;
1317 }
1318 break;
1319
1320 default:
1321 return VERR_IOM_IOPORT_UNUSED;
1322 }
1323
1324 Log(("index %d val %d\n", s->uSystemInfoIndex, *pu32));
1325 return VINF_SUCCESS;
1326}
1327
1328IO_WRITE_PROTO (acpiSysInfoDataWrite)
1329{
1330 ACPIState *s = (ACPIState *)pvUser;
1331
1332 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, s->uSystemInfoIndex));
1333
1334 if (cb == 4 && u32 == 0xbadc0de)
1335 {
1336 switch (s->uSystemInfoIndex)
1337 {
1338 case SYSTEM_INFO_INDEX_INVALID:
1339 s->u8IndexShift = 0;
1340 break;
1341
1342 case SYSTEM_INFO_INDEX_VALID:
1343 s->u8IndexShift = 2;
1344 break;
1345
1346 default:
1347 AssertMsgFailed(("Port=%#x cb=%d u32=%#x system_index=%#x\n",
1348 Port, cb, u32, s->uSystemInfoIndex));
1349 break;
1350 }
1351 }
1352 else
1353 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1354 return VINF_SUCCESS;
1355}
1356
1357/* IO Helpers */
1358IO_READ_PROTO (acpiPm1aEnRead)
1359{
1360 switch (cb)
1361 {
1362 case 2:
1363 *pu32 = acpiPm1aEnReadw ((ACPIState*)pvUser, Port);
1364 break;
1365 default:
1366 return VERR_IOM_IOPORT_UNUSED;
1367 }
1368 return VINF_SUCCESS;
1369}
1370
1371IO_READ_PROTO (acpiPm1aStsRead)
1372{
1373 switch (cb)
1374 {
1375 case 2:
1376 *pu32 = acpiPm1aStsReadw ((ACPIState*)pvUser, Port);
1377 break;
1378 default:
1379 return VERR_IOM_IOPORT_UNUSED;
1380 }
1381 return VINF_SUCCESS;
1382}
1383
1384IO_READ_PROTO (acpiPm1aCtlRead)
1385{
1386 switch (cb)
1387 {
1388 case 2:
1389 *pu32 = acpiPm1aCtlReadw ((ACPIState*)pvUser, Port);
1390 break;
1391 default:
1392 return VERR_IOM_IOPORT_UNUSED;
1393 }
1394 return VINF_SUCCESS;
1395}
1396
1397IO_WRITE_PROTO (acpiPM1aEnWrite)
1398{
1399 switch (cb)
1400 {
1401 case 2:
1402 acpiPM1aEnWritew ((ACPIState*)pvUser, Port, u32);
1403 break;
1404 default:
1405 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1406 break;
1407 }
1408 return VINF_SUCCESS;
1409}
1410
1411IO_WRITE_PROTO (acpiPM1aStsWrite)
1412{
1413 switch (cb)
1414 {
1415 case 2:
1416 acpiPM1aStsWritew ((ACPIState*)pvUser, Port, u32);
1417 break;
1418 default:
1419 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1420 break;
1421 }
1422 return VINF_SUCCESS;
1423}
1424
1425IO_WRITE_PROTO (acpiPM1aCtlWrite)
1426{
1427 switch (cb)
1428 {
1429 case 2:
1430 return acpiPM1aCtlWritew ((ACPIState*)pvUser, Port, u32);
1431 default:
1432 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1433 break;
1434 }
1435 return VINF_SUCCESS;
1436}
1437
1438#endif /* IN_RING3 */
1439
1440/**
1441 * PMTMR readable from host/guest.
1442 */
1443IO_READ_PROTO (acpiPMTmrRead)
1444{
1445 if (cb == 4)
1446 {
1447 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1448 int64_t now = TMTimerGet (s->CTX_SUFF(ts));
1449 int64_t elapsed = now - s->pm_timer_initial;
1450
1451 *pu32 = ASMMultU64ByU32DivByU32 (elapsed, PM_TMR_FREQ, TMTimerGetFreq (s->CTX_SUFF(ts)));
1452 Log (("acpi: acpiPMTmrRead -> %#x\n", *pu32));
1453 return VINF_SUCCESS;
1454 }
1455 return VERR_IOM_IOPORT_UNUSED;
1456}
1457
1458#ifdef IN_RING3
1459
1460IO_READ_PROTO (acpiGpe0StsRead)
1461{
1462 switch (cb)
1463 {
1464 case 1:
1465 *pu32 = acpiGpe0StsReadb ((ACPIState*)pvUser, Port);
1466 break;
1467 default:
1468 return VERR_IOM_IOPORT_UNUSED;
1469 }
1470 return VINF_SUCCESS;
1471}
1472
1473IO_READ_PROTO (acpiGpe0EnRead)
1474{
1475 switch (cb)
1476 {
1477 case 1:
1478 *pu32 = acpiGpe0EnReadb ((ACPIState*)pvUser, Port);
1479 break;
1480 default:
1481 return VERR_IOM_IOPORT_UNUSED;
1482 }
1483 return VINF_SUCCESS;
1484}
1485
1486IO_WRITE_PROTO (acpiGpe0StsWrite)
1487{
1488 switch (cb)
1489 {
1490 case 1:
1491 acpiGpe0StsWriteb ((ACPIState*)pvUser, Port, u32);
1492 break;
1493 default:
1494 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1495 break;
1496 }
1497 return VINF_SUCCESS;
1498}
1499
1500IO_WRITE_PROTO (acpiGpe0EnWrite)
1501{
1502 switch (cb)
1503 {
1504 case 1:
1505 acpiGpe0EnWriteb ((ACPIState*)pvUser, Port, u32);
1506 break;
1507 default:
1508 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1509 break;
1510 }
1511 return VINF_SUCCESS;
1512}
1513
1514IO_WRITE_PROTO (acpiSmiWrite)
1515{
1516 switch (cb)
1517 {
1518 case 1:
1519 acpiSmiWriteU8 ((ACPIState*)pvUser, Port, u32);
1520 break;
1521 default:
1522 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1523 break;
1524 }
1525 return VINF_SUCCESS;
1526}
1527
1528IO_WRITE_PROTO (acpiResetWrite)
1529{
1530 switch (cb)
1531 {
1532 case 1:
1533 return acpiResetWriteU8 ((ACPIState*)pvUser, Port, u32);
1534 default:
1535 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1536 break;
1537 }
1538 return VINF_SUCCESS;
1539}
1540
1541#ifdef DEBUG_ACPI
1542
1543IO_WRITE_PROTO (acpiDhexWrite)
1544{
1545 switch (cb)
1546 {
1547 case 1:
1548 Log (("%#x\n", u32 & 0xff));
1549 break;
1550 case 2:
1551 Log (("%#6x\n", u32 & 0xffff));
1552 case 4:
1553 Log (("%#10x\n", u32));
1554 break;
1555 default:
1556 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1557 break;
1558 }
1559 return VINF_SUCCESS;
1560}
1561
1562IO_WRITE_PROTO (acpiDchrWrite)
1563{
1564 switch (cb)
1565 {
1566 case 1:
1567 Log (("%c", u32 & 0xff));
1568 break;
1569 default:
1570 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1571 break;
1572 }
1573 return VINF_SUCCESS;
1574}
1575
1576#endif /* DEBUG_ACPI */
1577
1578
1579/**
1580 * Saved state structure description.
1581 */
1582static const SSMFIELD g_AcpiSavedStateFields[] =
1583{
1584 SSMFIELD_ENTRY (ACPIState, pm1a_en),
1585 SSMFIELD_ENTRY (ACPIState, pm1a_sts),
1586 SSMFIELD_ENTRY (ACPIState, pm1a_ctl),
1587 SSMFIELD_ENTRY (ACPIState, pm_timer_initial),
1588 SSMFIELD_ENTRY (ACPIState, gpe0_en),
1589 SSMFIELD_ENTRY (ACPIState, gpe0_sts),
1590 SSMFIELD_ENTRY (ACPIState, uBatteryIndex),
1591 SSMFIELD_ENTRY (ACPIState, uSystemInfoIndex),
1592 SSMFIELD_ENTRY (ACPIState, u64RamSize),
1593 SSMFIELD_ENTRY (ACPIState, u8IndexShift),
1594 SSMFIELD_ENTRY (ACPIState, u8UseIOApic),
1595 SSMFIELD_ENTRY (ACPIState, uSleepState),
1596 SSMFIELD_ENTRY_TERM ()
1597};
1598
1599static DECLCALLBACK(int) acpi_save_state (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1600{
1601 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1602 return SSMR3PutStruct (pSSMHandle, s, &g_AcpiSavedStateFields[0]);
1603}
1604
1605static DECLCALLBACK(int) acpi_load_state (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
1606 uint32_t u32Version)
1607{
1608 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1609 int rc;
1610
1611 if (u32Version != 4)
1612 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1613
1614 rc = SSMR3GetStruct (pSSMHandle, s, &g_AcpiSavedStateFields[0]);
1615 if (RT_SUCCESS (rc))
1616 {
1617 acpiFetchBatteryStatus (s);
1618 acpiFetchBatteryInfo (s);
1619 acpiPMTimerReset (s);
1620 }
1621 return rc;
1622}
1623
1624/**
1625 * Queries an interface to the driver.
1626 *
1627 * @returns Pointer to interface.
1628 * @returns NULL if the interface was not supported by the driver.
1629 * @param pInterface Pointer to this interface structure.
1630 * @param enmInterface The requested interface identification.
1631 * @thread Any thread.
1632 */
1633static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1634{
1635 ACPIState *pThis = (ACPIState*)((uintptr_t)pInterface - RT_OFFSETOF(ACPIState, IBase));
1636 switch (enmInterface)
1637 {
1638 case PDMINTERFACE_BASE:
1639 return &pThis->IBase;
1640 case PDMINTERFACE_ACPI_PORT:
1641 return &pThis->IACPIPort;
1642 default:
1643 return NULL;
1644 }
1645}
1646
1647/**
1648 * Create the ACPI tables.
1649 */
1650static int acpiPlantTables (ACPIState *s)
1651{
1652 int rc;
1653 RTGCPHYS32 rsdt_addr, xsdt_addr, fadt_addr, facs_addr, dsdt_addr, last_addr, apic_addr = 0;
1654 uint32_t addend = 0;
1655 RTGCPHYS32 rsdt_addrs[4];
1656 uint32_t cAddr;
1657 size_t rsdt_tbl_len = sizeof(ACPITBLHEADER);
1658 size_t xsdt_tbl_len = sizeof(ACPITBLHEADER);
1659
1660 cAddr = 1; /* FADT */
1661 if (s->u8UseIOApic)
1662 cAddr++; /* MADT */
1663
1664 rsdt_tbl_len += cAddr*4; /* each entry: 32 bits phys. address. */
1665 xsdt_tbl_len += cAddr*8; /* each entry: 64 bits phys. address. */
1666
1667 rc = CFGMR3QueryU64 (s->pDevIns->pCfgHandle, "RamSize", &s->u64RamSize);
1668 if (RT_FAILURE (rc))
1669 return PDMDEV_SET_ERROR(s->pDevIns, rc,
1670 N_("Configuration error: Querying "
1671 "\"RamSize\" as integer failed"));
1672
1673 if (s->u64RamSize > (0xffffffff - 0x10000))
1674 return PDMDEV_SET_ERROR(s->pDevIns, VERR_OUT_OF_RANGE,
1675 N_("Configuration error: Invalid \"RamSize\", maximum allowed "
1676 "value is 4095MB"));
1677 rsdt_addr = 0;
1678 xsdt_addr = RT_ALIGN_32 (rsdt_addr + rsdt_tbl_len, 16);
1679 fadt_addr = RT_ALIGN_32 (xsdt_addr + xsdt_tbl_len, 16);
1680 facs_addr = RT_ALIGN_32 (fadt_addr + sizeof(ACPITBLFADT), 16);
1681 if (s->u8UseIOApic)
1682 {
1683 apic_addr = RT_ALIGN_32 (facs_addr + sizeof(ACPITBLFACS), 16);
1684#ifdef VBOX_WITH_SMP_GUESTS
1685 /**
1686 * @todo nike: maybe some refactoring needed to compute tables layout,
1687 * but as this code is executed only once it doesn't make sense to optimize much
1688 */
1689 dsdt_addr = RT_ALIGN_32 (apic_addr + AcpiTableMADT::sizeFor(s), 16);
1690#else
1691 dsdt_addr = RT_ALIGN_32 (apic_addr + sizeof(ACPITBLMADT), 16);
1692#endif
1693 }
1694 else
1695 {
1696 dsdt_addr = RT_ALIGN_32 (facs_addr + sizeof(ACPITBLFACS), 16);
1697 }
1698
1699 last_addr = RT_ALIGN_32 (dsdt_addr + sizeof(AmlCode), 16);
1700 if (last_addr > 0x10000)
1701 return PDMDEV_SET_ERROR(s->pDevIns, VERR_TOO_MUCH_DATA,
1702 N_("Error: ACPI tables > 64KB"));
1703
1704 Log(("RSDP 0x%08X\n", find_rsdp_space()));
1705 addend = (uint32_t) s->u64RamSize - 0x10000;
1706 Log(("RSDT 0x%08X XSDT 0x%08X\n", rsdt_addr + addend, xsdt_addr + addend));
1707 Log(("FACS 0x%08X FADT 0x%08X\n", facs_addr + addend, fadt_addr + addend));
1708 Log(("DSDT 0x%08X\n", dsdt_addr + addend));
1709 acpiSetupRSDP ((ACPITBLRSDP*)s->au8RSDPPage, rsdt_addr + addend, xsdt_addr + addend);
1710 acpiSetupDSDT (s, dsdt_addr + addend);
1711 acpiSetupFACS (s, facs_addr + addend);
1712 acpiSetupFADT (s, fadt_addr + addend, facs_addr + addend, dsdt_addr + addend);
1713
1714 rsdt_addrs[0] = fadt_addr + addend;
1715 if (s->u8UseIOApic)
1716 {
1717 acpiSetupMADT (s, apic_addr + addend);
1718 rsdt_addrs[1] = apic_addr + addend;
1719 }
1720
1721 rc = acpiSetupRSDT (s, rsdt_addr + addend, cAddr, rsdt_addrs);
1722 if (RT_FAILURE(rc))
1723 return rc;
1724 return acpiSetupXSDT (s, xsdt_addr + addend, cAddr, rsdt_addrs);
1725}
1726
1727/**
1728 * Construct a device instance for a VM.
1729 *
1730 * @returns VBox status.
1731 * @param pDevIns The device instance data.
1732 * If the registration structure is needed, pDevIns->pDevReg points to it.
1733 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1734 * The device number is also found in pDevIns->iInstance, but since it's
1735 * likely to be freqently used PDM passes it as parameter.
1736 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1737 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1738 * iInstance it's expected to be used a bit in this function.
1739 */
1740static DECLCALLBACK(int) acpiConstruct (PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1741{
1742 int rc;
1743 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1744 uint32_t rsdp_addr;
1745 PCIDevice *dev;
1746 bool fGCEnabled;
1747 bool fR0Enabled;
1748
1749 /* Validate and read the configuration. */
1750 if (!CFGMR3AreValuesValid (pCfgHandle,
1751 "RamSize\0"
1752 "IOAPIC\0"
1753 "NumCPUs\0"
1754 "GCEnabled\0"
1755 "R0Enabled\0"
1756 "FdcEnabled\0"))
1757 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1758 N_("Configuration error: Invalid config key for ACPI device"));
1759
1760 s->pDevIns = pDevIns;
1761
1762 /* query whether we are supposed to present an IOAPIC */
1763 rc = CFGMR3QueryU8 (pCfgHandle, "IOAPIC", &s->u8UseIOApic);
1764 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1765 s->u8UseIOApic = 1;
1766 else if (RT_FAILURE (rc))
1767 return PDMDEV_SET_ERROR(pDevIns, rc,
1768 N_("Configuration error: Failed to read \"IOAPIC\""));
1769
1770 rc = CFGMR3QueryU16Def(pCfgHandle, "NumCPUs", &s->cCpus, 1);
1771 if (RT_FAILURE(rc))
1772 return PDMDEV_SET_ERROR(pDevIns, rc,
1773 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
1774
1775 /* query whether we are supposed to present an FDC controller */
1776 rc = CFGMR3QueryU8 (pCfgHandle, "FdcEnabled", &s->u8UseFdc);
1777 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1778 s->u8UseFdc = 1;
1779 else if (RT_FAILURE (rc))
1780 return PDMDEV_SET_ERROR(pDevIns, rc,
1781 N_("Configuration error: Failed to read \"FdcEnabled\""));
1782
1783 rc = CFGMR3QueryBool (pCfgHandle, "GCEnabled", &fGCEnabled);
1784 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1785 fGCEnabled = true;
1786 else if (RT_FAILURE (rc))
1787 return PDMDEV_SET_ERROR(pDevIns, rc,
1788 N_("Configuration error: Failed to read \"GCEnabled\""));
1789
1790 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
1791 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1792 fR0Enabled = true;
1793 else if (RT_FAILURE(rc))
1794 return PDMDEV_SET_ERROR(pDevIns, rc,
1795 N_("configuration error: failed to read R0Enabled as boolean"));
1796
1797 /* */
1798 rsdp_addr = find_rsdp_space ();
1799 if (!rsdp_addr)
1800 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
1801 N_("Can not find space for RSDP. ACPI is disabled"));
1802
1803 rc = acpiPlantTables (s);
1804 if (RT_FAILURE (rc))
1805 return rc;
1806
1807 rc = PDMDevHlpROMRegister (pDevIns, rsdp_addr, 0x1000, s->au8RSDPPage, false /* fShadow */, "ACPI RSDP");
1808 if (RT_FAILURE (rc))
1809 return rc;
1810
1811#define R(addr, cnt, writer, reader, description) \
1812 do { \
1813 rc = PDMDevHlpIOPortRegister (pDevIns, addr, cnt, s, writer, reader, \
1814 NULL, NULL, description); \
1815 if (RT_FAILURE (rc)) \
1816 return rc; \
1817 } while (0)
1818#define L (GPE0_BLK_LEN / 2)
1819
1820 R (PM1a_EVT_BLK+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
1821 R (PM1a_EVT_BLK, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
1822 R (PM1a_CTL_BLK, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
1823 R (PM_TMR_BLK, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
1824 R (SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
1825#ifdef DEBUG_ACPI
1826 R (DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
1827 R (DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
1828#endif
1829 R (BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
1830 R (BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
1831 R (SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
1832 R (SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
1833 R (FDC_STATUS, 1, NULL, acpiFdcStatusRead, "ACPI FDC status index");
1834 R (GPE0_BLK + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
1835 R (GPE0_BLK, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
1836 R (ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
1837#undef L
1838#undef R
1839
1840 /* register GC stuff */
1841 if (fGCEnabled)
1842 {
1843 rc = PDMDevHlpIOPortRegisterGC (pDevIns, PM_TMR_BLK, 1, 0, NULL, "acpiPMTmrRead",
1844 NULL, NULL, "ACPI PM Timer");
1845 AssertRCReturn(rc, rc);
1846 }
1847
1848 /* register R0 stuff */
1849 if (fR0Enabled)
1850 {
1851 rc = PDMDevHlpIOPortRegisterR0 (pDevIns, PM_TMR_BLK, 1, 0, NULL, "acpiPMTmrRead",
1852 NULL, NULL, "ACPI PM Timer");
1853 AssertRCReturn(rc, rc);
1854 }
1855
1856 rc = PDMDevHlpTMTimerCreate (pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiTimer, "ACPI Timer", &s->tsR3);
1857 if (RT_FAILURE(rc))
1858 {
1859 AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
1860 return rc;
1861 }
1862
1863 s->tsR0 = TMTimerR0Ptr (s->tsR3);
1864 s->tsRC = TMTimerRCPtr (s->tsR3);
1865 s->pm_timer_initial = TMTimerGet (s->tsR3);
1866 acpiPMTimerReset (s);
1867
1868 dev = &s->dev;
1869 dev->config[0x00] = 0x86;
1870 dev->config[0x01] = 0x80;
1871
1872 dev->config[0x02] = 0x13;
1873 dev->config[0x03] = 0x71;
1874
1875 dev->config[0x04] = 0x01;
1876 dev->config[0x05] = 0x00;
1877
1878 dev->config[0x06] = 0x80;
1879 dev->config[0x07] = 0x02;
1880 dev->config[0x08] = 0x08;
1881 dev->config[0x09] = 0x00;
1882
1883 dev->config[0x0a] = 0x80;
1884 dev->config[0x0b] = 0x06;
1885
1886 dev->config[0x0e] = 0x80;
1887 dev->config[0x0f] = 0x00;
1888
1889#if 0 /* The ACPI controller usually has no subsystem ID. */
1890 dev->config[0x2c] = 0x86;
1891 dev->config[0x2d] = 0x80;
1892 dev->config[0x2e] = 0x00;
1893 dev->config[0x2f] = 0x00;
1894#endif
1895 dev->config[0x3c] = SCI_INT;
1896
1897 rc = PDMDevHlpPCIRegister (pDevIns, dev);
1898 if (RT_FAILURE (rc))
1899 return rc;
1900
1901 rc = PDMDevHlpSSMRegister (pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 4, sizeof(*s),
1902 NULL, acpi_save_state, NULL, NULL, acpi_load_state, NULL);
1903 if (RT_FAILURE(rc))
1904 return rc;
1905
1906 /*
1907 * Interfaces
1908 */
1909 /* IBase */
1910 s->IBase.pfnQueryInterface = acpiQueryInterface;
1911 /* IACPIPort */
1912 s->IACPIPort.pfnSleepButtonPress = acpiSleepButtonPress;
1913 s->IACPIPort.pfnPowerButtonPress = acpiPowerButtonPress;
1914 s->IACPIPort.pfnGetPowerButtonHandled = acpiGetPowerButtonHandled;
1915 s->IACPIPort.pfnGetGuestEnteredACPIMode = acpiGetGuestEnteredACPIMode;
1916
1917 /*
1918 * Get the corresponding connector interface
1919 */
1920 rc = PDMDevHlpDriverAttach (pDevIns, 0, &s->IBase, &s->pDrvBase, "ACPI Driver Port");
1921 if (RT_SUCCESS (rc))
1922 {
1923 s->pDrv = (PPDMIACPICONNECTOR)s->pDrvBase->pfnQueryInterface (s->pDrvBase,
1924 PDMINTERFACE_ACPI_CONNECTOR);
1925 if (!s->pDrv)
1926 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
1927 N_("LUN #0 doesn't have an ACPI connector interface"));
1928 }
1929 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1930 {
1931 Log (("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
1932 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1933 rc = VINF_SUCCESS;
1934 }
1935 else
1936 return PDMDEV_SET_ERROR(pDevIns, rc,
1937 N_("Failed to attach LUN #0"));
1938
1939 return rc;
1940}
1941
1942/**
1943 * Relocates the GC pointer members.
1944 */
1945static DECLCALLBACK(void) acpiRelocate (PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1946{
1947 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1948 s->tsRC = TMTimerRCPtr (s->CTX_SUFF(ts));
1949}
1950
1951static DECLCALLBACK(void) acpiReset (PPDMDEVINS pDevIns)
1952{
1953 ACPIState *s = PDMINS_2_DATA (pDevIns, ACPIState *);
1954
1955 s->pm1a_en = 0;
1956 s->pm1a_sts = 0;
1957 s->pm1a_ctl = 0;
1958 s->pm_timer_initial = TMTimerGet (s->CTX_SUFF(ts));
1959 acpiPMTimerReset(s);
1960 s->uBatteryIndex = 0;
1961 s->uSystemInfoIndex = 0;
1962 s->gpe0_en = 0;
1963 s->gpe0_sts = 0;
1964 s->uSleepState = 0;
1965
1966 acpiPlantTables(s);
1967}
1968
1969/**
1970 * The device registration structure.
1971 */
1972const PDMDEVREG g_DeviceACPI =
1973{
1974 /* u32Version */
1975 PDM_DEVREG_VERSION,
1976 /* szDeviceName */
1977 "acpi",
1978 /* szRCMod */
1979 "VBoxDDGC.gc",
1980 /* szR0Mod */
1981 "VBoxDDR0.r0",
1982 /* pszDescription */
1983 "Advanced Configuration and Power Interface",
1984 /* fFlags */
1985 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1986 /* fClass */
1987 PDM_DEVREG_CLASS_ACPI,
1988 /* cMaxInstances */
1989 ~0,
1990 /* cbInstance */
1991 sizeof(ACPIState),
1992 /* pfnConstruct */
1993 acpiConstruct,
1994 /* pfnDestruct */
1995 NULL,
1996 /* pfnRelocate */
1997 acpiRelocate,
1998 /* pfnIOCtl */
1999 NULL,
2000 /* pfnPowerOn */
2001 NULL,
2002 /* pfnReset */
2003 acpiReset,
2004 /* pfnSuspend */
2005 NULL,
2006 /* pfnResume */
2007 NULL,
2008 /* pfnAttach */
2009 NULL,
2010 /* pfnDetach */
2011 NULL,
2012 /* pfnQueryInterface. */
2013 NULL,
2014 /* pfnInitComplete */
2015 NULL,
2016 /* pfnPowerOff */
2017 NULL,
2018 /* pfnSoftReset */
2019 NULL,
2020 /* u32VersionEnd */
2021 PDM_DEVREG_VERSION
2022};
2023
2024#endif /* IN_RING3 */
2025#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2026
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