VirtualBox

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

Last change on this file since 68249 was 68249, checked in by vboxsync, 8 years ago

DevACPI: temporary sanity check (take reset into account)

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