VirtualBox

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

Last change on this file since 73494 was 71892, checked in by vboxsync, 7 years ago

DevACPI: nit

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

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