VirtualBox

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

Last change on this file since 78125 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 150.5 KB
Line 
1/* $Id: DevACPI.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * DevACPI - Advanced Configuration and Power Interface (ACPI) Device.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_ACPI
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/pgm.h>
25#include <VBox/vmm/dbgftrace.h>
26#include <VBox/vmm/vmcpuset.h>
27#include <VBox/log.h>
28#include <VBox/param.h>
29#include <iprt/assert.h>
30#include <iprt/asm.h>
31#include <iprt/asm-math.h>
32#include <iprt/file.h>
33#ifdef IN_RING3
34# include <iprt/alloc.h>
35# include <iprt/string.h>
36# include <iprt/uuid.h>
37#endif /* IN_RING3 */
38
39#include "VBoxDD.h"
40
41#ifdef LOG_ENABLED
42# define DEBUG_ACPI
43#endif
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49#ifdef IN_RING3
50/** Locks the device state, ring-3 only. */
51# define DEVACPI_LOCK_R3(a_pThis) \
52 do { \
53 int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
54 AssertRC(rcLock); \
55 } while (0)
56#endif
57/** Unlocks the device state (all contexts). */
58#define DEVACPI_UNLOCK(a_pThis) \
59 do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
60
61
62#define DEBUG_HEX 0x3000
63#define DEBUG_CHR 0x3001
64
65/** PM Base Address PCI config space offset */
66#define PMBA 0x40
67/** PM Miscellaneous Power Management PCI config space offset */
68#define PMREGMISC 0x80
69
70#define PM_TMR_FREQ 3579545
71/** Default base for PM PIIX4 device */
72#define PM_PORT_BASE 0x4000
73/* Port offsets in PM device */
74enum
75{
76 PM1a_EVT_OFFSET = 0x00,
77 PM1b_EVT_OFFSET = -1, /**< not supported */
78 PM1a_CTL_OFFSET = 0x04,
79 PM1b_CTL_OFFSET = -1, /**< not supported */
80 PM2_CTL_OFFSET = -1, /**< not supported */
81 PM_TMR_OFFSET = 0x08,
82 GPE0_OFFSET = 0x20,
83 GPE1_OFFSET = -1 /**< not supported */
84};
85
86/* Maximum supported number of custom ACPI tables */
87#define MAX_CUST_TABLES 4
88
89/* Undef this to enable 24 bit PM timer (mostly for debugging purposes) */
90#define PM_TMR_32BIT
91
92#define BAT_INDEX 0x00004040
93#define BAT_DATA 0x00004044
94#define SYSI_INDEX 0x00004048
95#define SYSI_DATA 0x0000404c
96#define ACPI_RESET_BLK 0x00004050
97
98/* PM1x status register bits */
99#define TMR_STS RT_BIT(0)
100#define RSR1_STS (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
101#define BM_STS RT_BIT(4)
102#define GBL_STS RT_BIT(5)
103#define RSR2_STS (RT_BIT(6) | RT_BIT(7))
104#define PWRBTN_STS RT_BIT(8)
105#define SLPBTN_STS RT_BIT(9)
106#define RTC_STS RT_BIT(10)
107#define IGN_STS RT_BIT(11)
108#define RSR3_STS (RT_BIT(12) | RT_BIT(13) | RT_BIT(14))
109#define WAK_STS RT_BIT(15)
110#define RSR_STS (RSR1_STS | RSR2_STS | RSR3_STS)
111
112/* PM1x enable register bits */
113#define TMR_EN RT_BIT(0)
114#define RSR1_EN (RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
115#define GBL_EN RT_BIT(5)
116#define RSR2_EN (RT_BIT(6) | RT_BIT(7))
117#define PWRBTN_EN RT_BIT(8)
118#define SLPBTN_EN RT_BIT(9)
119#define RTC_EN RT_BIT(10)
120#define RSR3_EN (RT_BIT(11) | RT_BIT(12) | RT_BIT(13) | RT_BIT(14) | RT_BIT(15))
121#define RSR_EN (RSR1_EN | RSR2_EN | RSR3_EN)
122#define IGN_EN 0
123
124/* PM1x control register bits */
125#define SCI_EN RT_BIT(0)
126#define BM_RLD RT_BIT(1)
127#define GBL_RLS RT_BIT(2)
128#define RSR1_CNT (RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7) | RT_BIT(8))
129#define IGN_CNT RT_BIT(9)
130#define SLP_TYPx_SHIFT 10
131#define SLP_TYPx_MASK 7
132#define SLP_EN RT_BIT(13)
133#define RSR2_CNT (RT_BIT(14) | RT_BIT(15))
134#define RSR_CNT (RSR1_CNT | RSR2_CNT)
135
136#define GPE0_BATTERY_INFO_CHANGED RT_BIT(0)
137
138enum
139{
140 BAT_STATUS_STATE = 0x00, /**< BST battery state */
141 BAT_STATUS_PRESENT_RATE = 0x01, /**< BST battery present rate */
142 BAT_STATUS_REMAINING_CAPACITY = 0x02, /**< BST battery remaining capacity */
143 BAT_STATUS_PRESENT_VOLTAGE = 0x03, /**< BST battery present voltage */
144 BAT_INFO_UNITS = 0x04, /**< BIF power unit */
145 BAT_INFO_DESIGN_CAPACITY = 0x05, /**< BIF design capacity */
146 BAT_INFO_LAST_FULL_CHARGE_CAPACITY = 0x06, /**< BIF last full charge capacity */
147 BAT_INFO_TECHNOLOGY = 0x07, /**< BIF battery technology */
148 BAT_INFO_DESIGN_VOLTAGE = 0x08, /**< BIF design voltage */
149 BAT_INFO_DESIGN_CAPACITY_OF_WARNING = 0x09, /**< BIF design capacity of warning */
150 BAT_INFO_DESIGN_CAPACITY_OF_LOW = 0x0A, /**< BIF design capacity of low */
151 BAT_INFO_CAPACITY_GRANULARITY_1 = 0x0B, /**< BIF battery capacity granularity 1 */
152 BAT_INFO_CAPACITY_GRANULARITY_2 = 0x0C, /**< BIF battery capacity granularity 2 */
153 BAT_DEVICE_STATUS = 0x0D, /**< STA device status */
154 BAT_POWER_SOURCE = 0x0E, /**< PSR power source */
155 BAT_INDEX_LAST
156};
157
158enum
159{
160 CPU_EVENT_TYPE_ADD = 0x01, /**< Event type add */
161 CPU_EVENT_TYPE_REMOVE = 0x03 /**< Event type remove */
162};
163
164enum
165{
166 SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH = 0,
167 SYSTEM_INFO_INDEX_USE_IOAPIC = 1,
168 SYSTEM_INFO_INDEX_HPET_STATUS = 2,
169 SYSTEM_INFO_INDEX_SMC_STATUS = 3,
170 SYSTEM_INFO_INDEX_FDC_STATUS = 4,
171 SYSTEM_INFO_INDEX_SERIAL2_IOBASE = 5,
172 SYSTEM_INFO_INDEX_SERIAL2_IRQ = 6,
173 SYSTEM_INFO_INDEX_SERIAL3_IOBASE = 7,
174 SYSTEM_INFO_INDEX_SERIAL3_IRQ = 8,
175 SYSTEM_INFO_INDEX_PREF64_MEMORY_MIN = 9,
176 SYSTEM_INFO_INDEX_RTC_STATUS = 10,
177 SYSTEM_INFO_INDEX_CPU_LOCKED = 11, /**< Contains a flag indicating whether the CPU is locked or not */
178 SYSTEM_INFO_INDEX_CPU_LOCK_CHECK = 12, /**< For which CPU the lock status should be checked */
179 SYSTEM_INFO_INDEX_CPU_EVENT_TYPE = 13, /**< Type of the CPU hot-plug event */
180 SYSTEM_INFO_INDEX_CPU_EVENT = 14, /**< The CPU id the event is for */
181 SYSTEM_INFO_INDEX_NIC_ADDRESS = 15, /**< NIC PCI address, or 0 */
182 SYSTEM_INFO_INDEX_AUDIO_ADDRESS = 16, /**< Audio card PCI address, or 0 */
183 SYSTEM_INFO_INDEX_POWER_STATES = 17,
184 SYSTEM_INFO_INDEX_IOC_ADDRESS = 18, /**< IO controller PCI address */
185 SYSTEM_INFO_INDEX_HBC_ADDRESS = 19, /**< host bus controller PCI address */
186 SYSTEM_INFO_INDEX_PCI_BASE = 20, /**< PCI bus MCFG MMIO range base */
187 SYSTEM_INFO_INDEX_PCI_LENGTH = 21, /**< PCI bus MCFG MMIO range length */
188 SYSTEM_INFO_INDEX_SERIAL0_IOBASE = 22,
189 SYSTEM_INFO_INDEX_SERIAL0_IRQ = 23,
190 SYSTEM_INFO_INDEX_SERIAL1_IOBASE = 24,
191 SYSTEM_INFO_INDEX_SERIAL1_IRQ = 25,
192 SYSTEM_INFO_INDEX_PARALLEL0_IOBASE = 26,
193 SYSTEM_INFO_INDEX_PARALLEL0_IRQ = 27,
194 SYSTEM_INFO_INDEX_PARALLEL1_IOBASE = 28,
195 SYSTEM_INFO_INDEX_PARALLEL1_IRQ = 29,
196 SYSTEM_INFO_INDEX_PREF64_MEMORY_MAX = 30,
197 SYSTEM_INFO_INDEX_END = 31,
198 SYSTEM_INFO_INDEX_INVALID = 0x80,
199 SYSTEM_INFO_INDEX_VALID = 0x200
200};
201
202#define AC_OFFLINE 0
203#define AC_ONLINE 1
204
205#define BAT_TECH_PRIMARY 1
206#define BAT_TECH_SECONDARY 2
207
208#define STA_DEVICE_PRESENT_MASK RT_BIT(0) /**< present */
209#define STA_DEVICE_ENABLED_MASK RT_BIT(1) /**< enabled and decodes its resources */
210#define STA_DEVICE_SHOW_IN_UI_MASK RT_BIT(2) /**< should be shown in UI */
211#define STA_DEVICE_FUNCTIONING_PROPERLY_MASK RT_BIT(3) /**< functioning properly */
212#define STA_BATTERY_PRESENT_MASK RT_BIT(4) /**< the battery is present */
213
214/** SMBus Base Address PCI config space offset */
215#define SMBBA 0x90
216/** SMBus Host Configuration PCI config space offset */
217#define SMBHSTCFG 0xd2
218/** SMBus Slave Command PCI config space offset */
219#define SMBSLVC 0xd3
220/** SMBus Slave Shadow Port 1 PCI config space offset */
221#define SMBSHDW1 0xd4
222/** SMBus Slave Shadow Port 2 PCI config space offset */
223#define SMBSHDW2 0xd5
224/** SMBus Revision Identification PCI config space offset */
225#define SMBREV 0xd6
226
227#define SMBHSTCFG_SMB_HST_EN RT_BIT(0)
228#define SMBHSTCFG_INTRSEL (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
229#define SMBHSTCFG_INTRSEL_SMI 0
230#define SMBHSTCFG_INTRSEL_IRQ9 4
231#define SMBHSTCFG_INTRSEL_SHIFT 1
232
233/** Default base for SMBus PIIX4 device */
234#define SMB_PORT_BASE 0x4100
235
236/** SMBus Host Status Register I/O offset */
237#define SMBHSTSTS_OFF 0x0000
238/** SMBus Slave Status Register I/O offset */
239#define SMBSLVSTS_OFF 0x0001
240/** SMBus Host Count Register I/O offset */
241#define SMBHSTCNT_OFF 0x0002
242/** SMBus Host Command Register I/O offset */
243#define SMBHSTCMD_OFF 0x0003
244/** SMBus Host Address Register I/O offset */
245#define SMBHSTADD_OFF 0x0004
246/** SMBus Host Data 0 Register I/O offset */
247#define SMBHSTDAT0_OFF 0x0005
248/** SMBus Host Data 1 Register I/O offset */
249#define SMBHSTDAT1_OFF 0x0006
250/** SMBus Block Data Register I/O offset */
251#define SMBBLKDAT_OFF 0x0007
252/** SMBus Slave Control Register I/O offset */
253#define SMBSLVCNT_OFF 0x0008
254/** SMBus Shadow Command Register I/O offset */
255#define SMBSHDWCMD_OFF 0x0009
256/** SMBus Slave Event Register I/O offset */
257#define SMBSLVEVT_OFF 0x000a
258/** SMBus Slave Data Register I/O offset */
259#define SMBSLVDAT_OFF 0x000c
260
261#define SMBHSTSTS_HOST_BUSY RT_BIT(0)
262#define SMBHSTSTS_INTER RT_BIT(1)
263#define SMBHSTSTS_DEV_ERR RT_BIT(2)
264#define SMBHSTSTS_BUS_ERR RT_BIT(3)
265#define SMBHSTSTS_FAILED RT_BIT(4)
266#define SMBHSTSTS_INT_MASK (SMBHSTSTS_INTER | SMBHSTSTS_DEV_ERR | SMBHSTSTS_BUS_ERR | SMBHSTSTS_FAILED)
267
268#define SMBSLVSTS_WRITE_MASK 0x3c
269
270#define SMBHSTCNT_INTEREN RT_BIT(0)
271#define SMBHSTCNT_KILL RT_BIT(1)
272#define SMBHSTCNT_CMD_PROT (RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
273#define SMBHSTCNT_START RT_BIT(6)
274#define SMBHSTCNT_WRITE_MASK (SMBHSTCNT_INTEREN | SMBHSTCNT_KILL | SMBHSTCNT_CMD_PROT)
275
276#define SMBSLVCNT_WRITE_MASK (RT_BIT(0) | RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
277
278
279/*********************************************************************************************************************************
280* Structures and Typedefs *
281*********************************************************************************************************************************/
282/**
283 * The ACPI device state.
284 */
285typedef struct ACPIState
286{
287 PDMPCIDEV dev;
288 /** Critical section protecting the ACPI state. */
289 PDMCRITSECT CritSect;
290
291 uint16_t pm1a_en;
292 uint16_t pm1a_sts;
293 uint16_t pm1a_ctl;
294 /** Number of logical CPUs in guest */
295 uint16_t cCpus;
296 uint64_t u64PmTimerInitial;
297 PTMTIMERR3 pPmTimerR3;
298 PTMTIMERR0 pPmTimerR0;
299 PTMTIMERRC pPmTimerRC;
300
301 /* PM Timer last calculated value */
302 uint32_t uPmTimerVal;
303 uint32_t Alignment0;
304
305 uint32_t gpe0_en;
306 uint32_t gpe0_sts;
307
308 uint32_t uBatteryIndex;
309 uint32_t au8BatteryInfo[13];
310
311 uint32_t uSystemInfoIndex;
312 uint64_t u64RamSize;
313 /** Offset of the 64-bit prefetchable memory window. */
314 uint64_t u64PciPref64Min;
315 /** Limit of the 64-bit prefetchable memory window. */
316 uint64_t u64PciPref64Max;
317 /** The number of bytes below 4GB. */
318 uint32_t cbRamLow;
319
320 /** Current ACPI S* state. We support S0 and S5. */
321 uint32_t uSleepState;
322 uint8_t au8RSDPPage[0x1000];
323 /** This is a workaround for incorrect index field handling by Intels ACPICA.
324 * The system info _INI method writes to offset 0x200. We either observe a
325 * write request to index 0x80 (in that case we don't change the index) or a
326 * write request to offset 0x200 (in that case we divide the index value by
327 * 4. Note that the _STA method is sometimes called prior to the _INI method
328 * (ACPI spec 6.3.7, _STA). See the special case for BAT_DEVICE_STATUS in
329 * acpiR3BatIndexWrite() for handling this. */
330 uint8_t u8IndexShift;
331 /** provide an I/O-APIC */
332 uint8_t u8UseIOApic;
333 /** provide a floppy controller */
334 bool fUseFdc;
335 /** If High Precision Event Timer device should be supported */
336 bool fUseHpet;
337 /** If System Management Controller device should be supported */
338 bool fUseSmc;
339 /** the guest handled the last power button event */
340 bool fPowerButtonHandled;
341 /** If ACPI CPU device should be shown */
342 bool fShowCpu;
343 /** If Real Time Clock ACPI object to be shown */
344 bool fShowRtc;
345 /** I/O port address of PM device. */
346 RTIOPORT uPmIoPortBase;
347 /** I/O port address of SMBus device. */
348 RTIOPORT uSMBusIoPortBase;
349 /** Flag whether the GC part of the device is enabled. */
350 bool fGCEnabled;
351 /** Flag whether the R0 part of the device is enabled. */
352 bool fR0Enabled;
353 /** Array of flags of attached CPUs */
354 VMCPUSET CpuSetAttached;
355 /** Which CPU to check for the locked status. */
356 uint32_t idCpuLockCheck;
357 /** Mask of locked CPUs (used by the guest). */
358 VMCPUSET CpuSetLocked;
359 /** The CPU event type. */
360 uint32_t u32CpuEventType;
361 /** The CPU id affected. */
362 uint32_t u32CpuEvent;
363 /** Flag whether CPU hot plugging is enabled. */
364 bool fCpuHotPlug;
365 /** If MCFG ACPI table shown to the guest */
366 bool fUseMcfg;
367 /** if the 64-bit prefetchable memory window is shown to the guest */
368 bool fPciPref64Enabled;
369 /** Primary NIC PCI address. */
370 uint32_t u32NicPciAddress;
371 /** Primary audio card PCI address. */
372 uint32_t u32AudioPciAddress;
373 /** Flag whether S1 power state is enabled. */
374 bool fS1Enabled;
375 /** Flag whether S4 power state is enabled. */
376 bool fS4Enabled;
377 /** Flag whether S1 triggers a state save. */
378 bool fSuspendToSavedState;
379 /** Flag whether to set WAK_STS on resume (restore included). */
380 bool fSetWakeupOnResume;
381 /** PCI address of the IO controller device. */
382 uint32_t u32IocPciAddress;
383 /** PCI address of the host bus controller device. */
384 uint32_t u32HbcPciAddress;
385
386 uint32_t Alignment1;
387
388 /** Physical address of PCI config space MMIO region */
389 uint64_t u64PciConfigMMioAddress;
390 /** Length of PCI config space MMIO region */
391 uint64_t u64PciConfigMMioLength;
392 /** Serial 0 IRQ number */
393 uint8_t uSerial0Irq;
394 /** Serial 1 IRQ number */
395 uint8_t uSerial1Irq;
396 /** Serial 2 IRQ number */
397 uint8_t uSerial2Irq;
398 /** Serial 3 IRQ number */
399 uint8_t uSerial3Irq;
400 /** Serial 0 IO port base */
401 RTIOPORT uSerial0IoPortBase;
402 /** Serial 1 IO port base */
403 RTIOPORT uSerial1IoPortBase;
404 /** Serial 2 IO port base */
405 RTIOPORT uSerial2IoPortBase;
406 /** Serial 3 IO port base */
407 RTIOPORT uSerial3IoPortBase;
408
409 /** @name Parallel port config bits
410 * @{ */
411 /** Parallel 0 IRQ number */
412 uint8_t uParallel0Irq;
413 /** Parallel 1 IRQ number */
414 uint8_t uParallel1Irq;
415 /** Parallel 0 IO port base */
416 RTIOPORT uParallel0IoPortBase;
417 /** Parallel 1 IO port base */
418 RTIOPORT uParallel1IoPortBase;
419 /** @} */
420
421 uint32_t Alignment2;
422
423 /** ACPI port base interface. */
424 PDMIBASE IBase;
425 /** ACPI port interface. */
426 PDMIACPIPORT IACPIPort;
427 /** Pointer to the device instance. */
428 PPDMDEVINSR3 pDevInsR3;
429 PPDMDEVINSR0 pDevInsR0;
430 PPDMDEVINSRC pDevInsRC;
431
432 uint32_t Alignment3;
433 /** Pointer to the driver base interface. */
434 R3PTRTYPE(PPDMIBASE) pDrvBase;
435 /** Pointer to the driver connector interface. */
436 R3PTRTYPE(PPDMIACPICONNECTOR) pDrv;
437
438 /** Pointer to default PCI config read function. */
439 R3PTRTYPE(PFNPCICONFIGREAD) pfnAcpiPciConfigRead;
440 /** Pointer to default PCI config write function. */
441 R3PTRTYPE(PFNPCICONFIGWRITE) pfnAcpiPciConfigWrite;
442
443 /** Number of custom ACPI tables */
444 uint8_t cCustTbls;
445 /** ACPI OEM ID */
446 uint8_t au8OemId[6];
447 /** ACPI Crator ID */
448 uint8_t au8CreatorId[4];
449 /** ACPI Crator Rev */
450 uint32_t u32CreatorRev;
451 /** ACPI custom OEM Tab ID */
452 uint8_t au8OemTabId[8];
453 /** ACPI custom OEM Rev */
454 uint32_t u32OemRevision;
455 uint32_t Alignment4;
456
457 /** Custom ACPI tables binary data. */
458 R3PTRTYPE(uint8_t *) apu8CustBin[MAX_CUST_TABLES];
459 /** The size of the custom table binary. */
460 uint64_t acbCustBin[MAX_CUST_TABLES];
461
462 /** SMBus Host Status Register */
463 uint8_t u8SMBusHstSts;
464 /** SMBus Slave Status Register */
465 uint8_t u8SMBusSlvSts;
466 /** SMBus Host Control Register */
467 uint8_t u8SMBusHstCnt;
468 /** SMBus Host Command Register */
469 uint8_t u8SMBusHstCmd;
470 /** SMBus Host Address Register */
471 uint8_t u8SMBusHstAdd;
472 /** SMBus Host Data 0 Register */
473 uint8_t u8SMBusHstDat0;
474 /** SMBus Host Data 1 Register */
475 uint8_t u8SMBusHstDat1;
476 /** SMBus Slave Control Register */
477 uint8_t u8SMBusSlvCnt;
478 /** SMBus Shadow Command Register */
479 uint8_t u8SMBusShdwCmd;
480 /** SMBus Slave Event Register */
481 uint16_t u16SMBusSlvEvt;
482 /** SMBus Slave Data Register */
483 uint16_t u16SMBusSlvDat;
484 /** SMBus Host Block Data Buffer */
485 uint8_t au8SMBusBlkDat[32];
486 /** SMBus Host Block Index */
487 uint8_t u8SMBusBlkIdx;
488
489 /** @todo DEBUGGING */
490 uint32_t uPmTimeOld;
491 uint32_t uPmTimeA;
492 uint32_t uPmTimeB;
493 uint32_t Alignment5;
494} ACPIState;
495
496#pragma pack(1)
497
498/** Generic Address Structure (see ACPIspec 3.0, 5.2.3.1) */
499struct ACPIGENADDR
500{
501 uint8_t u8AddressSpaceId; /**< 0=sys, 1=IO, 2=PCICfg, 3=emb, 4=SMBus */
502 uint8_t u8RegisterBitWidth; /**< size in bits of the given register */
503 uint8_t u8RegisterBitOffset; /**< bit offset of register */
504 uint8_t u8AccessSize; /**< 1=byte, 2=word, 3=dword, 4=qword */
505 uint64_t u64Address; /**< 64-bit address of register */
506};
507AssertCompileSize(ACPIGENADDR, 12);
508
509/** Root System Description Pointer */
510struct ACPITBLRSDP
511{
512 uint8_t au8Signature[8]; /**< 'RSD PTR ' */
513 uint8_t u8Checksum; /**< checksum for the first 20 bytes */
514 uint8_t au8OemId[6]; /**< OEM-supplied identifier */
515 uint8_t u8Revision; /**< revision number, currently 2 */
516#define ACPI_REVISION 2 /**< ACPI 3.0 */
517 uint32_t u32RSDT; /**< phys addr of RSDT */
518 uint32_t u32Length; /**< bytes of this table */
519 uint64_t u64XSDT; /**< 64-bit phys addr of XSDT */
520 uint8_t u8ExtChecksum; /**< checksum of entire table */
521 uint8_t u8Reserved[3]; /**< reserved */
522};
523AssertCompileSize(ACPITBLRSDP, 36);
524
525/** System Description Table Header */
526struct ACPITBLHEADER
527{
528 uint8_t au8Signature[4]; /**< table identifier */
529 uint32_t u32Length; /**< length of the table including header */
530 uint8_t u8Revision; /**< revision number */
531 uint8_t u8Checksum; /**< all fields inclusive this add to zero */
532 uint8_t au8OemId[6]; /**< OEM-supplied string */
533 uint8_t au8OemTabId[8]; /**< to identify the particular data table */
534 uint32_t u32OemRevision; /**< OEM-supplied revision number */
535 uint8_t au8CreatorId[4]; /**< ID for the ASL compiler */
536 uint32_t u32CreatorRev; /**< revision for the ASL compiler */
537};
538AssertCompileSize(ACPITBLHEADER, 36);
539
540/** Root System Description Table */
541struct ACPITBLRSDT
542{
543 ACPITBLHEADER header;
544 uint32_t u32Entry[1]; /**< array of phys. addresses to other tables */
545};
546AssertCompileSize(ACPITBLRSDT, 40);
547
548/** Extended System Description Table */
549struct ACPITBLXSDT
550{
551 ACPITBLHEADER header;
552 uint64_t u64Entry[1]; /**< array of phys. addresses to other tables */
553};
554AssertCompileSize(ACPITBLXSDT, 44);
555
556/** Fixed ACPI Description Table */
557struct ACPITBLFADT
558{
559 ACPITBLHEADER header;
560 uint32_t u32FACS; /**< phys. address of FACS */
561 uint32_t u32DSDT; /**< phys. address of DSDT */
562 uint8_t u8IntModel; /**< was eleminated in ACPI 2.0 */
563#define INT_MODEL_DUAL_PIC 1 /**< for ACPI 2+ */
564#define INT_MODEL_MULTIPLE_APIC 2
565 uint8_t u8PreferredPMProfile; /**< preferred power management profile */
566 uint16_t u16SCIInt; /**< system vector the SCI is wired in 8259 mode */
567#define SCI_INT 9
568 uint32_t u32SMICmd; /**< system port address of SMI command port */
569#define SMI_CMD 0x0000442e
570 uint8_t u8AcpiEnable; /**< SMICmd val to disable ownership of ACPIregs */
571#define ACPI_ENABLE 0xa1
572 uint8_t u8AcpiDisable; /**< SMICmd val to re-enable ownership of ACPIregs */
573#define ACPI_DISABLE 0xa0
574 uint8_t u8S4BIOSReq; /**< SMICmd val to enter S4BIOS state */
575 uint8_t u8PStateCnt; /**< SMICmd val to assume processor performance
576 state control responsibility */
577 uint32_t u32PM1aEVTBLK; /**< port addr of PM1a event regs block */
578 uint32_t u32PM1bEVTBLK; /**< port addr of PM1b event regs block */
579 uint32_t u32PM1aCTLBLK; /**< port addr of PM1a control regs block */
580 uint32_t u32PM1bCTLBLK; /**< port addr of PM1b control regs block */
581 uint32_t u32PM2CTLBLK; /**< port addr of PM2 control regs block */
582 uint32_t u32PMTMRBLK; /**< port addr of PMTMR regs block */
583 uint32_t u32GPE0BLK; /**< port addr of gen-purp event 0 regs block */
584 uint32_t u32GPE1BLK; /**< port addr of gen-purp event 1 regs block */
585 uint8_t u8PM1EVTLEN; /**< bytes decoded by PM1a_EVT_BLK. >= 4 */
586 uint8_t u8PM1CTLLEN; /**< bytes decoded by PM1b_CNT_BLK. >= 2 */
587 uint8_t u8PM2CTLLEN; /**< bytes decoded by PM2_CNT_BLK. >= 1 or 0 */
588 uint8_t u8PMTMLEN; /**< bytes decoded by PM_TMR_BLK. ==4 */
589 uint8_t u8GPE0BLKLEN; /**< bytes decoded by GPE0_BLK. %2==0 */
590#define GPE0_BLK_LEN 2
591 uint8_t u8GPE1BLKLEN; /**< bytes decoded by GPE1_BLK. %2==0 */
592#define GPE1_BLK_LEN 0
593 uint8_t u8GPE1BASE; /**< offset of GPE1 based events */
594#define GPE1_BASE 0
595 uint8_t u8CSTCNT; /**< SMICmd val to indicate OS supp for C states */
596 uint16_t u16PLVL2LAT; /**< us to enter/exit C2. >100 => unsupported */
597#define P_LVL2_LAT 101 /**< C2 state not supported */
598 uint16_t u16PLVL3LAT; /**< us to enter/exit C3. >1000 => unsupported */
599#define P_LVL3_LAT 1001 /**< C3 state not supported */
600 uint16_t u16FlushSize; /**< # of flush strides to read to flush dirty
601 lines from any processors memory caches */
602#define FLUSH_SIZE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
603 uint16_t u16FlushStride; /**< cache line width */
604#define FLUSH_STRIDE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
605 uint8_t u8DutyOffset;
606 uint8_t u8DutyWidth;
607 uint8_t u8DayAlarm; /**< RTC CMOS RAM index of day-of-month alarm */
608 uint8_t u8MonAlarm; /**< RTC CMOS RAM index of month-of-year alarm */
609 uint8_t u8Century; /**< RTC CMOS RAM index of century */
610 uint16_t u16IAPCBOOTARCH; /**< IA-PC boot architecture flags */
611#define IAPC_BOOT_ARCH_LEGACY_DEV RT_BIT(0) /**< legacy devices present such as LPT
612 (COM too?) */
613#define IAPC_BOOT_ARCH_8042 RT_BIT(1) /**< legacy keyboard device present */
614#define IAPC_BOOT_ARCH_NO_VGA RT_BIT(2) /**< VGA not present */
615#define IAPC_BOOT_ARCH_NO_MSI RT_BIT(3) /**< OSPM must not enable MSIs on this platform */
616#define IAPC_BOOT_ARCH_NO_ASPM RT_BIT(4) /**< OSPM must not enable ASPM on this platform */
617 uint8_t u8Must0_0; /**< must be 0 */
618 uint32_t u32Flags; /**< fixed feature flags */
619#define FADT_FL_WBINVD RT_BIT(0) /**< emulation of WBINVD available */
620#define FADT_FL_WBINVD_FLUSH RT_BIT(1)
621#define FADT_FL_PROC_C1 RT_BIT(2) /**< 1=C1 supported on all processors */
622#define FADT_FL_P_LVL2_UP RT_BIT(3) /**< 1=C2 works on SMP and UNI systems */
623#define FADT_FL_PWR_BUTTON RT_BIT(4) /**< 1=power button handled as ctrl method dev */
624#define FADT_FL_SLP_BUTTON RT_BIT(5) /**< 1=sleep button handled as ctrl method dev */
625#define FADT_FL_FIX_RTC RT_BIT(6) /**< 0=RTC wake status in fixed register */
626#define FADT_FL_RTC_S4 RT_BIT(7) /**< 1=RTC can wake system from S4 */
627#define FADT_FL_TMR_VAL_EXT RT_BIT(8) /**< 1=TMR_VAL implemented as 32 bit */
628#define FADT_FL_DCK_CAP RT_BIT(9) /**< 0=system cannot support docking */
629#define FADT_FL_RESET_REG_SUP RT_BIT(10) /**< 1=system supports system resets */
630#define FADT_FL_SEALED_CASE RT_BIT(11) /**< 1=case is sealed */
631#define FADT_FL_HEADLESS RT_BIT(12) /**< 1=system cannot detect moni/keyb/mouse */
632#define FADT_FL_CPU_SW_SLP RT_BIT(13)
633#define FADT_FL_PCI_EXT_WAK RT_BIT(14) /**< 1=system supports PCIEXP_WAKE_STS */
634#define FADT_FL_USE_PLATFORM_CLOCK RT_BIT(15) /**< 1=system has ACPI PM timer */
635#define FADT_FL_S4_RTC_STS_VALID RT_BIT(16) /**< 1=RTC_STS flag is valid when waking from S4 */
636#define FADT_FL_REMOVE_POWER_ON_CAPABLE RT_BIT(17) /**< 1=platform can remote power on */
637#define FADT_FL_FORCE_APIC_CLUSTER_MODEL RT_BIT(18)
638#define FADT_FL_FORCE_APIC_PHYS_DEST_MODE RT_BIT(19)
639
640/* PM Timer mask and msb */
641#ifndef PM_TMR_32BIT
642#define TMR_VAL_MSB 0x800000
643#define TMR_VAL_MASK 0xffffff
644#undef FADT_FL_TMR_VAL_EXT
645#define FADT_FL_TMR_VAL_EXT 0
646#else
647#define TMR_VAL_MSB 0x80000000
648#define TMR_VAL_MASK 0xffffffff
649#endif
650
651 /** Start of the ACPI 2.0 extension. */
652 ACPIGENADDR ResetReg; /**< ext addr of reset register */
653 uint8_t u8ResetVal; /**< ResetReg value to reset the system */
654#define ACPI_RESET_REG_VAL 0x10
655 uint8_t au8Must0_1[3]; /**< must be 0 */
656 uint64_t u64XFACS; /**< 64-bit phys address of FACS */
657 uint64_t u64XDSDT; /**< 64-bit phys address of DSDT */
658 ACPIGENADDR X_PM1aEVTBLK; /**< ext addr of PM1a event regs block */
659 ACPIGENADDR X_PM1bEVTBLK; /**< ext addr of PM1b event regs block */
660 ACPIGENADDR X_PM1aCTLBLK; /**< ext addr of PM1a control regs block */
661 ACPIGENADDR X_PM1bCTLBLK; /**< ext addr of PM1b control regs block */
662 ACPIGENADDR X_PM2CTLBLK; /**< ext addr of PM2 control regs block */
663 ACPIGENADDR X_PMTMRBLK; /**< ext addr of PMTMR control regs block */
664 ACPIGENADDR X_GPE0BLK; /**< ext addr of GPE1 regs block */
665 ACPIGENADDR X_GPE1BLK; /**< ext addr of GPE1 regs block */
666};
667AssertCompileSize(ACPITBLFADT, 244);
668#define ACPITBLFADT_VERSION1_SIZE RT_OFFSETOF(ACPITBLFADT, ResetReg)
669
670/** Firmware ACPI Control Structure */
671struct ACPITBLFACS
672{
673 uint8_t au8Signature[4]; /**< 'FACS' */
674 uint32_t u32Length; /**< bytes of entire FACS structure >= 64 */
675 uint32_t u32HWSignature; /**< systems HW signature at last boot */
676 uint32_t u32FWVector; /**< address of waking vector */
677 uint32_t u32GlobalLock; /**< global lock to sync HW/SW */
678 uint32_t u32Flags; /**< FACS flags */
679 uint64_t u64X_FWVector; /**< 64-bit waking vector */
680 uint8_t u8Version; /**< version of this table */
681 uint8_t au8Reserved[31]; /**< zero */
682};
683AssertCompileSize(ACPITBLFACS, 64);
684
685/** Processor Local APIC Structure */
686struct ACPITBLLAPIC
687{
688 uint8_t u8Type; /**< 0 = LAPIC */
689 uint8_t u8Length; /**< 8 */
690 uint8_t u8ProcId; /**< processor ID */
691 uint8_t u8ApicId; /**< local APIC ID */
692 uint32_t u32Flags; /**< Flags */
693#define LAPIC_ENABLED 0x1
694};
695AssertCompileSize(ACPITBLLAPIC, 8);
696
697/** I/O APIC Structure */
698struct ACPITBLIOAPIC
699{
700 uint8_t u8Type; /**< 1 == I/O APIC */
701 uint8_t u8Length; /**< 12 */
702 uint8_t u8IOApicId; /**< I/O APIC ID */
703 uint8_t u8Reserved; /**< 0 */
704 uint32_t u32Address; /**< phys address to access I/O APIC */
705 uint32_t u32GSIB; /**< global system interrupt number to start */
706};
707AssertCompileSize(ACPITBLIOAPIC, 12);
708
709/** Interrupt Source Override Structure */
710struct ACPITBLISO
711{
712 uint8_t u8Type; /**< 2 == Interrupt Source Override*/
713 uint8_t u8Length; /**< 10 */
714 uint8_t u8Bus; /**< Bus */
715 uint8_t u8Source; /**< Bus-relative interrupt source (IRQ) */
716 uint32_t u32GSI; /**< Global System Interrupt */
717 uint16_t u16Flags; /**< MPS INTI flags Global */
718};
719AssertCompileSize(ACPITBLISO, 10);
720#define NUMBER_OF_IRQ_SOURCE_OVERRIDES 2
721
722/** HPET Descriptor Structure */
723struct ACPITBLHPET
724{
725 ACPITBLHEADER aHeader;
726 uint32_t u32Id; /**< hardware ID of event timer block
727 [31:16] PCI vendor ID of first timer block
728 [15] legacy replacement IRQ routing capable
729 [14] reserved
730 [13] COUNT_SIZE_CAP counter size
731 [12:8] number of comparators in first timer block
732 [7:0] hardware rev ID */
733 ACPIGENADDR HpetAddr; /**< lower 32-bit base address */
734 uint8_t u32Number; /**< sequence number starting at 0 */
735 uint16_t u32MinTick; /**< minimum clock ticks which can be set without
736 lost interrupts while the counter is programmed
737 to operate in periodic mode. Unit: clock tick. */
738 uint8_t u8Attributes; /**< page protection and OEM attribute. */
739};
740AssertCompileSize(ACPITBLHPET, 56);
741
742/** MCFG Descriptor Structure */
743typedef struct ACPITBLMCFG
744{
745 ACPITBLHEADER aHeader;
746 uint64_t u64Reserved;
747} ACPITBLMCFG;
748AssertCompileSize(ACPITBLMCFG, 44);
749
750/** Number of such entries can be computed from the whole table length in header */
751typedef struct ACPITBLMCFGENTRY
752{
753 uint64_t u64BaseAddress;
754 uint16_t u16PciSegmentGroup;
755 uint8_t u8StartBus;
756 uint8_t u8EndBus;
757 uint32_t u32Reserved;
758} ACPITBLMCFGENTRY;
759AssertCompileSize(ACPITBLMCFGENTRY, 16);
760
761#define PCAT_COMPAT 0x1 /**< system has also a dual-8259 setup */
762
763/** Custom Description Table */
764struct ACPITBLCUST
765{
766 ACPITBLHEADER header;
767 uint8_t au8Data[476];
768};
769AssertCompileSize(ACPITBLCUST, 512);
770
771
772#pragma pack()
773
774
775#ifndef VBOX_DEVICE_STRUCT_TESTCASE /* exclude the rest of the file */
776
777
778/*********************************************************************************************************************************
779* Internal Functions *
780*********************************************************************************************************************************/
781RT_C_DECLS_BEGIN
782PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
783RT_C_DECLS_END
784#ifdef IN_RING3
785static int acpiR3PlantTables(ACPIState *pThis);
786#endif
787
788/* SCI, usually IRQ9 */
789DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
790{
791 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, level);
792}
793
794DECLINLINE(bool) pm1a_level(ACPIState *pThis)
795{
796 return (pThis->pm1a_ctl & SCI_EN)
797 && (pThis->pm1a_en & pThis->pm1a_sts & ~(RSR_EN | IGN_EN));
798}
799
800DECLINLINE(bool) gpe0_level(ACPIState *pThis)
801{
802 return !!(pThis->gpe0_en & pThis->gpe0_sts);
803}
804
805DECLINLINE(bool) smbus_level(ACPIState *pThis)
806{
807 return (pThis->u8SMBusHstCnt & SMBHSTCNT_INTEREN)
808 && (pThis->dev.abConfig[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
809 && (pThis->dev.abConfig[SMBHSTCFG] & SMBHSTCFG_INTRSEL) == SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT
810 && (pThis->u8SMBusHstSts & SMBHSTSTS_INT_MASK);
811}
812
813DECLINLINE(bool) acpiSCILevel(ACPIState *pThis)
814{
815 return pm1a_level(pThis) || gpe0_level(pThis) || smbus_level(pThis);
816}
817
818/**
819 * Used by acpiR3PM1aStsWrite, acpiR3PM1aEnWrite, acpiR3PmTimer,
820 * acpiR3Port_PowerBuffonPress, acpiR3Port_SleepButtonPress
821 * and acpiPmTmrRead to update the PM1a.STS and PM1a.EN
822 * registers and trigger IRQs.
823 *
824 * Caller must hold the state lock.
825 *
826 * @param pThis The ACPI instance.
827 * @param sts The new PM1a.STS value.
828 * @param en The new PM1a.EN value.
829 */
830static void apicUpdatePm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
831{
832 Assert(PDMCritSectIsOwner(&pThis->CritSect));
833
834 const bool old_level = acpiSCILevel(pThis);
835 pThis->pm1a_en = en;
836 pThis->pm1a_sts = sts;
837 const bool new_level = acpiSCILevel(pThis);
838
839 LogFunc(("old=%x new=%x\n", old_level, new_level));
840
841 if (new_level != old_level)
842 acpiSetIrq(pThis, new_level);
843}
844
845#ifdef IN_RING3
846
847/**
848 * Used by acpiR3Gpe0StsWrite, acpiR3Gpe0EnWrite, acpiAttach and acpiDetach to
849 * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
850 *
851 * Caller must hold the state lock.
852 *
853 * @param pThis The ACPI instance.
854 * @param sts The new GPE0.STS value.
855 * @param en The new GPE0.EN value.
856 */
857static void apicR3UpdateGpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
858{
859 Assert(PDMCritSectIsOwner(&pThis->CritSect));
860
861 const bool old_level = acpiSCILevel(pThis);
862 pThis->gpe0_en = en;
863 pThis->gpe0_sts = sts;
864 const bool new_level = acpiSCILevel(pThis);
865
866 LogFunc(("old=%x new=%x\n", old_level, new_level));
867
868 if (new_level != old_level)
869 acpiSetIrq(pThis, new_level);
870}
871
872/**
873 * Used by acpiR3PM1aCtlWrite to power off the VM.
874 *
875 * @param pThis The ACPI instance.
876 * @returns Strict VBox status code.
877 */
878static int acpiR3DoPowerOff(ACPIState *pThis)
879{
880 int rc = PDMDevHlpVMPowerOff(pThis->pDevInsR3);
881 if (RT_FAILURE(rc))
882 AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
883 return rc;
884}
885
886/**
887 * Used by acpiR3PM1aCtlWrite to put the VM to sleep.
888 *
889 * @param pThis The ACPI instance.
890 * @returns Strict VBox status code.
891 */
892static int acpiR3DoSleep(ACPIState *pThis)
893{
894 /* We must set WAK_STS on resume (includes restore) so the guest knows that
895 we've woken up and can continue executing code. The guest is probably
896 reading the PMSTS register in a loop to check this. */
897 int rc;
898 pThis->fSetWakeupOnResume = true;
899 if (pThis->fSuspendToSavedState)
900 {
901 rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevInsR3);
902 if (rc != VERR_NOT_SUPPORTED)
903 AssertRC(rc);
904 else
905 {
906 LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
907 rc = PDMDevHlpVMSuspend(pThis->pDevInsR3);
908 AssertRC(rc);
909 }
910 }
911 else
912 {
913 rc = PDMDevHlpVMSuspend(pThis->pDevInsR3);
914 AssertRC(rc);
915 }
916 return rc;
917}
918
919
920/**
921 * @interface_method_impl{PDMIACPIPORT,pfnPowerButtonPress}
922 */
923static DECLCALLBACK(int) acpiR3Port_PowerButtonPress(PPDMIACPIPORT pInterface)
924{
925 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
926 DEVACPI_LOCK_R3(pThis);
927
928 Log(("acpiR3Port_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
929 pThis->fPowerButtonHandled = false;
930 apicUpdatePm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
931
932 DEVACPI_UNLOCK(pThis);
933 return VINF_SUCCESS;
934}
935
936/**
937 * @interface_method_impl{PDMIACPIPORT,pfnGetPowerButtonHandled}
938 */
939static DECLCALLBACK(int) acpiR3Port_GetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
940{
941 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
942 DEVACPI_LOCK_R3(pThis);
943
944 *pfHandled = pThis->fPowerButtonHandled;
945
946 DEVACPI_UNLOCK(pThis);
947 return VINF_SUCCESS;
948}
949
950/**
951 * @interface_method_impl{PDMIACPIPORT,pfnGetGuestEnteredACPIMode, Check if the
952 * Guest entered into G0 (working) or G1 (sleeping)}
953 */
954static DECLCALLBACK(int) acpiR3Port_GetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
955{
956 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
957 DEVACPI_LOCK_R3(pThis);
958
959 *pfEntered = (pThis->pm1a_ctl & SCI_EN) != 0;
960
961 DEVACPI_UNLOCK(pThis);
962 return VINF_SUCCESS;
963}
964
965/**
966 * @interface_method_impl{PDMIACPIPORT,pfnGetCpuStatus}
967 */
968static DECLCALLBACK(int) acpiR3Port_GetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
969{
970 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
971 DEVACPI_LOCK_R3(pThis);
972
973 *pfLocked = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, uCpu);
974
975 DEVACPI_UNLOCK(pThis);
976 return VINF_SUCCESS;
977}
978
979/**
980 * Send an ACPI sleep button event.
981 *
982 * @returns VBox status code
983 * @param pInterface Pointer to the interface structure containing the called function pointer.
984 */
985static DECLCALLBACK(int) acpiR3Port_SleepButtonPress(PPDMIACPIPORT pInterface)
986{
987 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
988 DEVACPI_LOCK_R3(pThis);
989
990 apicUpdatePm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
991
992 DEVACPI_UNLOCK(pThis);
993 return VINF_SUCCESS;
994}
995
996/**
997 * Send an ACPI monitor hot-plug event.
998 *
999 * @returns VBox status code
1000 * @param pInterface Pointer to the interface structure containing the
1001 * called function pointer.
1002 */
1003static DECLCALLBACK(int) acpiR3Port_MonitorHotPlugEvent(PPDMIACPIPORT pInterface)
1004{
1005 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
1006 DEVACPI_LOCK_R3(pThis);
1007
1008 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x4, pThis->gpe0_en);
1009
1010 DEVACPI_UNLOCK(pThis);
1011 return VINF_SUCCESS;
1012}
1013
1014/**
1015 * Send an ACPI battery status change event.
1016 *
1017 * @returns VBox status code
1018 * @param pInterface Pointer to the interface structure containing the
1019 * called function pointer.
1020 */
1021static DECLCALLBACK(int) acpiR3Port_BatteryStatusChangeEvent(PPDMIACPIPORT pInterface)
1022{
1023 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
1024 DEVACPI_LOCK_R3(pThis);
1025
1026 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x1, pThis->gpe0_en);
1027
1028 DEVACPI_UNLOCK(pThis);
1029 return VINF_SUCCESS;
1030}
1031
1032/**
1033 * Used by acpiR3PmTimer to re-arm the PM timer.
1034 *
1035 * The caller is expected to either hold the clock lock or to have made sure
1036 * the VM is resetting or loading state.
1037 *
1038 * @param pThis The ACPI instance.
1039 * @param uNow The current time.
1040 */
1041static void acpiR3PmTimerReset(ACPIState *pThis, uint64_t uNow)
1042{
1043 uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
1044 uint32_t uPmTmrCyclesToRollover = TMR_VAL_MSB - (pThis->uPmTimerVal & (TMR_VAL_MSB - 1));
1045 uint64_t uInterval = ASMMultU64ByU32DivByU32(uPmTmrCyclesToRollover, uTimerFreq, PM_TMR_FREQ);
1046 TMTimerSet(pThis->pPmTimerR3, uNow + uInterval + 1);
1047 Log(("acpi: uInterval = %RU64\n", uInterval));
1048}
1049
1050#endif /* IN_RING3 */
1051
1052/**
1053 * Used by acpiR3PMTimer & acpiPmTmrRead to update TMR_VAL and update TMR_STS
1054 *
1055 * The caller is expected to either hold the clock lock or to have made sure
1056 * the VM is resetting or loading state.
1057 *
1058 * @param pThis The ACPI instance
1059 * @param u64Now The current time
1060 */
1061
1062static void acpiPmTimerUpdate(ACPIState *pThis, uint64_t u64Now)
1063{
1064 uint32_t msb = pThis->uPmTimerVal & TMR_VAL_MSB;
1065 uint64_t u64Elapsed = u64Now - pThis->u64PmTimerInitial;
1066 Assert(TMTimerIsLockOwner(pThis->CTX_SUFF(pPmTimer)));
1067
1068 pThis->uPmTimerVal = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer))) & TMR_VAL_MASK;
1069
1070 if ( (pThis->uPmTimerVal & TMR_VAL_MSB) != msb)
1071 {
1072 apicUpdatePm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
1073 }
1074}
1075
1076#ifdef IN_RING3
1077
1078/**
1079 * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
1080 */
1081static DECLCALLBACK(void) acpiR3PmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1082{
1083 ACPIState *pThis = (ACPIState *)pvUser;
1084 Assert(TMTimerIsLockOwner(pTimer));
1085 NOREF(pDevIns);
1086
1087 DEVACPI_LOCK_R3(pThis);
1088 Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
1089 pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
1090 pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
1091 uint64_t u64Now = TMTimerGet(pTimer);
1092 acpiPmTimerUpdate(pThis, u64Now);
1093 DEVACPI_UNLOCK(pThis);
1094
1095 acpiR3PmTimerReset(pThis, u64Now);
1096}
1097
1098/**
1099 * _BST method - used by acpiR3BatDataRead to implement BAT_STATUS_STATE and
1100 * acpiR3LoadState.
1101 *
1102 * @returns VINF_SUCCESS.
1103 * @param pThis The ACPI instance.
1104 */
1105static int acpiR3FetchBatteryStatus(ACPIState *pThis)
1106{
1107 uint32_t *p = pThis->au8BatteryInfo;
1108 bool fPresent; /* battery present? */
1109 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1110 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1111 uint32_t hostPresentRate; /* 0..1000 */
1112 int rc;
1113
1114 if (!pThis->pDrv)
1115 return VINF_SUCCESS;
1116 rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
1117 &hostBatteryState, &hostPresentRate);
1118 AssertRC(rc);
1119
1120 /* default values */
1121 p[BAT_STATUS_STATE] = hostBatteryState;
1122 p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
1123 : hostPresentRate * 50; /* mW */
1124 p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
1125 p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
1126
1127 /* did we get a valid battery state? */
1128 if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
1129 p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
1130 if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
1131 p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
1132
1133 return VINF_SUCCESS;
1134}
1135
1136/**
1137 * _BIF method - used by acpiR3BatDataRead to implement BAT_INFO_UNITS and
1138 * acpiR3LoadState.
1139 *
1140 * @returns VINF_SUCCESS.
1141 * @param pThis The ACPI instance.
1142 */
1143static int acpiR3FetchBatteryInfo(ACPIState *pThis)
1144{
1145 uint32_t *p = pThis->au8BatteryInfo;
1146
1147 p[BAT_INFO_UNITS] = 0; /* mWh */
1148 p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
1149 p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
1150 p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
1151 p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
1152 p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
1153 p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
1154 p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
1155 p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
1156
1157 return VINF_SUCCESS;
1158}
1159
1160/**
1161 * The _STA method - used by acpiR3BatDataRead to implement BAT_DEVICE_STATUS.
1162 *
1163 * @returns status mask or 0.
1164 * @param pThis The ACPI instance.
1165 */
1166static uint32_t acpiR3GetBatteryDeviceStatus(ACPIState *pThis)
1167{
1168 bool fPresent; /* battery present? */
1169 PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
1170 PDMACPIBATSTATE hostBatteryState; /* bitfield */
1171 uint32_t hostPresentRate; /* 0..1000 */
1172 int rc;
1173
1174 if (!pThis->pDrv)
1175 return 0;
1176 rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
1177 &hostBatteryState, &hostPresentRate);
1178 AssertRC(rc);
1179
1180 return fPresent
1181 ? STA_DEVICE_PRESENT_MASK /* present */
1182 | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
1183 | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
1184 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
1185 | STA_BATTERY_PRESENT_MASK /* battery is present */
1186 : 0; /* device not present */
1187}
1188
1189/**
1190 * Used by acpiR3BatDataRead to implement BAT_POWER_SOURCE.
1191 *
1192 * @returns status.
1193 * @param pThis The ACPI instance.
1194 */
1195static uint32_t acpiR3GetPowerSource(ACPIState *pThis)
1196{
1197 /* query the current power source from the host driver */
1198 if (!pThis->pDrv)
1199 return AC_ONLINE;
1200
1201 PDMACPIPOWERSOURCE ps;
1202 int rc = pThis->pDrv->pfnQueryPowerSource(pThis->pDrv, &ps);
1203 AssertRC(rc);
1204 return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
1205}
1206
1207/**
1208 * @callback_method_impl{FNIOMIOPORTOUT, Battery status index}
1209 */
1210PDMBOTHCBDECL(int) acpiR3BatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1211{
1212 Log(("acpiR3BatIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
1213 if (cb != 4)
1214 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1215
1216 ACPIState *pThis = (ACPIState *)pvUser;
1217 DEVACPI_LOCK_R3(pThis);
1218
1219 u32 >>= pThis->u8IndexShift;
1220 /* see comment at the declaration of u8IndexShift */
1221 if (pThis->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
1222 {
1223 pThis->u8IndexShift = 2;
1224 u32 >>= 2;
1225 }
1226 Assert(u32 < BAT_INDEX_LAST);
1227 pThis->uBatteryIndex = u32;
1228
1229 DEVACPI_UNLOCK(pThis);
1230 return VINF_SUCCESS;
1231}
1232
1233/**
1234 * @callback_method_impl{FNIOMIOPORTIN, Battery status data}
1235 */
1236PDMBOTHCBDECL(int) acpiR3BatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1237{
1238 if (cb != 4)
1239 return VERR_IOM_IOPORT_UNUSED;
1240
1241 ACPIState *pThis = (ACPIState *)pvUser;
1242 DEVACPI_LOCK_R3(pThis);
1243
1244 int rc = VINF_SUCCESS;
1245 switch (pThis->uBatteryIndex)
1246 {
1247 case BAT_STATUS_STATE:
1248 acpiR3FetchBatteryStatus(pThis);
1249 RT_FALL_THRU();
1250 case BAT_STATUS_PRESENT_RATE:
1251 case BAT_STATUS_REMAINING_CAPACITY:
1252 case BAT_STATUS_PRESENT_VOLTAGE:
1253 *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
1254 break;
1255
1256 case BAT_INFO_UNITS:
1257 acpiR3FetchBatteryInfo(pThis);
1258 RT_FALL_THRU();
1259 case BAT_INFO_DESIGN_CAPACITY:
1260 case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
1261 case BAT_INFO_TECHNOLOGY:
1262 case BAT_INFO_DESIGN_VOLTAGE:
1263 case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
1264 case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
1265 case BAT_INFO_CAPACITY_GRANULARITY_1:
1266 case BAT_INFO_CAPACITY_GRANULARITY_2:
1267 *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
1268 break;
1269
1270 case BAT_DEVICE_STATUS:
1271 *pu32 = acpiR3GetBatteryDeviceStatus(pThis);
1272 break;
1273
1274 case BAT_POWER_SOURCE:
1275 *pu32 = acpiR3GetPowerSource(pThis);
1276 break;
1277
1278 default:
1279 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
1280 *pu32 = UINT32_MAX;
1281 break;
1282 }
1283
1284 DEVACPI_UNLOCK(pThis);
1285 return rc;
1286}
1287
1288/**
1289 * @callback_method_impl{FNIOMIOPORTOUT, System info index}
1290 */
1291PDMBOTHCBDECL(int) acpiR3SysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1292{
1293 Log(("acpiR3SysInfoIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
1294 if (cb != 4)
1295 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1296
1297 ACPIState *pThis = (ACPIState *)pvUser;
1298 DEVACPI_LOCK_R3(pThis);
1299
1300 if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
1301 pThis->uSystemInfoIndex = u32;
1302 else
1303 {
1304 /* see comment at the declaration of u8IndexShift */
1305 if (u32 > SYSTEM_INFO_INDEX_END && pThis->u8IndexShift == 0)
1306 {
1307 if ((u32 >> 2) < SYSTEM_INFO_INDEX_END && (u32 & 0x3) == 0)
1308 pThis->u8IndexShift = 2;
1309 }
1310
1311 u32 >>= pThis->u8IndexShift;
1312 Assert(u32 < SYSTEM_INFO_INDEX_END);
1313 pThis->uSystemInfoIndex = u32;
1314 }
1315
1316 DEVACPI_UNLOCK(pThis);
1317 return VINF_SUCCESS;
1318}
1319
1320/**
1321 * @callback_method_impl{FNIOMIOPORTIN, System info data}
1322 */
1323PDMBOTHCBDECL(int) acpiR3SysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1324{
1325 if (cb != 4)
1326 return VERR_IOM_IOPORT_UNUSED;
1327
1328 ACPIState *pThis = (ACPIState *)pvUser;
1329 DEVACPI_LOCK_R3(pThis);
1330
1331 int rc = VINF_SUCCESS;
1332 uint32_t const uSystemInfoIndex = pThis->uSystemInfoIndex;
1333 switch (uSystemInfoIndex)
1334 {
1335 case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
1336 *pu32 = pThis->cbRamLow;
1337 break;
1338
1339 case SYSTEM_INFO_INDEX_PREF64_MEMORY_MIN:
1340 *pu32 = pThis->u64PciPref64Min >> 16; /* 64KB units */
1341 Assert(((uint64_t)*pu32 << 16) == pThis->u64PciPref64Min);
1342 break;
1343
1344 case SYSTEM_INFO_INDEX_PREF64_MEMORY_MAX:
1345 *pu32 = pThis->u64PciPref64Max >> 16; /* 64KB units */
1346 Assert(((uint64_t)*pu32 << 16) == pThis->u64PciPref64Max);
1347 break;
1348
1349 case SYSTEM_INFO_INDEX_USE_IOAPIC:
1350 *pu32 = pThis->u8UseIOApic;
1351 break;
1352
1353 case SYSTEM_INFO_INDEX_HPET_STATUS:
1354 *pu32 = pThis->fUseHpet
1355 ? ( STA_DEVICE_PRESENT_MASK
1356 | STA_DEVICE_ENABLED_MASK
1357 | STA_DEVICE_SHOW_IN_UI_MASK
1358 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1359 : 0;
1360 break;
1361
1362 case SYSTEM_INFO_INDEX_SMC_STATUS:
1363 *pu32 = pThis->fUseSmc
1364 ? ( STA_DEVICE_PRESENT_MASK
1365 | STA_DEVICE_ENABLED_MASK
1366 /* no need to show this device in the UI */
1367 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1368 : 0;
1369 break;
1370
1371 case SYSTEM_INFO_INDEX_FDC_STATUS:
1372 *pu32 = pThis->fUseFdc
1373 ? ( STA_DEVICE_PRESENT_MASK
1374 | STA_DEVICE_ENABLED_MASK
1375 | STA_DEVICE_SHOW_IN_UI_MASK
1376 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1377 : 0;
1378 break;
1379
1380 case SYSTEM_INFO_INDEX_NIC_ADDRESS:
1381 *pu32 = pThis->u32NicPciAddress;
1382 break;
1383
1384 case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
1385 *pu32 = pThis->u32AudioPciAddress;
1386 break;
1387
1388 case SYSTEM_INFO_INDEX_POWER_STATES:
1389 *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
1390 if (pThis->fS1Enabled) /* Optionally expose S1 and S4 */
1391 *pu32 |= RT_BIT(1);
1392 if (pThis->fS4Enabled)
1393 *pu32 |= RT_BIT(4);
1394 break;
1395
1396 case SYSTEM_INFO_INDEX_IOC_ADDRESS:
1397 *pu32 = pThis->u32IocPciAddress;
1398 break;
1399
1400 case SYSTEM_INFO_INDEX_HBC_ADDRESS:
1401 *pu32 = pThis->u32HbcPciAddress;
1402 break;
1403
1404 case SYSTEM_INFO_INDEX_PCI_BASE:
1405 /** @todo couldn't MCFG be in 64-bit range? */
1406 Assert(pThis->u64PciConfigMMioAddress < 0xffffffff);
1407 *pu32 = (uint32_t)pThis->u64PciConfigMMioAddress;
1408 break;
1409
1410 case SYSTEM_INFO_INDEX_PCI_LENGTH:
1411 /** @todo couldn't MCFG be in 64-bit range? */
1412 Assert(pThis->u64PciConfigMMioLength < 0xffffffff);
1413 *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
1414 break;
1415
1416 case SYSTEM_INFO_INDEX_RTC_STATUS:
1417 *pu32 = pThis->fShowRtc
1418 ? ( STA_DEVICE_PRESENT_MASK
1419 | STA_DEVICE_ENABLED_MASK
1420 | STA_DEVICE_SHOW_IN_UI_MASK
1421 | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
1422 : 0;
1423 break;
1424
1425 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1426 if (pThis->idCpuLockCheck < VMM_MAX_CPU_COUNT)
1427 {
1428 *pu32 = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, pThis->idCpuLockCheck);
1429 pThis->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
1430 }
1431 else
1432 {
1433 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "CPU lock check protocol violation (idCpuLockCheck=%#x)\n",
1434 pThis->idCpuLockCheck);
1435 /* Always return locked status just to be safe */
1436 *pu32 = 1;
1437 }
1438 break;
1439
1440 case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
1441 *pu32 = pThis->u32CpuEventType;
1442 break;
1443
1444 case SYSTEM_INFO_INDEX_CPU_EVENT:
1445 *pu32 = pThis->u32CpuEvent;
1446 break;
1447
1448 case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
1449 *pu32 = pThis->uSerial0IoPortBase;
1450 break;
1451
1452 case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
1453 *pu32 = pThis->uSerial0Irq;
1454 break;
1455
1456 case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
1457 *pu32 = pThis->uSerial1IoPortBase;
1458 break;
1459
1460 case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
1461 *pu32 = pThis->uSerial1Irq;
1462 break;
1463
1464 case SYSTEM_INFO_INDEX_SERIAL2_IOBASE:
1465 *pu32 = pThis->uSerial2IoPortBase;
1466 break;
1467
1468 case SYSTEM_INFO_INDEX_SERIAL2_IRQ:
1469 *pu32 = pThis->uSerial2Irq;
1470 break;
1471
1472 case SYSTEM_INFO_INDEX_SERIAL3_IOBASE:
1473 *pu32 = pThis->uSerial3IoPortBase;
1474 break;
1475
1476 case SYSTEM_INFO_INDEX_SERIAL3_IRQ:
1477 *pu32 = pThis->uSerial3Irq;
1478 break;
1479
1480 case SYSTEM_INFO_INDEX_PARALLEL0_IOBASE:
1481 *pu32 = pThis->uParallel0IoPortBase;
1482 break;
1483
1484 case SYSTEM_INFO_INDEX_PARALLEL0_IRQ:
1485 *pu32 = pThis->uParallel0Irq;
1486 break;
1487
1488 case SYSTEM_INFO_INDEX_PARALLEL1_IOBASE:
1489 *pu32 = pThis->uParallel1IoPortBase;
1490 break;
1491
1492 case SYSTEM_INFO_INDEX_PARALLEL1_IRQ:
1493 *pu32 = pThis->uParallel1Irq;
1494 break;
1495
1496 case SYSTEM_INFO_INDEX_END:
1497 /** @todo why isn't this setting any output value? */
1498 break;
1499
1500 /* Solaris 9 tries to read from this index */
1501 case SYSTEM_INFO_INDEX_INVALID:
1502 *pu32 = 0;
1503 break;
1504
1505 default:
1506 *pu32 = UINT32_MAX;
1507 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
1508 break;
1509 }
1510
1511 DEVACPI_UNLOCK(pThis);
1512 Log(("acpiR3SysInfoDataRead: idx=%d val=%#x (%u) rc=%Rrc\n", uSystemInfoIndex, *pu32, *pu32, rc));
1513 return rc;
1514}
1515
1516/**
1517 * @callback_method_impl{FNIOMIOPORTOUT, System info data}
1518 */
1519PDMBOTHCBDECL(int) acpiR3SysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1520{
1521 ACPIState *pThis = (ACPIState *)pvUser;
1522 if (cb != 4)
1523 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
1524
1525 DEVACPI_LOCK_R3(pThis);
1526 Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, pThis->uSystemInfoIndex));
1527
1528 int rc = VINF_SUCCESS;
1529 switch (pThis->uSystemInfoIndex)
1530 {
1531 case SYSTEM_INFO_INDEX_INVALID:
1532 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1533 pThis->u8IndexShift = 0;
1534 break;
1535
1536 case SYSTEM_INFO_INDEX_VALID:
1537 AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
1538 pThis->u8IndexShift = 2;
1539 break;
1540
1541 case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
1542 pThis->idCpuLockCheck = u32;
1543 break;
1544
1545 case SYSTEM_INFO_INDEX_CPU_LOCKED:
1546 if (u32 < pThis->cCpus)
1547 VMCPUSET_DEL(&pThis->CpuSetLocked, u32); /* Unlock the CPU */
1548 else
1549 LogRel(("ACPI: CPU %u does not exist\n", u32));
1550 break;
1551
1552 default:
1553 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
1554 break;
1555 }
1556
1557 DEVACPI_UNLOCK(pThis);
1558 return rc;
1559}
1560
1561/**
1562 * @callback_method_impl{FNIOMIOPORTIN, PM1a Enable}
1563 */
1564PDMBOTHCBDECL(int) acpiR3Pm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1565{
1566 NOREF(pDevIns); NOREF(Port);
1567 if (cb != 2)
1568 return VERR_IOM_IOPORT_UNUSED;
1569
1570 ACPIState *pThis = (ACPIState *)pvUser;
1571 DEVACPI_LOCK_R3(pThis);
1572
1573 *pu32 = pThis->pm1a_en;
1574
1575 DEVACPI_UNLOCK(pThis);
1576 Log(("acpiR3Pm1aEnRead -> %#x\n", *pu32));
1577 return VINF_SUCCESS;
1578}
1579
1580/**
1581 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Enable}
1582 */
1583PDMBOTHCBDECL(int) acpiR3PM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1584{
1585 if (cb != 2 && cb != 4)
1586 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1587
1588 ACPIState *pThis = (ACPIState *)pvUser;
1589 DEVACPI_LOCK_R3(pThis);
1590
1591 Log(("acpiR3PM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
1592 u32 &= ~(RSR_EN | IGN_EN);
1593 u32 &= 0xffff;
1594 apicUpdatePm1a(pThis, pThis->pm1a_sts, u32);
1595
1596 DEVACPI_UNLOCK(pThis);
1597 return VINF_SUCCESS;
1598}
1599
1600/**
1601 * @callback_method_impl{FNIOMIOPORTIN, PM1a Status}
1602 */
1603PDMBOTHCBDECL(int) acpiR3Pm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1604{
1605 if (cb != 2)
1606 {
1607 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1608 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1609 }
1610
1611 ACPIState *pThis = (ACPIState *)pvUser;
1612 DEVACPI_LOCK_R3(pThis);
1613
1614 *pu32 = pThis->pm1a_sts;
1615
1616 DEVACPI_UNLOCK(pThis);
1617 Log(("acpiR3Pm1aStsRead: %#x\n", *pu32));
1618 return VINF_SUCCESS;
1619}
1620
1621/**
1622 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Status}
1623 */
1624PDMBOTHCBDECL(int) acpiR3PM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1625{
1626 if (cb != 2 && cb != 4)
1627 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1628
1629 ACPIState *pThis = (ACPIState *)pvUser;
1630 DEVACPI_LOCK_R3(pThis);
1631
1632 Log(("acpiR3PM1aStsWrite: %#x (%#x)\n", u32, u32 & ~(RSR_STS | IGN_STS) & 0xffff));
1633 u32 &= 0xffff;
1634 if (u32 & PWRBTN_STS)
1635 pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
1636 u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
1637 apicUpdatePm1a(pThis, u32, pThis->pm1a_en);
1638
1639 DEVACPI_UNLOCK(pThis);
1640 return VINF_SUCCESS;
1641}
1642
1643/**
1644 * @callback_method_impl{FNIOMIOPORTIN, PM1a Control}
1645 */
1646PDMBOTHCBDECL(int) acpiR3Pm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1647{
1648 if (cb != 2)
1649 {
1650 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1651 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1652 }
1653
1654 ACPIState *pThis = (ACPIState *)pvUser;
1655 DEVACPI_LOCK_R3(pThis);
1656
1657 *pu32 = pThis->pm1a_ctl;
1658
1659 DEVACPI_UNLOCK(pThis);
1660 Log(("acpiR3Pm1aCtlRead: %#x\n", *pu32));
1661 return VINF_SUCCESS;
1662}
1663
1664/**
1665 * @callback_method_impl{FNIOMIOPORTOUT, PM1a Control}
1666 */
1667PDMBOTHCBDECL(int) acpiR3PM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1668{
1669 if (cb != 2 && cb != 4)
1670 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1671
1672 ACPIState *pThis = (ACPIState *)pvUser;
1673 DEVACPI_LOCK_R3(pThis);
1674
1675 Log(("acpiR3PM1aCtlWrite: %#x (%#x)\n", u32, u32 & ~(RSR_CNT | IGN_CNT) & 0xffff));
1676 u32 &= 0xffff;
1677 pThis->pm1a_ctl = u32 & ~(RSR_CNT | IGN_CNT);
1678
1679 int rc = VINF_SUCCESS;
1680 uint32_t const uSleepState = (pThis->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
1681 if (uSleepState != pThis->uSleepState)
1682 {
1683 pThis->uSleepState = uSleepState;
1684 switch (uSleepState)
1685 {
1686 case 0x00: /* S0 */
1687 break;
1688
1689 case 0x01: /* S1 */
1690 if (pThis->fS1Enabled)
1691 {
1692 LogRel(("ACPI: Entering S1 power state (powered-on suspend)\n"));
1693 rc = acpiR3DoSleep(pThis);
1694 break;
1695 }
1696 LogRel(("ACPI: Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
1697 RT_FALL_THRU();
1698
1699 case 0x04: /* S4 */
1700 if (pThis->fS4Enabled)
1701 {
1702 LogRel(("ACPI: Entering S4 power state (suspend to disk)\n"));
1703 rc = acpiR3DoPowerOff(pThis);/* Same behavior as S5 */
1704 break;
1705 }
1706 LogRel(("ACPI: Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
1707 RT_FALL_THRU();
1708
1709 case 0x05: /* S5 */
1710 LogRel(("ACPI: Entering S5 power state (power down)\n"));
1711 rc = acpiR3DoPowerOff(pThis);
1712 break;
1713
1714 default:
1715 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Unknown sleep state %#x (u32=%#x)\n", uSleepState, u32);
1716 break;
1717 }
1718 }
1719
1720 DEVACPI_UNLOCK(pThis);
1721 Log(("acpiR3PM1aCtlWrite: rc=%Rrc\n", rc));
1722 return rc;
1723}
1724
1725#endif /* IN_RING3 */
1726
1727/**
1728 * @callback_method_impl{FNIOMIOPORTIN, PMTMR}
1729 *
1730 * @remarks Only I/O port currently implemented in all contexts.
1731 */
1732PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1733{
1734 if (cb != 4)
1735 return VERR_IOM_IOPORT_UNUSED;
1736
1737 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
1738
1739 /*
1740 * We use the clock lock to serialize access to u64PmTimerInitial and to
1741 * make sure we get a reliable time from the clock
1742 * as well as and to prevent uPmTimerVal from being updated during read.
1743 */
1744
1745 int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_R3_IOPORT_READ);
1746 if (rc != VINF_SUCCESS)
1747 return rc;
1748
1749 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
1750 if (rc != VINF_SUCCESS)
1751 {
1752 TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
1753 return rc;
1754 }
1755
1756 uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
1757 acpiPmTimerUpdate(pThis, u64Now);
1758 *pu32 = pThis->uPmTimerVal;
1759
1760 DEVACPI_UNLOCK(pThis);
1761 TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
1762
1763 DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
1764 Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
1765
1766#if 0
1767 /** @todo temporary: sanity check against running backwards */
1768 uint32_t uOld = ASMAtomicXchgU32(&pThis->uPmTimeOld, *pu32);
1769 if (*pu32 - uOld >= 0x10000000)
1770 {
1771#if defined(IN_RING0)
1772 pThis->uPmTimeA = uOld;
1773 pThis->uPmTimeB = *pu32;
1774 return VERR_TM_TIMER_BAD_CLOCK;
1775#elif defined(IN_RING3)
1776 AssertReleaseMsgFailed(("acpiPMTmrRead: old=%08RX32, current=%08RX32\n", uOld, *pu32));
1777#endif
1778 }
1779#endif
1780
1781 NOREF(pvUser); NOREF(Port);
1782 return rc;
1783}
1784
1785#ifdef IN_RING3
1786
1787static DECLCALLBACK(void) acpiR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1788{
1789 RT_NOREF(pszArgs);
1790 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
1791 pHlp->pfnPrintf(pHlp,
1792 "timer: old=%08RX32, current=%08RX32\n", pThis->uPmTimeA, pThis->uPmTimeB);
1793}
1794
1795/**
1796 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Status}
1797 */
1798PDMBOTHCBDECL(int) acpiR3Gpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1799{
1800 if (cb != 1)
1801 {
1802 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1803 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1804 }
1805
1806 ACPIState *pThis = (ACPIState *)pvUser;
1807 DEVACPI_LOCK_R3(pThis);
1808
1809 *pu32 = pThis->gpe0_sts & 0xff;
1810
1811 DEVACPI_UNLOCK(pThis);
1812 Log(("acpiR3Gpe0StsRead: %#x\n", *pu32));
1813 return VINF_SUCCESS;
1814}
1815
1816/**
1817 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Status}
1818 */
1819PDMBOTHCBDECL(int) acpiR3Gpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1820{
1821 if (cb != 1)
1822 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1823
1824 ACPIState *pThis = (ACPIState *)pvUser;
1825 DEVACPI_LOCK_R3(pThis);
1826
1827 Log(("acpiR3Gpe0StsWrite: %#x (%#x)\n", u32, pThis->gpe0_sts & ~u32));
1828 u32 = pThis->gpe0_sts & ~u32;
1829 apicR3UpdateGpe0(pThis, u32, pThis->gpe0_en);
1830
1831 DEVACPI_UNLOCK(pThis);
1832 return VINF_SUCCESS;
1833}
1834
1835/**
1836 * @callback_method_impl{FNIOMIOPORTIN, GPE0 Enable}
1837 */
1838PDMBOTHCBDECL(int) acpiR3Gpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1839{
1840 if (cb != 1)
1841 {
1842 int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
1843 return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
1844 }
1845
1846 ACPIState *pThis = (ACPIState *)pvUser;
1847 DEVACPI_LOCK_R3(pThis);
1848
1849 *pu32 = pThis->gpe0_en & 0xff;
1850
1851 DEVACPI_UNLOCK(pThis);
1852 Log(("acpiR3Gpe0EnRead: %#x\n", *pu32));
1853 return VINF_SUCCESS;
1854}
1855
1856/**
1857 * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Enable}
1858 */
1859PDMBOTHCBDECL(int) acpiR3Gpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1860{
1861 if (cb != 1)
1862 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1863
1864 ACPIState *pThis = (ACPIState *)pvUser;
1865 DEVACPI_LOCK_R3(pThis);
1866
1867 Log(("acpiR3Gpe0EnWrite: %#x\n", u32));
1868 apicR3UpdateGpe0(pThis, pThis->gpe0_sts, u32);
1869
1870 DEVACPI_UNLOCK(pThis);
1871 return VINF_SUCCESS;
1872}
1873
1874/**
1875 * @callback_method_impl{FNIOMIOPORTOUT, SMI_CMD}
1876 */
1877PDMBOTHCBDECL(int) acpiR3SmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1878{
1879 Log(("acpiR3SmiWrite %#x\n", u32));
1880 if (cb != 1)
1881 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1882
1883 ACPIState *pThis = (ACPIState *)pvUser;
1884 DEVACPI_LOCK_R3(pThis);
1885
1886 if (u32 == ACPI_ENABLE)
1887 pThis->pm1a_ctl |= SCI_EN;
1888 else if (u32 == ACPI_DISABLE)
1889 pThis->pm1a_ctl &= ~SCI_EN;
1890 else
1891 Log(("acpiR3SmiWrite: %#x <- unknown value\n", u32));
1892
1893 DEVACPI_UNLOCK(pThis);
1894 return VINF_SUCCESS;
1895}
1896
1897/**
1898 * @{FNIOMIOPORTOUT, ACPI_RESET_BLK}
1899 */
1900PDMBOTHCBDECL(int) acpiR3ResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1901{
1902 Log(("acpiR3ResetWrite: %#x\n", u32));
1903 NOREF(pvUser);
1904 if (cb != 1)
1905 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1906
1907 /* No state locking required. */
1908 int rc = VINF_SUCCESS;
1909 if (u32 == ACPI_RESET_REG_VAL)
1910 {
1911 LogRel(("ACPI: Reset initiated by ACPI\n"));
1912 rc = PDMDevHlpVMReset(pDevIns, PDMVMRESET_F_ACPI);
1913 }
1914 else
1915 Log(("acpiR3ResetWrite: %#x <- unknown value\n", u32));
1916
1917 return rc;
1918}
1919
1920# ifdef DEBUG_ACPI
1921
1922/**
1923 * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
1924 */
1925PDMBOTHCBDECL(int) acpiR3DhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1926{
1927 NOREF(pvUser);
1928 switch (cb)
1929 {
1930 case 1:
1931 Log(("%#x\n", u32 & 0xff));
1932 break;
1933 case 2:
1934 Log(("%#6x\n", u32 & 0xffff));
1935 break;
1936 case 4:
1937 Log(("%#10x\n", u32));
1938 break;
1939 default:
1940 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1941 }
1942 return VINF_SUCCESS;
1943}
1944
1945/**
1946 * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
1947 */
1948PDMBOTHCBDECL(int) acpiR3DchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1949{
1950 NOREF(pvUser);
1951 switch (cb)
1952 {
1953 case 1:
1954 Log(("%c", u32 & 0xff));
1955 break;
1956 default:
1957 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
1958 }
1959 return VINF_SUCCESS;
1960}
1961
1962# endif /* DEBUG_ACPI */
1963
1964/**
1965 * Called by acpiR3Reset and acpiR3Construct to set up the PM PCI config space.
1966 *
1967 * @param pThis The ACPI instance.
1968 */
1969static void acpiR3PmPCIBIOSFake(ACPIState *pThis)
1970{
1971 pThis->dev.abConfig[PMBA ] = pThis->uPmIoPortBase | 1; /* PMBA, PM base address, bit 0 marks it as IO range */
1972 pThis->dev.abConfig[PMBA+1] = pThis->uPmIoPortBase >> 8;
1973 pThis->dev.abConfig[PMBA+2] = 0x00;
1974 pThis->dev.abConfig[PMBA+3] = 0x00;
1975}
1976
1977/**
1978 * Used to calculate the value of a PM I/O port.
1979 *
1980 * @returns The actual I/O port value.
1981 * @param pThis The ACPI instance.
1982 * @param offset The offset into the I/O space, or -1 if invalid.
1983 */
1984static RTIOPORT acpiR3CalcPmPort(ACPIState *pThis, int32_t offset)
1985{
1986 Assert(pThis->uPmIoPortBase != 0);
1987
1988 if (offset == -1)
1989 return 0;
1990
1991 return (RTIOPORT)(pThis->uPmIoPortBase + offset);
1992}
1993
1994/**
1995 * Called by acpiR3LoadState and acpiR3UpdatePmHandlers to register the PM1a, PM
1996 * timer and GPE0 I/O ports.
1997 *
1998 * @returns VBox status code.
1999 * @param pThis The ACPI instance.
2000 */
2001static int acpiR3RegisterPmHandlers(ACPIState *pThis)
2002{
2003 if (pThis->uPmIoPortBase == 0)
2004 return VINF_SUCCESS;
2005
2006#define R(offset, cnt, writer, reader, description) \
2007 do { \
2008 int rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
2009 NULL, NULL, description); \
2010 if (RT_FAILURE(rc)) \
2011 return rc; \
2012 } while (0)
2013#define L (GPE0_BLK_LEN / 2)
2014
2015 R(PM1a_EVT_OFFSET+2, 1, acpiR3PM1aEnWrite, acpiR3Pm1aEnRead, "ACPI PM1a Enable");
2016 R(PM1a_EVT_OFFSET, 1, acpiR3PM1aStsWrite, acpiR3Pm1aStsRead, "ACPI PM1a Status");
2017 R(PM1a_CTL_OFFSET, 1, acpiR3PM1aCtlWrite, acpiR3Pm1aCtlRead, "ACPI PM1a Control");
2018 R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
2019 R(GPE0_OFFSET + L, L, acpiR3Gpe0EnWrite, acpiR3Gpe0EnRead, "ACPI GPE0 Enable");
2020 R(GPE0_OFFSET, L, acpiR3Gpe0StsWrite, acpiR3Gpe0StsRead, "ACPI GPE0 Status");
2021#undef L
2022#undef R
2023
2024 /* register RC stuff */
2025 if (pThis->fGCEnabled)
2026 {
2027 int rc = PDMDevHlpIOPortRegisterRC(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
2028 1, 0, NULL, "acpiPMTmrRead",
2029 NULL, NULL, "ACPI PM Timer");
2030 AssertRCReturn(rc, rc);
2031 }
2032
2033 /* register R0 stuff */
2034 if (pThis->fR0Enabled)
2035 {
2036 int rc = PDMDevHlpIOPortRegisterR0(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
2037 1, 0, NULL, "acpiPMTmrRead",
2038 NULL, NULL, "ACPI PM Timer");
2039 AssertRCReturn(rc, rc);
2040 }
2041
2042 return VINF_SUCCESS;
2043}
2044
2045/**
2046 * Called by acpiR3LoadState and acpiR3UpdatePmHandlers to unregister the PM1a, PM
2047 * timer and GPE0 I/O ports.
2048 *
2049 * @returns VBox status code.
2050 * @param pThis The ACPI instance.
2051 */
2052static int acpiR3UnregisterPmHandlers(ACPIState *pThis)
2053{
2054 if (pThis->uPmIoPortBase == 0)
2055 return VINF_SUCCESS;
2056
2057#define U(offset, cnt) \
2058 do { \
2059 int rc = PDMDevHlpIOPortDeregister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt); \
2060 AssertRCReturn(rc, rc); \
2061 } while (0)
2062#define L (GPE0_BLK_LEN / 2)
2063
2064 U(PM1a_EVT_OFFSET+2, 1);
2065 U(PM1a_EVT_OFFSET, 1);
2066 U(PM1a_CTL_OFFSET, 1);
2067 U(PM_TMR_OFFSET, 1);
2068 U(GPE0_OFFSET + L, L);
2069 U(GPE0_OFFSET, L);
2070#undef L
2071#undef U
2072
2073 return VINF_SUCCESS;
2074}
2075
2076/**
2077 * Called by acpiR3PciConfigWrite and acpiReset to change the location of the
2078 * PM1a, PM timer and GPE0 ports.
2079 *
2080 * @returns VBox status code.
2081 *
2082 * @param pThis The ACPI instance.
2083 * @param NewIoPortBase The new base address of the I/O ports.
2084 */
2085static int acpiR3UpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
2086{
2087 Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
2088 if (NewIoPortBase != pThis->uPmIoPortBase)
2089 {
2090 int rc = acpiR3UnregisterPmHandlers(pThis);
2091 if (RT_FAILURE(rc))
2092 return rc;
2093
2094 pThis->uPmIoPortBase = NewIoPortBase;
2095
2096 rc = acpiR3RegisterPmHandlers(pThis);
2097 if (RT_FAILURE(rc))
2098 return rc;
2099
2100 /* We have to update FADT table acccording to the new base */
2101 rc = acpiR3PlantTables(pThis);
2102 AssertRC(rc);
2103 if (RT_FAILURE(rc))
2104 return rc;
2105 }
2106
2107 return VINF_SUCCESS;
2108}
2109
2110/**
2111 * @callback_method_impl{FNIOMIOPORTOUT, SMBus}
2112 */
2113PDMBOTHCBDECL(int) acpiR3SMBusWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
2114{
2115 ACPIState *pThis = (ACPIState *)pvUser;
2116 DEVACPI_LOCK_R3(pThis);
2117
2118 LogFunc(("Port=%#x u32=%#x cb=%u\n", Port, u32, cb));
2119 uint8_t off = Port & 0x000f;
2120 if ( (cb != 1 && off <= SMBSHDWCMD_OFF)
2121 || (cb != 2 && (off == SMBSLVEVT_OFF || off == SMBSLVDAT_OFF)))
2122 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
2123
2124 switch (off)
2125 {
2126 case SMBHSTSTS_OFF:
2127 /* Bit 0 is readonly, bits 1..4 are write clear, bits 5..7 are reserved */
2128 pThis->u8SMBusHstSts &= ~(u32 & SMBHSTSTS_INT_MASK);
2129 break;
2130 case SMBSLVSTS_OFF:
2131 /* Bit 0 is readonly, bit 1 is reserved, bits 2..5 are write clear, bits 6..7 are reserved */
2132 pThis->u8SMBusSlvSts &= ~(u32 & SMBSLVSTS_WRITE_MASK);
2133 break;
2134 case SMBHSTCNT_OFF:
2135 {
2136 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2137
2138 const bool old_level = acpiSCILevel(pThis);
2139 pThis->u8SMBusHstCnt = u32 & SMBHSTCNT_WRITE_MASK;
2140 if (u32 & SMBHSTCNT_START)
2141 {
2142 /* Start, trigger error as this is a dummy implementation */
2143 pThis->u8SMBusHstSts |= SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTER;
2144 }
2145 if (u32 & SMBHSTCNT_KILL)
2146 {
2147 /* Kill */
2148 pThis->u8SMBusHstSts |= SMBHSTSTS_FAILED | SMBHSTSTS_INTER;
2149 }
2150 const bool new_level = acpiSCILevel(pThis);
2151
2152 LogFunc(("old=%x new=%x\n", old_level, new_level));
2153
2154 /* This handles only SCI/IRQ9. SMI# makes not much sense today and
2155 * needs to be implemented later if it ever becomes relevant. */
2156 if (new_level != old_level)
2157 acpiSetIrq(pThis, new_level);
2158 break;
2159 }
2160 case SMBHSTCMD_OFF:
2161 pThis->u8SMBusHstCmd = u32;
2162 break;
2163 case SMBHSTADD_OFF:
2164 pThis->u8SMBusHstAdd = u32;
2165 break;
2166 case SMBHSTDAT0_OFF:
2167 pThis->u8SMBusHstDat0 = u32;
2168 break;
2169 case SMBHSTDAT1_OFF:
2170 pThis->u8SMBusHstDat1 = u32;
2171 break;
2172 case SMBBLKDAT_OFF:
2173 pThis->au8SMBusBlkDat[pThis->u8SMBusBlkIdx] = u32;
2174 pThis->u8SMBusBlkIdx++;
2175 pThis->u8SMBusBlkIdx &= sizeof(pThis->au8SMBusBlkDat) - 1;
2176 break;
2177 case SMBSLVCNT_OFF:
2178 pThis->u8SMBusSlvCnt = u32 & SMBSLVCNT_WRITE_MASK;
2179 break;
2180 case SMBSHDWCMD_OFF:
2181 /* readonly register */
2182 break;
2183 case SMBSLVEVT_OFF:
2184 pThis->u16SMBusSlvEvt = u32;
2185 break;
2186 case SMBSLVDAT_OFF:
2187 /* readonly register */
2188 break;
2189 default:
2190 /* caught by the sanity check above */
2191 ;
2192 }
2193
2194 DEVACPI_UNLOCK(pThis);
2195 return VINF_SUCCESS;
2196}
2197
2198/**
2199 * @callback_method_impl{FNIOMIOPORTIN, SMBus}
2200 */
2201PDMBOTHCBDECL(int) acpiR3SMBusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
2202{
2203 RT_NOREF1(pDevIns);
2204 ACPIState *pThis = (ACPIState *)pvUser;
2205 DEVACPI_LOCK_R3(pThis);
2206
2207 int rc = VINF_SUCCESS;
2208 LogFunc(("Port=%#x cb=%u\n", Port, cb));
2209 uint8_t off = Port & 0x000f;
2210 if ( (cb != 1 && off <= SMBSHDWCMD_OFF)
2211 || (cb != 2 && (off == SMBSLVEVT_OFF || off == SMBSLVDAT_OFF)))
2212 return VERR_IOM_IOPORT_UNUSED;
2213
2214 switch (off)
2215 {
2216 case SMBHSTSTS_OFF:
2217 *pu32 = pThis->u8SMBusHstSts;
2218 break;
2219 case SMBSLVSTS_OFF:
2220 *pu32 = pThis->u8SMBusSlvSts;
2221 break;
2222 case SMBHSTCNT_OFF:
2223 pThis->u8SMBusBlkIdx = 0;
2224 *pu32 = pThis->u8SMBusHstCnt;
2225 break;
2226 case SMBHSTCMD_OFF:
2227 *pu32 = pThis->u8SMBusHstCmd;
2228 break;
2229 case SMBHSTADD_OFF:
2230 *pu32 = pThis->u8SMBusHstAdd;
2231 break;
2232 case SMBHSTDAT0_OFF:
2233 *pu32 = pThis->u8SMBusHstDat0;
2234 break;
2235 case SMBHSTDAT1_OFF:
2236 *pu32 = pThis->u8SMBusHstDat1;
2237 break;
2238 case SMBBLKDAT_OFF:
2239 *pu32 = pThis->au8SMBusBlkDat[pThis->u8SMBusBlkIdx];
2240 pThis->u8SMBusBlkIdx++;
2241 pThis->u8SMBusBlkIdx &= sizeof(pThis->au8SMBusBlkDat) - 1;
2242 break;
2243 case SMBSLVCNT_OFF:
2244 *pu32 = pThis->u8SMBusSlvCnt;
2245 break;
2246 case SMBSHDWCMD_OFF:
2247 *pu32 = pThis->u8SMBusShdwCmd;
2248 break;
2249 case SMBSLVEVT_OFF:
2250 *pu32 = pThis->u16SMBusSlvEvt;
2251 break;
2252 case SMBSLVDAT_OFF:
2253 *pu32 = pThis->u16SMBusSlvDat;
2254 break;
2255 default:
2256 /* caught by the sanity check above */
2257 rc = VERR_IOM_IOPORT_UNUSED;
2258 }
2259
2260 DEVACPI_UNLOCK(pThis);
2261 LogFunc(("Port=%#x u32=%#x cb=%u rc=%Rrc\n", Port, *pu32, cb, rc));
2262 return rc;
2263}
2264
2265/**
2266 * Called by acpiR3Reset and acpiR3Construct to set up the SMBus PCI config space.
2267 *
2268 * @param pThis The ACPI instance.
2269 */
2270static void acpiR3SMBusPCIBIOSFake(ACPIState *pThis)
2271{
2272 pThis->dev.abConfig[SMBBA ] = pThis->uSMBusIoPortBase | 1; /* SMBBA, SMBus base address, bit 0 marks it as IO range */
2273 pThis->dev.abConfig[SMBBA+1] = pThis->uSMBusIoPortBase >> 8;
2274 pThis->dev.abConfig[SMBBA+2] = 0x00;
2275 pThis->dev.abConfig[SMBBA+3] = 0x00;
2276 pThis->dev.abConfig[SMBHSTCFG] = SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT | SMBHSTCFG_SMB_HST_EN; /* SMBHSTCFG */
2277 pThis->dev.abConfig[SMBSLVC] = 0x00; /* SMBSLVC */
2278 pThis->dev.abConfig[SMBSHDW1] = 0x00; /* SMBSHDW1 */
2279 pThis->dev.abConfig[SMBSHDW2] = 0x00; /* SMBSHDW2 */
2280 pThis->dev.abConfig[SMBREV] = 0x00; /* SMBREV */
2281}
2282
2283/**
2284 * Called by acpiR3LoadState, acpiR3Reset and acpiR3Construct to reset the SMBus device register state.
2285 *
2286 * @param pThis The ACPI instance.
2287 */
2288static void acpiR3SMBusResetDevice(ACPIState *pThis)
2289{
2290 pThis->u8SMBusHstSts = 0x00;
2291 pThis->u8SMBusSlvSts = 0x00;
2292 pThis->u8SMBusHstCnt = 0x00;
2293 pThis->u8SMBusHstCmd = 0x00;
2294 pThis->u8SMBusHstAdd = 0x00;
2295 pThis->u8SMBusHstDat0 = 0x00;
2296 pThis->u8SMBusHstDat1 = 0x00;
2297 pThis->u8SMBusSlvCnt = 0x00;
2298 pThis->u8SMBusShdwCmd = 0x00;
2299 pThis->u16SMBusSlvEvt = 0x0000;
2300 pThis->u16SMBusSlvDat = 0x0000;
2301 memset(pThis->au8SMBusBlkDat, 0x00, sizeof(pThis->au8SMBusBlkDat));
2302 pThis->u8SMBusBlkIdx = 0;
2303}
2304
2305/**
2306 * Called by acpiR3LoadState and acpiR3UpdateSMBusHandlers to register the SMBus ports.
2307 *
2308 * @returns VBox status code.
2309 * @param pThis The ACPI instance.
2310 */
2311static int acpiR3RegisterSMBusHandlers(ACPIState *pThis)
2312{
2313 int rc = VINF_SUCCESS;
2314
2315 if (pThis->uSMBusIoPortBase == 0)
2316 return VINF_SUCCESS;
2317
2318 rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, pThis->uSMBusIoPortBase, 16, pThis, acpiR3SMBusWrite, acpiR3SMBusRead, NULL, NULL, "SMBus");
2319 if (RT_FAILURE(rc))
2320 return rc;
2321
2322 return VINF_SUCCESS;
2323}
2324
2325/**
2326 * Called by acpiR3LoadState and acpiR3UpdateSMBusHandlers to unregister the SMBus ports.
2327 *
2328 * @returns VBox status code.
2329 * @param pThis The ACPI instance.
2330 */
2331static int acpiR3UnregisterSMBusHandlers(ACPIState *pThis)
2332{
2333 if (pThis->uSMBusIoPortBase == 0)
2334 return VINF_SUCCESS;
2335
2336 int rc = PDMDevHlpIOPortDeregister(pThis->pDevInsR3, pThis->uSMBusIoPortBase, 16);
2337 AssertRCReturn(rc, rc);
2338
2339 return VINF_SUCCESS;
2340}
2341
2342/**
2343 * Called by acpiR3PciConfigWrite and acpiReset to change the location of the
2344 * SMBus ports.
2345 *
2346 * @returns VBox status code.
2347 *
2348 * @param pThis The ACPI instance.
2349 * @param NewIoPortBase The new base address of the I/O ports.
2350 */
2351static int acpiR3UpdateSMBusHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
2352{
2353 Log(("acpi: rebasing SMBus 0x%x -> 0x%x\n", pThis->uSMBusIoPortBase, NewIoPortBase));
2354 if (NewIoPortBase != pThis->uSMBusIoPortBase)
2355 {
2356 int rc = acpiR3UnregisterSMBusHandlers(pThis);
2357 if (RT_FAILURE(rc))
2358 return rc;
2359
2360 pThis->uSMBusIoPortBase = NewIoPortBase;
2361
2362 rc = acpiR3RegisterSMBusHandlers(pThis);
2363 if (RT_FAILURE(rc))
2364 return rc;
2365
2366#if 0 /* is there an FADT table entry for the SMBus base? */
2367 /* We have to update FADT table acccording to the new base */
2368 rc = acpiR3PlantTables(pThis);
2369 AssertRC(rc);
2370 if (RT_FAILURE(rc))
2371 return rc;
2372#endif
2373 }
2374
2375 return VINF_SUCCESS;
2376}
2377
2378
2379/**
2380 * Saved state structure description, version 4.
2381 */
2382static const SSMFIELD g_AcpiSavedStateFields4[] =
2383{
2384 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2385 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2386 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2387 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
2388 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2389 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2390 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2391 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2392 SSMFIELD_ENTRY(ACPIState, u64RamSize),
2393 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2394 SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
2395 SSMFIELD_ENTRY(ACPIState, uSleepState),
2396 SSMFIELD_ENTRY_TERM()
2397};
2398
2399/**
2400 * Saved state structure description, version 5.
2401 */
2402static const SSMFIELD g_AcpiSavedStateFields5[] =
2403{
2404 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2405 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2406 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2407 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
2408 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2409 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2410 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2411 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2412 SSMFIELD_ENTRY(ACPIState, uSleepState),
2413 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2414 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2415 SSMFIELD_ENTRY_TERM()
2416};
2417
2418/**
2419 * Saved state structure description, version 6.
2420 */
2421static const SSMFIELD g_AcpiSavedStateFields6[] =
2422{
2423 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2424 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2425 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2426 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
2427 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2428 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2429 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2430 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2431 SSMFIELD_ENTRY(ACPIState, uSleepState),
2432 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2433 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2434 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
2435 SSMFIELD_ENTRY_TERM()
2436};
2437
2438/**
2439 * Saved state structure description, version 7.
2440 */
2441static const SSMFIELD g_AcpiSavedStateFields7[] =
2442{
2443 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2444 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2445 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2446 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
2447 SSMFIELD_ENTRY(ACPIState, uPmTimerVal),
2448 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2449 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2450 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2451 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2452 SSMFIELD_ENTRY(ACPIState, uSleepState),
2453 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2454 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2455 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
2456 SSMFIELD_ENTRY_TERM()
2457};
2458
2459/**
2460 * Saved state structure description, version 8.
2461 */
2462static const SSMFIELD g_AcpiSavedStateFields8[] =
2463{
2464 SSMFIELD_ENTRY(ACPIState, pm1a_en),
2465 SSMFIELD_ENTRY(ACPIState, pm1a_sts),
2466 SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
2467 SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
2468 SSMFIELD_ENTRY(ACPIState, uPmTimerVal),
2469 SSMFIELD_ENTRY(ACPIState, gpe0_en),
2470 SSMFIELD_ENTRY(ACPIState, gpe0_sts),
2471 SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
2472 SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
2473 SSMFIELD_ENTRY(ACPIState, uSleepState),
2474 SSMFIELD_ENTRY(ACPIState, u8IndexShift),
2475 SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
2476 SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
2477 SSMFIELD_ENTRY(ACPIState, uSMBusIoPortBase),
2478 SSMFIELD_ENTRY(ACPIState, u8SMBusHstSts),
2479 SSMFIELD_ENTRY(ACPIState, u8SMBusSlvSts),
2480 SSMFIELD_ENTRY(ACPIState, u8SMBusHstCnt),
2481 SSMFIELD_ENTRY(ACPIState, u8SMBusHstCmd),
2482 SSMFIELD_ENTRY(ACPIState, u8SMBusHstAdd),
2483 SSMFIELD_ENTRY(ACPIState, u8SMBusHstDat0),
2484 SSMFIELD_ENTRY(ACPIState, u8SMBusHstDat1),
2485 SSMFIELD_ENTRY(ACPIState, u8SMBusSlvCnt),
2486 SSMFIELD_ENTRY(ACPIState, u8SMBusShdwCmd),
2487 SSMFIELD_ENTRY(ACPIState, u16SMBusSlvEvt),
2488 SSMFIELD_ENTRY(ACPIState, u16SMBusSlvDat),
2489 SSMFIELD_ENTRY(ACPIState, au8SMBusBlkDat),
2490 SSMFIELD_ENTRY(ACPIState, u8SMBusBlkIdx),
2491 SSMFIELD_ENTRY_TERM()
2492};
2493
2494/**
2495 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2496 */
2497static DECLCALLBACK(int) acpiR3SaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2498{
2499 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2500 return SSMR3PutStruct(pSSM, pThis, &g_AcpiSavedStateFields8[0]);
2501}
2502
2503/**
2504 * @callback_method_impl{FNSSMDEVLOADEXEC}
2505 */
2506static DECLCALLBACK(int) acpiR3LoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2507{
2508 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
2509 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2510
2511 /*
2512 * Unregister PM handlers, will register with actual base after state
2513 * successfully loaded.
2514 */
2515 int rc = acpiR3UnregisterPmHandlers(pThis);
2516 if (RT_FAILURE(rc))
2517 return rc;
2518
2519 /*
2520 * Unregister SMBus handlers, will register with actual base after state
2521 * successfully loaded.
2522 */
2523 rc = acpiR3UnregisterSMBusHandlers(pThis);
2524 if (RT_FAILURE(rc))
2525 return rc;
2526 acpiR3SMBusResetDevice(pThis);
2527
2528 switch (uVersion)
2529 {
2530 case 4:
2531 rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields4[0]);
2532 break;
2533 case 5:
2534 rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields5[0]);
2535 break;
2536 case 6:
2537 rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields6[0]);
2538 break;
2539 case 7:
2540 rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields7[0]);
2541 break;
2542 case 8:
2543 rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields8[0]);
2544 break;
2545 default:
2546 rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2547 break;
2548 }
2549 if (RT_SUCCESS(rc))
2550 {
2551 AssertLogRelMsgReturn(pThis->u8SMBusBlkIdx < RT_ELEMENTS(pThis->au8SMBusBlkDat),
2552 ("%#x\n", pThis->u8SMBusBlkIdx), VERR_SSM_LOAD_CONFIG_MISMATCH);
2553 rc = acpiR3RegisterPmHandlers(pThis);
2554 if (RT_FAILURE(rc))
2555 return rc;
2556 rc = acpiR3RegisterSMBusHandlers(pThis);
2557 if (RT_FAILURE(rc))
2558 return rc;
2559 rc = acpiR3FetchBatteryStatus(pThis);
2560 if (RT_FAILURE(rc))
2561 return rc;
2562 rc = acpiR3FetchBatteryInfo(pThis);
2563 if (RT_FAILURE(rc))
2564 return rc;
2565 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
2566 DEVACPI_LOCK_R3(pThis);
2567 uint64_t u64Now = TMTimerGet(pThis->pPmTimerR3);
2568 /* The interrupt may be incorrectly re-generated
2569 * if the state is restored from versions < 7
2570 */
2571 acpiPmTimerUpdate(pThis, u64Now);
2572 acpiR3PmTimerReset(pThis, u64Now);
2573 DEVACPI_UNLOCK(pThis);
2574 TMTimerUnlock(pThis->pPmTimerR3);
2575 }
2576 return rc;
2577}
2578
2579/**
2580 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2581 */
2582static DECLCALLBACK(void *) acpiR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2583{
2584 ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
2585 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2586 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
2587 return NULL;
2588}
2589
2590/**
2591 * Calculate the check sum for some ACPI data before planting it.
2592 *
2593 * All the bytes must add up to 0.
2594 *
2595 * @returns check sum.
2596 * @param pvSrc What to check sum.
2597 * @param cbData The amount of data to checksum.
2598 */
2599static uint8_t acpiR3Checksum(const void * const pvSrc, size_t cbData)
2600{
2601 uint8_t const *pbSrc = (uint8_t const *)pvSrc;
2602 uint8_t uSum = 0;
2603 for (size_t i = 0; i < cbData; ++i)
2604 uSum += pbSrc[i];
2605 return -uSum;
2606}
2607
2608/**
2609 * Prepare a ACPI table header.
2610 */
2611static void acpiR3PrepareHeader(ACPIState *pThis, ACPITBLHEADER *header,
2612 const char au8Signature[4],
2613 uint32_t u32Length, uint8_t u8Revision)
2614{
2615 memcpy(header->au8Signature, au8Signature, 4);
2616 header->u32Length = RT_H2LE_U32(u32Length);
2617 header->u8Revision = u8Revision;
2618 memcpy(header->au8OemId, pThis->au8OemId, 6);
2619 memcpy(header->au8OemTabId, "VBOX", 4);
2620 memcpy(header->au8OemTabId+4, au8Signature, 4);
2621 header->u32OemRevision = RT_H2LE_U32(1);
2622 memcpy(header->au8CreatorId, pThis->au8CreatorId, 4);
2623 header->u32CreatorRev = pThis->u32CreatorRev;
2624}
2625
2626/**
2627 * Initialize a generic address structure (ACPIGENADDR).
2628 */
2629static void acpiR3WriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
2630 uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
2631 uint8_t u8AccessSize, uint64_t u64Address)
2632{
2633 g->u8AddressSpaceId = u8AddressSpaceId;
2634 g->u8RegisterBitWidth = u8RegisterBitWidth;
2635 g->u8RegisterBitOffset = u8RegisterBitOffset;
2636 g->u8AccessSize = u8AccessSize;
2637 g->u64Address = RT_H2LE_U64(u64Address);
2638}
2639
2640/**
2641 * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
2642 */
2643DECLINLINE(void) acpiR3PhysCopy(ACPIState *pThis, RTGCPHYS32 GCPhys32Dst, const void *pvSrc, size_t cbToCopy)
2644{
2645 PDMDevHlpPhysWrite(pThis->pDevInsR3, GCPhys32Dst, pvSrc, cbToCopy);
2646}
2647
2648/**
2649 * Plant the Differentiated System Description Table (DSDT).
2650 */
2651static void acpiR3SetupDsdt(ACPIState *pThis, RTGCPHYS32 GCPhys32, void *pvPtr, size_t cbDsdt)
2652{
2653 acpiR3PhysCopy(pThis, GCPhys32, pvPtr, cbDsdt);
2654}
2655
2656/**
2657 * Plan the Secondary System Description Table (SSDT).
2658 */
2659static void acpiR3SetupSsdt(ACPIState *pThis, RTGCPHYS32 addr,
2660 void* pPtr, size_t uSsdtLen)
2661{
2662 acpiR3PhysCopy(pThis, addr, pPtr, uSsdtLen);
2663}
2664
2665/**
2666 * Plant the Firmware ACPI Control Structure (FACS).
2667 */
2668static void acpiR3SetupFacs(ACPIState *pThis, RTGCPHYS32 addr)
2669{
2670 ACPITBLFACS facs;
2671
2672 memset(&facs, 0, sizeof(facs));
2673 memcpy(facs.au8Signature, "FACS", 4);
2674 facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
2675 facs.u32HWSignature = RT_H2LE_U32(0);
2676 facs.u32FWVector = RT_H2LE_U32(0);
2677 facs.u32GlobalLock = RT_H2LE_U32(0);
2678 facs.u32Flags = RT_H2LE_U32(0);
2679 facs.u64X_FWVector = RT_H2LE_U64(0);
2680 facs.u8Version = 1;
2681
2682 acpiR3PhysCopy(pThis, addr, (const uint8_t *)&facs, sizeof(facs));
2683}
2684
2685/**
2686 * Plant the Fixed ACPI Description Table (FADT aka FACP).
2687 */
2688static void acpiR3SetupFadt(ACPIState *pThis, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2,
2689 RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
2690{
2691 ACPITBLFADT fadt;
2692
2693 /* First the ACPI version 2+ version of the structure. */
2694 memset(&fadt, 0, sizeof(fadt));
2695 acpiR3PrepareHeader(pThis, &fadt.header, "FACP", sizeof(fadt), 4);
2696 fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
2697 fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
2698 fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
2699 fadt.u8PreferredPMProfile = 0; /* unspecified */
2700 fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
2701 fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
2702 fadt.u8AcpiEnable = ACPI_ENABLE;
2703 fadt.u8AcpiDisable = ACPI_DISABLE;
2704 fadt.u8S4BIOSReq = 0;
2705 fadt.u8PStateCnt = 0;
2706 fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1a_EVT_OFFSET));
2707 fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1b_EVT_OFFSET));
2708 fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1a_CTL_OFFSET));
2709 fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM1b_CTL_OFFSET));
2710 fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM2_CTL_OFFSET));
2711 fadt.u32PMTMRBLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, PM_TMR_OFFSET));
2712 fadt.u32GPE0BLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, GPE0_OFFSET));
2713 fadt.u32GPE1BLK = RT_H2LE_U32(acpiR3CalcPmPort(pThis, GPE1_OFFSET));
2714 fadt.u8PM1EVTLEN = 4;
2715 fadt.u8PM1CTLLEN = 2;
2716 fadt.u8PM2CTLLEN = 0;
2717 fadt.u8PMTMLEN = 4;
2718 fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
2719 fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
2720 fadt.u8GPE1BASE = GPE1_BASE;
2721 fadt.u8CSTCNT = 0;
2722 fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
2723 fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
2724 fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
2725 fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
2726 fadt.u8DutyOffset = 0;
2727 fadt.u8DutyWidth = 0;
2728 fadt.u8DayAlarm = 0;
2729 fadt.u8MonAlarm = 0;
2730 fadt.u8Century = 0;
2731 fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
2732 /** @note WBINVD is required for ACPI versions newer than 1.0 */
2733 fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
2734 | FADT_FL_FIX_RTC
2735 | FADT_FL_TMR_VAL_EXT
2736 | FADT_FL_RESET_REG_SUP);
2737
2738 /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
2739 if (pThis->fCpuHotPlug)
2740 fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
2741
2742 acpiR3WriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
2743 fadt.u8ResetVal = ACPI_RESET_REG_VAL;
2744 fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
2745 fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
2746 acpiR3WriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiR3CalcPmPort(pThis, PM1a_EVT_OFFSET));
2747 acpiR3WriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, PM1b_EVT_OFFSET));
2748 acpiR3WriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiR3CalcPmPort(pThis, PM1a_CTL_OFFSET));
2749 acpiR3WriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, PM1b_CTL_OFFSET));
2750 acpiR3WriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, PM2_CTL_OFFSET));
2751 acpiR3WriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET));
2752 acpiR3WriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiR3CalcPmPort(pThis, GPE0_OFFSET));
2753 acpiR3WriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiR3CalcPmPort(pThis, GPE1_OFFSET));
2754 fadt.header.u8Checksum = acpiR3Checksum(&fadt, sizeof(fadt));
2755 acpiR3PhysCopy(pThis, GCPhysAcpi2, &fadt, sizeof(fadt));
2756
2757 /* Now the ACPI 1.0 version. */
2758 fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
2759 fadt.u8IntModel = INT_MODEL_DUAL_PIC;
2760 fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
2761 fadt.header.u8Checksum = acpiR3Checksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
2762 acpiR3PhysCopy(pThis, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
2763}
2764
2765/**
2766 * Plant the root System Description Table.
2767 *
2768 * The RSDT and XSDT tables are basically identical. The only difference is 32
2769 * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
2770 * ACPI 2.0 and up.
2771 */
2772static int acpiR3SetupRsdt(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
2773{
2774 ACPITBLRSDT *rsdt;
2775 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
2776
2777 rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
2778 if (!rsdt)
2779 return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
2780
2781 acpiR3PrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
2782 for (unsigned int i = 0; i < nb_entries; ++i)
2783 {
2784 rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
2785 Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
2786 }
2787 rsdt->header.u8Checksum = acpiR3Checksum(rsdt, size);
2788 acpiR3PhysCopy(pThis, addr, rsdt, size);
2789 RTMemFree(rsdt);
2790 return VINF_SUCCESS;
2791}
2792
2793/**
2794 * Plant the Extended System Description Table.
2795 */
2796static int acpiR3SetupXsdt(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
2797{
2798 ACPITBLXSDT *xsdt;
2799 const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
2800
2801 xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
2802 if (!xsdt)
2803 return VERR_NO_TMP_MEMORY;
2804
2805 acpiR3PrepareHeader(pThis, &xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
2806
2807 if (pThis->cCustTbls > 0)
2808 memcpy(xsdt->header.au8OemTabId, pThis->au8OemTabId, 8);
2809
2810 for (unsigned int i = 0; i < nb_entries; ++i)
2811 {
2812 xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
2813 Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
2814 }
2815 xsdt->header.u8Checksum = acpiR3Checksum(xsdt, size);
2816 acpiR3PhysCopy(pThis, addr, xsdt, size);
2817 RTMemFree(xsdt);
2818 return VINF_SUCCESS;
2819}
2820
2821/**
2822 * Plant the Root System Description Pointer (RSDP).
2823 */
2824static void acpiR3SetupRsdp(ACPIState *pThis, ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
2825{
2826 memset(rsdp, 0, sizeof(*rsdp));
2827
2828 /* ACPI 1.0 part (RSDT) */
2829 memcpy(rsdp->au8Signature, "RSD PTR ", 8);
2830 memcpy(rsdp->au8OemId, pThis->au8OemId, 6);
2831 rsdp->u8Revision = ACPI_REVISION;
2832 rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
2833 rsdp->u8Checksum = acpiR3Checksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
2834
2835 /* ACPI 2.0 part (XSDT) */
2836 rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
2837 rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
2838 rsdp->u8ExtChecksum = acpiR3Checksum(rsdp, sizeof(ACPITBLRSDP));
2839}
2840
2841/**
2842 * Multiple APIC Description Table.
2843 *
2844 * This structure looks somewhat convoluted due layout of MADT table in MP case.
2845 * There extpected to be multiple LAPIC records for each CPU, thus we cannot
2846 * use regular C structure and proxy to raw memory instead.
2847 */
2848class AcpiTableMadt
2849{
2850 /**
2851 * All actual data stored in dynamically allocated memory pointed by this field.
2852 */
2853 uint8_t *m_pbData;
2854 /**
2855 * Number of CPU entries in this MADT.
2856 */
2857 uint32_t m_cCpus;
2858
2859 /**
2860 * Number of interrupt overrides.
2861 */
2862 uint32_t m_cIsos;
2863
2864public:
2865 /**
2866 * Address of ACPI header
2867 */
2868 inline ACPITBLHEADER *header_addr(void) const
2869 {
2870 return (ACPITBLHEADER *)m_pbData;
2871 }
2872
2873 /**
2874 * Address of local APIC for each CPU. Note that different CPUs address different LAPICs,
2875 * although address is the same for all of them.
2876 */
2877 inline uint32_t *u32LAPIC_addr(void) const
2878 {
2879 return (uint32_t *)(header_addr() + 1);
2880 }
2881
2882 /**
2883 * Address of APIC flags
2884 */
2885 inline uint32_t *u32Flags_addr(void) const
2886 {
2887 return (uint32_t *)(u32LAPIC_addr() + 1);
2888 }
2889
2890 /**
2891 * Address of ISO description
2892 */
2893 inline ACPITBLISO *ISO_addr(void) const
2894 {
2895 return (ACPITBLISO *)(u32Flags_addr() + 1);
2896 }
2897
2898 /**
2899 * Address of per-CPU LAPIC descriptions
2900 */
2901 inline ACPITBLLAPIC *LApics_addr(void) const
2902 {
2903 return (ACPITBLLAPIC *)(ISO_addr() + m_cIsos);
2904 }
2905
2906 /**
2907 * Address of IO APIC description
2908 */
2909 inline ACPITBLIOAPIC *IOApic_addr(void) const
2910 {
2911 return (ACPITBLIOAPIC *)(LApics_addr() + m_cCpus);
2912 }
2913
2914 /**
2915 * Size of MADT.
2916 * Note that this function assumes IOApic to be the last field in structure.
2917 */
2918 inline uint32_t size(void) const
2919 {
2920 return (uint8_t *)(IOApic_addr() + 1) - (uint8_t *)header_addr();
2921 }
2922
2923 /**
2924 * Raw data of MADT.
2925 */
2926 inline const uint8_t *data(void) const
2927 {
2928 return m_pbData;
2929 }
2930
2931 /**
2932 * Size of MADT for given ACPI config, useful to compute layout.
2933 */
2934 static uint32_t sizeFor(ACPIState *pThis, uint32_t cIsos)
2935 {
2936 return AcpiTableMadt(pThis->cCpus, cIsos).size();
2937 }
2938
2939 /*
2940 * Constructor, only works in Ring 3, doesn't look like a big deal.
2941 */
2942 AcpiTableMadt(uint32_t cCpus, uint32_t cIsos)
2943 {
2944 m_cCpus = cCpus;
2945 m_cIsos = cIsos;
2946 m_pbData = NULL; /* size() uses this and gcc will complain if not initialized. */
2947 uint32_t cb = size();
2948 m_pbData = (uint8_t *)RTMemAllocZ(cb);
2949 }
2950
2951 ~AcpiTableMadt()
2952 {
2953 RTMemFree(m_pbData);
2954 }
2955};
2956
2957
2958/**
2959 * Plant the Multiple APIC Description Table (MADT).
2960 *
2961 * @note APIC without IO-APIC hangs Windows Vista therefore we setup both.
2962 *
2963 * @todo All hardcoded, should set this up based on the actual VM config!!!!!
2964 */
2965static void acpiR3SetupMadt(ACPIState *pThis, RTGCPHYS32 addr)
2966{
2967 uint16_t cpus = pThis->cCpus;
2968 AcpiTableMadt madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
2969
2970 acpiR3PrepareHeader(pThis, madt.header_addr(), "APIC", madt.size(), 2);
2971
2972 *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
2973 *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
2974
2975 /* LAPICs records */
2976 ACPITBLLAPIC* lapic = madt.LApics_addr();
2977 for (uint16_t i = 0; i < cpus; i++)
2978 {
2979 lapic->u8Type = 0;
2980 lapic->u8Length = sizeof(ACPITBLLAPIC);
2981 lapic->u8ProcId = i;
2982 /** Must match numbering convention in MPTABLES */
2983 lapic->u8ApicId = i;
2984 lapic->u32Flags = VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
2985 lapic++;
2986 }
2987
2988 /* IO-APIC record */
2989 ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
2990 ioapic->u8Type = 1;
2991 ioapic->u8Length = sizeof(ACPITBLIOAPIC);
2992 /** Must match MP tables ID */
2993 ioapic->u8IOApicId = cpus;
2994 ioapic->u8Reserved = 0;
2995 ioapic->u32Address = RT_H2LE_U32(0xfec00000);
2996 ioapic->u32GSIB = RT_H2LE_U32(0);
2997
2998 /* Interrupt Source Overrides */
2999 /* Flags:
3000 bits[3:2]:
3001 00 conforms to the bus
3002 01 edge-triggered
3003 10 reserved
3004 11 level-triggered
3005 bits[1:0]
3006 00 conforms to the bus
3007 01 active-high
3008 10 reserved
3009 11 active-low */
3010 /* If changing, also update PDMIsaSetIrq() and MPS */
3011 ACPITBLISO* isos = madt.ISO_addr();
3012 /* Timer interrupt rule IRQ0 to GSI2 */
3013 isos[0].u8Type = 2;
3014 isos[0].u8Length = sizeof(ACPITBLISO);
3015 isos[0].u8Bus = 0; /* Must be 0 */
3016 isos[0].u8Source = 0; /* IRQ0 */
3017 isos[0].u32GSI = 2; /* connected to pin 2 */
3018 isos[0].u16Flags = 0; /* conform to the bus */
3019
3020 /* ACPI interrupt rule - IRQ9 to GSI9 */
3021 isos[1].u8Type = 2;
3022 isos[1].u8Length = sizeof(ACPITBLISO);
3023 isos[1].u8Bus = 0; /* Must be 0 */
3024 isos[1].u8Source = 9; /* IRQ9 */
3025 isos[1].u32GSI = 9; /* connected to pin 9 */
3026 isos[1].u16Flags = 0xf; /* active low, level triggered */
3027 Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
3028
3029 madt.header_addr()->u8Checksum = acpiR3Checksum(madt.data(), madt.size());
3030 acpiR3PhysCopy(pThis, addr, madt.data(), madt.size());
3031}
3032
3033/**
3034 * Plant the High Performance Event Timer (HPET) descriptor.
3035 */
3036static void acpiR3SetupHpet(ACPIState *pThis, RTGCPHYS32 addr)
3037{
3038 ACPITBLHPET hpet;
3039
3040 memset(&hpet, 0, sizeof(hpet));
3041
3042 acpiR3PrepareHeader(pThis, &hpet.aHeader, "HPET", sizeof(hpet), 1);
3043 /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
3044 acpiR3WriteGenericAddr(&hpet.HpetAddr,
3045 0 /* Memory address space */,
3046 64 /* Register bit width */,
3047 0 /* Bit offset */,
3048 0, /* Register access size, is it correct? */
3049 0xfed00000 /* Address */);
3050
3051 hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
3052 hpet.u32Number = 0;
3053 hpet.u32MinTick = 4096;
3054 hpet.u8Attributes = 0;
3055
3056 hpet.aHeader.u8Checksum = acpiR3Checksum(&hpet, sizeof(hpet));
3057
3058 acpiR3PhysCopy(pThis, addr, (const uint8_t *)&hpet, sizeof(hpet));
3059}
3060
3061
3062/**
3063 * Used by acpiR3PlantTables to plant a MMCONFIG PCI config space access (MCFG)
3064 * descriptor.
3065 *
3066 * @param pThis The ACPI instance.
3067 * @param GCPhysDst Where to plant it.
3068 */
3069static void acpiR3SetupMcfg(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
3070{
3071 struct
3072 {
3073 ACPITBLMCFG hdr;
3074 ACPITBLMCFGENTRY entry;
3075 } tbl;
3076 uint8_t u8StartBus = 0;
3077 uint8_t u8EndBus = (pThis->u64PciConfigMMioLength >> 20) - 1;
3078
3079 RT_ZERO(tbl);
3080
3081 acpiR3PrepareHeader(pThis, &tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
3082 tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
3083 tbl.entry.u8StartBus = u8StartBus;
3084 tbl.entry.u8EndBus = u8EndBus;
3085 // u16PciSegmentGroup must match _SEG in ACPI table
3086
3087 tbl.hdr.aHeader.u8Checksum = acpiR3Checksum(&tbl, sizeof(tbl));
3088
3089 acpiR3PhysCopy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
3090}
3091
3092/**
3093 * Used by acpiR3PlantTables and acpiConstruct.
3094 *
3095 * @returns Guest memory address.
3096 */
3097static uint32_t apicR3FindRsdpSpace(void)
3098{
3099 return 0xe0000;
3100}
3101
3102/**
3103 * Called by acpiR3Construct to read and allocate a custom ACPI table
3104 *
3105 * @param pDevIns The device instance.
3106 * @param ppu8CustBin Address to receive the address of the table
3107 * @param pcbCustBin Address to receive the size of the the table.
3108 * @param pszCustBinFile
3109 * @param cbBufAvail Maximum space in bytes available for the custom
3110 * table (including header).
3111 */
3112static int acpiR3ReadCustomTable(PPDMDEVINS pDevIns, uint8_t **ppu8CustBin, uint64_t *pcbCustBin,
3113 char *pszCustBinFile, uint32_t cbBufAvail)
3114{
3115 RTFILE FileCUSTBin;
3116 int rc = RTFileOpen(&FileCUSTBin, pszCustBinFile,
3117 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
3118 if (RT_SUCCESS(rc))
3119 {
3120 rc = RTFileGetSize(FileCUSTBin, pcbCustBin);
3121 if (RT_SUCCESS(rc))
3122 {
3123 /* The following checks should be in sync the AssertReleaseMsg's below. */
3124 if ( *pcbCustBin > cbBufAvail
3125 || *pcbCustBin < sizeof(ACPITBLHEADER))
3126 rc = VERR_TOO_MUCH_DATA;
3127
3128 /*
3129 * Allocate buffer for the custom table binary data.
3130 */
3131 *ppu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, *pcbCustBin);
3132 if (*ppu8CustBin)
3133 {
3134 rc = RTFileRead(FileCUSTBin, *ppu8CustBin, *pcbCustBin, NULL);
3135 if (RT_FAILURE(rc))
3136 {
3137 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", *pcbCustBin, rc));
3138 PDMDevHlpMMHeapFree(pDevIns, *ppu8CustBin);
3139 *ppu8CustBin = NULL;
3140 }
3141 }
3142 else
3143 {
3144 rc = VERR_NO_MEMORY;
3145 }
3146 RTFileClose(FileCUSTBin);
3147 }
3148 }
3149 return rc;
3150}
3151
3152/**
3153 * Create the ACPI tables in guest memory.
3154 */
3155static int acpiR3PlantTables(ACPIState *pThis)
3156{
3157 int rc;
3158 RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
3159 RTGCPHYS32 GCPhysHpet = 0;
3160 RTGCPHYS32 GCPhysApic = 0;
3161 RTGCPHYS32 GCPhysSsdt = 0;
3162 RTGCPHYS32 GCPhysMcfg = 0;
3163 RTGCPHYS32 aGCPhysCust[MAX_CUST_TABLES] = {0};
3164 uint32_t addend = 0;
3165 RTGCPHYS32 aGCPhysRsdt[7 + MAX_CUST_TABLES];
3166 RTGCPHYS32 aGCPhysXsdt[7 + MAX_CUST_TABLES];
3167 uint32_t cAddr;
3168 uint32_t iMadt = 0;
3169 uint32_t iHpet = 0;
3170 uint32_t iSsdt = 0;
3171 uint32_t iMcfg = 0;
3172 uint32_t iCust = 0;
3173 size_t cbRsdt = sizeof(ACPITBLHEADER);
3174 size_t cbXsdt = sizeof(ACPITBLHEADER);
3175
3176 cAddr = 1; /* FADT */
3177 if (pThis->u8UseIOApic)
3178 iMadt = cAddr++; /* MADT */
3179
3180 if (pThis->fUseHpet)
3181 iHpet = cAddr++; /* HPET */
3182
3183 if (pThis->fUseMcfg)
3184 iMcfg = cAddr++; /* MCFG */
3185
3186 if (pThis->cCustTbls > 0)
3187 {
3188 iCust = cAddr; /* CUST */
3189 cAddr += pThis->cCustTbls;
3190 }
3191
3192 iSsdt = cAddr++; /* SSDT */
3193
3194 Assert(cAddr < RT_ELEMENTS(aGCPhysRsdt));
3195 Assert(cAddr < RT_ELEMENTS(aGCPhysXsdt));
3196
3197 cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
3198 cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
3199
3200 /*
3201 * Calculate the sizes for the low region and for the 64-bit prefetchable memory.
3202 * The latter starts never below 4G.
3203 */
3204 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
3205 uint32_t cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
3206 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
3207
3208 pThis->u64RamSize = MMR3PhysGetRamSize(pVM);
3209 if (pThis->fPciPref64Enabled)
3210 {
3211 uint64_t const u64PciPref64Min = _4G + cbAbove4GB;
3212 if (pThis->u64PciPref64Max > u64PciPref64Min)
3213 {
3214 /* Activate MEM4. See also DevPciIch9.cpp / ich9pciFakePCIBIOS() / uPciBiosMmio64 */
3215 pThis->u64PciPref64Min = u64PciPref64Min;
3216 LogRel(("ACPI: enabling 64-bit prefetch root bus resource %#018RX64..%#018RX64\n",
3217 u64PciPref64Min, pThis->u64PciPref64Max-1));
3218 }
3219 else
3220 LogRel(("ACPI: NOT enabling 64-bit prefetch root bus resource (min/%#018RX64 >= max/%#018RX64)\n",
3221 u64PciPref64Min, pThis->u64PciPref64Max-1));
3222 }
3223 if (cbBelow4GB > UINT32_C(0xfe000000)) /* See MEM3. */
3224 {
3225 /* Note: This is also enforced by DevPcBios.cpp. */
3226 LogRel(("ACPI: Clipping cbRamLow=%#RX64 down to 0xfe000000.\n", cbBelow4GB));
3227 cbBelow4GB = UINT32_C(0xfe000000);
3228 }
3229 pThis->cbRamLow = cbBelow4GB;
3230
3231 GCPhysCur = 0;
3232 GCPhysRsdt = GCPhysCur;
3233
3234 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
3235 GCPhysXsdt = GCPhysCur;
3236
3237 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
3238 GCPhysFadtAcpi1 = GCPhysCur;
3239
3240 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
3241 GCPhysFadtAcpi2 = GCPhysCur;
3242
3243 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
3244 GCPhysFacs = GCPhysCur;
3245
3246 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
3247 if (pThis->u8UseIOApic)
3248 {
3249 GCPhysApic = GCPhysCur;
3250 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMadt::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
3251 }
3252 if (pThis->fUseHpet)
3253 {
3254 GCPhysHpet = GCPhysCur;
3255 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
3256 }
3257 if (pThis->fUseMcfg)
3258 {
3259 GCPhysMcfg = GCPhysCur;
3260 /* Assume one entry */
3261 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
3262 }
3263
3264 for (uint8_t i = 0; i < pThis->cCustTbls; i++)
3265 {
3266 aGCPhysCust[i] = GCPhysCur;
3267 GCPhysCur = RT_ALIGN_32(GCPhysCur + pThis->acbCustBin[i], 16);
3268 }
3269
3270 void *pvSsdtCode = NULL;
3271 size_t cbSsdt = 0;
3272 rc = acpiPrepareSsdt(pThis->pDevInsR3, &pvSsdtCode, &cbSsdt);
3273 if (RT_FAILURE(rc))
3274 return rc;
3275
3276 GCPhysSsdt = GCPhysCur;
3277 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdt, 16);
3278
3279 GCPhysDsdt = GCPhysCur;
3280
3281 void *pvDsdtCode = NULL;
3282 size_t cbDsdt = 0;
3283 rc = acpiPrepareDsdt(pThis->pDevInsR3, &pvDsdtCode, &cbDsdt);
3284 if (RT_FAILURE(rc))
3285 return rc;
3286
3287 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdt, 16);
3288
3289 if (GCPhysCur > 0x10000)
3290 return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_TOO_MUCH_DATA,
3291 N_("Error: ACPI tables bigger than 64KB"));
3292
3293 Log(("RSDP 0x%08X\n", apicR3FindRsdpSpace()));
3294 addend = pThis->cbRamLow - 0x10000;
3295 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
3296 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
3297 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
3298 if (pThis->u8UseIOApic)
3299 Log((" MADT 0x%08X", GCPhysApic + addend));
3300 if (pThis->fUseHpet)
3301 Log((" HPET 0x%08X", GCPhysHpet + addend));
3302 if (pThis->fUseMcfg)
3303 Log((" MCFG 0x%08X", GCPhysMcfg + addend));
3304 for (uint8_t i = 0; i < pThis->cCustTbls; i++)
3305 Log((" CUST(%d) 0x%08X", i, aGCPhysCust[i] + addend));
3306 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
3307 Log(("\n"));
3308
3309 acpiR3SetupRsdp(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
3310 acpiR3SetupDsdt(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdt);
3311 acpiCleanupDsdt(pThis->pDevInsR3, pvDsdtCode);
3312 acpiR3SetupFacs(pThis, GCPhysFacs + addend);
3313 acpiR3SetupFadt(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
3314
3315 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
3316 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
3317 if (pThis->u8UseIOApic)
3318 {
3319 acpiR3SetupMadt(pThis, GCPhysApic + addend);
3320 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
3321 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
3322 }
3323 if (pThis->fUseHpet)
3324 {
3325 acpiR3SetupHpet(pThis, GCPhysHpet + addend);
3326 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
3327 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
3328 }
3329 if (pThis->fUseMcfg)
3330 {
3331 acpiR3SetupMcfg(pThis, GCPhysMcfg + addend);
3332 aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
3333 aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
3334 }
3335 for (uint8_t i = 0; i < pThis->cCustTbls; i++)
3336 {
3337 Assert(i < MAX_CUST_TABLES);
3338 acpiR3PhysCopy(pThis, aGCPhysCust[i] + addend, pThis->apu8CustBin[i], pThis->acbCustBin[i]);
3339 aGCPhysRsdt[iCust + i] = aGCPhysCust[i] + addend;
3340 aGCPhysXsdt[iCust + i] = aGCPhysCust[i] + addend;
3341 uint8_t* pSig = pThis->apu8CustBin[i];
3342 LogRel(("ACPI: Planted custom table '%c%c%c%c' at 0x%08X\n",
3343 pSig[0], pSig[1], pSig[2], pSig[3], aGCPhysCust[i] + addend));
3344 }
3345
3346 acpiR3SetupSsdt(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdt);
3347 acpiCleanupSsdt(pThis->pDevInsR3, pvSsdtCode);
3348 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
3349 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
3350
3351 rc = acpiR3SetupRsdt(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
3352 if (RT_FAILURE(rc))
3353 return rc;
3354 return acpiR3SetupXsdt(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
3355}
3356
3357/**
3358 * @callback_method_impl{FNPCICONFIGREAD}
3359 */
3360static DECLCALLBACK(uint32_t) acpiR3PciConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb)
3361{
3362 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3363
3364 Log2(("acpi: PCI config read: 0x%x (%d)\n", uAddress, cb));
3365 return pThis->pfnAcpiPciConfigRead(pDevIns, pPciDev, uAddress, cb);
3366}
3367
3368/**
3369 * @callback_method_impl{FNPCICONFIGWRITE}
3370 */
3371static DECLCALLBACK(VBOXSTRICTRC) acpiR3PciConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress,
3372 uint32_t u32Value, unsigned cb)
3373{
3374 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3375
3376 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, uAddress, cb));
3377 DEVACPI_LOCK_R3(pThis);
3378
3379 if (uAddress == VBOX_PCI_INTERRUPT_LINE)
3380 {
3381 Log(("acpi: ignore interrupt line settings: %d, we'll use hardcoded value %d\n", u32Value, SCI_INT));
3382 u32Value = SCI_INT;
3383 }
3384
3385 VBOXSTRICTRC rcBase = pThis->pfnAcpiPciConfigWrite(pDevIns, pPciDev, uAddress, u32Value, cb);
3386
3387 /* Assume that the base address is only changed when the corresponding
3388 * hardware functionality is disabled. The IO region is mapped when the
3389 * functionality is enabled by the guest. */
3390
3391 if (uAddress == PMREGMISC)
3392 {
3393 RTIOPORT NewIoPortBase = 0;
3394 /* Check Power Management IO Space Enable (PMIOSE) bit */
3395 if (pPciDev->abConfig[PMREGMISC] & 0x01)
3396 {
3397 NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, PMBA);
3398 NewIoPortBase &= 0xffc0;
3399 }
3400
3401 int rc = acpiR3UpdatePmHandlers(pThis, NewIoPortBase);
3402 AssertRC(rc);
3403 }
3404
3405 if (uAddress == SMBHSTCFG)
3406 {
3407 RTIOPORT NewIoPortBase = 0;
3408 /* Check SMBus Controller Host Interface Enable (SMB_HST_EN) bit */
3409 if (pPciDev->abConfig[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
3410 {
3411 NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, SMBBA);
3412 NewIoPortBase &= 0xfff0;
3413 }
3414
3415 int rc = acpiR3UpdateSMBusHandlers(pThis, NewIoPortBase);
3416 AssertRC(rc);
3417 }
3418
3419 DEVACPI_UNLOCK(pThis);
3420 return rcBase;
3421}
3422
3423/**
3424 * Attach a new CPU.
3425 *
3426 * @returns VBox status code.
3427 * @param pDevIns The device instance.
3428 * @param iLUN The logical unit which is being attached.
3429 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
3430 *
3431 * @remarks This code path is not used during construction.
3432 */
3433static DECLCALLBACK(int) acpiR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
3434{
3435 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3436 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
3437
3438 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
3439 ("Hot-plug flag is not set\n"),
3440 VERR_NOT_SUPPORTED);
3441 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
3442
3443 /* Check if it was already attached */
3444 int rc = VINF_SUCCESS;
3445 DEVACPI_LOCK_R3(pThis);
3446 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
3447 {
3448 PPDMIBASE IBaseTmp;
3449 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
3450 if (RT_SUCCESS(rc))
3451 {
3452 /* Enable the CPU */
3453 VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
3454
3455 /*
3456 * Lock the CPU because we don't know if the guest will use it or not.
3457 * Prevents ejection while the CPU is still used
3458 */
3459 VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
3460 pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
3461 pThis->u32CpuEvent = iLUN;
3462
3463 /* Notify the guest */
3464 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
3465 }
3466 }
3467 DEVACPI_UNLOCK(pThis);
3468 return rc;
3469}
3470
3471/**
3472 * Detach notification.
3473 *
3474 * @param pDevIns The device instance.
3475 * @param iLUN The logical unit which is being detached.
3476 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
3477 */
3478static DECLCALLBACK(void) acpiR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
3479{
3480 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3481
3482 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
3483
3484 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
3485 ("Hot-plug flag is not set\n"));
3486
3487 /* Check if it was already detached */
3488 DEVACPI_LOCK_R3(pThis);
3489 if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
3490 {
3491 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
3492 {
3493 /* Disable the CPU */
3494 VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
3495 pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
3496 pThis->u32CpuEvent = iLUN;
3497
3498 /* Notify the guest */
3499 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
3500 }
3501 else
3502 AssertMsgFailed(("CPU is still locked by the guest\n"));
3503 }
3504 DEVACPI_UNLOCK(pThis);
3505}
3506
3507/**
3508 * @interface_method_impl{PDMDEVREG,pfnResume}
3509 */
3510static DECLCALLBACK(void) acpiR3Resume(PPDMDEVINS pDevIns)
3511{
3512 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3513 if (pThis->fSetWakeupOnResume)
3514 {
3515 Log(("acpiResume: setting WAK_STS\n"));
3516 pThis->fSetWakeupOnResume = false;
3517 pThis->pm1a_sts |= WAK_STS;
3518 }
3519}
3520
3521/**
3522 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
3523 */
3524static DECLCALLBACK(void) acpiR3MemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
3525{
3526 RT_NOREF1(enmCtx);
3527 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3528 acpiR3PlantTables(pThis);
3529}
3530
3531/**
3532 * @interface_method_impl{PDMDEVREG,pfnReset}
3533 */
3534static DECLCALLBACK(void) acpiR3Reset(PPDMDEVINS pDevIns)
3535{
3536 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3537
3538 /* Play safe: make sure that the IRQ isn't stuck after a reset. */
3539 acpiSetIrq(pThis, 0);
3540
3541 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
3542 pThis->pm1a_en = 0;
3543 pThis->pm1a_sts = 0;
3544 pThis->pm1a_ctl = 0;
3545 pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
3546 pThis->uPmTimerVal = 0;
3547 acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
3548 pThis->uPmTimeOld = pThis->uPmTimerVal;
3549 pThis->uBatteryIndex = 0;
3550 pThis->uSystemInfoIndex = 0;
3551 pThis->gpe0_en = 0;
3552 pThis->gpe0_sts = 0;
3553 pThis->uSleepState = 0;
3554 TMTimerUnlock(pThis->pPmTimerR3);
3555
3556 /* Real device behavior is resetting only the PM controller state,
3557 * but we're additionally doing the job of the BIOS. */
3558 acpiR3UpdatePmHandlers(pThis, PM_PORT_BASE);
3559 acpiR3PmPCIBIOSFake(pThis);
3560
3561 /* Reset SMBus base and PCI config space in addition to the SMBus controller
3562 * state. Real device behavior is only the SMBus controller state reset,
3563 * but we're additionally doing the job of the BIOS. */
3564 acpiR3UpdateSMBusHandlers(pThis, SMB_PORT_BASE);
3565 acpiR3SMBusPCIBIOSFake(pThis);
3566 acpiR3SMBusResetDevice(pThis);
3567}
3568
3569/**
3570 * @interface_method_impl{PDMDEVREG,pfnRelocate}
3571 */
3572static DECLCALLBACK(void) acpiR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3573{
3574 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3575 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3576 pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
3577 NOREF(offDelta);
3578}
3579
3580/**
3581 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3582 */
3583static DECLCALLBACK(int) acpiR3Destruct(PPDMDEVINS pDevIns)
3584{
3585 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3586 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3587 for (uint8_t i = 0; i < pThis->cCustTbls; i++)
3588 {
3589 if (pThis->apu8CustBin[i])
3590 {
3591 PDMDevHlpMMHeapFree(pDevIns, pThis->apu8CustBin[i]);
3592 pThis->apu8CustBin[i] = NULL;
3593 }
3594 }
3595 return VINF_SUCCESS;
3596}
3597
3598/**
3599 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3600 */
3601static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3602{
3603 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3604 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3605
3606 /*
3607 * Init data and set defaults.
3608 */
3609 /** @todo move more of the code up! */
3610
3611 pThis->pDevInsR3 = pDevIns;
3612 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
3613 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3614 VMCPUSET_EMPTY(&pThis->CpuSetAttached);
3615 VMCPUSET_EMPTY(&pThis->CpuSetLocked);
3616 pThis->idCpuLockCheck = UINT32_C(0xffffffff);
3617 pThis->u32CpuEventType = 0;
3618 pThis->u32CpuEvent = UINT32_C(0xffffffff);
3619
3620 /* The first CPU can't be attached/detached */
3621 VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
3622 VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
3623
3624 /* IBase */
3625 pThis->IBase.pfnQueryInterface = acpiR3QueryInterface;
3626 /* IACPIPort */
3627 pThis->IACPIPort.pfnSleepButtonPress = acpiR3Port_SleepButtonPress;
3628 pThis->IACPIPort.pfnPowerButtonPress = acpiR3Port_PowerButtonPress;
3629 pThis->IACPIPort.pfnGetPowerButtonHandled = acpiR3Port_GetPowerButtonHandled;
3630 pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiR3Port_GetGuestEnteredACPIMode;
3631 pThis->IACPIPort.pfnGetCpuStatus = acpiR3Port_GetCpuStatus;
3632 pThis->IACPIPort.pfnMonitorHotPlugEvent = acpiR3Port_MonitorHotPlugEvent;
3633 pThis->IACPIPort.pfnBatteryStatusChangeEvent = acpiR3Port_BatteryStatusChangeEvent;
3634
3635 /*
3636 * Set the default critical section to NOP (related to the PM timer).
3637 */
3638 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3639 AssertRCReturn(rc, rc);
3640
3641 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi#%u", iInstance);
3642 AssertRCReturn(rc, rc);
3643
3644 /*
3645 * Validate and read the configuration.
3646 */
3647 if (!CFGMR3AreValuesValid(pCfg,
3648 "IOAPIC\0"
3649 "NumCPUs\0"
3650 "GCEnabled\0"
3651 "R0Enabled\0"
3652 "HpetEnabled\0"
3653 "McfgEnabled\0"
3654 "McfgBase\0"
3655 "McfgLength\0"
3656 "PciPref64Enabled\0"
3657 "PciPref64LimitGB\0"
3658 "SmcEnabled\0"
3659 "FdcEnabled\0"
3660 "ShowRtc\0"
3661 "ShowCpu\0"
3662 "NicPciAddress\0"
3663 "AudioPciAddress\0"
3664 "IocPciAddress\0"
3665 "HostBusPciAddress\0"
3666 "EnableSuspendToDisk\0"
3667 "PowerS1Enabled\0"
3668 "PowerS4Enabled\0"
3669 "CpuHotPlug\0"
3670 "AmlFilePath\0"
3671 "Serial0IoPortBase\0"
3672 "Serial1IoPortBase\0"
3673 "Serial2IoPortBase\0"
3674 "Serial3IoPortBase\0"
3675 "Serial0Irq\0"
3676 "Serial1Irq\0"
3677 "Serial2Irq\0"
3678 "Serial3Irq\0"
3679 "AcpiOemId\0"
3680 "AcpiCreatorId\0"
3681 "AcpiCreatorRev\0"
3682 "CustomTable\0"
3683 "CustomTable0\0"
3684 "CustomTable1\0"
3685 "CustomTable2\0"
3686 "CustomTable3\0"
3687 "Parallel0IoPortBase\0"
3688 "Parallel1IoPortBase\0"
3689 "Parallel0Irq\0"
3690 "Parallel1Irq\0"
3691 ))
3692 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
3693 N_("Configuration error: Invalid config key for ACPI device"));
3694
3695 /* query whether we are supposed to present an IOAPIC */
3696 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
3697 if (RT_FAILURE(rc))
3698 return PDMDEV_SET_ERROR(pDevIns, rc,
3699 N_("Configuration error: Failed to read \"IOAPIC\""));
3700
3701 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
3702 if (RT_FAILURE(rc))
3703 return PDMDEV_SET_ERROR(pDevIns, rc,
3704 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
3705
3706 /* query whether we are supposed to present an FDC controller */
3707 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
3708 if (RT_FAILURE(rc))
3709 return PDMDEV_SET_ERROR(pDevIns, rc,
3710 N_("Configuration error: Failed to read \"FdcEnabled\""));
3711
3712 /* query whether we are supposed to present HPET */
3713 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
3714 if (RT_FAILURE(rc))
3715 return PDMDEV_SET_ERROR(pDevIns, rc,
3716 N_("Configuration error: Failed to read \"HpetEnabled\""));
3717 /* query MCFG configuration */
3718 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
3719 if (RT_FAILURE(rc))
3720 return PDMDEV_SET_ERROR(pDevIns, rc,
3721 N_("Configuration error: Failed to read \"McfgBase\""));
3722 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
3723 if (RT_FAILURE(rc))
3724 return PDMDEV_SET_ERROR(pDevIns, rc,
3725 N_("Configuration error: Failed to read \"McfgLength\""));
3726 pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
3727
3728 /* query whether we are supposed to set up the 64-bit prefetchable memory window */
3729 rc = CFGMR3QueryBoolDef(pCfg, "PciPref64Enabled", &pThis->fPciPref64Enabled, false);
3730 if (RT_FAILURE(rc))
3731 return PDMDEV_SET_ERROR(pDevIns, rc,
3732 N_("Configuration error: Failed to read \"PciPref64Enabled\""));
3733
3734 /* query the limit of the the 64-bit prefetchable memory window */
3735 uint64_t u64PciPref64MaxGB;
3736 rc = CFGMR3QueryU64Def(pCfg, "PciPref64LimitGB", &u64PciPref64MaxGB, 64);
3737 if (RT_FAILURE(rc))
3738 return PDMDEV_SET_ERROR(pDevIns, rc,
3739 N_("Configuration error: Failed to read \"PciPref64LimitGB\""));
3740 pThis->u64PciPref64Max = _1G64 * u64PciPref64MaxGB;
3741
3742 /* query whether we are supposed to present SMC */
3743 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
3744 if (RT_FAILURE(rc))
3745 return PDMDEV_SET_ERROR(pDevIns, rc,
3746 N_("Configuration error: Failed to read \"SmcEnabled\""));
3747
3748 /* query whether we are supposed to present RTC object */
3749 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
3750 if (RT_FAILURE(rc))
3751 return PDMDEV_SET_ERROR(pDevIns, rc,
3752 N_("Configuration error: Failed to read \"ShowRtc\""));
3753
3754 /* query whether we are supposed to present CPU objects */
3755 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
3756 if (RT_FAILURE(rc))
3757 return PDMDEV_SET_ERROR(pDevIns, rc,
3758 N_("Configuration error: Failed to read \"ShowCpu\""));
3759
3760 /* query primary NIC PCI address */
3761 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
3762 if (RT_FAILURE(rc))
3763 return PDMDEV_SET_ERROR(pDevIns, rc,
3764 N_("Configuration error: Failed to read \"NicPciAddress\""));
3765
3766 /* query primary NIC PCI address */
3767 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
3768 if (RT_FAILURE(rc))
3769 return PDMDEV_SET_ERROR(pDevIns, rc,
3770 N_("Configuration error: Failed to read \"AudioPciAddress\""));
3771
3772 /* query IO controller (southbridge) PCI address */
3773 rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
3774 if (RT_FAILURE(rc))
3775 return PDMDEV_SET_ERROR(pDevIns, rc,
3776 N_("Configuration error: Failed to read \"IocPciAddress\""));
3777
3778 /* query host bus controller PCI address */
3779 rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
3780 if (RT_FAILURE(rc))
3781 return PDMDEV_SET_ERROR(pDevIns, rc,
3782 N_("Configuration error: Failed to read \"HostBusPciAddress\""));
3783
3784 /* query whether S1 power state should be exposed */
3785 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
3786 if (RT_FAILURE(rc))
3787 return PDMDEV_SET_ERROR(pDevIns, rc,
3788 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
3789
3790 /* query whether S4 power state should be exposed */
3791 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
3792 if (RT_FAILURE(rc))
3793 return PDMDEV_SET_ERROR(pDevIns, rc,
3794 N_("Configuration error: Failed to read \"PowerS4Enabled\""));
3795
3796 /* query whether S1 power state should save the VM state */
3797 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
3798 if (RT_FAILURE(rc))
3799 return PDMDEV_SET_ERROR(pDevIns, rc,
3800 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
3801
3802 /* query whether we are allow CPU hot plugging */
3803 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
3804 if (RT_FAILURE(rc))
3805 return PDMDEV_SET_ERROR(pDevIns, rc,
3806 N_("Configuration error: Failed to read \"CpuHotPlug\""));
3807
3808 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
3809 if (RT_FAILURE(rc))
3810 return PDMDEV_SET_ERROR(pDevIns, rc,
3811 N_("Configuration error: Failed to read \"GCEnabled\""));
3812
3813 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
3814 if (RT_FAILURE(rc))
3815 return PDMDEV_SET_ERROR(pDevIns, rc,
3816 N_("configuration error: failed to read \"R0Enabled\""));
3817
3818 /* query serial info */
3819 rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
3820 if (RT_FAILURE(rc))
3821 return PDMDEV_SET_ERROR(pDevIns, rc,
3822 N_("Configuration error: Failed to read \"Serial0Irq\""));
3823
3824 rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
3825 if (RT_FAILURE(rc))
3826 return PDMDEV_SET_ERROR(pDevIns, rc,
3827 N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
3828
3829 /* Serial 1 is enabled, get config data */
3830 rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
3831 if (RT_FAILURE(rc))
3832 return PDMDEV_SET_ERROR(pDevIns, rc,
3833 N_("Configuration error: Failed to read \"Serial1Irq\""));
3834
3835 rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
3836 if (RT_FAILURE(rc))
3837 return PDMDEV_SET_ERROR(pDevIns, rc,
3838 N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
3839
3840 /* Read serial port 2 settings; disabled if CFGM keys do not exist. */
3841 rc = CFGMR3QueryU8Def(pCfg, "Serial2Irq", &pThis->uSerial2Irq, 0);
3842 if (RT_FAILURE(rc))
3843 return PDMDEV_SET_ERROR(pDevIns, rc,
3844 N_("Configuration error: Failed to read \"Serial2Irq\""));
3845
3846 rc = CFGMR3QueryU16Def(pCfg, "Serial2IoPortBase", &pThis->uSerial2IoPortBase, 0);
3847 if (RT_FAILURE(rc))
3848 return PDMDEV_SET_ERROR(pDevIns, rc,
3849 N_("Configuration error: Failed to read \"Serial2IoPortBase\""));
3850
3851 /* Read serial port 3 settings; disabled if CFGM keys do not exist. */
3852 rc = CFGMR3QueryU8Def(pCfg, "Serial3Irq", &pThis->uSerial3Irq, 0);
3853 if (RT_FAILURE(rc))
3854 return PDMDEV_SET_ERROR(pDevIns, rc,
3855 N_("Configuration error: Failed to read \"Serial3Irq\""));
3856
3857 rc = CFGMR3QueryU16Def(pCfg, "Serial3IoPortBase", &pThis->uSerial3IoPortBase, 0);
3858 if (RT_FAILURE(rc))
3859 return PDMDEV_SET_ERROR(pDevIns, rc,
3860 N_("Configuration error: Failed to read \"Serial3IoPortBase\""));
3861 /*
3862 * Query settings for both parallel ports, if the CFGM keys don't exist pretend that
3863 * the corresponding parallel port is not enabled.
3864 */
3865 rc = CFGMR3QueryU8Def(pCfg, "Parallel0Irq", &pThis->uParallel0Irq, 0);
3866 if (RT_FAILURE(rc))
3867 return PDMDEV_SET_ERROR(pDevIns, rc,
3868 N_("Configuration error: Failed to read \"Parallel0Irq\""));
3869
3870 rc = CFGMR3QueryU16Def(pCfg, "Parallel0IoPortBase", &pThis->uParallel0IoPortBase, 0);
3871 if (RT_FAILURE(rc))
3872 return PDMDEV_SET_ERROR(pDevIns, rc,
3873 N_("Configuration error: Failed to read \"Parallel0IoPortBase\""));
3874
3875 rc = CFGMR3QueryU8Def(pCfg, "Parallel1Irq", &pThis->uParallel1Irq, 0);
3876 if (RT_FAILURE(rc))
3877 return PDMDEV_SET_ERROR(pDevIns, rc,
3878 N_("Configuration error: Failed to read \"Parallel1Irq\""));
3879
3880 rc = CFGMR3QueryU16Def(pCfg, "Parallel1IoPortBase", &pThis->uParallel1IoPortBase, 0);
3881 if (RT_FAILURE(rc))
3882 return PDMDEV_SET_ERROR(pDevIns, rc,
3883 N_("Configuration error: Failed to read \"Parallel1IoPortBase\""));
3884
3885 /* Try to attach the other CPUs */
3886 for (unsigned i = 1; i < pThis->cCpus; i++)
3887 {
3888 if (pThis->fCpuHotPlug)
3889 {
3890 PPDMIBASE IBaseTmp;
3891 rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
3892
3893 if (RT_SUCCESS(rc))
3894 {
3895 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3896 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3897 Log(("acpi: Attached CPU %u\n", i));
3898 }
3899 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3900 Log(("acpi: CPU %u not attached yet\n", i));
3901 else
3902 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
3903 }
3904 else
3905 {
3906 /* CPU is always attached if hot-plug is not enabled. */
3907 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3908 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3909 }
3910 }
3911
3912 char *pszOemId = NULL;
3913 rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiOemId", &pszOemId, "VBOX ");
3914 if (RT_FAILURE(rc))
3915 return PDMDEV_SET_ERROR(pDevIns, rc,
3916 N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
3917 size_t cbOemId = strlen(pszOemId);
3918 if (cbOemId > 6)
3919 return PDMDEV_SET_ERROR(pDevIns, rc,
3920 N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
3921 memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
3922 memcpy(pThis->au8OemId, pszOemId, cbOemId);
3923 MMR3HeapFree(pszOemId);
3924
3925 char *pszCreatorId = NULL;
3926 rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
3927 if (RT_FAILURE(rc))
3928 return PDMDEV_SET_ERROR(pDevIns, rc,
3929 N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
3930 size_t cbCreatorId = strlen(pszCreatorId);
3931 if (cbCreatorId > 4)
3932 return PDMDEV_SET_ERROR(pDevIns, rc,
3933 N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
3934 memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
3935 memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
3936 MMR3HeapFree(pszCreatorId);
3937
3938 rc = CFGMR3QueryU32Def(pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
3939 if (RT_FAILURE(rc))
3940 return PDMDEV_SET_ERROR(pDevIns, rc,
3941 N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
3942 pThis->u32OemRevision = RT_H2LE_U32(0x1);
3943
3944 /*
3945 * Load custom ACPI tables.
3946 */
3947 char *pszCustBinFile;
3948
3949 /* Maintain legacy behavior for CustomTable config key.
3950 * If present, use it as alias for CustomTable1. */
3951 rc = CFGMR3QueryStringAlloc(pCfg, "CustomTable", &pszCustBinFile);
3952 if (rc != VERR_CFGM_VALUE_NOT_FOUND)
3953 {
3954 if (RT_FAILURE(rc))
3955 return PDMDEV_SET_ERROR(pDevIns, rc,
3956 N_("Configuration error: Querying \"CustomTable\" as a string failed"));
3957 if (!*pszCustBinFile)
3958 {
3959 MMR3HeapFree(pszCustBinFile);
3960 pszCustBinFile = NULL;
3961 }
3962 else if (pszCustBinFile)
3963 {
3964 /* Try creating CustomTable0 using legacy value. */
3965 rc = CFGMR3InsertString(pCfg, "CustomTable0", pszCustBinFile);
3966 if (rc == VERR_CFGM_LEAF_EXISTS)
3967 LogRel(("ACPI: Warning: \"CustomTable\" configuration"
3968 " setting ignored as \"CustomTable0\" setting exists.\n"));
3969 MMR3HeapFree(pszCustBinFile);
3970 }
3971 }
3972
3973 /* Total space available for custom ACPI tables
3974 * @todo define as appropriate, remove as a magic number, and document
3975 * limitation in product manual */
3976 uint32_t cbBufAvail = 3072;
3977 pThis->cCustTbls = 0;
3978
3979 const char* custTblConfigKeys[] = {"CustomTable0", "CustomTable1", "CustomTable2", "CustomTable3"};
3980 for (unsigned i = 0; i < RT_ELEMENTS(custTblConfigKeys); ++i)
3981 {
3982 const char* pszConfigKey = custTblConfigKeys[i];
3983
3984 /*
3985 * Get the custom table binary file name.
3986 */
3987 rc = CFGMR3QueryStringAlloc(pCfg, pszConfigKey, &pszCustBinFile);
3988 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3989 {
3990 pszCustBinFile = NULL;
3991 rc = VINF_SUCCESS;
3992 }
3993 else if (RT_FAILURE(rc))
3994 return PDMDEV_SET_ERROR(pDevIns, rc,
3995 N_("Configuration error: Querying \"CustomTableN\" as a string failed"));
3996 else if (!*pszCustBinFile)
3997 {
3998 MMR3HeapFree(pszCustBinFile);
3999 pszCustBinFile = NULL;
4000 }
4001 /*
4002 * Determine the custom table binary size, open specified file in the process.
4003 */
4004 if (pszCustBinFile)
4005 {
4006 uint32_t tblIdx = pThis->cCustTbls;
4007 rc = acpiR3ReadCustomTable(pDevIns, &(pThis->apu8CustBin[tblIdx]),
4008 &(pThis->acbCustBin[tblIdx]), pszCustBinFile, cbBufAvail);
4009 LogRel(("ACPI: Reading custom ACPI table(%u) from file '%s' (%d bytes)\n",
4010 tblIdx, pszCustBinFile, pThis->acbCustBin[tblIdx]));
4011 MMR3HeapFree(pszCustBinFile);
4012 if (RT_FAILURE(rc))
4013 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Error reading custom ACPI table."));
4014 cbBufAvail -= pThis->acbCustBin[tblIdx];
4015
4016 /* Update custom OEM attributes based on custom table
4017 * @todo: is it intended for custom tables to overwrite user provided values above? */
4018 ACPITBLHEADER *pTblHdr = (ACPITBLHEADER*)pThis->apu8CustBin[tblIdx];
4019 memcpy(&pThis->au8OemId[0], &pTblHdr->au8OemId[0], 6);
4020 memcpy(&pThis->au8OemTabId[0], &pTblHdr->au8OemTabId[0], 8);
4021 pThis->u32OemRevision = pTblHdr->u32OemRevision;
4022 memcpy(&pThis->au8CreatorId[0], &pTblHdr->au8CreatorId[0], 4);
4023 pThis->u32CreatorRev = pTblHdr->u32CreatorRev;
4024
4025 pThis->cCustTbls++;
4026 Assert(pThis->cCustTbls <= MAX_CUST_TABLES);
4027 }
4028 }
4029
4030 /* Set default PM port base */
4031 pThis->uPmIoPortBase = PM_PORT_BASE;
4032
4033 /* Set default SMBus port base */
4034 pThis->uSMBusIoPortBase = SMB_PORT_BASE;
4035
4036 /*
4037 * FDC and SMC try to use the same non-shareable interrupt (6),
4038 * enable only one device.
4039 */
4040 if (pThis->fUseSmc)
4041 pThis->fUseFdc = false;
4042
4043 /*
4044 * Plant ACPI tables.
4045 */
4046 /** @todo Part of this is redone by acpiR3MemSetup, we only need to init the
4047 * au8RSDPPage here. However, there should be no harm in doing it
4048 * twice, so the lazy bird is taking the quick way out for now. */
4049 RTGCPHYS32 GCPhysRsdp = apicR3FindRsdpSpace();
4050 if (!GCPhysRsdp)
4051 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
4052 N_("Can not find space for RSDP. ACPI is disabled"));
4053
4054 rc = acpiR3PlantTables(pThis);
4055 if (RT_FAILURE(rc))
4056 return rc;
4057
4058 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
4059 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
4060 if (RT_FAILURE(rc))
4061 return rc;
4062
4063 /*
4064 * Register I/O ports.
4065 */
4066 rc = acpiR3RegisterPmHandlers(pThis);
4067 if (RT_FAILURE(rc))
4068 return rc;
4069
4070 rc = acpiR3RegisterSMBusHandlers(pThis);
4071 if (RT_FAILURE(rc))
4072 return rc;
4073
4074#define R(addr, cnt, writer, reader, description) \
4075 do { \
4076 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
4077 NULL, NULL, description); \
4078 if (RT_FAILURE(rc)) \
4079 return rc; \
4080 } while (0)
4081 R(SMI_CMD, 1, acpiR3SmiWrite, NULL, "ACPI SMI");
4082#ifdef DEBUG_ACPI
4083 R(DEBUG_HEX, 1, acpiR3DhexWrite, NULL, "ACPI Debug hex");
4084 R(DEBUG_CHR, 1, acpiR3DchrWrite, NULL, "ACPI Debug char");
4085#endif
4086 R(BAT_INDEX, 1, acpiR3BatIndexWrite, NULL, "ACPI Battery status index");
4087 R(BAT_DATA, 1, NULL, acpiR3BatDataRead, "ACPI Battery status data");
4088 R(SYSI_INDEX, 1, acpiR3SysInfoIndexWrite, NULL, "ACPI system info index");
4089 R(SYSI_DATA, 1, acpiR3SysInfoDataWrite, acpiR3SysInfoDataRead, "ACPI system info data");
4090 R(ACPI_RESET_BLK, 1, acpiR3ResetWrite, NULL, "ACPI Reset");
4091#undef R
4092
4093 /*
4094 * Create the PM timer.
4095 */
4096 PTMTIMER pTimer;
4097 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiR3PmTimer, &pThis->dev,
4098 TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
4099 AssertRCReturn(rc, rc);
4100 pThis->pPmTimerR3 = pTimer;
4101 pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
4102 pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
4103
4104 rc = TMTimerLock(pTimer, VERR_IGNORED);
4105 AssertRCReturn(rc, rc);
4106 pThis->u64PmTimerInitial = TMTimerGet(pTimer);
4107 acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
4108 TMTimerUnlock(pTimer);
4109
4110 /*
4111 * Set up the PCI device.
4112 */
4113 PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
4114 PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
4115
4116 /* See p. 50 of PIIX4 manual */
4117 PCIDevSetCommand(&pThis->dev, PCI_COMMAND_IOACCESS);
4118 PCIDevSetStatus(&pThis->dev, 0x0280);
4119
4120 PCIDevSetRevisionId(&pThis->dev, 0x08);
4121
4122 PCIDevSetClassProg(&pThis->dev, 0x00);
4123 PCIDevSetClassSub(&pThis->dev, 0x80);
4124 PCIDevSetClassBase(&pThis->dev, 0x06);
4125
4126 PCIDevSetHeaderType(&pThis->dev, 0x80);
4127
4128 PCIDevSetBIST(&pThis->dev, 0x00);
4129
4130 PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
4131 PCIDevSetInterruptPin (&pThis->dev, 0x01);
4132
4133 Assert((pThis->uPmIoPortBase & 0x003f) == 0);
4134 acpiR3PmPCIBIOSFake(pThis);
4135
4136 Assert((pThis->uSMBusIoPortBase & 0x000f) == 0);
4137 acpiR3SMBusPCIBIOSFake(pThis);
4138 acpiR3SMBusResetDevice(pThis);
4139
4140 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
4141 if (RT_FAILURE(rc))
4142 return rc;
4143
4144 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
4145 acpiR3PciConfigRead, &pThis->pfnAcpiPciConfigRead,
4146 acpiR3PciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
4147
4148 /*
4149 * Register the saved state.
4150 */
4151 rc = PDMDevHlpSSMRegister(pDevIns, 8, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
4152 if (RT_FAILURE(rc))
4153 return rc;
4154
4155 /*
4156 * Get the corresponding connector interface
4157 */
4158 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
4159 if (RT_SUCCESS(rc))
4160 {
4161 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
4162 if (!pThis->pDrv)
4163 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
4164 N_("LUN #0 doesn't have an ACPI connector interface"));
4165 }
4166 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4167 {
4168 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
4169 pDevIns->pReg->szName, pDevIns->iInstance));
4170 rc = VINF_SUCCESS;
4171 }
4172 else
4173 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
4174
4175 PDMDevHlpDBGFInfoRegister(pDevIns, "acpi", "ACPI info", acpiR3Info);
4176
4177 return rc;
4178}
4179
4180/**
4181 * The device registration structure.
4182 */
4183const PDMDEVREG g_DeviceACPI =
4184{
4185 /* u32Version */
4186 PDM_DEVREG_VERSION,
4187 /* szName */
4188 "acpi",
4189 /* szRCMod */
4190 "VBoxDDRC.rc",
4191 /* szR0Mod */
4192 "VBoxDDR0.r0",
4193 /* pszDescription */
4194 "Advanced Configuration and Power Interface",
4195 /* fFlags */
4196 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
4197 /* fClass */
4198 PDM_DEVREG_CLASS_ACPI,
4199 /* cMaxInstances */
4200 ~0U,
4201 /* cbInstance */
4202 sizeof(ACPIState),
4203 /* pfnConstruct */
4204 acpiR3Construct,
4205 /* pfnDestruct */
4206 acpiR3Destruct,
4207 /* pfnRelocate */
4208 acpiR3Relocate,
4209 /* pfnMemSetup */
4210 acpiR3MemSetup,
4211 /* pfnPowerOn */
4212 NULL,
4213 /* pfnReset */
4214 acpiR3Reset,
4215 /* pfnSuspend */
4216 NULL,
4217 /* pfnResume */
4218 acpiR3Resume,
4219 /* pfnAttach */
4220 acpiR3Attach,
4221 /* pfnDetach */
4222 acpiR3Detach,
4223 /* pfnQueryInterface. */
4224 NULL,
4225 /* pfnInitComplete */
4226 NULL,
4227 /* pfnPowerOff */
4228 NULL,
4229 /* pfnSoftReset */
4230 NULL,
4231 /* u32VersionEnd */
4232 PDM_DEVREG_VERSION
4233};
4234
4235#endif /* IN_RING3 */
4236#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