VirtualBox

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

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

DevACPI: 64-bit prefetch window is 1G-aligned, mostly paranoia

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

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