VirtualBox

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

Last change on this file since 81089 was 81031, checked in by vboxsync, 5 years ago

PDM,Devices: Moving the PDMPCIDEV structures into the PDMDEVINS allocation. Preps for extending the config space to 4KB. bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette