VirtualBox

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

最後變更 在這個檔案從62640是 62554,由 vboxsync 提交於 9 年 前

Devices/ACPI: build fix, the result is intentionally bool

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

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