VirtualBox

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

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

DevACPI: make the condition for u64PciPref64 and cbRamLow more obvious and for u64PciPref64 it's actually sufficient to add cbRamHole, not offRamHole

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 145.9 KB
Line 
1/* $Id: DevACPI.cpp 65619 2017-02-06 10:36:00Z 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 {
3139 /* Activate MEM4 */
3140 if (pThis->u64RamSize > offRamHole)
3141 pThis->u64PciPref64 = RT_ALIGN_64(pThis->u64RamSize + cbRamHole, _1G);
3142 else
3143 pThis->u64PciPref64 = _4G;
3144 }
3145 uint64_t cbRamLow = pThis->u64RamSize > offRamHole ? offRamHole : pThis->u64RamSize;
3146 if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
3147 {
3148 /* Note: This is also enforced by DevPcBios.cpp. */
3149 LogRel(("ACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
3150 cbRamLow = UINT32_C(0xffe00000);
3151 }
3152 pThis->cbRamLow = (uint32_t)cbRamLow;
3153
3154 GCPhysCur = 0;
3155 GCPhysRsdt = GCPhysCur;
3156
3157 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
3158 GCPhysXsdt = GCPhysCur;
3159
3160 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
3161 GCPhysFadtAcpi1 = GCPhysCur;
3162
3163 GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
3164 GCPhysFadtAcpi2 = GCPhysCur;
3165
3166 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
3167 GCPhysFacs = GCPhysCur;
3168
3169 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
3170 if (pThis->u8UseIOApic)
3171 {
3172 GCPhysApic = GCPhysCur;
3173 GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMadt::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
3174 }
3175 if (pThis->fUseHpet)
3176 {
3177 GCPhysHpet = GCPhysCur;
3178 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
3179 }
3180 if (pThis->fUseMcfg)
3181 {
3182 GCPhysMcfg = GCPhysCur;
3183 /* Assume one entry */
3184 GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
3185 }
3186 if (pThis->fUseCust)
3187 {
3188 GCPhysCust = GCPhysCur;
3189 GCPhysCur = RT_ALIGN_32(GCPhysCur + pThis->cbCustBin, 16);
3190 }
3191
3192 void *pvSsdtCode = NULL;
3193 size_t cbSsdt = 0;
3194 rc = acpiPrepareSsdt(pThis->pDevInsR3, &pvSsdtCode, &cbSsdt);
3195 if (RT_FAILURE(rc))
3196 return rc;
3197
3198 GCPhysSsdt = GCPhysCur;
3199 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdt, 16);
3200
3201 GCPhysDsdt = GCPhysCur;
3202
3203 void *pvDsdtCode = NULL;
3204 size_t cbDsdt = 0;
3205 rc = acpiPrepareDsdt(pThis->pDevInsR3, &pvDsdtCode, &cbDsdt);
3206 if (RT_FAILURE(rc))
3207 return rc;
3208
3209 GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdt, 16);
3210
3211 if (GCPhysCur > 0x10000)
3212 return PDMDEV_SET_ERROR(pThis->pDevInsR3, VERR_TOO_MUCH_DATA,
3213 N_("Error: ACPI tables bigger than 64KB"));
3214
3215 Log(("RSDP 0x%08X\n", apicR3FindRsdpSpace()));
3216 addend = pThis->cbRamLow - 0x10000;
3217 Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
3218 Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
3219 Log(("DSDT 0x%08X", GCPhysDsdt + addend));
3220 if (pThis->u8UseIOApic)
3221 Log((" MADT 0x%08X", GCPhysApic + addend));
3222 if (pThis->fUseHpet)
3223 Log((" HPET 0x%08X", GCPhysHpet + addend));
3224 if (pThis->fUseMcfg)
3225 Log((" MCFG 0x%08X", GCPhysMcfg + addend));
3226 if (pThis->fUseCust)
3227 Log((" CUST 0x%08X", GCPhysCust + addend));
3228 Log((" SSDT 0x%08X", GCPhysSsdt + addend));
3229 Log(("\n"));
3230
3231 acpiR3SetupRsdp(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
3232 acpiR3SetupDsdt(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdt);
3233 acpiCleanupDsdt(pThis->pDevInsR3, pvDsdtCode);
3234 acpiR3SetupFacs(pThis, GCPhysFacs + addend);
3235 acpiR3SetupFadt(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
3236
3237 aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
3238 aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
3239 if (pThis->u8UseIOApic)
3240 {
3241 acpiR3SetupMadt(pThis, GCPhysApic + addend);
3242 aGCPhysRsdt[iMadt] = GCPhysApic + addend;
3243 aGCPhysXsdt[iMadt] = GCPhysApic + addend;
3244 }
3245 if (pThis->fUseHpet)
3246 {
3247 acpiR3SetupHpet(pThis, GCPhysHpet + addend);
3248 aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
3249 aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
3250 }
3251 if (pThis->fUseMcfg)
3252 {
3253 acpiR3SetupMcfg(pThis, GCPhysMcfg + addend);
3254 aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
3255 aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
3256 }
3257 if (pThis->fUseCust)
3258 {
3259 acpiR3SetupCust(pThis, GCPhysCust + addend);
3260 aGCPhysRsdt[iCust] = GCPhysCust + addend;
3261 aGCPhysXsdt[iCust] = GCPhysCust + addend;
3262 }
3263
3264 acpiR3SetupSsdt(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdt);
3265 acpiCleanupSsdt(pThis->pDevInsR3, pvSsdtCode);
3266 aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
3267 aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
3268
3269 rc = acpiR3SetupRsdt(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
3270 if (RT_FAILURE(rc))
3271 return rc;
3272 return acpiR3SetupXsdt(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
3273}
3274
3275/**
3276 * @callback_method_impl{FNPCICONFIGREAD}
3277 */
3278static DECLCALLBACK(uint32_t) acpiR3PciConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb)
3279{
3280 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3281
3282 Log2(("acpi: PCI config read: 0x%x (%d)\n", uAddress, cb));
3283 return pThis->pfnAcpiPciConfigRead(pDevIns, pPciDev, uAddress, cb);
3284}
3285
3286/**
3287 * @callback_method_impl{FNPCICONFIGWRITE}
3288 */
3289static DECLCALLBACK(void) acpiR3PciConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress,
3290 uint32_t u32Value, unsigned cb)
3291{
3292 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3293
3294 Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, uAddress, cb));
3295 DEVACPI_LOCK_R3(pThis);
3296
3297 if (uAddress == VBOX_PCI_INTERRUPT_LINE)
3298 {
3299 Log(("acpi: ignore interrupt line settings: %d, we'll use hardcoded value %d\n", u32Value, SCI_INT));
3300 u32Value = SCI_INT;
3301 }
3302
3303 pThis->pfnAcpiPciConfigWrite(pDevIns, pPciDev, uAddress, u32Value, cb);
3304
3305 /* Assume that the base address is only changed when the corresponding
3306 * hardware functionality is disabled. The IO region is mapped when the
3307 * functionality is enabled by the guest. */
3308
3309 if (uAddress == PMREGMISC)
3310 {
3311 RTIOPORT NewIoPortBase = 0;
3312 /* Check Power Management IO Space Enable (PMIOSE) bit */
3313 if (pPciDev->abConfig[PMREGMISC] & 0x01)
3314 {
3315 NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, PMBA);
3316 NewIoPortBase &= 0xffc0;
3317 }
3318
3319 int rc = acpiR3UpdatePmHandlers(pThis, NewIoPortBase);
3320 AssertRC(rc);
3321 }
3322
3323 if (uAddress == SMBHSTCFG)
3324 {
3325 RTIOPORT NewIoPortBase = 0;
3326 /* Check SMBus Controller Host Interface Enable (SMB_HST_EN) bit */
3327 if (pPciDev->abConfig[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
3328 {
3329 NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, SMBBA);
3330 NewIoPortBase &= 0xfff0;
3331 }
3332
3333 int rc = acpiR3UpdateSMBusHandlers(pThis, NewIoPortBase);
3334 AssertRC(rc);
3335 }
3336
3337 DEVACPI_UNLOCK(pThis);
3338}
3339
3340/**
3341 * Attach a new CPU.
3342 *
3343 * @returns VBox status code.
3344 * @param pDevIns The device instance.
3345 * @param iLUN The logical unit which is being attached.
3346 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
3347 *
3348 * @remarks This code path is not used during construction.
3349 */
3350static DECLCALLBACK(int) acpiR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
3351{
3352 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3353 LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
3354
3355 AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
3356 ("Hot-plug flag is not set\n"),
3357 VERR_NOT_SUPPORTED);
3358 AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
3359
3360 /* Check if it was already attached */
3361 int rc = VINF_SUCCESS;
3362 DEVACPI_LOCK_R3(pThis);
3363 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
3364 {
3365 PPDMIBASE IBaseTmp;
3366 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
3367 if (RT_SUCCESS(rc))
3368 {
3369 /* Enable the CPU */
3370 VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
3371
3372 /*
3373 * Lock the CPU because we don't know if the guest will use it or not.
3374 * Prevents ejection while the CPU is still used
3375 */
3376 VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
3377 pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
3378 pThis->u32CpuEvent = iLUN;
3379
3380 /* Notify the guest */
3381 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
3382 }
3383 }
3384 DEVACPI_UNLOCK(pThis);
3385 return rc;
3386}
3387
3388/**
3389 * Detach notification.
3390 *
3391 * @param pDevIns The device instance.
3392 * @param iLUN The logical unit which is being detached.
3393 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
3394 */
3395static DECLCALLBACK(void) acpiR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
3396{
3397 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3398
3399 LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
3400
3401 AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
3402 ("Hot-plug flag is not set\n"));
3403
3404 /* Check if it was already detached */
3405 DEVACPI_LOCK_R3(pThis);
3406 if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
3407 {
3408 if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
3409 {
3410 /* Disable the CPU */
3411 VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
3412 pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
3413 pThis->u32CpuEvent = iLUN;
3414
3415 /* Notify the guest */
3416 apicR3UpdateGpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
3417 }
3418 else
3419 AssertMsgFailed(("CPU is still locked by the guest\n"));
3420 }
3421 DEVACPI_UNLOCK(pThis);
3422}
3423
3424/**
3425 * @interface_method_impl{PDMDEVREG,pfnResume}
3426 */
3427static DECLCALLBACK(void) acpiR3Resume(PPDMDEVINS pDevIns)
3428{
3429 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3430 if (pThis->fSetWakeupOnResume)
3431 {
3432 Log(("acpiResume: setting WAK_STS\n"));
3433 pThis->fSetWakeupOnResume = false;
3434 pThis->pm1a_sts |= WAK_STS;
3435 }
3436}
3437
3438/**
3439 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
3440 */
3441static DECLCALLBACK(void) acpiR3MemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
3442{
3443 RT_NOREF1(enmCtx);
3444 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3445 acpiR3PlantTables(pThis);
3446}
3447
3448/**
3449 * @interface_method_impl{PDMDEVREG,pfnReset}
3450 */
3451static DECLCALLBACK(void) acpiR3Reset(PPDMDEVINS pDevIns)
3452{
3453 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3454
3455 /* Play safe: make sure that the IRQ isn't stuck after a reset. */
3456 acpiSetIrq(pThis, 0);
3457
3458 TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
3459 pThis->pm1a_en = 0;
3460 pThis->pm1a_sts = 0;
3461 pThis->pm1a_ctl = 0;
3462 pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
3463 pThis->uPmTimerVal = 0;
3464 acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
3465 pThis->uBatteryIndex = 0;
3466 pThis->uSystemInfoIndex = 0;
3467 pThis->gpe0_en = 0;
3468 pThis->gpe0_sts = 0;
3469 pThis->uSleepState = 0;
3470 TMTimerUnlock(pThis->pPmTimerR3);
3471
3472 /* Real device behavior is resetting only the PM controller state,
3473 * but we're additionally doing the job of the BIOS. */
3474 acpiR3UpdatePmHandlers(pThis, PM_PORT_BASE);
3475 acpiR3PmPCIBIOSFake(pThis);
3476
3477 /* Reset SMBus base and PCI config space in addition to the SMBus controller
3478 * state. Real device behavior is only the SMBus controller state reset,
3479 * but we're additionally doing the job of the BIOS. */
3480 acpiR3UpdateSMBusHandlers(pThis, SMB_PORT_BASE);
3481 acpiR3SMBusPCIBIOSFake(pThis);
3482 acpiR3SMBusResetDevice(pThis);
3483}
3484
3485/**
3486 * @interface_method_impl{PDMDEVREG,pfnRelocate}
3487 */
3488static DECLCALLBACK(void) acpiR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3489{
3490 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3491 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3492 pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
3493 NOREF(offDelta);
3494}
3495
3496/**
3497 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3498 */
3499static DECLCALLBACK(int) acpiR3Destruct(PPDMDEVINS pDevIns)
3500{
3501 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3502 if (pThis->pu8CustBin)
3503 {
3504 MMR3HeapFree(pThis->pu8CustBin);
3505 pThis->pu8CustBin = NULL;
3506 }
3507 return VINF_SUCCESS;
3508}
3509
3510/**
3511 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3512 */
3513static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3514{
3515 ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
3516 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3517
3518 /*
3519 * Init data and set defaults.
3520 */
3521 /** @todo move more of the code up! */
3522
3523 pThis->pDevInsR3 = pDevIns;
3524 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
3525 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
3526 VMCPUSET_EMPTY(&pThis->CpuSetAttached);
3527 VMCPUSET_EMPTY(&pThis->CpuSetLocked);
3528 pThis->idCpuLockCheck = UINT32_C(0xffffffff);
3529 pThis->u32CpuEventType = 0;
3530 pThis->u32CpuEvent = UINT32_C(0xffffffff);
3531
3532 /* The first CPU can't be attached/detached */
3533 VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
3534 VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
3535
3536 /* IBase */
3537 pThis->IBase.pfnQueryInterface = acpiR3QueryInterface;
3538 /* IACPIPort */
3539 pThis->IACPIPort.pfnSleepButtonPress = acpiR3Port_SleepButtonPress;
3540 pThis->IACPIPort.pfnPowerButtonPress = acpiR3Port_PowerButtonPress;
3541 pThis->IACPIPort.pfnGetPowerButtonHandled = acpiR3Port_GetPowerButtonHandled;
3542 pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiR3Port_GetGuestEnteredACPIMode;
3543 pThis->IACPIPort.pfnGetCpuStatus = acpiR3Port_GetCpuStatus;
3544 pThis->IACPIPort.pfnMonitorHotPlugEvent = acpiR3Port_MonitorHotPlugEvent;
3545 pThis->IACPIPort.pfnBatteryStatusChangeEvent = acpiR3Port_BatteryStatusChangeEvent;
3546
3547 /*
3548 * Set the default critical section to NOP (related to the PM timer).
3549 */
3550 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3551 AssertRCReturn(rc, rc);
3552
3553 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi#%u", iInstance);
3554 AssertRCReturn(rc, rc);
3555
3556 /*
3557 * Validate and read the configuration.
3558 */
3559 if (!CFGMR3AreValuesValid(pCfg,
3560 "RamSize\0"
3561 "RamHoleSize\0"
3562 "IOAPIC\0"
3563 "NumCPUs\0"
3564 "GCEnabled\0"
3565 "R0Enabled\0"
3566 "HpetEnabled\0"
3567 "McfgEnabled\0"
3568 "McfgBase\0"
3569 "McfgLength\0"
3570 "PciPref64Enabled\0"
3571 "SmcEnabled\0"
3572 "FdcEnabled\0"
3573 "ShowRtc\0"
3574 "ShowCpu\0"
3575 "NicPciAddress\0"
3576 "AudioPciAddress\0"
3577 "IocPciAddress\0"
3578 "HostBusPciAddress\0"
3579 "EnableSuspendToDisk\0"
3580 "PowerS1Enabled\0"
3581 "PowerS4Enabled\0"
3582 "CpuHotPlug\0"
3583 "AmlFilePath\0"
3584 "Serial0IoPortBase\0"
3585 "Serial1IoPortBase\0"
3586 "Serial2IoPortBase\0"
3587 "Serial3IoPortBase\0"
3588 "Serial0Irq\0"
3589 "Serial1Irq\0"
3590 "Serial2Irq\0"
3591 "Serial3Irq\0"
3592 "AcpiOemId\0"
3593 "AcpiCreatorId\0"
3594 "AcpiCreatorRev\0"
3595 "CustomTable\0"
3596 "SLICTable\0"
3597 "Parallel0IoPortBase\0"
3598 "Parallel1IoPortBase\0"
3599 "Parallel0Irq\0"
3600 "Parallel1Irq\0"
3601 ))
3602 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
3603 N_("Configuration error: Invalid config key for ACPI device"));
3604
3605 /* query whether we are supposed to present an IOAPIC */
3606 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
3607 if (RT_FAILURE(rc))
3608 return PDMDEV_SET_ERROR(pDevIns, rc,
3609 N_("Configuration error: Failed to read \"IOAPIC\""));
3610
3611 rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
3612 if (RT_FAILURE(rc))
3613 return PDMDEV_SET_ERROR(pDevIns, rc,
3614 N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
3615
3616 /* query whether we are supposed to present an FDC controller */
3617 rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
3618 if (RT_FAILURE(rc))
3619 return PDMDEV_SET_ERROR(pDevIns, rc,
3620 N_("Configuration error: Failed to read \"FdcEnabled\""));
3621
3622 /* query whether we are supposed to present HPET */
3623 rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
3624 if (RT_FAILURE(rc))
3625 return PDMDEV_SET_ERROR(pDevIns, rc,
3626 N_("Configuration error: Failed to read \"HpetEnabled\""));
3627 /* query MCFG configuration */
3628 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
3629 if (RT_FAILURE(rc))
3630 return PDMDEV_SET_ERROR(pDevIns, rc,
3631 N_("Configuration error: Failed to read \"McfgBase\""));
3632 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
3633 if (RT_FAILURE(rc))
3634 return PDMDEV_SET_ERROR(pDevIns, rc,
3635 N_("Configuration error: Failed to read \"McfgLength\""));
3636 pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
3637
3638 /* query whether we are supposed to set up the 64-bit prefetchable memory window */
3639 rc = CFGMR3QueryBoolDef(pCfg, "PciPref64Enabled", &pThis->fPciPref64Enabled, false);
3640 if (RT_FAILURE(rc))
3641 return PDMDEV_SET_ERROR(pDevIns, rc,
3642 N_("Configuration error: Failed to read \"PciPref64Enabled\""));
3643
3644 /* query whether we are supposed to present custom table */
3645 pThis->fUseCust = false;
3646
3647 /* query whether we are supposed to present SMC */
3648 rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
3649 if (RT_FAILURE(rc))
3650 return PDMDEV_SET_ERROR(pDevIns, rc,
3651 N_("Configuration error: Failed to read \"SmcEnabled\""));
3652
3653 /* query whether we are supposed to present RTC object */
3654 rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
3655 if (RT_FAILURE(rc))
3656 return PDMDEV_SET_ERROR(pDevIns, rc,
3657 N_("Configuration error: Failed to read \"ShowRtc\""));
3658
3659 /* query whether we are supposed to present CPU objects */
3660 rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
3661 if (RT_FAILURE(rc))
3662 return PDMDEV_SET_ERROR(pDevIns, rc,
3663 N_("Configuration error: Failed to read \"ShowCpu\""));
3664
3665 /* query primary NIC PCI address */
3666 rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
3667 if (RT_FAILURE(rc))
3668 return PDMDEV_SET_ERROR(pDevIns, rc,
3669 N_("Configuration error: Failed to read \"NicPciAddress\""));
3670
3671 /* query primary NIC PCI address */
3672 rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
3673 if (RT_FAILURE(rc))
3674 return PDMDEV_SET_ERROR(pDevIns, rc,
3675 N_("Configuration error: Failed to read \"AudioPciAddress\""));
3676
3677 /* query IO controller (southbridge) PCI address */
3678 rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
3679 if (RT_FAILURE(rc))
3680 return PDMDEV_SET_ERROR(pDevIns, rc,
3681 N_("Configuration error: Failed to read \"IocPciAddress\""));
3682
3683 /* query host bus controller PCI address */
3684 rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
3685 if (RT_FAILURE(rc))
3686 return PDMDEV_SET_ERROR(pDevIns, rc,
3687 N_("Configuration error: Failed to read \"HostBusPciAddress\""));
3688
3689 /* query whether S1 power state should be exposed */
3690 rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
3691 if (RT_FAILURE(rc))
3692 return PDMDEV_SET_ERROR(pDevIns, rc,
3693 N_("Configuration error: Failed to read \"PowerS1Enabled\""));
3694
3695 /* query whether S4 power state should be exposed */
3696 rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
3697 if (RT_FAILURE(rc))
3698 return PDMDEV_SET_ERROR(pDevIns, rc,
3699 N_("Configuration error: Failed to read \"PowerS4Enabled\""));
3700
3701 /* query whether S1 power state should save the VM state */
3702 rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
3703 if (RT_FAILURE(rc))
3704 return PDMDEV_SET_ERROR(pDevIns, rc,
3705 N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
3706
3707 /* query whether we are allow CPU hot plugging */
3708 rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
3709 if (RT_FAILURE(rc))
3710 return PDMDEV_SET_ERROR(pDevIns, rc,
3711 N_("Configuration error: Failed to read \"CpuHotPlug\""));
3712
3713 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
3714 if (RT_FAILURE(rc))
3715 return PDMDEV_SET_ERROR(pDevIns, rc,
3716 N_("Configuration error: Failed to read \"GCEnabled\""));
3717
3718 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
3719 if (RT_FAILURE(rc))
3720 return PDMDEV_SET_ERROR(pDevIns, rc,
3721 N_("configuration error: failed to read \"R0Enabled\""));
3722
3723 /* query serial info */
3724 rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
3725 if (RT_FAILURE(rc))
3726 return PDMDEV_SET_ERROR(pDevIns, rc,
3727 N_("Configuration error: Failed to read \"Serial0Irq\""));
3728
3729 rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
3730 if (RT_FAILURE(rc))
3731 return PDMDEV_SET_ERROR(pDevIns, rc,
3732 N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
3733
3734 /* Serial 1 is enabled, get config data */
3735 rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
3736 if (RT_FAILURE(rc))
3737 return PDMDEV_SET_ERROR(pDevIns, rc,
3738 N_("Configuration error: Failed to read \"Serial1Irq\""));
3739
3740 rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
3741 if (RT_FAILURE(rc))
3742 return PDMDEV_SET_ERROR(pDevIns, rc,
3743 N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
3744
3745 /* Read serial port 2 settings; disabled if CFGM keys do not exist. */
3746 rc = CFGMR3QueryU8Def(pCfg, "Serial2Irq", &pThis->uSerial2Irq, 0);
3747 if (RT_FAILURE(rc))
3748 return PDMDEV_SET_ERROR(pDevIns, rc,
3749 N_("Configuration error: Failed to read \"Serial2Irq\""));
3750
3751 rc = CFGMR3QueryU16Def(pCfg, "Serial2IoPortBase", &pThis->uSerial2IoPortBase, 0);
3752 if (RT_FAILURE(rc))
3753 return PDMDEV_SET_ERROR(pDevIns, rc,
3754 N_("Configuration error: Failed to read \"Serial2IoPortBase\""));
3755
3756 /* Read serial port 3 settings; disabled if CFGM keys do not exist. */
3757 rc = CFGMR3QueryU8Def(pCfg, "Serial3Irq", &pThis->uSerial3Irq, 0);
3758 if (RT_FAILURE(rc))
3759 return PDMDEV_SET_ERROR(pDevIns, rc,
3760 N_("Configuration error: Failed to read \"Serial3Irq\""));
3761
3762 rc = CFGMR3QueryU16Def(pCfg, "Serial3IoPortBase", &pThis->uSerial3IoPortBase, 0);
3763 if (RT_FAILURE(rc))
3764 return PDMDEV_SET_ERROR(pDevIns, rc,
3765 N_("Configuration error: Failed to read \"Serial3IoPortBase\""));
3766 /*
3767 * Query settings for both parallel ports, if the CFGM keys don't exist pretend that
3768 * the corresponding parallel port is not enabled.
3769 */
3770 rc = CFGMR3QueryU8Def(pCfg, "Parallel0Irq", &pThis->uParallel0Irq, 0);
3771 if (RT_FAILURE(rc))
3772 return PDMDEV_SET_ERROR(pDevIns, rc,
3773 N_("Configuration error: Failed to read \"Parallel0Irq\""));
3774
3775 rc = CFGMR3QueryU16Def(pCfg, "Parallel0IoPortBase", &pThis->uParallel0IoPortBase, 0);
3776 if (RT_FAILURE(rc))
3777 return PDMDEV_SET_ERROR(pDevIns, rc,
3778 N_("Configuration error: Failed to read \"Parallel0IoPortBase\""));
3779
3780 rc = CFGMR3QueryU8Def(pCfg, "Parallel1Irq", &pThis->uParallel1Irq, 0);
3781 if (RT_FAILURE(rc))
3782 return PDMDEV_SET_ERROR(pDevIns, rc,
3783 N_("Configuration error: Failed to read \"Parallel1Irq\""));
3784
3785 rc = CFGMR3QueryU16Def(pCfg, "Parallel1IoPortBase", &pThis->uParallel1IoPortBase, 0);
3786 if (RT_FAILURE(rc))
3787 return PDMDEV_SET_ERROR(pDevIns, rc,
3788 N_("Configuration error: Failed to read \"Parallel1IoPortBase\""));
3789
3790 /* Try to attach the other CPUs */
3791 for (unsigned i = 1; i < pThis->cCpus; i++)
3792 {
3793 if (pThis->fCpuHotPlug)
3794 {
3795 PPDMIBASE IBaseTmp;
3796 rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
3797
3798 if (RT_SUCCESS(rc))
3799 {
3800 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3801 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3802 Log(("acpi: Attached CPU %u\n", i));
3803 }
3804 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3805 Log(("acpi: CPU %u not attached yet\n", i));
3806 else
3807 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
3808 }
3809 else
3810 {
3811 /* CPU is always attached if hot-plug is not enabled. */
3812 VMCPUSET_ADD(&pThis->CpuSetAttached, i);
3813 VMCPUSET_ADD(&pThis->CpuSetLocked, i);
3814 }
3815 }
3816
3817 char *pszOemId = NULL;
3818 rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiOemId", &pszOemId, "VBOX ");
3819 if (RT_FAILURE(rc))
3820 return PDMDEV_SET_ERROR(pDevIns, rc,
3821 N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
3822 size_t cbOemId = strlen(pszOemId);
3823 if (cbOemId > 6)
3824 return PDMDEV_SET_ERROR(pDevIns, rc,
3825 N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
3826 memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
3827 memcpy(pThis->au8OemId, pszOemId, cbOemId);
3828 MMR3HeapFree(pszOemId);
3829
3830 char *pszCreatorId = NULL;
3831 rc = CFGMR3QueryStringAllocDef(pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
3832 if (RT_FAILURE(rc))
3833 return PDMDEV_SET_ERROR(pDevIns, rc,
3834 N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
3835 size_t cbCreatorId = strlen(pszCreatorId);
3836 if (cbCreatorId > 4)
3837 return PDMDEV_SET_ERROR(pDevIns, rc,
3838 N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
3839 memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
3840 memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
3841 MMR3HeapFree(pszCreatorId);
3842
3843 rc = CFGMR3QueryU32Def(pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
3844 if (RT_FAILURE(rc))
3845 return PDMDEV_SET_ERROR(pDevIns, rc,
3846 N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
3847 pThis->u32OemRevision = RT_H2LE_U32(0x1);
3848
3849 /*
3850 * Get the custom table binary file name.
3851 */
3852 char *pszCustBinFile;
3853 rc = CFGMR3QueryStringAlloc(pCfg, "CustomTable", &pszCustBinFile);
3854 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3855 rc = CFGMR3QueryStringAlloc(pCfg, "SLICTable", &pszCustBinFile);
3856 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
3857 {
3858 pszCustBinFile = NULL;
3859 rc = VINF_SUCCESS;
3860 }
3861 else if (RT_FAILURE(rc))
3862 return PDMDEV_SET_ERROR(pDevIns, rc,
3863 N_("Configuration error: Querying \"CustomTable\" as a string failed"));
3864 else if (!*pszCustBinFile)
3865 {
3866 MMR3HeapFree(pszCustBinFile);
3867 pszCustBinFile = NULL;
3868 }
3869
3870 /*
3871 * Determine the custom table binary size, open specified ROM file in the process.
3872 */
3873 if (pszCustBinFile)
3874 {
3875 RTFILE FileCUSTBin;
3876 rc = RTFileOpen(&FileCUSTBin, pszCustBinFile,
3877 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
3878 if (RT_SUCCESS(rc))
3879 {
3880 rc = RTFileGetSize(FileCUSTBin, &pThis->cbCustBin);
3881 if (RT_SUCCESS(rc))
3882 {
3883 /* The following checks should be in sync the AssertReleaseMsg's below. */
3884 if ( pThis->cbCustBin > 3072
3885 || pThis->cbCustBin < sizeof(ACPITBLHEADER))
3886 rc = VERR_TOO_MUCH_DATA;
3887
3888 /*
3889 * Allocate buffer for the custom table binary data.
3890 */
3891 pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbCustBin);
3892 if (pThis->pu8CustBin)
3893 {
3894 rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
3895 if (RT_FAILURE(rc))
3896 {
3897 AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbCustBin, rc));
3898 MMR3HeapFree(pThis->pu8CustBin);
3899 pThis->pu8CustBin = NULL;
3900 }
3901 else
3902 {
3903 pThis->fUseCust = true;
3904 memcpy(&pThis->au8OemId[0], &pThis->pu8CustBin[10], 6);
3905 memcpy(&pThis->au8OemTabId[0], &pThis->pu8CustBin[16], 8);
3906 memcpy(&pThis->u32OemRevision, &pThis->pu8CustBin[24], 4);
3907 memcpy(&pThis->au8CreatorId[0], &pThis->pu8CustBin[28], 4);
3908 memcpy(&pThis->u32CreatorRev, &pThis->pu8CustBin[32], 4);
3909 LogRel(("ACPI: Reading custom ACPI table from file '%s' (%d bytes)\n", pszCustBinFile,
3910 pThis->cbCustBin));
3911 }
3912 }
3913 else
3914 rc = VERR_NO_MEMORY;
3915
3916 RTFileClose(FileCUSTBin);
3917 }
3918 }
3919 MMR3HeapFree(pszCustBinFile);
3920 if (RT_FAILURE(rc))
3921 return PDMDEV_SET_ERROR(pDevIns, rc,
3922 N_("Error reading custom ACPI table"));
3923 }
3924
3925 /* Set default PM port base */
3926 pThis->uPmIoPortBase = PM_PORT_BASE;
3927
3928 /* Set default SMBus port base */
3929 pThis->uSMBusIoPortBase = SMB_PORT_BASE;
3930
3931 /*
3932 * FDC and SMC try to use the same non-shareable interrupt (6),
3933 * enable only one device.
3934 */
3935 if (pThis->fUseSmc)
3936 pThis->fUseFdc = false;
3937
3938 /*
3939 * Plant ACPI tables.
3940 */
3941 /** @todo Part of this is redone by acpiR3MemSetup, we only need to init the
3942 * au8RSDPPage here. However, there should be no harm in doing it
3943 * twice, so the lazy bird is taking the quick way out for now. */
3944 RTGCPHYS32 GCPhysRsdp = apicR3FindRsdpSpace();
3945 if (!GCPhysRsdp)
3946 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
3947 N_("Can not find space for RSDP. ACPI is disabled"));
3948
3949 rc = acpiR3PlantTables(pThis);
3950 if (RT_FAILURE(rc))
3951 return rc;
3952
3953 rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
3954 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
3955 if (RT_FAILURE(rc))
3956 return rc;
3957
3958 /*
3959 * Register I/O ports.
3960 */
3961 rc = acpiR3RegisterPmHandlers(pThis);
3962 if (RT_FAILURE(rc))
3963 return rc;
3964
3965 rc = acpiR3RegisterSMBusHandlers(pThis);
3966 if (RT_FAILURE(rc))
3967 return rc;
3968
3969#define R(addr, cnt, writer, reader, description) \
3970 do { \
3971 rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
3972 NULL, NULL, description); \
3973 if (RT_FAILURE(rc)) \
3974 return rc; \
3975 } while (0)
3976 R(SMI_CMD, 1, acpiR3SmiWrite, NULL, "ACPI SMI");
3977#ifdef DEBUG_ACPI
3978 R(DEBUG_HEX, 1, acpiR3DhexWrite, NULL, "ACPI Debug hex");
3979 R(DEBUG_CHR, 1, acpiR3DchrWrite, NULL, "ACPI Debug char");
3980#endif
3981 R(BAT_INDEX, 1, acpiR3BatIndexWrite, NULL, "ACPI Battery status index");
3982 R(BAT_DATA, 1, NULL, acpiR3BatDataRead, "ACPI Battery status data");
3983 R(SYSI_INDEX, 1, acpiR3SysInfoIndexWrite, NULL, "ACPI system info index");
3984 R(SYSI_DATA, 1, acpiR3SysInfoDataWrite, acpiR3SysInfoDataRead, "ACPI system info data");
3985 R(ACPI_RESET_BLK, 1, acpiR3ResetWrite, NULL, "ACPI Reset");
3986#undef R
3987
3988 /*
3989 * Create the PM timer.
3990 */
3991 PTMTIMER pTimer;
3992 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiR3PmTimer, &pThis->dev,
3993 TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
3994 AssertRCReturn(rc, rc);
3995 pThis->pPmTimerR3 = pTimer;
3996 pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
3997 pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
3998
3999 rc = TMTimerLock(pTimer, VERR_IGNORED);
4000 AssertRCReturn(rc, rc);
4001 pThis->u64PmTimerInitial = TMTimerGet(pTimer);
4002 acpiR3PmTimerReset(pThis, pThis->u64PmTimerInitial);
4003 TMTimerUnlock(pTimer);
4004
4005 /*
4006 * Set up the PCI device.
4007 */
4008 PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
4009 PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
4010
4011 /* See p. 50 of PIIX4 manual */
4012 PCIDevSetCommand(&pThis->dev, 0x01);
4013 PCIDevSetStatus(&pThis->dev, 0x0280);
4014
4015 PCIDevSetRevisionId(&pThis->dev, 0x08);
4016
4017 PCIDevSetClassProg(&pThis->dev, 0x00);
4018 PCIDevSetClassSub(&pThis->dev, 0x80);
4019 PCIDevSetClassBase(&pThis->dev, 0x06);
4020
4021 PCIDevSetHeaderType(&pThis->dev, 0x80);
4022
4023 PCIDevSetBIST(&pThis->dev, 0x00);
4024
4025 PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
4026 PCIDevSetInterruptPin (&pThis->dev, 0x01);
4027
4028 Assert((pThis->uPmIoPortBase & 0x003f) == 0);
4029 acpiR3PmPCIBIOSFake(pThis);
4030
4031 Assert((pThis->uSMBusIoPortBase & 0x000f) == 0);
4032 acpiR3SMBusPCIBIOSFake(pThis);
4033 acpiR3SMBusResetDevice(pThis);
4034
4035 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
4036 if (RT_FAILURE(rc))
4037 return rc;
4038
4039 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
4040 acpiR3PciConfigRead, &pThis->pfnAcpiPciConfigRead,
4041 acpiR3PciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
4042
4043 /*
4044 * Register the saved state.
4045 */
4046 rc = PDMDevHlpSSMRegister(pDevIns, 8, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
4047 if (RT_FAILURE(rc))
4048 return rc;
4049
4050 /*
4051 * Get the corresponding connector interface
4052 */
4053 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
4054 if (RT_SUCCESS(rc))
4055 {
4056 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
4057 if (!pThis->pDrv)
4058 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
4059 N_("LUN #0 doesn't have an ACPI connector interface"));
4060 }
4061 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4062 {
4063 Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
4064 pDevIns->pReg->szName, pDevIns->iInstance));
4065 rc = VINF_SUCCESS;
4066 }
4067 else
4068 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
4069
4070 return rc;
4071}
4072
4073/**
4074 * The device registration structure.
4075 */
4076const PDMDEVREG g_DeviceACPI =
4077{
4078 /* u32Version */
4079 PDM_DEVREG_VERSION,
4080 /* szName */
4081 "acpi",
4082 /* szRCMod */
4083 "VBoxDDRC.rc",
4084 /* szR0Mod */
4085 "VBoxDDR0.r0",
4086 /* pszDescription */
4087 "Advanced Configuration and Power Interface",
4088 /* fFlags */
4089 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
4090 /* fClass */
4091 PDM_DEVREG_CLASS_ACPI,
4092 /* cMaxInstances */
4093 ~0U,
4094 /* cbInstance */
4095 sizeof(ACPIState),
4096 /* pfnConstruct */
4097 acpiR3Construct,
4098 /* pfnDestruct */
4099 acpiR3Destruct,
4100 /* pfnRelocate */
4101 acpiR3Relocate,
4102 /* pfnMemSetup */
4103 acpiR3MemSetup,
4104 /* pfnPowerOn */
4105 NULL,
4106 /* pfnReset */
4107 acpiR3Reset,
4108 /* pfnSuspend */
4109 NULL,
4110 /* pfnResume */
4111 acpiR3Resume,
4112 /* pfnAttach */
4113 acpiR3Attach,
4114 /* pfnDetach */
4115 acpiR3Detach,
4116 /* pfnQueryInterface. */
4117 NULL,
4118 /* pfnInitComplete */
4119 NULL,
4120 /* pfnPowerOff */
4121 NULL,
4122 /* pfnSoftReset */
4123 NULL,
4124 /* u32VersionEnd */
4125 PDM_DEVREG_VERSION
4126};
4127
4128#endif /* IN_RING3 */
4129#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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