[2781] | 1 | /* $Id: DevACPI.cpp 40282 2012-02-28 21:02:40Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[11166] | 3 | * DevACPI - Advanced Configuration and Power Interface (ACPI) Device.
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[37444] | 7 | * Copyright (C) 2006-2011 Oracle Corporation
|
---|
[1] | 8 | *
|
---|
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
[5999] | 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.
|
---|
[1] | 16 | */
|
---|
| 17 |
|
---|
[17572] | 18 | /*******************************************************************************
|
---|
| 19 | * Header Files *
|
---|
| 20 | *******************************************************************************/
|
---|
[1] | 21 | #define LOG_GROUP LOG_GROUP_DEV_ACPI
|
---|
[35346] | 22 | #include <VBox/vmm/pdmdev.h>
|
---|
| 23 | #include <VBox/vmm/pgm.h>
|
---|
[37444] | 24 | #include <VBox/vmm/dbgftrace.h>
|
---|
[39303] | 25 | #include <VBox/vmm/vmcpuset.h>
|
---|
[1] | 26 | #include <VBox/log.h>
|
---|
[17542] | 27 | #include <VBox/param.h>
|
---|
[1] | 28 | #include <iprt/assert.h>
|
---|
[1912] | 29 | #include <iprt/asm.h>
|
---|
[29250] | 30 | #include <iprt/asm-math.h>
|
---|
[40019] | 31 | #include <iprt/file.h>
|
---|
[1] | 32 | #ifdef IN_RING3
|
---|
[11208] | 33 | # include <iprt/alloc.h>
|
---|
| 34 | # include <iprt/string.h>
|
---|
[25966] | 35 | # include <iprt/uuid.h>
|
---|
[1] | 36 | #endif /* IN_RING3 */
|
---|
| 37 |
|
---|
[35353] | 38 | #include "VBoxDD.h"
|
---|
[1] | 39 |
|
---|
[11208] | 40 | #ifdef LOG_ENABLED
|
---|
| 41 | # define DEBUG_ACPI
|
---|
[1] | 42 | #endif
|
---|
| 43 |
|
---|
[491] | 44 | #if defined(IN_RING3) && !defined(VBOX_DEVICE_STRUCT_TESTCASE)
|
---|
[20400] | 45 | int acpiPrepareDsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puDsdtLen);
|
---|
| 46 | int acpiCleanupDsdt(PPDMDEVINS pDevIns, void* pPtr);
|
---|
[26183] | 47 |
|
---|
| 48 | int acpiPrepareSsdt(PPDMDEVINS pDevIns, void* *ppPtr, size_t *puSsdtLen);
|
---|
| 49 | int acpiCleanupSsdt(PPDMDEVINS pDevIns, void* pPtr);
|
---|
[1] | 50 | #endif /* !IN_RING3 */
|
---|
| 51 |
|
---|
| 52 |
|
---|
| 53 |
|
---|
[17572] | 54 | /*******************************************************************************
|
---|
| 55 | * Defined Constants And Macros *
|
---|
| 56 | *******************************************************************************/
|
---|
[37444] | 57 | #ifdef IN_RING3
|
---|
| 58 | /** Locks the device state, ring-3 only. */
|
---|
| 59 | # define DEVACPI_LOCK_R3(a_pThis) \
|
---|
| 60 | do { \
|
---|
| 61 | int rcLock = PDMCritSectEnter(&(a_pThis)->CritSect, VERR_IGNORED); \
|
---|
| 62 | AssertRC(rcLock); \
|
---|
| 63 | } while (0)
|
---|
| 64 | #endif
|
---|
| 65 | /** Unlocks the device state (all contexts). */
|
---|
| 66 | #define DEVACPI_UNLOCK(a_pThis) \
|
---|
| 67 | do { PDMCritSectLeave(&(a_pThis)->CritSect); } while (0)
|
---|
| 68 |
|
---|
| 69 |
|
---|
[1] | 70 | #define DEBUG_HEX 0x3000
|
---|
| 71 | #define DEBUG_CHR 0x3001
|
---|
| 72 |
|
---|
| 73 | #define PM_TMR_FREQ 3579545
|
---|
[21829] | 74 | /* Default base for PM PIIX4 device */
|
---|
| 75 | #define PM_PORT_BASE 0x4000
|
---|
[21820] | 76 | /* Port offsets in PM device */
|
---|
| 77 | enum
|
---|
| 78 | {
|
---|
[21829] | 79 | PM1a_EVT_OFFSET = 0x00,
|
---|
[21820] | 80 | PM1b_EVT_OFFSET = -1, /**< not supported */
|
---|
| 81 | PM1a_CTL_OFFSET = 0x04,
|
---|
| 82 | PM1b_CTL_OFFSET = -1, /**< not supported */
|
---|
| 83 | PM2_CTL_OFFSET = -1, /**< not supported */
|
---|
| 84 | PM_TMR_OFFSET = 0x08,
|
---|
| 85 | GPE0_OFFSET = 0x20,
|
---|
[21837] | 86 | GPE1_OFFSET = -1 /**< not supported */
|
---|
[21820] | 87 | };
|
---|
| 88 |
|
---|
[1] | 89 | #define BAT_INDEX 0x00004040
|
---|
| 90 | #define BAT_DATA 0x00004044
|
---|
| 91 | #define SYSI_INDEX 0x00004048
|
---|
| 92 | #define SYSI_DATA 0x0000404c
|
---|
| 93 | #define ACPI_RESET_BLK 0x00004050
|
---|
| 94 |
|
---|
| 95 | /* PM1x status register bits */
|
---|
[5605] | 96 | #define TMR_STS RT_BIT(0)
|
---|
| 97 | #define RSR1_STS (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
|
---|
| 98 | #define BM_STS RT_BIT(4)
|
---|
| 99 | #define GBL_STS RT_BIT(5)
|
---|
| 100 | #define RSR2_STS (RT_BIT(6) | RT_BIT(7))
|
---|
| 101 | #define PWRBTN_STS RT_BIT(8)
|
---|
| 102 | #define SLPBTN_STS RT_BIT(9)
|
---|
| 103 | #define RTC_STS RT_BIT(10)
|
---|
| 104 | #define IGN_STS RT_BIT(11)
|
---|
| 105 | #define RSR3_STS (RT_BIT(12) | RT_BIT(13) | RT_BIT(14))
|
---|
| 106 | #define WAK_STS RT_BIT(15)
|
---|
[1] | 107 | #define RSR_STS (RSR1_STS | RSR2_STS | RSR3_STS)
|
---|
| 108 |
|
---|
| 109 | /* PM1x enable register bits */
|
---|
[5605] | 110 | #define TMR_EN RT_BIT(0)
|
---|
| 111 | #define RSR1_EN (RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
|
---|
| 112 | #define GBL_EN RT_BIT(5)
|
---|
| 113 | #define RSR2_EN (RT_BIT(6) | RT_BIT(7))
|
---|
| 114 | #define PWRBTN_EN RT_BIT(8)
|
---|
| 115 | #define SLPBTN_EN RT_BIT(9)
|
---|
| 116 | #define RTC_EN RT_BIT(10)
|
---|
| 117 | #define RSR3_EN (RT_BIT(11) | RT_BIT(12) | RT_BIT(13) | RT_BIT(14) | RT_BIT(15))
|
---|
[1] | 118 | #define RSR_EN (RSR1_EN | RSR2_EN | RSR3_EN)
|
---|
| 119 | #define IGN_EN 0
|
---|
| 120 |
|
---|
| 121 | /* PM1x control register bits */
|
---|
[5605] | 122 | #define SCI_EN RT_BIT(0)
|
---|
| 123 | #define BM_RLD RT_BIT(1)
|
---|
| 124 | #define GBL_RLS RT_BIT(2)
|
---|
| 125 | #define RSR1_CNT (RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7) | RT_BIT(8))
|
---|
| 126 | #define IGN_CNT RT_BIT(9)
|
---|
[1] | 127 | #define SLP_TYPx_SHIFT 10
|
---|
| 128 | #define SLP_TYPx_MASK 7
|
---|
[5605] | 129 | #define SLP_EN RT_BIT(13)
|
---|
| 130 | #define RSR2_CNT (RT_BIT(14) | RT_BIT(15))
|
---|
[1] | 131 | #define RSR_CNT (RSR1_CNT | RSR2_CNT)
|
---|
| 132 |
|
---|
[5605] | 133 | #define GPE0_BATTERY_INFO_CHANGED RT_BIT(0)
|
---|
[1] | 134 |
|
---|
| 135 | enum
|
---|
| 136 | {
|
---|
| 137 | BAT_STATUS_STATE = 0x00, /**< BST battery state */
|
---|
| 138 | BAT_STATUS_PRESENT_RATE = 0x01, /**< BST battery present rate */
|
---|
| 139 | BAT_STATUS_REMAINING_CAPACITY = 0x02, /**< BST battery remaining capacity */
|
---|
| 140 | BAT_STATUS_PRESENT_VOLTAGE = 0x03, /**< BST battery present voltage */
|
---|
| 141 | BAT_INFO_UNITS = 0x04, /**< BIF power unit */
|
---|
| 142 | BAT_INFO_DESIGN_CAPACITY = 0x05, /**< BIF design capacity */
|
---|
| 143 | BAT_INFO_LAST_FULL_CHARGE_CAPACITY = 0x06, /**< BIF last full charge capacity */
|
---|
| 144 | BAT_INFO_TECHNOLOGY = 0x07, /**< BIF battery technology */
|
---|
| 145 | BAT_INFO_DESIGN_VOLTAGE = 0x08, /**< BIF design voltage */
|
---|
| 146 | BAT_INFO_DESIGN_CAPACITY_OF_WARNING = 0x09, /**< BIF design capacity of warning */
|
---|
| 147 | BAT_INFO_DESIGN_CAPACITY_OF_LOW = 0x0A, /**< BIF design capacity of low */
|
---|
| 148 | BAT_INFO_CAPACITY_GRANULARITY_1 = 0x0B, /**< BIF battery capacity granularity 1 */
|
---|
| 149 | BAT_INFO_CAPACITY_GRANULARITY_2 = 0x0C, /**< BIF battery capacity granularity 2 */
|
---|
| 150 | BAT_DEVICE_STATUS = 0x0D, /**< STA device status */
|
---|
| 151 | BAT_POWER_SOURCE = 0x0E, /**< PSR power source */
|
---|
| 152 | BAT_INDEX_LAST
|
---|
| 153 | };
|
---|
| 154 |
|
---|
| 155 | enum
|
---|
| 156 | {
|
---|
[26594] | 157 | CPU_EVENT_TYPE_ADD = 0x01, /**< Event type add */
|
---|
| 158 | CPU_EVENT_TYPE_REMOVE = 0x03 /**< Event type remove */
|
---|
| 159 | };
|
---|
| 160 |
|
---|
| 161 | enum
|
---|
| 162 | {
|
---|
[17590] | 163 | SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH = 0,
|
---|
[1] | 164 | SYSTEM_INFO_INDEX_USE_IOAPIC = 1,
|
---|
[16170] | 165 | SYSTEM_INFO_INDEX_HPET_STATUS = 2,
|
---|
| 166 | SYSTEM_INFO_INDEX_SMC_STATUS = 3,
|
---|
| 167 | SYSTEM_INFO_INDEX_FDC_STATUS = 4,
|
---|
[33540] | 168 | SYSTEM_INFO_INDEX_CPU0_STATUS = 5, /**< For compatibility with older saved states. */
|
---|
| 169 | SYSTEM_INFO_INDEX_CPU1_STATUS = 6, /**< For compatibility with older saved states. */
|
---|
| 170 | SYSTEM_INFO_INDEX_CPU2_STATUS = 7, /**< For compatibility with older saved states. */
|
---|
| 171 | SYSTEM_INFO_INDEX_CPU3_STATUS = 8, /**< For compatibility with older saved states. */
|
---|
[21829] | 172 | SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH= 9,
|
---|
| 173 | SYSTEM_INFO_INDEX_RTC_STATUS = 10,
|
---|
[26592] | 174 | SYSTEM_INFO_INDEX_CPU_LOCKED = 11, /**< Contains a flag indicating whether the CPU is locked or not */
|
---|
| 175 | SYSTEM_INFO_INDEX_CPU_LOCK_CHECK = 12, /**< For which CPU the lock status should be checked */
|
---|
[26594] | 176 | SYSTEM_INFO_INDEX_CPU_EVENT_TYPE = 13, /**< Type of the CPU hot-plug event */
|
---|
| 177 | SYSTEM_INFO_INDEX_CPU_EVENT = 14, /**< The CPU id the event is for */
|
---|
[28487] | 178 | SYSTEM_INFO_INDEX_NIC_ADDRESS = 15, /**< NIC PCI address, or 0 */
|
---|
[31519] | 179 | SYSTEM_INFO_INDEX_AUDIO_ADDRESS = 16, /**< Audio card PCI address, or 0 */
|
---|
[32477] | 180 | SYSTEM_INFO_INDEX_POWER_STATES = 17,
|
---|
[32471] | 181 | SYSTEM_INFO_INDEX_IOC_ADDRESS = 18, /**< IO controller PCI address */
|
---|
[32477] | 182 | SYSTEM_INFO_INDEX_HBC_ADDRESS = 19, /**< host bus controller PCI address */
|
---|
[32637] | 183 | SYSTEM_INFO_INDEX_PCI_BASE = 20, /**< PCI bus MCFG MMIO range base */
|
---|
| 184 | SYSTEM_INFO_INDEX_PCI_LENGTH = 21, /**< PCI bus MCFG MMIO range length */
|
---|
[35746] | 185 | SYSTEM_INFO_INDEX_SERIAL0_IOBASE = 22,
|
---|
| 186 | SYSTEM_INFO_INDEX_SERIAL0_IRQ = 23,
|
---|
| 187 | SYSTEM_INFO_INDEX_SERIAL1_IOBASE = 24,
|
---|
| 188 | SYSTEM_INFO_INDEX_SERIAL1_IRQ = 25,
|
---|
[35773] | 189 | SYSTEM_INFO_INDEX_END = 26,
|
---|
[1] | 190 | SYSTEM_INFO_INDEX_INVALID = 0x80,
|
---|
| 191 | SYSTEM_INFO_INDEX_VALID = 0x200
|
---|
| 192 | };
|
---|
| 193 |
|
---|
| 194 | #define AC_OFFLINE 0
|
---|
| 195 | #define AC_ONLINE 1
|
---|
| 196 |
|
---|
| 197 | #define BAT_TECH_PRIMARY 1
|
---|
| 198 | #define BAT_TECH_SECONDARY 2
|
---|
| 199 |
|
---|
[16041] | 200 | #define STA_DEVICE_PRESENT_MASK RT_BIT(0) /**< present */
|
---|
| 201 | #define STA_DEVICE_ENABLED_MASK RT_BIT(1) /**< enabled and decodes its resources */
|
---|
| 202 | #define STA_DEVICE_SHOW_IN_UI_MASK RT_BIT(2) /**< should be shown in UI */
|
---|
| 203 | #define STA_DEVICE_FUNCTIONING_PROPERLY_MASK RT_BIT(3) /**< functioning properly */
|
---|
| 204 | #define STA_BATTERY_PRESENT_MASK RT_BIT(4) /**< the battery is present */
|
---|
[1] | 205 |
|
---|
[17572] | 206 |
|
---|
| 207 | /*******************************************************************************
|
---|
| 208 | * Structures and Typedefs *
|
---|
| 209 | *******************************************************************************/
|
---|
| 210 | /**
|
---|
| 211 | * The ACPI device state.
|
---|
| 212 | */
|
---|
| 213 | typedef struct ACPIState
|
---|
[1] | 214 | {
|
---|
| 215 | PCIDevice dev;
|
---|
[37444] | 216 | /** Critical section protecting the ACPI state. */
|
---|
| 217 | PDMCRITSECT CritSect;
|
---|
| 218 |
|
---|
[1] | 219 | uint16_t pm1a_en;
|
---|
| 220 | uint16_t pm1a_sts;
|
---|
| 221 | uint16_t pm1a_ctl;
|
---|
[12428] | 222 | /** Number of logical CPUs in guest */
|
---|
| 223 | uint16_t cCpus;
|
---|
[37237] | 224 | uint64_t u64PmTimerInitial;
|
---|
[37444] | 225 | PTMTIMERR3 pPmTimerR3;
|
---|
| 226 | PTMTIMERR0 pPmTimerR0;
|
---|
| 227 | PTMTIMERRC pPmTimerRC;
|
---|
[1] | 228 |
|
---|
| 229 | uint32_t gpe0_en;
|
---|
| 230 | uint32_t gpe0_sts;
|
---|
| 231 |
|
---|
[40019] | 232 | uint32_t uBatteryIndex;
|
---|
[1] | 233 | uint32_t au8BatteryInfo[13];
|
---|
| 234 |
|
---|
[40019] | 235 | uint32_t uSystemInfoIndex;
|
---|
[1] | 236 | uint64_t u64RamSize;
|
---|
[17590] | 237 | /** The number of bytes above 4GB. */
|
---|
| 238 | uint64_t cbRamHigh;
|
---|
| 239 | /** The number of bytes below 4GB. */
|
---|
| 240 | uint32_t cbRamLow;
|
---|
[1] | 241 |
|
---|
[32189] | 242 | /** Current ACPI S* state. We support S0 and S5. */
|
---|
[1] | 243 | uint32_t uSleepState;
|
---|
| 244 | uint8_t au8RSDPPage[0x1000];
|
---|
[4279] | 245 | /** This is a workaround for incorrect index field handling by Intels ACPICA.
|
---|
| 246 | * The system info _INI method writes to offset 0x200. We either observe a
|
---|
| 247 | * write request to index 0x80 (in that case we don't change the index) or a
|
---|
| 248 | * write request to offset 0x200 (in that case we divide the index value by
|
---|
| 249 | * 4. Note that the _STA method is sometimes called prior to the _INI method
|
---|
| 250 | * (ACPI spec 6.3.7, _STA). See the special case for BAT_DEVICE_STATUS in
|
---|
| 251 | * acpiBatIndexWrite() for handling this. */
|
---|
[1] | 252 | uint8_t u8IndexShift;
|
---|
[16247] | 253 | /** provide an I/O-APIC */
|
---|
[1] | 254 | uint8_t u8UseIOApic;
|
---|
[16247] | 255 | /** provide a floppy controller */
|
---|
| 256 | bool fUseFdc;
|
---|
[16211] | 257 | /** If High Precision Event Timer device should be supported */
|
---|
[16247] | 258 | bool fUseHpet;
|
---|
[16211] | 259 | /** If System Management Controller device should be supported */
|
---|
[16247] | 260 | bool fUseSmc;
|
---|
| 261 | /** the guest handled the last power button event */
|
---|
[6852] | 262 | bool fPowerButtonHandled;
|
---|
[16711] | 263 | /** If ACPI CPU device should be shown */
|
---|
| 264 | bool fShowCpu;
|
---|
[19007] | 265 | /** If Real Time Clock ACPI object to be shown */
|
---|
| 266 | bool fShowRtc;
|
---|
[21820] | 267 | /** I/O port address of PM device. */
|
---|
| 268 | RTIOPORT uPmIoPortBase;
|
---|
| 269 | /** Flag whether the GC part of the device is enabled. */
|
---|
| 270 | bool fGCEnabled;
|
---|
| 271 | /** Flag whether the R0 part of the device is enabled. */
|
---|
| 272 | bool fR0Enabled;
|
---|
[25817] | 273 | /** Array of flags of attached CPUs */
|
---|
[25838] | 274 | VMCPUSET CpuSetAttached;
|
---|
| 275 | /** Which CPU to check for the locked status. */
|
---|
| 276 | uint32_t idCpuLockCheck;
|
---|
[32189] | 277 | /** Mask of locked CPUs (used by the guest). */
|
---|
[25838] | 278 | VMCPUSET CpuSetLocked;
|
---|
[32189] | 279 | /** The CPU event type. */
|
---|
[26594] | 280 | uint32_t u32CpuEventType;
|
---|
[32189] | 281 | /** The CPU id affected. */
|
---|
[26594] | 282 | uint32_t u32CpuEvent;
|
---|
[32189] | 283 | /** Flag whether CPU hot plugging is enabled. */
|
---|
[25825] | 284 | bool fCpuHotPlug;
|
---|
[32591] | 285 | /** If MCFG ACPI table shown to the guest */
|
---|
| 286 | bool fUseMcfg;
|
---|
[32189] | 287 | /** Primary NIC PCI address. */
|
---|
[31519] | 288 | uint32_t u32NicPciAddress;
|
---|
[32189] | 289 | /** Primary audio card PCI address. */
|
---|
[31519] | 290 | uint32_t u32AudioPciAddress;
|
---|
[32189] | 291 | /** Flag whether S1 power state is enabled. */
|
---|
[31963] | 292 | bool fS1Enabled;
|
---|
[32189] | 293 | /** Flag whether S4 power state is enabled. */
|
---|
[31963] | 294 | bool fS4Enabled;
|
---|
[32189] | 295 | /** Flag whether S1 triggers a state save. */
|
---|
| 296 | bool fSuspendToSavedState;
|
---|
| 297 | /** Flag whether to set WAK_STS on resume (restore included). */
|
---|
| 298 | bool fSetWakeupOnResume;
|
---|
[32471] | 299 | /** PCI address of the IO controller device. */
|
---|
| 300 | uint32_t u32IocPciAddress;
|
---|
[32477] | 301 | /** PCI address of the host bus controller device. */
|
---|
| 302 | uint32_t u32HbcPciAddress;
|
---|
[32591] | 303 | /* Physical address of PCI config space MMIO region */
|
---|
| 304 | uint64_t u64PciConfigMMioAddress;
|
---|
[32637] | 305 | /* Length of PCI config space MMIO region */
|
---|
| 306 | uint64_t u64PciConfigMMioLength;
|
---|
[35746] | 307 | /** Serial 0 IRQ number */
|
---|
| 308 | uint8_t uSerial0Irq;
|
---|
| 309 | /** Serial 1 IRQ number */
|
---|
| 310 | uint8_t uSerial1Irq;
|
---|
| 311 | /** Serial 0 IO port base */
|
---|
| 312 | RTIOPORT uSerial0IoPortBase;
|
---|
| 313 | /** Serial 1 IO port base */
|
---|
| 314 | RTIOPORT uSerial1IoPortBase;
|
---|
[1] | 315 | /** ACPI port base interface. */
|
---|
| 316 | PDMIBASE IBase;
|
---|
| 317 | /** ACPI port interface. */
|
---|
| 318 | PDMIACPIPORT IACPIPort;
|
---|
| 319 | /** Pointer to the device instance. */
|
---|
[491] | 320 | PPDMDEVINSR3 pDevIns;
|
---|
[32189] | 321 | /** Pointer to the driver base interface. */
|
---|
[491] | 322 | R3PTRTYPE(PPDMIBASE) pDrvBase;
|
---|
[32189] | 323 | /** Pointer to the driver connector interface. */
|
---|
[491] | 324 | R3PTRTYPE(PPDMIACPICONNECTOR) pDrv;
|
---|
[21829] | 325 |
|
---|
[32189] | 326 | /** Pointer to default PCI config read function. */
|
---|
[21820] | 327 | R3PTRTYPE(PFNPCICONFIGREAD) pfnAcpiPciConfigRead;
|
---|
[32189] | 328 | /** Pointer to default PCI config write function. */
|
---|
[21820] | 329 | R3PTRTYPE(PFNPCICONFIGWRITE) pfnAcpiPciConfigWrite;
|
---|
[40019] | 330 |
|
---|
| 331 | /** If custom table should be supported */
|
---|
| 332 | bool fUseCust;
|
---|
| 333 | /** ACPI OEM ID */
|
---|
| 334 | uint8_t au8OemId[6];
|
---|
| 335 | /** ACPI Crator ID */
|
---|
| 336 | uint8_t au8CreatorId[4];
|
---|
| 337 | /** ACPI Crator Rev */
|
---|
| 338 | uint32_t u32CreatorRev;
|
---|
| 339 | /** ACPI custom OEM Tab ID */
|
---|
| 340 | uint8_t au8OemTabId[8];
|
---|
| 341 | /** ACPI custom OEM Rev */
|
---|
| 342 | uint32_t u32OemRevision;
|
---|
| 343 | uint32_t Alignment0;
|
---|
| 344 |
|
---|
| 345 | /** The custom table binary data. */
|
---|
| 346 | R3PTRTYPE(uint8_t *) pu8CustBin;
|
---|
| 347 | /** The size of the custom table binary. */
|
---|
| 348 | uint64_t cbCustBin;
|
---|
[17572] | 349 | } ACPIState;
|
---|
[1] | 350 |
|
---|
| 351 | #pragma pack(1)
|
---|
| 352 |
|
---|
| 353 | /** Generic Address Structure (see ACPIspec 3.0, 5.2.3.1) */
|
---|
| 354 | struct ACPIGENADDR
|
---|
| 355 | {
|
---|
| 356 | uint8_t u8AddressSpaceId; /**< 0=sys, 1=IO, 2=PCICfg, 3=emb, 4=SMBus */
|
---|
| 357 | uint8_t u8RegisterBitWidth; /**< size in bits of the given register */
|
---|
| 358 | uint8_t u8RegisterBitOffset; /**< bit offset of register */
|
---|
| 359 | uint8_t u8AccessSize; /**< 1=byte, 2=word, 3=dword, 4=qword */
|
---|
| 360 | uint64_t u64Address; /**< 64-bit address of register */
|
---|
| 361 | };
|
---|
| 362 | AssertCompileSize(ACPIGENADDR, 12);
|
---|
| 363 |
|
---|
| 364 | /** Root System Description Pointer */
|
---|
| 365 | struct ACPITBLRSDP
|
---|
| 366 | {
|
---|
| 367 | uint8_t au8Signature[8]; /**< 'RSD PTR ' */
|
---|
| 368 | uint8_t u8Checksum; /**< checksum for the first 20 bytes */
|
---|
| 369 | uint8_t au8OemId[6]; /**< OEM-supplied identifier */
|
---|
| 370 | uint8_t u8Revision; /**< revision number, currently 2 */
|
---|
| 371 | #define ACPI_REVISION 2 /**< ACPI 3.0 */
|
---|
| 372 | uint32_t u32RSDT; /**< phys addr of RSDT */
|
---|
| 373 | uint32_t u32Length; /**< bytes of this table */
|
---|
| 374 | uint64_t u64XSDT; /**< 64-bit phys addr of XSDT */
|
---|
| 375 | uint8_t u8ExtChecksum; /**< checksum of entire table */
|
---|
| 376 | uint8_t u8Reserved[3]; /**< reserved */
|
---|
| 377 | };
|
---|
| 378 | AssertCompileSize(ACPITBLRSDP, 36);
|
---|
| 379 |
|
---|
| 380 | /** System Description Table Header */
|
---|
| 381 | struct ACPITBLHEADER
|
---|
| 382 | {
|
---|
| 383 | uint8_t au8Signature[4]; /**< table identifier */
|
---|
| 384 | uint32_t u32Length; /**< length of the table including header */
|
---|
| 385 | uint8_t u8Revision; /**< revision number */
|
---|
| 386 | uint8_t u8Checksum; /**< all fields inclusive this add to zero */
|
---|
| 387 | uint8_t au8OemId[6]; /**< OEM-supplied string */
|
---|
| 388 | uint8_t au8OemTabId[8]; /**< to identify the particular data table */
|
---|
| 389 | uint32_t u32OemRevision; /**< OEM-supplied revision number */
|
---|
| 390 | uint8_t au8CreatorId[4]; /**< ID for the ASL compiler */
|
---|
| 391 | uint32_t u32CreatorRev; /**< revision for the ASL compiler */
|
---|
| 392 | };
|
---|
| 393 | AssertCompileSize(ACPITBLHEADER, 36);
|
---|
| 394 |
|
---|
| 395 | /** Root System Description Table */
|
---|
| 396 | struct ACPITBLRSDT
|
---|
| 397 | {
|
---|
| 398 | ACPITBLHEADER header;
|
---|
| 399 | uint32_t u32Entry[1]; /**< array of phys. addresses to other tables */
|
---|
| 400 | };
|
---|
| 401 | AssertCompileSize(ACPITBLRSDT, 40);
|
---|
| 402 |
|
---|
| 403 | /** Extended System Description Table */
|
---|
| 404 | struct ACPITBLXSDT
|
---|
| 405 | {
|
---|
| 406 | ACPITBLHEADER header;
|
---|
| 407 | uint64_t u64Entry[1]; /**< array of phys. addresses to other tables */
|
---|
| 408 | };
|
---|
| 409 | AssertCompileSize(ACPITBLXSDT, 44);
|
---|
| 410 |
|
---|
| 411 | /** Fixed ACPI Description Table */
|
---|
| 412 | struct ACPITBLFADT
|
---|
| 413 | {
|
---|
| 414 | ACPITBLHEADER header;
|
---|
| 415 | uint32_t u32FACS; /**< phys. address of FACS */
|
---|
| 416 | uint32_t u32DSDT; /**< phys. address of DSDT */
|
---|
| 417 | uint8_t u8IntModel; /**< was eleminated in ACPI 2.0 */
|
---|
| 418 | #define INT_MODEL_DUAL_PIC 1 /**< for ACPI 2+ */
|
---|
| 419 | #define INT_MODEL_MULTIPLE_APIC 2
|
---|
| 420 | uint8_t u8PreferredPMProfile; /**< preferred power management profile */
|
---|
| 421 | uint16_t u16SCIInt; /**< system vector the SCI is wired in 8259 mode */
|
---|
| 422 | #define SCI_INT 9
|
---|
| 423 | uint32_t u32SMICmd; /**< system port address of SMI command port */
|
---|
| 424 | #define SMI_CMD 0x0000442e
|
---|
[33540] | 425 | uint8_t u8AcpiEnable; /**< SMICmd val to disable ownership of ACPIregs */
|
---|
[1] | 426 | #define ACPI_ENABLE 0xa1
|
---|
[33540] | 427 | uint8_t u8AcpiDisable; /**< SMICmd val to re-enable ownership of ACPIregs */
|
---|
[1] | 428 | #define ACPI_DISABLE 0xa0
|
---|
| 429 | uint8_t u8S4BIOSReq; /**< SMICmd val to enter S4BIOS state */
|
---|
| 430 | uint8_t u8PStateCnt; /**< SMICmd val to assume processor performance
|
---|
| 431 | state control responsibility */
|
---|
| 432 | uint32_t u32PM1aEVTBLK; /**< port addr of PM1a event regs block */
|
---|
| 433 | uint32_t u32PM1bEVTBLK; /**< port addr of PM1b event regs block */
|
---|
| 434 | uint32_t u32PM1aCTLBLK; /**< port addr of PM1a control regs block */
|
---|
| 435 | uint32_t u32PM1bCTLBLK; /**< port addr of PM1b control regs block */
|
---|
| 436 | uint32_t u32PM2CTLBLK; /**< port addr of PM2 control regs block */
|
---|
| 437 | uint32_t u32PMTMRBLK; /**< port addr of PMTMR regs block */
|
---|
| 438 | uint32_t u32GPE0BLK; /**< port addr of gen-purp event 0 regs block */
|
---|
| 439 | uint32_t u32GPE1BLK; /**< port addr of gen-purp event 1 regs block */
|
---|
| 440 | uint8_t u8PM1EVTLEN; /**< bytes decoded by PM1a_EVT_BLK. >= 4 */
|
---|
| 441 | uint8_t u8PM1CTLLEN; /**< bytes decoded by PM1b_CNT_BLK. >= 2 */
|
---|
| 442 | uint8_t u8PM2CTLLEN; /**< bytes decoded by PM2_CNT_BLK. >= 1 or 0 */
|
---|
| 443 | uint8_t u8PMTMLEN; /**< bytes decoded by PM_TMR_BLK. ==4 */
|
---|
| 444 | uint8_t u8GPE0BLKLEN; /**< bytes decoded by GPE0_BLK. %2==0 */
|
---|
| 445 | #define GPE0_BLK_LEN 2
|
---|
| 446 | uint8_t u8GPE1BLKLEN; /**< bytes decoded by GPE1_BLK. %2==0 */
|
---|
| 447 | #define GPE1_BLK_LEN 0
|
---|
| 448 | uint8_t u8GPE1BASE; /**< offset of GPE1 based events */
|
---|
| 449 | #define GPE1_BASE 0
|
---|
| 450 | uint8_t u8CSTCNT; /**< SMICmd val to indicate OS supp for C states */
|
---|
| 451 | uint16_t u16PLVL2LAT; /**< us to enter/exit C2. >100 => unsupported */
|
---|
| 452 | #define P_LVL2_LAT 101 /**< C2 state not supported */
|
---|
| 453 | uint16_t u16PLVL3LAT; /**< us to enter/exit C3. >1000 => unsupported */
|
---|
| 454 | #define P_LVL3_LAT 1001 /**< C3 state not supported */
|
---|
| 455 | uint16_t u16FlushSize; /**< # of flush strides to read to flush dirty
|
---|
| 456 | lines from any processors memory caches */
|
---|
| 457 | #define FLUSH_SIZE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
|
---|
| 458 | uint16_t u16FlushStride; /**< cache line width */
|
---|
| 459 | #define FLUSH_STRIDE 0 /**< Ignored if WBVIND set in FADT_FLAGS */
|
---|
| 460 | uint8_t u8DutyOffset;
|
---|
| 461 | uint8_t u8DutyWidth;
|
---|
| 462 | uint8_t u8DayAlarm; /**< RTC CMOS RAM index of day-of-month alarm */
|
---|
| 463 | uint8_t u8MonAlarm; /**< RTC CMOS RAM index of month-of-year alarm */
|
---|
| 464 | uint8_t u8Century; /**< RTC CMOS RAM index of century */
|
---|
| 465 | uint16_t u16IAPCBOOTARCH; /**< IA-PC boot architecture flags */
|
---|
[5605] | 466 | #define IAPC_BOOT_ARCH_LEGACY_DEV RT_BIT(0) /**< legacy devices present such as LPT
|
---|
[1] | 467 | (COM too?) */
|
---|
[5605] | 468 | #define IAPC_BOOT_ARCH_8042 RT_BIT(1) /**< legacy keyboard device present */
|
---|
| 469 | #define IAPC_BOOT_ARCH_NO_VGA RT_BIT(2) /**< VGA not present */
|
---|
[26057] | 470 | uint8_t u8Must0_0; /**< must be 0 */
|
---|
| 471 | uint32_t u32Flags; /**< fixed feature flags */
|
---|
[5605] | 472 | #define FADT_FL_WBINVD RT_BIT(0) /**< emulation of WBINVD available */
|
---|
| 473 | #define FADT_FL_WBINVD_FLUSH RT_BIT(1)
|
---|
| 474 | #define FADT_FL_PROC_C1 RT_BIT(2) /**< 1=C1 supported on all processors */
|
---|
| 475 | #define FADT_FL_P_LVL2_UP RT_BIT(3) /**< 1=C2 works on SMP and UNI systems */
|
---|
| 476 | #define FADT_FL_PWR_BUTTON RT_BIT(4) /**< 1=power button handled as ctrl method dev */
|
---|
| 477 | #define FADT_FL_SLP_BUTTON RT_BIT(5) /**< 1=sleep button handled as ctrl method dev */
|
---|
| 478 | #define FADT_FL_FIX_RTC RT_BIT(6) /**< 0=RTC wake status in fixed register */
|
---|
| 479 | #define FADT_FL_RTC_S4 RT_BIT(7) /**< 1=RTC can wake system from S4 */
|
---|
| 480 | #define FADT_FL_TMR_VAL_EXT RT_BIT(8) /**< 1=TMR_VAL implemented as 32 bit */
|
---|
| 481 | #define FADT_FL_DCK_CAP RT_BIT(9) /**< 0=system cannot support docking */
|
---|
| 482 | #define FADT_FL_RESET_REG_SUP RT_BIT(10) /**< 1=system supports system resets */
|
---|
| 483 | #define FADT_FL_SEALED_CASE RT_BIT(11) /**< 1=case is sealed */
|
---|
| 484 | #define FADT_FL_HEADLESS RT_BIT(12) /**< 1=system cannot detect moni/keyb/mouse */
|
---|
| 485 | #define FADT_FL_CPU_SW_SLP RT_BIT(13)
|
---|
| 486 | #define FADT_FL_PCI_EXT_WAK RT_BIT(14) /**< 1=system supports PCIEXP_WAKE_STS */
|
---|
| 487 | #define FADT_FL_USE_PLATFORM_CLOCK RT_BIT(15) /**< 1=system has ACPI PM timer */
|
---|
| 488 | #define FADT_FL_S4_RTC_STS_VALID RT_BIT(16) /**< 1=RTC_STS flag is valid when waking from S4 */
|
---|
| 489 | #define FADT_FL_REMOVE_POWER_ON_CAPABLE RT_BIT(17) /**< 1=platform can remote power on */
|
---|
| 490 | #define FADT_FL_FORCE_APIC_CLUSTER_MODEL RT_BIT(18)
|
---|
| 491 | #define FADT_FL_FORCE_APIC_PHYS_DEST_MODE RT_BIT(19)
|
---|
[21334] | 492 |
|
---|
| 493 | /** Start of the ACPI 2.0 extension. */
|
---|
[1] | 494 | ACPIGENADDR ResetReg; /**< ext addr of reset register */
|
---|
| 495 | uint8_t u8ResetVal; /**< ResetReg value to reset the system */
|
---|
| 496 | #define ACPI_RESET_REG_VAL 0x10
|
---|
| 497 | uint8_t au8Must0_1[3]; /**< must be 0 */
|
---|
| 498 | uint64_t u64XFACS; /**< 64-bit phys address of FACS */
|
---|
| 499 | uint64_t u64XDSDT; /**< 64-bit phys address of DSDT */
|
---|
| 500 | ACPIGENADDR X_PM1aEVTBLK; /**< ext addr of PM1a event regs block */
|
---|
| 501 | ACPIGENADDR X_PM1bEVTBLK; /**< ext addr of PM1b event regs block */
|
---|
| 502 | ACPIGENADDR X_PM1aCTLBLK; /**< ext addr of PM1a control regs block */
|
---|
| 503 | ACPIGENADDR X_PM1bCTLBLK; /**< ext addr of PM1b control regs block */
|
---|
| 504 | ACPIGENADDR X_PM2CTLBLK; /**< ext addr of PM2 control regs block */
|
---|
| 505 | ACPIGENADDR X_PMTMRBLK; /**< ext addr of PMTMR control regs block */
|
---|
| 506 | ACPIGENADDR X_GPE0BLK; /**< ext addr of GPE1 regs block */
|
---|
| 507 | ACPIGENADDR X_GPE1BLK; /**< ext addr of GPE1 regs block */
|
---|
| 508 | };
|
---|
| 509 | AssertCompileSize(ACPITBLFADT, 244);
|
---|
[21334] | 510 | #define ACPITBLFADT_VERSION1_SIZE RT_OFFSETOF(ACPITBLFADT, ResetReg)
|
---|
[1] | 511 |
|
---|
| 512 | /** Firmware ACPI Control Structure */
|
---|
| 513 | struct ACPITBLFACS
|
---|
| 514 | {
|
---|
| 515 | uint8_t au8Signature[4]; /**< 'FACS' */
|
---|
| 516 | uint32_t u32Length; /**< bytes of entire FACS structure >= 64 */
|
---|
| 517 | uint32_t u32HWSignature; /**< systems HW signature at last boot */
|
---|
| 518 | uint32_t u32FWVector; /**< address of waking vector */
|
---|
| 519 | uint32_t u32GlobalLock; /**< global lock to sync HW/SW */
|
---|
| 520 | uint32_t u32Flags; /**< FACS flags */
|
---|
| 521 | uint64_t u64X_FWVector; /**< 64-bit waking vector */
|
---|
| 522 | uint8_t u8Version; /**< version of this table */
|
---|
| 523 | uint8_t au8Reserved[31]; /**< zero */
|
---|
| 524 | };
|
---|
| 525 | AssertCompileSize(ACPITBLFACS, 64);
|
---|
| 526 |
|
---|
| 527 | /** Processor Local APIC Structure */
|
---|
| 528 | struct ACPITBLLAPIC
|
---|
| 529 | {
|
---|
| 530 | uint8_t u8Type; /**< 0 = LAPIC */
|
---|
| 531 | uint8_t u8Length; /**< 8 */
|
---|
| 532 | uint8_t u8ProcId; /**< processor ID */
|
---|
| 533 | uint8_t u8ApicId; /**< local APIC ID */
|
---|
| 534 | uint32_t u32Flags; /**< Flags */
|
---|
| 535 | #define LAPIC_ENABLED 0x1
|
---|
| 536 | };
|
---|
| 537 | AssertCompileSize(ACPITBLLAPIC, 8);
|
---|
| 538 |
|
---|
| 539 | /** I/O APIC Structure */
|
---|
| 540 | struct ACPITBLIOAPIC
|
---|
| 541 | {
|
---|
| 542 | uint8_t u8Type; /**< 1 == I/O APIC */
|
---|
| 543 | uint8_t u8Length; /**< 12 */
|
---|
| 544 | uint8_t u8IOApicId; /**< I/O APIC ID */
|
---|
| 545 | uint8_t u8Reserved; /**< 0 */
|
---|
| 546 | uint32_t u32Address; /**< phys address to access I/O APIC */
|
---|
| 547 | uint32_t u32GSIB; /**< global system interrupt number to start */
|
---|
| 548 | };
|
---|
| 549 | AssertCompileSize(ACPITBLIOAPIC, 12);
|
---|
| 550 |
|
---|
[26939] | 551 | /** Interrupt Source Override Structure */
|
---|
| 552 | struct ACPITBLISO
|
---|
| 553 | {
|
---|
| 554 | uint8_t u8Type; /**< 2 == Interrupt Source Override*/
|
---|
| 555 | uint8_t u8Length; /**< 10 */
|
---|
| 556 | uint8_t u8Bus; /**< Bus */
|
---|
| 557 | uint8_t u8Source; /**< Bus-relative interrupt source (IRQ) */
|
---|
| 558 | uint32_t u32GSI; /**< Global System Interrupt */
|
---|
| 559 | uint16_t u16Flags; /**< MPS INTI flags Global */
|
---|
| 560 | };
|
---|
| 561 | AssertCompileSize(ACPITBLISO, 10);
|
---|
[34035] | 562 | #define NUMBER_OF_IRQ_SOURCE_OVERRIDES 2
|
---|
[25928] | 563 |
|
---|
[26057] | 564 | /** HPET Descriptor Structure */
|
---|
[25928] | 565 | struct ACPITBLHPET
|
---|
| 566 | {
|
---|
| 567 | ACPITBLHEADER aHeader;
|
---|
[26057] | 568 | uint32_t u32Id; /**< hardware ID of event timer block
|
---|
| 569 | [31:16] PCI vendor ID of first timer block
|
---|
| 570 | [15] legacy replacement IRQ routing capable
|
---|
| 571 | [14] reserved
|
---|
| 572 | [13] COUNT_SIZE_CAP counter size
|
---|
[26157] | 573 | [12:8] number of comparators in first timer block
|
---|
[26057] | 574 | [7:0] hardware rev ID */
|
---|
| 575 | ACPIGENADDR HpetAddr; /**< lower 32-bit base address */
|
---|
| 576 | uint8_t u32Number; /**< sequence number starting at 0 */
|
---|
| 577 | uint16_t u32MinTick; /**< minimum clock ticks which can be set without
|
---|
| 578 | lost interrupts while the counter is programmed
|
---|
| 579 | to operate in periodic mode. Unit: clock tick. */
|
---|
[33540] | 580 | uint8_t u8Attributes; /**< page protection and OEM attribute. */
|
---|
[25928] | 581 | };
|
---|
[26057] | 582 | AssertCompileSize(ACPITBLHPET, 56);
|
---|
[25928] | 583 |
|
---|
[32591] | 584 | /** MCFG Descriptor Structure */
|
---|
[32825] | 585 | typedef struct ACPITBLMCFG
|
---|
[32591] | 586 | {
|
---|
| 587 | ACPITBLHEADER aHeader;
|
---|
| 588 | uint64_t u64Reserved;
|
---|
[32825] | 589 | } ACPITBLMCFG;
|
---|
[32591] | 590 | AssertCompileSize(ACPITBLMCFG, 44);
|
---|
| 591 |
|
---|
[32825] | 592 | /** Number of such entries can be computed from the whole table length in header */
|
---|
| 593 | typedef struct ACPITBLMCFGENTRY
|
---|
[32591] | 594 | {
|
---|
| 595 | uint64_t u64BaseAddress;
|
---|
| 596 | uint16_t u16PciSegmentGroup;
|
---|
| 597 | uint8_t u8StartBus;
|
---|
| 598 | uint8_t u8EndBus;
|
---|
| 599 | uint32_t u32Reserved;
|
---|
[32825] | 600 | } ACPITBLMCFGENTRY;
|
---|
[32591] | 601 | AssertCompileSize(ACPITBLMCFGENTRY, 16);
|
---|
| 602 |
|
---|
[21829] | 603 | # ifdef IN_RING3 /** @todo r=bird: Move this down to where it's used. */
|
---|
[12428] | 604 |
|
---|
[17572] | 605 | # define PCAT_COMPAT 0x1 /**< system has also a dual-8259 setup */
|
---|
[12428] | 606 |
|
---|
[40019] | 607 | /** Custom Description Table */
|
---|
| 608 | struct ACPITBLCUST
|
---|
| 609 | {
|
---|
| 610 | ACPITBLHEADER header;
|
---|
| 611 | uint8_t au8Data[476];
|
---|
| 612 | };
|
---|
| 613 | AssertCompileSize(ACPITBLCUST, 512);
|
---|
| 614 |
|
---|
[12431] | 615 | /**
|
---|
| 616 | * Multiple APIC Description Table.
|
---|
| 617 | *
|
---|
[12428] | 618 | * This structure looks somewhat convoluted due layout of MADT table in MP case.
|
---|
[12431] | 619 | * There extpected to be multiple LAPIC records for each CPU, thus we cannot
|
---|
[12428] | 620 | * use regular C structure and proxy to raw memory instead.
|
---|
| 621 | */
|
---|
[12431] | 622 | class AcpiTableMADT
|
---|
[12428] | 623 | {
|
---|
[12431] | 624 | /**
|
---|
[12428] | 625 | * All actual data stored in dynamically allocated memory pointed by this field.
|
---|
| 626 | */
|
---|
[17572] | 627 | uint8_t *m_pbData;
|
---|
[12431] | 628 | /**
|
---|
[12428] | 629 | * Number of CPU entries in this MADT.
|
---|
| 630 | */
|
---|
[17572] | 631 | uint32_t m_cCpus;
|
---|
[12431] | 632 |
|
---|
[26939] | 633 | /**
|
---|
| 634 | * Number of interrupt overrides.
|
---|
| 635 | */
|
---|
| 636 | uint32_t m_cIsos;
|
---|
| 637 |
|
---|
[17572] | 638 | public:
|
---|
[12431] | 639 | /**
|
---|
[12428] | 640 | * Address of ACPI header
|
---|
| 641 | */
|
---|
[17572] | 642 | inline ACPITBLHEADER *header_addr(void) const
|
---|
[12428] | 643 | {
|
---|
[17572] | 644 | return (ACPITBLHEADER *)m_pbData;
|
---|
[12428] | 645 | }
|
---|
[12431] | 646 |
|
---|
| 647 | /**
|
---|
[12428] | 648 | * Address of local APIC for each CPU. Note that different CPUs address different LAPICs,
|
---|
| 649 | * although address is the same for all of them.
|
---|
| 650 | */
|
---|
[17572] | 651 | inline uint32_t *u32LAPIC_addr(void) const
|
---|
[12428] | 652 | {
|
---|
[17572] | 653 | return (uint32_t *)(header_addr() + 1);
|
---|
[12428] | 654 | }
|
---|
[12431] | 655 |
|
---|
| 656 | /**
|
---|
[12428] | 657 | * Address of APIC flags
|
---|
| 658 | */
|
---|
[17572] | 659 | inline uint32_t *u32Flags_addr(void) const
|
---|
[12428] | 660 | {
|
---|
[17572] | 661 | return (uint32_t *)(u32LAPIC_addr() + 1);
|
---|
[12428] | 662 | }
|
---|
[12431] | 663 |
|
---|
| 664 | /**
|
---|
[26939] | 665 | * Address of ISO description
|
---|
| 666 | */
|
---|
| 667 | inline ACPITBLISO *ISO_addr(void) const
|
---|
| 668 | {
|
---|
| 669 | return (ACPITBLISO *)(u32Flags_addr() + 1);
|
---|
| 670 | }
|
---|
| 671 |
|
---|
| 672 | /**
|
---|
[12428] | 673 | * Address of per-CPU LAPIC descriptions
|
---|
| 674 | */
|
---|
[17572] | 675 | inline ACPITBLLAPIC *LApics_addr(void) const
|
---|
[12428] | 676 | {
|
---|
[26939] | 677 | return (ACPITBLLAPIC *)(ISO_addr() + m_cIsos);
|
---|
[12428] | 678 | }
|
---|
| 679 |
|
---|
[12431] | 680 | /**
|
---|
[12428] | 681 | * Address of IO APIC description
|
---|
| 682 | */
|
---|
[17572] | 683 | inline ACPITBLIOAPIC *IOApic_addr(void) const
|
---|
[12428] | 684 | {
|
---|
[17572] | 685 | return (ACPITBLIOAPIC *)(LApics_addr() + m_cCpus);
|
---|
[12428] | 686 | }
|
---|
| 687 |
|
---|
[12431] | 688 | /**
|
---|
[12428] | 689 | * Size of MADT.
|
---|
| 690 | * Note that this function assumes IOApic to be the last field in structure.
|
---|
| 691 | */
|
---|
[17572] | 692 | inline uint32_t size(void) const
|
---|
[12428] | 693 | {
|
---|
[17572] | 694 | return (uint8_t *)(IOApic_addr() + 1) - (uint8_t *)header_addr();
|
---|
[12428] | 695 | }
|
---|
| 696 |
|
---|
[12431] | 697 | /**
|
---|
[12428] | 698 | * Raw data of MADT.
|
---|
| 699 | */
|
---|
[17572] | 700 | inline const uint8_t *data(void) const
|
---|
[12428] | 701 | {
|
---|
[17572] | 702 | return m_pbData;
|
---|
[12428] | 703 | }
|
---|
| 704 |
|
---|
[12431] | 705 | /**
|
---|
[12428] | 706 | * Size of MADT for given ACPI config, useful to compute layout.
|
---|
| 707 | */
|
---|
[37446] | 708 | static uint32_t sizeFor(ACPIState *pThis, uint32_t cIsos)
|
---|
[12428] | 709 | {
|
---|
[37446] | 710 | return AcpiTableMADT(pThis->cCpus, cIsos).size();
|
---|
[12428] | 711 | }
|
---|
| 712 |
|
---|
| 713 | /*
|
---|
| 714 | * Constructor, only works in Ring 3, doesn't look like a big deal.
|
---|
| 715 | */
|
---|
[26939] | 716 | AcpiTableMADT(uint32_t cCpus, uint32_t cIsos)
|
---|
[12428] | 717 | {
|
---|
[24669] | 718 | m_cCpus = cCpus;
|
---|
[26939] | 719 | m_cIsos = cIsos;
|
---|
[33540] | 720 | m_pbData = NULL; /* size() uses this and gcc will complain if not initialized. */
|
---|
[17572] | 721 | uint32_t cb = size();
|
---|
| 722 | m_pbData = (uint8_t *)RTMemAllocZ(cb);
|
---|
[12428] | 723 | }
|
---|
| 724 |
|
---|
[12431] | 725 | ~AcpiTableMADT()
|
---|
[12428] | 726 | {
|
---|
[17572] | 727 | RTMemFree(m_pbData);
|
---|
[12428] | 728 | }
|
---|
| 729 | };
|
---|
[17572] | 730 | # endif /* IN_RING3 */
|
---|
[12431] | 731 |
|
---|
[1] | 732 | #pragma pack()
|
---|
| 733 |
|
---|
[491] | 734 |
|
---|
[17572] | 735 | #ifndef VBOX_DEVICE_STRUCT_TESTCASE /* exclude the rest of the file */
|
---|
| 736 | /*******************************************************************************
|
---|
| 737 | * Internal Functions *
|
---|
| 738 | *******************************************************************************/
|
---|
[20374] | 739 | RT_C_DECLS_BEGIN
|
---|
[37444] | 740 | PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
|
---|
| 741 | RT_C_DECLS_END
|
---|
[1] | 742 | #ifdef IN_RING3
|
---|
[37446] | 743 | static int acpiPlantTables(ACPIState *pThis);
|
---|
[37444] | 744 | #endif
|
---|
[1] | 745 |
|
---|
| 746 | #ifdef IN_RING3
|
---|
| 747 |
|
---|
| 748 | /* SCI IRQ */
|
---|
[37446] | 749 | DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
|
---|
[1] | 750 | {
|
---|
[37446] | 751 | if (pThis->pm1a_ctl & SCI_EN)
|
---|
| 752 | PDMDevHlpPCISetIrq(pThis->pDevIns, -1, level);
|
---|
[1] | 753 | }
|
---|
| 754 |
|
---|
[17572] | 755 | DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
|
---|
[1] | 756 | {
|
---|
| 757 | return en & ~(RSR_EN | IGN_EN);
|
---|
| 758 | }
|
---|
| 759 |
|
---|
[17572] | 760 | DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
|
---|
[1] | 761 | {
|
---|
| 762 | return sts & ~(RSR_STS | IGN_STS);
|
---|
| 763 | }
|
---|
| 764 |
|
---|
[37446] | 765 | DECLINLINE(int) pm1a_level(ACPIState *pThis)
|
---|
[1] | 766 | {
|
---|
[37446] | 767 | return (pm1a_pure_en(pThis->pm1a_en) & pm1a_pure_sts(pThis->pm1a_sts)) != 0;
|
---|
[1] | 768 | }
|
---|
| 769 |
|
---|
[37446] | 770 | DECLINLINE(int) gpe0_level(ACPIState *pThis)
|
---|
[1] | 771 | {
|
---|
[37446] | 772 | return (pThis->gpe0_en & pThis->gpe0_sts) != 0;
|
---|
[1] | 773 | }
|
---|
| 774 |
|
---|
[37444] | 775 | /**
|
---|
| 776 | * Used by acpiPM1aStsWrite, acpiPM1aEnWrite, acpiPmTimer,
|
---|
| 777 | * acpiPort_PowerBuffonPress and acpiPort_SleepButtonPress to
|
---|
| 778 | * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
|
---|
| 779 | *
|
---|
| 780 | * Caller must hold the state lock.
|
---|
| 781 | *
|
---|
| 782 | * @param pThis The ACPI instance.
|
---|
| 783 | * @param sts The new GPE0.STS value.
|
---|
| 784 | * @param en The new GPE0.EN value.
|
---|
| 785 | */
|
---|
| 786 | static void update_pm1a(ACPIState *pThis, uint32_t sts, uint32_t en)
|
---|
[1] | 787 | {
|
---|
[37444] | 788 | Assert(PDMCritSectIsOwner(&pThis->CritSect));
|
---|
[1] | 789 |
|
---|
[37444] | 790 | if (gpe0_level(pThis))
|
---|
[1] | 791 | return;
|
---|
| 792 |
|
---|
[37444] | 793 | int const old_level = pm1a_level(pThis);
|
---|
| 794 | int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
|
---|
[1] | 795 |
|
---|
[34035] | 796 | Log(("update_pm1a() old=%x new=%x\n", old_level, new_level));
|
---|
| 797 |
|
---|
[37444] | 798 | pThis->pm1a_en = en;
|
---|
| 799 | pThis->pm1a_sts = sts;
|
---|
[1] | 800 |
|
---|
| 801 | if (new_level != old_level)
|
---|
[37444] | 802 | acpiSetIrq(pThis, new_level);
|
---|
[1] | 803 | }
|
---|
| 804 |
|
---|
[37444] | 805 | /**
|
---|
| 806 | * Used by acpiGpe0StsWrite, acpiGpe0EnWrite, acpiAttach and acpiDetach to
|
---|
| 807 | * update the GPE0.STS and GPE0.EN registers and trigger IRQs.
|
---|
| 808 | *
|
---|
| 809 | * Caller must hold the state lock.
|
---|
| 810 | *
|
---|
| 811 | * @param pThis The ACPI instance.
|
---|
| 812 | * @param sts The new GPE0.STS value.
|
---|
| 813 | * @param en The new GPE0.EN value.
|
---|
| 814 | */
|
---|
| 815 | static void update_gpe0(ACPIState *pThis, uint32_t sts, uint32_t en)
|
---|
[1] | 816 | {
|
---|
[37444] | 817 | Assert(PDMCritSectIsOwner(&pThis->CritSect));
|
---|
[1] | 818 |
|
---|
[37444] | 819 | if (pm1a_level(pThis))
|
---|
[1] | 820 | return;
|
---|
| 821 |
|
---|
[37444] | 822 | int const old_level = (pThis->gpe0_en & pThis->gpe0_sts) != 0;
|
---|
| 823 | int const new_level = (en & sts) != 0;
|
---|
[1] | 824 |
|
---|
[37444] | 825 | pThis->gpe0_en = en;
|
---|
| 826 | pThis->gpe0_sts = sts;
|
---|
[1] | 827 |
|
---|
| 828 | if (new_level != old_level)
|
---|
[37444] | 829 | acpiSetIrq(pThis, new_level);
|
---|
[1] | 830 | }
|
---|
| 831 |
|
---|
[37444] | 832 | /**
|
---|
| 833 | * Used by acpiPM1aCtlWrite to power off the VM.
|
---|
| 834 | *
|
---|
| 835 | * @param pThis The ACPI instance.
|
---|
| 836 | * @returns Strict VBox status code.
|
---|
| 837 | */
|
---|
| 838 | static int acpiPowerOff(ACPIState *pThis)
|
---|
[1] | 839 | {
|
---|
[37444] | 840 | int rc = PDMDevHlpVMPowerOff(pThis->pDevIns);
|
---|
[17572] | 841 | if (RT_FAILURE(rc))
|
---|
| 842 | AssertMsgFailed(("Could not power down the VM. rc = %Rrc\n", rc));
|
---|
[1] | 843 | return rc;
|
---|
| 844 | }
|
---|
| 845 |
|
---|
[37444] | 846 | /**
|
---|
| 847 | * Used by acpiPM1aCtlWrite to put the VM to sleep.
|
---|
| 848 | *
|
---|
| 849 | * @param pThis The ACPI instance.
|
---|
| 850 | * @returns Strict VBox status code.
|
---|
| 851 | */
|
---|
[32189] | 852 | static int acpiSleep(ACPIState *pThis)
|
---|
[31963] | 853 | {
|
---|
[32189] | 854 | /* We must set WAK_STS on resume (includes restore) so the guest knows that
|
---|
| 855 | we've woken up and can continue executing code. The guest is probably
|
---|
| 856 | reading the PMSTS register in a loop to check this. */
|
---|
[37444] | 857 | int rc;
|
---|
[32189] | 858 | pThis->fSetWakeupOnResume = true;
|
---|
| 859 | if (pThis->fSuspendToSavedState)
|
---|
| 860 | {
|
---|
| 861 | rc = PDMDevHlpVMSuspendSaveAndPowerOff(pThis->pDevIns);
|
---|
[32190] | 862 | if (rc != VERR_NOT_SUPPORTED)
|
---|
| 863 | AssertRC(rc);
|
---|
| 864 | else
|
---|
| 865 | {
|
---|
| 866 | LogRel(("ACPI: PDMDevHlpVMSuspendSaveAndPowerOff is not supported, falling back to suspend-only\n"));
|
---|
| 867 | rc = PDMDevHlpVMSuspend(pThis->pDevIns);
|
---|
| 868 | AssertRC(rc);
|
---|
| 869 | }
|
---|
[31963] | 870 | }
|
---|
[32189] | 871 | else
|
---|
| 872 | {
|
---|
| 873 | rc = PDMDevHlpVMSuspend(pThis->pDevIns);
|
---|
| 874 | AssertRC(rc);
|
---|
| 875 | }
|
---|
[31963] | 876 | return rc;
|
---|
| 877 | }
|
---|
| 878 |
|
---|
[1] | 879 |
|
---|
| 880 | /**
|
---|
[37444] | 881 | * @interface_method_impl{PDMIACPIPORT,pfnPowerButtonPress}
|
---|
[1] | 882 | */
|
---|
[37444] | 883 | static DECLCALLBACK(int) acpiPort_PowerButtonPress(PPDMIACPIPORT pInterface)
|
---|
[1] | 884 | {
|
---|
[37444] | 885 | ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
|
---|
| 886 | DEVACPI_LOCK_R3(pThis);
|
---|
| 887 |
|
---|
| 888 | Log(("acpiPort_PowerButtonPress: handled=%d status=%x\n", pThis->fPowerButtonHandled, pThis->pm1a_sts));
|
---|
| 889 | pThis->fPowerButtonHandled = false;
|
---|
| 890 | update_pm1a(pThis, pThis->pm1a_sts | PWRBTN_STS, pThis->pm1a_en);
|
---|
| 891 |
|
---|
| 892 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 893 | return VINF_SUCCESS;
|
---|
| 894 | }
|
---|
| 895 |
|
---|
[13079] | 896 | /**
|
---|
[37444] | 897 | * @interface_method_impl{PDMIACPIPORT,pfnGetPowerButtonHandled}
|
---|
[13079] | 898 | */
|
---|
[37444] | 899 | static DECLCALLBACK(int) acpiPort_GetPowerButtonHandled(PPDMIACPIPORT pInterface, bool *pfHandled)
|
---|
[6852] | 900 | {
|
---|
[37444] | 901 | ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
|
---|
| 902 | DEVACPI_LOCK_R3(pThis);
|
---|
| 903 |
|
---|
| 904 | *pfHandled = pThis->fPowerButtonHandled;
|
---|
| 905 |
|
---|
| 906 | DEVACPI_UNLOCK(pThis);
|
---|
[6852] | 907 | return VINF_SUCCESS;
|
---|
| 908 | }
|
---|
| 909 |
|
---|
[6156] | 910 | /**
|
---|
[37444] | 911 | * @interface_method_impl{PDMIACPIPORT,pfnGetGuestEnteredACPIMode, Check if the
|
---|
| 912 | * Guest entered into G0 (working) or G1 (sleeping)}
|
---|
[13079] | 913 | */
|
---|
[37444] | 914 | static DECLCALLBACK(int) acpiPort_GetGuestEnteredACPIMode(PPDMIACPIPORT pInterface, bool *pfEntered)
|
---|
[13079] | 915 | {
|
---|
[37444] | 916 | ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
|
---|
| 917 | DEVACPI_LOCK_R3(pThis);
|
---|
| 918 |
|
---|
| 919 | *pfEntered = (pThis->pm1a_ctl & SCI_EN) != 0;
|
---|
| 920 |
|
---|
| 921 | DEVACPI_UNLOCK(pThis);
|
---|
[13079] | 922 | return VINF_SUCCESS;
|
---|
| 923 | }
|
---|
| 924 |
|
---|
[37444] | 925 | /**
|
---|
| 926 | * @interface_method_impl{PDMIACPIPORT,pfnGetCpuStatus}
|
---|
| 927 | */
|
---|
| 928 | static DECLCALLBACK(int) acpiPort_GetCpuStatus(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)
|
---|
[25817] | 929 | {
|
---|
[37444] | 930 | ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
|
---|
| 931 | DEVACPI_LOCK_R3(pThis);
|
---|
| 932 |
|
---|
| 933 | *pfLocked = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, uCpu);
|
---|
| 934 |
|
---|
| 935 | DEVACPI_UNLOCK(pThis);
|
---|
[25817] | 936 | return VINF_SUCCESS;
|
---|
| 937 | }
|
---|
| 938 |
|
---|
[13079] | 939 | /**
|
---|
[6156] | 940 | * Send an ACPI sleep button event.
|
---|
| 941 | *
|
---|
| 942 | * @returns VBox status code
|
---|
| 943 | * @param pInterface Pointer to the interface structure containing the called function pointer.
|
---|
| 944 | */
|
---|
[37444] | 945 | static DECLCALLBACK(int) acpiPort_SleepButtonPress(PPDMIACPIPORT pInterface)
|
---|
[6156] | 946 | {
|
---|
[37444] | 947 | ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IACPIPort);
|
---|
| 948 | DEVACPI_LOCK_R3(pThis);
|
---|
[6156] | 949 |
|
---|
[37444] | 950 | update_pm1a(pThis, pThis->pm1a_sts | SLPBTN_STS, pThis->pm1a_en);
|
---|
[1] | 951 |
|
---|
[37444] | 952 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 953 | return VINF_SUCCESS;
|
---|
| 954 | }
|
---|
| 955 |
|
---|
[37444] | 956 | /**
|
---|
| 957 | * Used by acpiPmTimer to re-arm the PM timer.
|
---|
| 958 | *
|
---|
| 959 | * The caller is expected to either hold the clock lock or to have made sure
|
---|
| 960 | * the VM is resetting or loading state.
|
---|
| 961 | *
|
---|
| 962 | * @param pThis The ACPI instance.
|
---|
| 963 | * @param uNow The current time.
|
---|
| 964 | */
|
---|
| 965 | static void acpiPmTimerReset(ACPIState *pThis, uint64_t uNow)
|
---|
[1] | 966 | {
|
---|
[37444] | 967 | uint64_t uTimerFreq = TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer));
|
---|
| 968 | uint64_t uInterval = ASMMultU64ByU32DivByU32(0xffffffff, uTimerFreq, PM_TMR_FREQ);
|
---|
| 969 | TMTimerSet(pThis->pPmTimerR3, uNow + uInterval);
|
---|
| 970 | Log(("acpi: uInterval = %RU64\n", uInterval));
|
---|
[1] | 971 | }
|
---|
| 972 |
|
---|
[37444] | 973 | /**
|
---|
| 974 | * @callback_method_impl{FNTMTIMERDEV, PM Timer callback}
|
---|
| 975 | */
|
---|
| 976 | static DECLCALLBACK(void) acpiPmTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
|
---|
[1] | 977 | {
|
---|
[37444] | 978 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
[39091] | 979 | Assert(TMTimerIsLockOwner(pTimer));
|
---|
| 980 | NOREF(pDevIns);
|
---|
[1] | 981 |
|
---|
[37444] | 982 | DEVACPI_LOCK_R3(pThis);
|
---|
[17572] | 983 | Log(("acpi: pm timer sts %#x (%d), en %#x (%d)\n",
|
---|
[37444] | 984 | pThis->pm1a_sts, (pThis->pm1a_sts & TMR_STS) != 0,
|
---|
| 985 | pThis->pm1a_en, (pThis->pm1a_en & TMR_EN) != 0));
|
---|
| 986 | update_pm1a(pThis, pThis->pm1a_sts | TMR_STS, pThis->pm1a_en);
|
---|
| 987 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 988 |
|
---|
[39091] | 989 | acpiPmTimerReset(pThis, TMTimerGet(pTimer));
|
---|
[1] | 990 | }
|
---|
| 991 |
|
---|
| 992 | /**
|
---|
[37444] | 993 | * _BST method - used by acpiBatDataRead to implement BAT_STATUS_STATE and
|
---|
| 994 | * acpiLoadState.
|
---|
| 995 | *
|
---|
| 996 | * @returns VINF_SUCCESS.
|
---|
| 997 | * @param pThis The ACPI instance.
|
---|
[1] | 998 | */
|
---|
[37444] | 999 | static int acpiFetchBatteryStatus(ACPIState *pThis)
|
---|
[1] | 1000 | {
|
---|
[37444] | 1001 | uint32_t *p = pThis->au8BatteryInfo;
|
---|
[1] | 1002 | bool fPresent; /* battery present? */
|
---|
| 1003 | PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
|
---|
| 1004 | PDMACPIBATSTATE hostBatteryState; /* bitfield */
|
---|
| 1005 | uint32_t hostPresentRate; /* 0..1000 */
|
---|
| 1006 | int rc;
|
---|
| 1007 |
|
---|
[37444] | 1008 | if (!pThis->pDrv)
|
---|
[21820] | 1009 | return VINF_SUCCESS;
|
---|
[37444] | 1010 | rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
|
---|
| 1011 | &hostBatteryState, &hostPresentRate);
|
---|
[17572] | 1012 | AssertRC(rc);
|
---|
[1] | 1013 |
|
---|
| 1014 | /* default values */
|
---|
| 1015 | p[BAT_STATUS_STATE] = hostBatteryState;
|
---|
| 1016 | p[BAT_STATUS_PRESENT_RATE] = hostPresentRate == ~0U ? 0xFFFFFFFF
|
---|
| 1017 | : hostPresentRate * 50; /* mW */
|
---|
| 1018 | p[BAT_STATUS_REMAINING_CAPACITY] = 50000; /* mWh */
|
---|
| 1019 | p[BAT_STATUS_PRESENT_VOLTAGE] = 10000; /* mV */
|
---|
| 1020 |
|
---|
| 1021 | /* did we get a valid battery state? */
|
---|
| 1022 | if (hostRemainingCapacity != PDM_ACPI_BAT_CAPACITY_UNKNOWN)
|
---|
| 1023 | p[BAT_STATUS_REMAINING_CAPACITY] = hostRemainingCapacity * 500; /* mWh */
|
---|
| 1024 | if (hostBatteryState == PDM_ACPI_BAT_STATE_CHARGED)
|
---|
| 1025 | p[BAT_STATUS_PRESENT_RATE] = 0; /* mV */
|
---|
[21820] | 1026 |
|
---|
| 1027 | return VINF_SUCCESS;
|
---|
[1] | 1028 | }
|
---|
| 1029 |
|
---|
| 1030 | /**
|
---|
[37444] | 1031 | * _BIF method - used by acpiBatDataRead to implement BAT_INFO_UNITS and
|
---|
| 1032 | * acpiLoadState.
|
---|
| 1033 | *
|
---|
| 1034 | * @returns VINF_SUCCESS.
|
---|
| 1035 | * @param pThis The ACPI instance.
|
---|
[1] | 1036 | */
|
---|
[37444] | 1037 | static int acpiFetchBatteryInfo(ACPIState *pThis)
|
---|
[1] | 1038 | {
|
---|
[37444] | 1039 | uint32_t *p = pThis->au8BatteryInfo;
|
---|
[1] | 1040 |
|
---|
| 1041 | p[BAT_INFO_UNITS] = 0; /* mWh */
|
---|
| 1042 | p[BAT_INFO_DESIGN_CAPACITY] = 50000; /* mWh */
|
---|
| 1043 | p[BAT_INFO_LAST_FULL_CHARGE_CAPACITY] = 50000; /* mWh */
|
---|
| 1044 | p[BAT_INFO_TECHNOLOGY] = BAT_TECH_PRIMARY;
|
---|
| 1045 | p[BAT_INFO_DESIGN_VOLTAGE] = 10000; /* mV */
|
---|
| 1046 | p[BAT_INFO_DESIGN_CAPACITY_OF_WARNING] = 100; /* mWh */
|
---|
| 1047 | p[BAT_INFO_DESIGN_CAPACITY_OF_LOW] = 50; /* mWh */
|
---|
| 1048 | p[BAT_INFO_CAPACITY_GRANULARITY_1] = 1; /* mWh */
|
---|
| 1049 | p[BAT_INFO_CAPACITY_GRANULARITY_2] = 1; /* mWh */
|
---|
[21820] | 1050 |
|
---|
| 1051 | return VINF_SUCCESS;
|
---|
[1] | 1052 | }
|
---|
| 1053 |
|
---|
| 1054 | /**
|
---|
[37444] | 1055 | * The _STA method - used by acpiBatDataRead to implement BAT_DEVICE_STATUS.
|
---|
| 1056 | *
|
---|
| 1057 | * @returns status mask or 0.
|
---|
| 1058 | * @param pThis The ACPI instance.
|
---|
[1] | 1059 | */
|
---|
[37444] | 1060 | static uint32_t acpiGetBatteryDeviceStatus(ACPIState *pThis)
|
---|
[1] | 1061 | {
|
---|
| 1062 | bool fPresent; /* battery present? */
|
---|
| 1063 | PDMACPIBATCAPACITY hostRemainingCapacity; /* 0..100 */
|
---|
| 1064 | PDMACPIBATSTATE hostBatteryState; /* bitfield */
|
---|
| 1065 | uint32_t hostPresentRate; /* 0..1000 */
|
---|
| 1066 | int rc;
|
---|
| 1067 |
|
---|
[37444] | 1068 | if (!pThis->pDrv)
|
---|
[4195] | 1069 | return 0;
|
---|
[37444] | 1070 | rc = pThis->pDrv->pfnQueryBatteryStatus(pThis->pDrv, &fPresent, &hostRemainingCapacity,
|
---|
| 1071 | &hostBatteryState, &hostPresentRate);
|
---|
[17572] | 1072 | AssertRC(rc);
|
---|
[1] | 1073 |
|
---|
| 1074 | return fPresent
|
---|
| 1075 | ? STA_DEVICE_PRESENT_MASK /* present */
|
---|
| 1076 | | STA_DEVICE_ENABLED_MASK /* enabled and decodes its resources */
|
---|
| 1077 | | STA_DEVICE_SHOW_IN_UI_MASK /* should be shown in UI */
|
---|
| 1078 | | STA_DEVICE_FUNCTIONING_PROPERLY_MASK /* functioning properly */
|
---|
| 1079 | | STA_BATTERY_PRESENT_MASK /* battery is present */
|
---|
| 1080 | : 0; /* device not present */
|
---|
| 1081 | }
|
---|
| 1082 |
|
---|
[37444] | 1083 | /**
|
---|
| 1084 | * Used by acpiBatDataRead to implement BAT_POWER_SOURCE.
|
---|
| 1085 | *
|
---|
| 1086 | * @returns status.
|
---|
| 1087 | * @param pThis The ACPI instance.
|
---|
| 1088 | */
|
---|
| 1089 | static uint32_t acpiGetPowerSource(ACPIState *pThis)
|
---|
[1] | 1090 | {
|
---|
| 1091 | /* query the current power source from the host driver */
|
---|
[37444] | 1092 | if (!pThis->pDrv)
|
---|
[4195] | 1093 | return AC_ONLINE;
|
---|
[37444] | 1094 |
|
---|
| 1095 | PDMACPIPOWERSOURCE ps;
|
---|
| 1096 | int rc = pThis->pDrv->pfnQueryPowerSource(pThis->pDrv, &ps);
|
---|
[17572] | 1097 | AssertRC(rc);
|
---|
[1] | 1098 | return ps == PDM_ACPI_POWER_SOURCE_BATTERY ? AC_OFFLINE : AC_ONLINE;
|
---|
| 1099 | }
|
---|
| 1100 |
|
---|
[37444] | 1101 | /**
|
---|
| 1102 | * @callback_method_impl{FNIOMIOPORTOUT, Battery status index}
|
---|
| 1103 | */
|
---|
[17572] | 1104 | PDMBOTHCBDECL(int) acpiBatIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1105 | {
|
---|
[37444] | 1106 | Log(("acpiBatIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
|
---|
| 1107 | if (cb != 4)
|
---|
| 1108 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
[1] | 1109 |
|
---|
[37444] | 1110 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1111 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1112 |
|
---|
| 1113 | u32 >>= pThis->u8IndexShift;
|
---|
| 1114 | /* see comment at the declaration of u8IndexShift */
|
---|
| 1115 | if (pThis->u8IndexShift == 0 && u32 == (BAT_DEVICE_STATUS << 2))
|
---|
[1] | 1116 | {
|
---|
[37444] | 1117 | pThis->u8IndexShift = 2;
|
---|
| 1118 | u32 >>= 2;
|
---|
[1] | 1119 | }
|
---|
[37444] | 1120 | Assert(u32 < BAT_INDEX_LAST);
|
---|
| 1121 | pThis->uBatteryIndex = u32;
|
---|
| 1122 |
|
---|
| 1123 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1124 | return VINF_SUCCESS;
|
---|
| 1125 | }
|
---|
| 1126 |
|
---|
[37444] | 1127 | /**
|
---|
| 1128 | * @callback_method_impl{FNIOMIOPORTIN, Battery status data}
|
---|
| 1129 | */
|
---|
[17572] | 1130 | PDMBOTHCBDECL(int) acpiBatDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1131 | {
|
---|
[37444] | 1132 | if (cb != 4)
|
---|
| 1133 | return VERR_IOM_IOPORT_UNUSED;
|
---|
[1] | 1134 |
|
---|
[37444] | 1135 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1136 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1137 |
|
---|
| 1138 | int rc = VINF_SUCCESS;
|
---|
| 1139 | switch (pThis->uBatteryIndex)
|
---|
[1] | 1140 | {
|
---|
[37444] | 1141 | case BAT_STATUS_STATE:
|
---|
| 1142 | acpiFetchBatteryStatus(pThis);
|
---|
| 1143 | /* fall thru */
|
---|
| 1144 | case BAT_STATUS_PRESENT_RATE:
|
---|
| 1145 | case BAT_STATUS_REMAINING_CAPACITY:
|
---|
| 1146 | case BAT_STATUS_PRESENT_VOLTAGE:
|
---|
| 1147 | *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
|
---|
| 1148 | break;
|
---|
[1] | 1149 |
|
---|
[37444] | 1150 | case BAT_INFO_UNITS:
|
---|
| 1151 | acpiFetchBatteryInfo(pThis);
|
---|
| 1152 | /* fall thru */
|
---|
| 1153 | case BAT_INFO_DESIGN_CAPACITY:
|
---|
| 1154 | case BAT_INFO_LAST_FULL_CHARGE_CAPACITY:
|
---|
| 1155 | case BAT_INFO_TECHNOLOGY:
|
---|
| 1156 | case BAT_INFO_DESIGN_VOLTAGE:
|
---|
| 1157 | case BAT_INFO_DESIGN_CAPACITY_OF_WARNING:
|
---|
| 1158 | case BAT_INFO_DESIGN_CAPACITY_OF_LOW:
|
---|
| 1159 | case BAT_INFO_CAPACITY_GRANULARITY_1:
|
---|
| 1160 | case BAT_INFO_CAPACITY_GRANULARITY_2:
|
---|
| 1161 | *pu32 = pThis->au8BatteryInfo[pThis->uBatteryIndex];
|
---|
| 1162 | break;
|
---|
[1] | 1163 |
|
---|
[37444] | 1164 | case BAT_DEVICE_STATUS:
|
---|
| 1165 | *pu32 = acpiGetBatteryDeviceStatus(pThis);
|
---|
| 1166 | break;
|
---|
[1] | 1167 |
|
---|
[37444] | 1168 | case BAT_POWER_SOURCE:
|
---|
| 1169 | *pu32 = acpiGetPowerSource(pThis);
|
---|
| 1170 | break;
|
---|
[1] | 1171 |
|
---|
[37444] | 1172 | default:
|
---|
| 1173 | rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
|
---|
| 1174 | *pu32 = UINT32_MAX;
|
---|
[1] | 1175 | break;
|
---|
| 1176 | }
|
---|
[37444] | 1177 |
|
---|
| 1178 | DEVACPI_UNLOCK(pThis);
|
---|
| 1179 | return rc;
|
---|
[1] | 1180 | }
|
---|
| 1181 |
|
---|
[37444] | 1182 | /**
|
---|
| 1183 | * @callback_method_impl{FNIOMIOPORTOUT, System info index}
|
---|
| 1184 | */
|
---|
[17572] | 1185 | PDMBOTHCBDECL(int) acpiSysInfoIndexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1186 | {
|
---|
[37444] | 1187 | Log(("acpiSysInfoIndexWrite: %#x (%#x)\n", u32, u32 >> 2));
|
---|
| 1188 | if (cb != 4)
|
---|
| 1189 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
[1] | 1190 |
|
---|
[37444] | 1191 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1192 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1193 |
|
---|
| 1194 | if (u32 == SYSTEM_INFO_INDEX_VALID || u32 == SYSTEM_INFO_INDEX_INVALID)
|
---|
| 1195 | pThis->uSystemInfoIndex = u32;
|
---|
| 1196 | else
|
---|
[17572] | 1197 | {
|
---|
[37444] | 1198 | /* see comment at the declaration of u8IndexShift */
|
---|
| 1199 | if (u32 > SYSTEM_INFO_INDEX_END && pThis->u8IndexShift == 0)
|
---|
| 1200 | {
|
---|
| 1201 | if ((u32 >> 2) < SYSTEM_INFO_INDEX_END && (u32 & 0x3) == 0)
|
---|
| 1202 | pThis->u8IndexShift = 2;
|
---|
| 1203 | }
|
---|
[17572] | 1204 |
|
---|
[37444] | 1205 | u32 >>= pThis->u8IndexShift;
|
---|
| 1206 | Assert(u32 < SYSTEM_INFO_INDEX_END);
|
---|
| 1207 | pThis->uSystemInfoIndex = u32;
|
---|
| 1208 | }
|
---|
[16170] | 1209 |
|
---|
[37444] | 1210 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1211 | return VINF_SUCCESS;
|
---|
| 1212 | }
|
---|
| 1213 |
|
---|
[37444] | 1214 | /**
|
---|
| 1215 | * @callback_method_impl{FNIOMIOPORTIN, System info data}
|
---|
| 1216 | */
|
---|
[17572] | 1217 | PDMBOTHCBDECL(int) acpiSysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1218 | {
|
---|
[37444] | 1219 | if (cb != 4)
|
---|
| 1220 | return VERR_IOM_IOPORT_UNUSED;
|
---|
[16042] | 1221 |
|
---|
[37444] | 1222 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1223 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1224 |
|
---|
| 1225 | int rc = VINF_SUCCESS;
|
---|
[40019] | 1226 | uint32_t const uSystemInfoIndex = pThis->uSystemInfoIndex;
|
---|
[37444] | 1227 | switch (uSystemInfoIndex)
|
---|
[1] | 1228 | {
|
---|
[37444] | 1229 | case SYSTEM_INFO_INDEX_LOW_MEMORY_LENGTH:
|
---|
| 1230 | *pu32 = pThis->cbRamLow;
|
---|
| 1231 | break;
|
---|
[1] | 1232 |
|
---|
[37444] | 1233 | case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
|
---|
| 1234 | *pu32 = pThis->cbRamHigh >> 16; /* 64KB units */
|
---|
| 1235 | Assert(((uint64_t)*pu32 << 16) == pThis->cbRamHigh);
|
---|
| 1236 | break;
|
---|
[17590] | 1237 |
|
---|
[37444] | 1238 | case SYSTEM_INFO_INDEX_USE_IOAPIC:
|
---|
| 1239 | *pu32 = pThis->u8UseIOApic;
|
---|
| 1240 | break;
|
---|
[16170] | 1241 |
|
---|
[37444] | 1242 | case SYSTEM_INFO_INDEX_HPET_STATUS:
|
---|
| 1243 | *pu32 = pThis->fUseHpet
|
---|
| 1244 | ? ( STA_DEVICE_PRESENT_MASK
|
---|
| 1245 | | STA_DEVICE_ENABLED_MASK
|
---|
| 1246 | | STA_DEVICE_SHOW_IN_UI_MASK
|
---|
| 1247 | | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
|
---|
| 1248 | : 0;
|
---|
| 1249 | break;
|
---|
[16170] | 1250 |
|
---|
[37444] | 1251 | case SYSTEM_INFO_INDEX_SMC_STATUS:
|
---|
| 1252 | *pu32 = pThis->fUseSmc
|
---|
| 1253 | ? ( STA_DEVICE_PRESENT_MASK
|
---|
| 1254 | | STA_DEVICE_ENABLED_MASK
|
---|
| 1255 | /* no need to show this device in the UI */
|
---|
| 1256 | | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
|
---|
| 1257 | : 0;
|
---|
| 1258 | break;
|
---|
[16170] | 1259 |
|
---|
[37444] | 1260 | case SYSTEM_INFO_INDEX_FDC_STATUS:
|
---|
| 1261 | *pu32 = pThis->fUseFdc
|
---|
| 1262 | ? ( STA_DEVICE_PRESENT_MASK
|
---|
| 1263 | | STA_DEVICE_ENABLED_MASK
|
---|
| 1264 | | STA_DEVICE_SHOW_IN_UI_MASK
|
---|
| 1265 | | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
|
---|
| 1266 | : 0;
|
---|
| 1267 | break;
|
---|
[20087] | 1268 |
|
---|
[37444] | 1269 | case SYSTEM_INFO_INDEX_NIC_ADDRESS:
|
---|
| 1270 | *pu32 = pThis->u32NicPciAddress;
|
---|
| 1271 | break;
|
---|
[28487] | 1272 |
|
---|
[37444] | 1273 | case SYSTEM_INFO_INDEX_AUDIO_ADDRESS:
|
---|
| 1274 | *pu32 = pThis->u32AudioPciAddress;
|
---|
| 1275 | break;
|
---|
[31519] | 1276 |
|
---|
[37444] | 1277 | case SYSTEM_INFO_INDEX_POWER_STATES:
|
---|
| 1278 | *pu32 = RT_BIT(0) | RT_BIT(5); /* S1 and S5 always exposed */
|
---|
| 1279 | if (pThis->fS1Enabled) /* Optionally expose S1 and S4 */
|
---|
| 1280 | *pu32 |= RT_BIT(1);
|
---|
| 1281 | if (pThis->fS4Enabled)
|
---|
| 1282 | *pu32 |= RT_BIT(4);
|
---|
| 1283 | break;
|
---|
[31963] | 1284 |
|
---|
[37444] | 1285 | case SYSTEM_INFO_INDEX_IOC_ADDRESS:
|
---|
| 1286 | *pu32 = pThis->u32IocPciAddress;
|
---|
| 1287 | break;
|
---|
[32471] | 1288 |
|
---|
[37444] | 1289 | case SYSTEM_INFO_INDEX_HBC_ADDRESS:
|
---|
| 1290 | *pu32 = pThis->u32HbcPciAddress;
|
---|
| 1291 | break;
|
---|
[32477] | 1292 |
|
---|
[37444] | 1293 | case SYSTEM_INFO_INDEX_PCI_BASE:
|
---|
| 1294 | /** @todo couldn't MCFG be in 64-bit range? */
|
---|
| 1295 | Assert(pThis->u64PciConfigMMioAddress < 0xffffffff);
|
---|
| 1296 | *pu32 = (uint32_t)pThis->u64PciConfigMMioAddress;
|
---|
| 1297 | break;
|
---|
[32637] | 1298 |
|
---|
[37444] | 1299 | case SYSTEM_INFO_INDEX_PCI_LENGTH:
|
---|
| 1300 | /** @todo couldn't MCFG be in 64-bit range? */
|
---|
| 1301 | Assert(pThis->u64PciConfigMMioLength< 0xffffffff);
|
---|
| 1302 | *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
|
---|
| 1303 | break;
|
---|
[32637] | 1304 |
|
---|
[37444] | 1305 | /* This is only for compatibility with older saved states that
|
---|
| 1306 | may include ACPI code that read these values. Legacy is
|
---|
| 1307 | a wonderful thing, isn't it? :-) */
|
---|
| 1308 | case SYSTEM_INFO_INDEX_CPU0_STATUS:
|
---|
| 1309 | case SYSTEM_INFO_INDEX_CPU1_STATUS:
|
---|
| 1310 | case SYSTEM_INFO_INDEX_CPU2_STATUS:
|
---|
| 1311 | case SYSTEM_INFO_INDEX_CPU3_STATUS:
|
---|
| 1312 | *pu32 = ( pThis->fShowCpu
|
---|
| 1313 | && pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS < pThis->cCpus
|
---|
| 1314 | && VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached,
|
---|
| 1315 | pThis->uSystemInfoIndex - SYSTEM_INFO_INDEX_CPU0_STATUS) )
|
---|
| 1316 | ? ( STA_DEVICE_PRESENT_MASK
|
---|
| 1317 | | STA_DEVICE_ENABLED_MASK
|
---|
| 1318 | | STA_DEVICE_SHOW_IN_UI_MASK
|
---|
| 1319 | | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
|
---|
| 1320 | : 0;
|
---|
| 1321 | break;
|
---|
[27666] | 1322 |
|
---|
[37444] | 1323 | case SYSTEM_INFO_INDEX_RTC_STATUS:
|
---|
| 1324 | *pu32 = pThis->fShowRtc
|
---|
| 1325 | ? ( STA_DEVICE_PRESENT_MASK
|
---|
| 1326 | | STA_DEVICE_ENABLED_MASK
|
---|
| 1327 | | STA_DEVICE_SHOW_IN_UI_MASK
|
---|
| 1328 | | STA_DEVICE_FUNCTIONING_PROPERLY_MASK)
|
---|
| 1329 | : 0;
|
---|
| 1330 | break;
|
---|
[19007] | 1331 |
|
---|
[37444] | 1332 | case SYSTEM_INFO_INDEX_CPU_LOCKED:
|
---|
| 1333 | if (pThis->idCpuLockCheck < VMM_MAX_CPU_COUNT)
|
---|
| 1334 | {
|
---|
| 1335 | *pu32 = VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, pThis->idCpuLockCheck);
|
---|
| 1336 | pThis->idCpuLockCheck = UINT32_C(0xffffffff); /* Make the entry invalid */
|
---|
| 1337 | }
|
---|
| 1338 | else
|
---|
| 1339 | {
|
---|
| 1340 | rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "CPU lock check protocol violation (idCpuLockCheck=%#x)\n",
|
---|
| 1341 | pThis->idCpuLockCheck);
|
---|
| 1342 | /* Always return locked status just to be safe */
|
---|
| 1343 | *pu32 = 1;
|
---|
| 1344 | }
|
---|
| 1345 | break;
|
---|
[25817] | 1346 |
|
---|
[37444] | 1347 | case SYSTEM_INFO_INDEX_CPU_EVENT_TYPE:
|
---|
| 1348 | *pu32 = pThis->u32CpuEventType;
|
---|
| 1349 | break;
|
---|
[26594] | 1350 |
|
---|
[37444] | 1351 | case SYSTEM_INFO_INDEX_CPU_EVENT:
|
---|
| 1352 | *pu32 = pThis->u32CpuEvent;
|
---|
| 1353 | break;
|
---|
[26594] | 1354 |
|
---|
[37444] | 1355 | case SYSTEM_INFO_INDEX_SERIAL0_IOBASE:
|
---|
| 1356 | *pu32 = pThis->uSerial0IoPortBase;
|
---|
| 1357 | break;
|
---|
[35746] | 1358 |
|
---|
[37444] | 1359 | case SYSTEM_INFO_INDEX_SERIAL0_IRQ:
|
---|
| 1360 | *pu32 = pThis->uSerial0Irq;
|
---|
| 1361 | break;
|
---|
[35746] | 1362 |
|
---|
[37444] | 1363 | case SYSTEM_INFO_INDEX_SERIAL1_IOBASE:
|
---|
| 1364 | *pu32 = pThis->uSerial1IoPortBase;
|
---|
| 1365 | break;
|
---|
[35746] | 1366 |
|
---|
[37444] | 1367 | case SYSTEM_INFO_INDEX_SERIAL1_IRQ:
|
---|
| 1368 | *pu32 = pThis->uSerial1Irq;
|
---|
| 1369 | break;
|
---|
[35746] | 1370 |
|
---|
[37444] | 1371 | case SYSTEM_INFO_INDEX_END:
|
---|
| 1372 | /** @todo why isn't this setting any output value? */
|
---|
| 1373 | break;
|
---|
[35746] | 1374 |
|
---|
[37444] | 1375 | /* Solaris 9 tries to read from this index */
|
---|
| 1376 | case SYSTEM_INFO_INDEX_INVALID:
|
---|
| 1377 | *pu32 = 0;
|
---|
[1] | 1378 | break;
|
---|
| 1379 |
|
---|
| 1380 | default:
|
---|
[37444] | 1381 | *pu32 = UINT32_MAX;
|
---|
| 1382 | rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u idx=%u\n", cb, Port, pThis->uBatteryIndex);
|
---|
| 1383 | break;
|
---|
[1] | 1384 | }
|
---|
| 1385 |
|
---|
[37444] | 1386 | DEVACPI_UNLOCK(pThis);
|
---|
| 1387 | Log(("acpiSysInfoDataRead: idx=%d val=%#x (%d) rc=%Rrc\n", uSystemInfoIndex, *pu32, *pu32, rc));
|
---|
| 1388 | return rc;
|
---|
[1] | 1389 | }
|
---|
| 1390 |
|
---|
[37444] | 1391 | /**
|
---|
| 1392 | * @callback_method_impl{FNIOMIOPORTOUT, System info data}
|
---|
| 1393 | */
|
---|
[17572] | 1394 | PDMBOTHCBDECL(int) acpiSysInfoDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1395 | {
|
---|
[37444] | 1396 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1397 | if (cb != 4)
|
---|
| 1398 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
|
---|
[1] | 1399 |
|
---|
[37444] | 1400 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1401 | Log(("addr=%#x cb=%d u32=%#x si=%#x\n", Port, cb, u32, pThis->uSystemInfoIndex));
|
---|
[1] | 1402 |
|
---|
[37444] | 1403 | int rc = VINF_SUCCESS;
|
---|
| 1404 | switch (pThis->uSystemInfoIndex)
|
---|
[1] | 1405 | {
|
---|
[37444] | 1406 | case SYSTEM_INFO_INDEX_INVALID:
|
---|
| 1407 | AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
|
---|
| 1408 | pThis->u8IndexShift = 0;
|
---|
| 1409 | break;
|
---|
[1] | 1410 |
|
---|
[37444] | 1411 | case SYSTEM_INFO_INDEX_VALID:
|
---|
| 1412 | AssertMsg(u32 == 0xbadc0de, ("u32=%u\n", u32));
|
---|
| 1413 | pThis->u8IndexShift = 2;
|
---|
| 1414 | break;
|
---|
[1] | 1415 |
|
---|
[37444] | 1416 | case SYSTEM_INFO_INDEX_CPU_LOCK_CHECK:
|
---|
| 1417 | pThis->idCpuLockCheck = u32;
|
---|
| 1418 | break;
|
---|
[26057] | 1419 |
|
---|
[37444] | 1420 | case SYSTEM_INFO_INDEX_CPU_LOCKED:
|
---|
| 1421 | if (u32 < pThis->cCpus)
|
---|
| 1422 | VMCPUSET_DEL(&pThis->CpuSetLocked, u32); /* Unlock the CPU */
|
---|
| 1423 | else
|
---|
| 1424 | LogRel(("ACPI: CPU %u does not exist\n", u32));
|
---|
| 1425 | break;
|
---|
[25817] | 1426 |
|
---|
[37444] | 1427 | default:
|
---|
| 1428 | rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x idx=%u\n", cb, Port, u32, pThis->uSystemInfoIndex);
|
---|
| 1429 | break;
|
---|
[1] | 1430 | }
|
---|
[37444] | 1431 |
|
---|
| 1432 | DEVACPI_UNLOCK(pThis);
|
---|
| 1433 | return rc;
|
---|
[1] | 1434 | }
|
---|
| 1435 |
|
---|
[37444] | 1436 | /**
|
---|
| 1437 | * @callback_method_impl{FNIOMIOPORTIN, PM1a Enable}
|
---|
| 1438 | */
|
---|
[17572] | 1439 | PDMBOTHCBDECL(int) acpiPm1aEnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1440 | {
|
---|
[39091] | 1441 | NOREF(pDevIns); NOREF(Port);
|
---|
[37444] | 1442 | if (cb != 2)
|
---|
| 1443 | return VERR_IOM_IOPORT_UNUSED;
|
---|
| 1444 |
|
---|
| 1445 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1446 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1447 |
|
---|
| 1448 | *pu32 = pThis->pm1a_en;
|
---|
| 1449 |
|
---|
| 1450 | DEVACPI_UNLOCK(pThis);
|
---|
| 1451 | Log(("acpiPm1aEnRead -> %#x\n", *pu32));
|
---|
[1] | 1452 | return VINF_SUCCESS;
|
---|
| 1453 | }
|
---|
| 1454 |
|
---|
[37444] | 1455 | /**
|
---|
| 1456 | * @callback_method_impl{FNIOMIOPORTOUT, PM1a Enable}
|
---|
| 1457 | */
|
---|
| 1458 | PDMBOTHCBDECL(int) acpiPM1aEnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1459 | {
|
---|
[37444] | 1460 | if (cb != 2 && cb != 4)
|
---|
| 1461 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1462 |
|
---|
| 1463 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1464 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1465 |
|
---|
| 1466 | Log(("acpiPM1aEnWrite: %#x (%#x)\n", u32, u32 & ~(RSR_EN | IGN_EN) & 0xffff));
|
---|
| 1467 | u32 &= ~(RSR_EN | IGN_EN);
|
---|
| 1468 | u32 &= 0xffff;
|
---|
| 1469 | update_pm1a(pThis, pThis->pm1a_sts, u32);
|
---|
| 1470 |
|
---|
| 1471 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1472 | return VINF_SUCCESS;
|
---|
| 1473 | }
|
---|
| 1474 |
|
---|
[37444] | 1475 | /**
|
---|
| 1476 | * @callback_method_impl{FNIOMIOPORTIN, PM1a Status}
|
---|
| 1477 | */
|
---|
| 1478 | PDMBOTHCBDECL(int) acpiPm1aStsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1479 | {
|
---|
[37444] | 1480 | if (cb != 2)
|
---|
[1] | 1481 | {
|
---|
[37444] | 1482 | int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
|
---|
| 1483 | return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
|
---|
[1] | 1484 | }
|
---|
[37444] | 1485 |
|
---|
| 1486 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1487 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1488 |
|
---|
| 1489 | *pu32 = pThis->pm1a_sts;
|
---|
| 1490 |
|
---|
| 1491 | DEVACPI_UNLOCK(pThis);
|
---|
| 1492 | Log(("acpiPm1aStsRead: %#x\n", *pu32));
|
---|
[1] | 1493 | return VINF_SUCCESS;
|
---|
| 1494 | }
|
---|
| 1495 |
|
---|
[37444] | 1496 | /**
|
---|
| 1497 | * @callback_method_impl{FNIOMIOPORTOUT, PM1a Status}
|
---|
| 1498 | */
|
---|
| 1499 | PDMBOTHCBDECL(int) acpiPM1aStsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1500 | {
|
---|
[37444] | 1501 | if (cb != 2 && cb != 4)
|
---|
| 1502 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1503 |
|
---|
| 1504 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1505 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1506 |
|
---|
| 1507 | Log(("acpiPM1aStsWrite: %#x (%#x)\n", u32, u32 & ~(RSR_STS | IGN_STS) & 0xffff));
|
---|
| 1508 | u32 &= 0xffff;
|
---|
| 1509 | if (u32 & PWRBTN_STS)
|
---|
| 1510 | pThis->fPowerButtonHandled = true; /* Remember that the guest handled the last power button event */
|
---|
| 1511 | u32 = pThis->pm1a_sts & ~(u32 & ~(RSR_STS | IGN_STS));
|
---|
| 1512 | update_pm1a(pThis, u32, pThis->pm1a_en);
|
---|
| 1513 |
|
---|
| 1514 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1515 | return VINF_SUCCESS;
|
---|
| 1516 | }
|
---|
| 1517 |
|
---|
[37444] | 1518 | /**
|
---|
| 1519 | * @callback_method_impl{FNIOMIOPORTIN, PM1a Control}
|
---|
| 1520 | */
|
---|
| 1521 | PDMBOTHCBDECL(int) acpiPm1aCtlRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1522 | {
|
---|
[37444] | 1523 | if (cb != 2)
|
---|
[1] | 1524 | {
|
---|
[37444] | 1525 | int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
|
---|
| 1526 | return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
|
---|
[1] | 1527 | }
|
---|
[37444] | 1528 |
|
---|
| 1529 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1530 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1531 |
|
---|
| 1532 | *pu32 = pThis->pm1a_ctl;
|
---|
| 1533 |
|
---|
| 1534 | DEVACPI_UNLOCK(pThis);
|
---|
| 1535 | Log(("acpiPm1aCtlRead: %#x\n", *pu32));
|
---|
[1] | 1536 | return VINF_SUCCESS;
|
---|
| 1537 | }
|
---|
| 1538 |
|
---|
[37444] | 1539 | /**
|
---|
| 1540 | * @callback_method_impl{FNIOMIOPORTOUT, PM1a Control}
|
---|
| 1541 | */
|
---|
[17572] | 1542 | PDMBOTHCBDECL(int) acpiPM1aCtlWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1543 | {
|
---|
[37444] | 1544 | if (cb != 2 && cb != 4)
|
---|
| 1545 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1546 |
|
---|
| 1547 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1548 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1549 |
|
---|
| 1550 | Log(("acpiPM1aCtlWrite: %#x (%#x)\n", u32, u32 & ~(RSR_CNT | IGN_CNT) & 0xffff));
|
---|
| 1551 | u32 &= 0xffff;
|
---|
| 1552 | pThis->pm1a_ctl = u32 & ~(RSR_CNT | IGN_CNT);
|
---|
| 1553 |
|
---|
| 1554 | int rc = VINF_SUCCESS;
|
---|
| 1555 | uint32_t const uSleepState = (pThis->pm1a_ctl >> SLP_TYPx_SHIFT) & SLP_TYPx_MASK;
|
---|
| 1556 | if (uSleepState != pThis->uSleepState)
|
---|
[1] | 1557 | {
|
---|
[37444] | 1558 | pThis->uSleepState = uSleepState;
|
---|
| 1559 | switch (uSleepState)
|
---|
| 1560 | {
|
---|
| 1561 | case 0x00: /* S0 */
|
---|
| 1562 | break;
|
---|
| 1563 |
|
---|
| 1564 | case 0x01: /* S1 */
|
---|
| 1565 | if (pThis->fS1Enabled)
|
---|
| 1566 | {
|
---|
| 1567 | LogRel(("Entering S1 power state (powered-on suspend)\n"));
|
---|
| 1568 | rc = acpiSleep(pThis);
|
---|
| 1569 | break;
|
---|
| 1570 | }
|
---|
| 1571 | LogRel(("Ignoring guest attempt to enter S1 power state (powered-on suspend)!\n"));
|
---|
| 1572 | /* fall thru */
|
---|
| 1573 |
|
---|
| 1574 | case 0x04: /* S4 */
|
---|
| 1575 | if (pThis->fS4Enabled)
|
---|
| 1576 | {
|
---|
| 1577 | LogRel(("Entering S4 power state (suspend to disk)\n"));
|
---|
| 1578 | rc = acpiPowerOff(pThis);/* Same behavior as S5 */
|
---|
| 1579 | break;
|
---|
| 1580 | }
|
---|
| 1581 | LogRel(("Ignoring guest attempt to enter S4 power state (suspend to disk)!\n"));
|
---|
| 1582 | /* fall thru */
|
---|
| 1583 |
|
---|
| 1584 | case 0x05: /* S5 */
|
---|
| 1585 | LogRel(("Entering S5 power state (power down)\n"));
|
---|
| 1586 | rc = acpiPowerOff(pThis);
|
---|
| 1587 | break;
|
---|
| 1588 |
|
---|
| 1589 | default:
|
---|
| 1590 | rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Unknown sleep state %#x (u32=%#x)\n", uSleepState, u32);
|
---|
| 1591 | break;
|
---|
| 1592 | }
|
---|
[1] | 1593 | }
|
---|
[37444] | 1594 |
|
---|
| 1595 | DEVACPI_UNLOCK(pThis);
|
---|
| 1596 | Log(("acpiPM1aCtlWrite: rc=%Rrc\n", rc));
|
---|
| 1597 | return rc;
|
---|
[1] | 1598 | }
|
---|
| 1599 |
|
---|
| 1600 | #endif /* IN_RING3 */
|
---|
| 1601 |
|
---|
| 1602 | /**
|
---|
[37444] | 1603 | * @callback_method_impl{FNIOMIOPORTIN, PMTMR}
|
---|
| 1604 | *
|
---|
| 1605 | * @remarks Only I/O port currently implemented in all contexts.
|
---|
[1] | 1606 | */
|
---|
[17572] | 1607 | PDMBOTHCBDECL(int) acpiPMTmrRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1608 | {
|
---|
[37444] | 1609 | if (cb != 4)
|
---|
| 1610 | return VERR_IOM_IOPORT_UNUSED;
|
---|
| 1611 |
|
---|
| 1612 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
| 1613 |
|
---|
| 1614 | /*
|
---|
| 1615 | * We use the clock lock to serialize access to u64PmTimerInitial and to
|
---|
| 1616 | * make sure we get a reliable time from the clock.
|
---|
| 1617 | */
|
---|
[40280] | 1618 | int rc = TMTimerLock(pThis->CTX_SUFF(pPmTimer), VINF_IOM_R3_IOPORT_READ);
|
---|
[37444] | 1619 | if (rc == VINF_SUCCESS)
|
---|
[1] | 1620 | {
|
---|
[37444] | 1621 | uint64_t const u64PmTimerInitial = pThis->u64PmTimerInitial;
|
---|
| 1622 | uint64_t u64Now = TMTimerGet(pThis->CTX_SUFF(pPmTimer));
|
---|
| 1623 | TMTimerUnlock(pThis->CTX_SUFF(pPmTimer));
|
---|
| 1624 |
|
---|
| 1625 | /*
|
---|
| 1626 | * Calculate the return value.
|
---|
| 1627 | */
|
---|
| 1628 | DBGFTRACE_PDM_U64_TAG(pDevIns, u64Now, "acpi");
|
---|
| 1629 | uint64_t u64Elapsed = u64Now - u64PmTimerInitial;
|
---|
| 1630 | *pu32 = ASMMultU64ByU32DivByU32(u64Elapsed, PM_TMR_FREQ, TMTimerGetFreq(pThis->CTX_SUFF(pPmTimer)));
|
---|
[17572] | 1631 | Log(("acpi: acpiPMTmrRead -> %#x\n", *pu32));
|
---|
[1] | 1632 | }
|
---|
[37444] | 1633 |
|
---|
[39091] | 1634 | NOREF(pvUser); NOREF(Port);
|
---|
[37444] | 1635 | return rc;
|
---|
[1] | 1636 | }
|
---|
| 1637 |
|
---|
| 1638 | #ifdef IN_RING3
|
---|
| 1639 |
|
---|
[37444] | 1640 | /**
|
---|
| 1641 | * @callback_method_impl{FNIOMIOPORTIN, GPE0 Status}
|
---|
| 1642 | */
|
---|
[17572] | 1643 | PDMBOTHCBDECL(int) acpiGpe0StsRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1644 | {
|
---|
[37444] | 1645 | if (cb != 1)
|
---|
[1] | 1646 | {
|
---|
[37444] | 1647 | int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
|
---|
| 1648 | return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
|
---|
[1] | 1649 | }
|
---|
[37444] | 1650 |
|
---|
| 1651 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1652 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1653 |
|
---|
| 1654 | *pu32 = pThis->gpe0_sts & 0xff;
|
---|
| 1655 |
|
---|
| 1656 | DEVACPI_UNLOCK(pThis);
|
---|
| 1657 | Log(("acpiGpe0StsRead: %#x\n", *pu32));
|
---|
[1] | 1658 | return VINF_SUCCESS;
|
---|
| 1659 | }
|
---|
| 1660 |
|
---|
[37444] | 1661 | /**
|
---|
| 1662 | * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Status}
|
---|
| 1663 | */
|
---|
| 1664 | PDMBOTHCBDECL(int) acpiGpe0StsWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1665 | {
|
---|
[37444] | 1666 | if (cb != 1)
|
---|
| 1667 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1668 |
|
---|
| 1669 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1670 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1671 |
|
---|
| 1672 | Log(("acpiGpe0StsWrite: %#x (%#x)\n", u32, pThis->gpe0_sts & ~u32));
|
---|
| 1673 | u32 = pThis->gpe0_sts & ~u32;
|
---|
| 1674 | update_gpe0(pThis, u32, pThis->gpe0_en);
|
---|
| 1675 |
|
---|
| 1676 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1677 | return VINF_SUCCESS;
|
---|
| 1678 | }
|
---|
| 1679 |
|
---|
[37444] | 1680 | /**
|
---|
| 1681 | * @callback_method_impl{FNIOMIOPORTIN, GPE0 Enable}
|
---|
| 1682 | */
|
---|
| 1683 | PDMBOTHCBDECL(int) acpiGpe0EnRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
|
---|
[1] | 1684 | {
|
---|
[37444] | 1685 | if (cb != 1)
|
---|
[1] | 1686 | {
|
---|
[37444] | 1687 | int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u\n", cb, Port);
|
---|
| 1688 | return rc == VINF_SUCCESS ? VERR_IOM_IOPORT_UNUSED : rc;
|
---|
[1] | 1689 | }
|
---|
[37444] | 1690 |
|
---|
| 1691 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1692 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1693 |
|
---|
| 1694 | *pu32 = pThis->gpe0_en & 0xff;
|
---|
| 1695 |
|
---|
| 1696 | DEVACPI_UNLOCK(pThis);
|
---|
| 1697 | Log(("acpiGpe0EnRead: %#x\n", *pu32));
|
---|
[1] | 1698 | return VINF_SUCCESS;
|
---|
| 1699 | }
|
---|
| 1700 |
|
---|
[37444] | 1701 | /**
|
---|
| 1702 | * @callback_method_impl{FNIOMIOPORTOUT, GPE0 Enable}
|
---|
| 1703 | */
|
---|
[17572] | 1704 | PDMBOTHCBDECL(int) acpiGpe0EnWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1705 | {
|
---|
[37444] | 1706 | if (cb != 1)
|
---|
| 1707 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1708 |
|
---|
| 1709 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1710 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1711 |
|
---|
| 1712 | Log(("acpiGpe0EnWrite: %#x\n", u32));
|
---|
| 1713 | update_gpe0(pThis, pThis->gpe0_sts, u32);
|
---|
| 1714 |
|
---|
| 1715 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1716 | return VINF_SUCCESS;
|
---|
| 1717 | }
|
---|
| 1718 |
|
---|
[37444] | 1719 | /**
|
---|
| 1720 | * @callback_method_impl{FNIOMIOPORTOUT, SMI_CMD}
|
---|
| 1721 | */
|
---|
[17572] | 1722 | PDMBOTHCBDECL(int) acpiSmiWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1723 | {
|
---|
[37444] | 1724 | Log(("acpiSmiWrite %#x\n", u32));
|
---|
| 1725 | if (cb != 1)
|
---|
| 1726 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1727 |
|
---|
| 1728 | ACPIState *pThis = (ACPIState *)pvUser;
|
---|
| 1729 | DEVACPI_LOCK_R3(pThis);
|
---|
| 1730 |
|
---|
| 1731 | if (u32 == ACPI_ENABLE)
|
---|
| 1732 | pThis->pm1a_ctl |= SCI_EN;
|
---|
| 1733 | else if (u32 == ACPI_DISABLE)
|
---|
| 1734 | pThis->pm1a_ctl &= ~SCI_EN;
|
---|
| 1735 | else
|
---|
| 1736 | Log(("acpiSmiWrite: %#x <- unknown value\n", u32));
|
---|
| 1737 |
|
---|
| 1738 | DEVACPI_UNLOCK(pThis);
|
---|
[1] | 1739 | return VINF_SUCCESS;
|
---|
| 1740 | }
|
---|
| 1741 |
|
---|
[37444] | 1742 | /**
|
---|
| 1743 | * @{FNIOMIOPORTOUT, ACPI_RESET_BLK}
|
---|
| 1744 | */
|
---|
[17572] | 1745 | PDMBOTHCBDECL(int) acpiResetWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1746 | {
|
---|
[37444] | 1747 | Log(("acpiResetWrite: %#x\n", u32));
|
---|
[39091] | 1748 | NOREF(pvUser);
|
---|
[37444] | 1749 | if (cb != 1)
|
---|
| 1750 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
| 1751 |
|
---|
| 1752 | /* No state locking required. */
|
---|
| 1753 | int rc = VINF_SUCCESS;
|
---|
| 1754 | if (u32 == ACPI_RESET_REG_VAL)
|
---|
| 1755 | rc = PDMDevHlpVMReset(pDevIns);
|
---|
| 1756 | else
|
---|
| 1757 | Log(("acpiResetWrite: %#x <- unknown value\n", u32));
|
---|
| 1758 |
|
---|
| 1759 | return rc;
|
---|
[1] | 1760 | }
|
---|
| 1761 |
|
---|
[37444] | 1762 | # ifdef DEBUG_ACPI
|
---|
[1] | 1763 |
|
---|
[37444] | 1764 | /**
|
---|
| 1765 | * @callback_method_impl{FNIOMIOPORTOUT, Debug hex value logger}
|
---|
| 1766 | */
|
---|
[17572] | 1767 | PDMBOTHCBDECL(int) acpiDhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1768 | {
|
---|
[39091] | 1769 | NOREF(pvUser);
|
---|
[1] | 1770 | switch (cb)
|
---|
| 1771 | {
|
---|
| 1772 | case 1:
|
---|
[17572] | 1773 | Log(("%#x\n", u32 & 0xff));
|
---|
[1] | 1774 | break;
|
---|
| 1775 | case 2:
|
---|
[17572] | 1776 | Log(("%#6x\n", u32 & 0xffff));
|
---|
[1] | 1777 | case 4:
|
---|
[17572] | 1778 | Log(("%#10x\n", u32));
|
---|
[1] | 1779 | break;
|
---|
| 1780 | default:
|
---|
[37444] | 1781 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
[1] | 1782 | }
|
---|
| 1783 | return VINF_SUCCESS;
|
---|
| 1784 | }
|
---|
| 1785 |
|
---|
[37444] | 1786 | /**
|
---|
| 1787 | * @callback_method_impl{FNIOMIOPORTOUT, Debug char logger}
|
---|
| 1788 | */
|
---|
[17572] | 1789 | PDMBOTHCBDECL(int) acpiDchrWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
|
---|
[1] | 1790 | {
|
---|
[39091] | 1791 | NOREF(pvUser);
|
---|
[1] | 1792 | switch (cb)
|
---|
| 1793 | {
|
---|
| 1794 | case 1:
|
---|
[17572] | 1795 | Log(("%c", u32 & 0xff));
|
---|
[1] | 1796 | break;
|
---|
| 1797 | default:
|
---|
[37444] | 1798 | return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
|
---|
[1] | 1799 | }
|
---|
| 1800 | return VINF_SUCCESS;
|
---|
| 1801 | }
|
---|
| 1802 |
|
---|
[37444] | 1803 | # endif /* DEBUG_ACPI */
|
---|
[1] | 1804 |
|
---|
[37444] | 1805 | /**
|
---|
| 1806 | * Used to calculate the value of a PM I/O port.
|
---|
| 1807 | *
|
---|
| 1808 | * @returns The actual I/O port value.
|
---|
| 1809 | * @param pThis The ACPI instance.
|
---|
| 1810 | * @param offset The offset into the I/O space, or -1 if invalid.
|
---|
| 1811 | */
|
---|
| 1812 | static RTIOPORT acpiCalcPmPort(ACPIState *pThis, int32_t offset)
|
---|
[21820] | 1813 | {
|
---|
[37444] | 1814 | Assert(pThis->uPmIoPortBase != 0);
|
---|
| 1815 |
|
---|
| 1816 | if (offset == -1)
|
---|
| 1817 | return 0;
|
---|
| 1818 |
|
---|
| 1819 | return (RTIOPORT)(pThis->uPmIoPortBase + offset);
|
---|
| 1820 | }
|
---|
| 1821 |
|
---|
| 1822 | /**
|
---|
| 1823 | * Called by acpiLoadState and acpiUpdatePmHandlers to register the PM1a, PM
|
---|
| 1824 | * timer and GPE0 I/O ports.
|
---|
| 1825 | *
|
---|
| 1826 | * @returns VBox status code.
|
---|
| 1827 | * @param pThis The ACPI instance.
|
---|
| 1828 | */
|
---|
| 1829 | static int acpiRegisterPmHandlers(ACPIState *pThis)
|
---|
| 1830 | {
|
---|
[21820] | 1831 | int rc = VINF_SUCCESS;
|
---|
[1] | 1832 |
|
---|
[21820] | 1833 | #define R(offset, cnt, writer, reader, description) \
|
---|
| 1834 | do { \
|
---|
[37444] | 1835 | rc = PDMDevHlpIOPortRegister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
|
---|
[21820] | 1836 | NULL, NULL, description); \
|
---|
| 1837 | if (RT_FAILURE(rc)) \
|
---|
| 1838 | return rc; \
|
---|
| 1839 | } while (0)
|
---|
| 1840 | #define L (GPE0_BLK_LEN / 2)
|
---|
| 1841 |
|
---|
| 1842 | R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
|
---|
| 1843 | R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
|
---|
| 1844 | R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
|
---|
| 1845 | R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
|
---|
| 1846 | R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
|
---|
| 1847 | R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
|
---|
| 1848 | #undef L
|
---|
| 1849 | #undef R
|
---|
| 1850 |
|
---|
[26157] | 1851 | /* register RC stuff */
|
---|
[21820] | 1852 | if (pThis->fGCEnabled)
|
---|
| 1853 | {
|
---|
[37444] | 1854 | rc = PDMDevHlpIOPortRegisterRC(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
|
---|
[21820] | 1855 | 1, 0, NULL, "acpiPMTmrRead",
|
---|
| 1856 | NULL, NULL, "ACPI PM Timer");
|
---|
| 1857 | AssertRCReturn(rc, rc);
|
---|
| 1858 | }
|
---|
| 1859 |
|
---|
| 1860 | /* register R0 stuff */
|
---|
| 1861 | if (pThis->fR0Enabled)
|
---|
| 1862 | {
|
---|
[37444] | 1863 | rc = PDMDevHlpIOPortRegisterR0(pThis->pDevIns, acpiCalcPmPort(pThis, PM_TMR_OFFSET),
|
---|
[21820] | 1864 | 1, 0, NULL, "acpiPMTmrRead",
|
---|
| 1865 | NULL, NULL, "ACPI PM Timer");
|
---|
| 1866 | AssertRCReturn(rc, rc);
|
---|
| 1867 | }
|
---|
| 1868 |
|
---|
| 1869 | return rc;
|
---|
| 1870 | }
|
---|
| 1871 |
|
---|
[37444] | 1872 | /**
|
---|
| 1873 | * Called by acpiLoadState and acpiUpdatePmHandlers to unregister the PM1a, PM
|
---|
| 1874 | * timer and GPE0 I/O ports.
|
---|
| 1875 | *
|
---|
| 1876 | * @returns VBox status code.
|
---|
| 1877 | * @param pThis The ACPI instance.
|
---|
| 1878 | */
|
---|
[21829] | 1879 | static int acpiUnregisterPmHandlers(ACPIState *pThis)
|
---|
[21820] | 1880 | {
|
---|
[21829] | 1881 | #define U(offset, cnt) \
|
---|
[21820] | 1882 | do { \
|
---|
[37444] | 1883 | int rc = PDMDevHlpIOPortDeregister(pThis->pDevIns, acpiCalcPmPort(pThis, offset), cnt); \
|
---|
[21829] | 1884 | AssertRCReturn(rc, rc); \
|
---|
[21820] | 1885 | } while (0)
|
---|
| 1886 | #define L (GPE0_BLK_LEN / 2)
|
---|
| 1887 |
|
---|
| 1888 | U(PM1a_EVT_OFFSET+2, 1);
|
---|
| 1889 | U(PM1a_EVT_OFFSET, 1);
|
---|
| 1890 | U(PM1a_CTL_OFFSET, 1);
|
---|
| 1891 | U(PM_TMR_OFFSET, 1);
|
---|
| 1892 | U(GPE0_OFFSET + L, L);
|
---|
| 1893 | U(GPE0_OFFSET, L);
|
---|
| 1894 | #undef L
|
---|
| 1895 | #undef U
|
---|
| 1896 |
|
---|
[21829] | 1897 | return VINF_SUCCESS;
|
---|
[21820] | 1898 | }
|
---|
| 1899 |
|
---|
[1] | 1900 | /**
|
---|
[37444] | 1901 | * Called by acpiPciConfigWrite and acpiReset to change the location of the
|
---|
| 1902 | * PM1a, PM timer and GPE0 ports.
|
---|
| 1903 | *
|
---|
| 1904 | * @returns VBox status code.
|
---|
| 1905 | *
|
---|
| 1906 | * @param pThis The ACPI instance.
|
---|
| 1907 | * @param NewIoPortBase The new base address of the I/O ports.
|
---|
| 1908 | */
|
---|
| 1909 | static int acpiUpdatePmHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
|
---|
| 1910 | {
|
---|
| 1911 | Log(("acpi: rebasing PM 0x%x -> 0x%x\n", pThis->uPmIoPortBase, NewIoPortBase));
|
---|
| 1912 | if (NewIoPortBase != pThis->uPmIoPortBase)
|
---|
| 1913 | {
|
---|
| 1914 | int rc = acpiUnregisterPmHandlers(pThis);
|
---|
| 1915 | if (RT_FAILURE(rc))
|
---|
| 1916 | return rc;
|
---|
| 1917 |
|
---|
| 1918 | pThis->uPmIoPortBase = NewIoPortBase;
|
---|
| 1919 |
|
---|
| 1920 | rc = acpiRegisterPmHandlers(pThis);
|
---|
| 1921 | if (RT_FAILURE(rc))
|
---|
| 1922 | return rc;
|
---|
| 1923 |
|
---|
| 1924 | /* We have to update FADT table acccording to the new base */
|
---|
| 1925 | rc = acpiPlantTables(pThis);
|
---|
| 1926 | AssertRC(rc);
|
---|
| 1927 | if (RT_FAILURE(rc))
|
---|
| 1928 | return rc;
|
---|
| 1929 | }
|
---|
| 1930 |
|
---|
| 1931 | return VINF_SUCCESS;
|
---|
| 1932 | }
|
---|
| 1933 |
|
---|
| 1934 |
|
---|
| 1935 | /**
|
---|
[21820] | 1936 | * Saved state structure description, version 4.
|
---|
[1] | 1937 | */
|
---|
[21820] | 1938 | static const SSMFIELD g_AcpiSavedStateFields4[] =
|
---|
[1] | 1939 | {
|
---|
[17572] | 1940 | SSMFIELD_ENTRY(ACPIState, pm1a_en),
|
---|
| 1941 | SSMFIELD_ENTRY(ACPIState, pm1a_sts),
|
---|
| 1942 | SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
|
---|
[37237] | 1943 | SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
|
---|
[17572] | 1944 | SSMFIELD_ENTRY(ACPIState, gpe0_en),
|
---|
| 1945 | SSMFIELD_ENTRY(ACPIState, gpe0_sts),
|
---|
| 1946 | SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
|
---|
| 1947 | SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
|
---|
[21829] | 1948 | SSMFIELD_ENTRY(ACPIState, u64RamSize),
|
---|
[17572] | 1949 | SSMFIELD_ENTRY(ACPIState, u8IndexShift),
|
---|
| 1950 | SSMFIELD_ENTRY(ACPIState, u8UseIOApic),
|
---|
| 1951 | SSMFIELD_ENTRY(ACPIState, uSleepState),
|
---|
| 1952 | SSMFIELD_ENTRY_TERM()
|
---|
[1] | 1953 | };
|
---|
| 1954 |
|
---|
[21820] | 1955 | /**
|
---|
| 1956 | * Saved state structure description, version 5.
|
---|
| 1957 | */
|
---|
| 1958 | static const SSMFIELD g_AcpiSavedStateFields5[] =
|
---|
| 1959 | {
|
---|
| 1960 | SSMFIELD_ENTRY(ACPIState, pm1a_en),
|
---|
| 1961 | SSMFIELD_ENTRY(ACPIState, pm1a_sts),
|
---|
| 1962 | SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
|
---|
[37237] | 1963 | SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
|
---|
[21820] | 1964 | SSMFIELD_ENTRY(ACPIState, gpe0_en),
|
---|
| 1965 | SSMFIELD_ENTRY(ACPIState, gpe0_sts),
|
---|
| 1966 | SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
|
---|
| 1967 | SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
|
---|
| 1968 | SSMFIELD_ENTRY(ACPIState, uSleepState),
|
---|
| 1969 | SSMFIELD_ENTRY(ACPIState, u8IndexShift),
|
---|
| 1970 | SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
|
---|
| 1971 | SSMFIELD_ENTRY_TERM()
|
---|
| 1972 | };
|
---|
| 1973 |
|
---|
[32189] | 1974 | /**
|
---|
| 1975 | * Saved state structure description, version 6.
|
---|
| 1976 | */
|
---|
| 1977 | static const SSMFIELD g_AcpiSavedStateFields6[] =
|
---|
| 1978 | {
|
---|
| 1979 | SSMFIELD_ENTRY(ACPIState, pm1a_en),
|
---|
| 1980 | SSMFIELD_ENTRY(ACPIState, pm1a_sts),
|
---|
| 1981 | SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
|
---|
[37237] | 1982 | SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
|
---|
[32189] | 1983 | SSMFIELD_ENTRY(ACPIState, gpe0_en),
|
---|
| 1984 | SSMFIELD_ENTRY(ACPIState, gpe0_sts),
|
---|
| 1985 | SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
|
---|
| 1986 | SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
|
---|
| 1987 | SSMFIELD_ENTRY(ACPIState, uSleepState),
|
---|
| 1988 | SSMFIELD_ENTRY(ACPIState, u8IndexShift),
|
---|
| 1989 | SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
|
---|
| 1990 | SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
|
---|
| 1991 | SSMFIELD_ENTRY_TERM()
|
---|
| 1992 | };
|
---|
[21820] | 1993 |
|
---|
[32189] | 1994 |
|
---|
| 1995 | /**
|
---|
| 1996 | * @callback_method_impl{FNSSMDEVSAVEEXEC}
|
---|
| 1997 | */
|
---|
| 1998 | static DECLCALLBACK(int) acpiSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
|
---|
[1] | 1999 | {
|
---|
[32189] | 2000 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
| 2001 | return SSMR3PutStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
|
---|
[1] | 2002 | }
|
---|
| 2003 |
|
---|
[32189] | 2004 | /**
|
---|
| 2005 | * @callback_method_impl{FNSSMDEVLOADEXEC}
|
---|
| 2006 | */
|
---|
| 2007 | static DECLCALLBACK(int) acpiLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
|
---|
| 2008 | uint32_t uVersion, uint32_t uPass)
|
---|
[1] | 2009 | {
|
---|
[32189] | 2010 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
| 2011 | Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
|
---|
[1] | 2012 |
|
---|
[21837] | 2013 | /*
|
---|
[32189] | 2014 | * Unregister PM handlers, will register with actual base after state
|
---|
| 2015 | * successfully loaded.
|
---|
[21837] | 2016 | */
|
---|
[32189] | 2017 | int rc = acpiUnregisterPmHandlers(pThis);
|
---|
[21837] | 2018 | if (RT_FAILURE(rc))
|
---|
| 2019 | return rc;
|
---|
| 2020 |
|
---|
[22480] | 2021 | switch (uVersion)
|
---|
[21820] | 2022 | {
|
---|
| 2023 | case 4:
|
---|
[32189] | 2024 | rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields4[0]);
|
---|
[21820] | 2025 | break;
|
---|
| 2026 | case 5:
|
---|
[32189] | 2027 | rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields5[0]);
|
---|
[21820] | 2028 | break;
|
---|
[32189] | 2029 | case 6:
|
---|
| 2030 | rc = SSMR3GetStruct(pSSMHandle, pThis, &g_AcpiSavedStateFields6[0]);
|
---|
| 2031 | break;
|
---|
[21829] | 2032 | default:
|
---|
[32189] | 2033 | rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
|
---|
| 2034 | break;
|
---|
[21820] | 2035 | }
|
---|
[17572] | 2036 | if (RT_SUCCESS(rc))
|
---|
[1] | 2037 | {
|
---|
[32189] | 2038 | rc = acpiRegisterPmHandlers(pThis);
|
---|
[21820] | 2039 | if (RT_FAILURE(rc))
|
---|
| 2040 | return rc;
|
---|
[32189] | 2041 | rc = acpiFetchBatteryStatus(pThis);
|
---|
[21820] | 2042 | if (RT_FAILURE(rc))
|
---|
| 2043 | return rc;
|
---|
[32189] | 2044 | rc = acpiFetchBatteryInfo(pThis);
|
---|
[21820] | 2045 | if (RT_FAILURE(rc))
|
---|
| 2046 | return rc;
|
---|
[37526] | 2047 | TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
|
---|
[37444] | 2048 | acpiPmTimerReset(pThis, TMTimerGet(pThis->pPmTimerR3));
|
---|
[37526] | 2049 | TMTimerUnlock(pThis->pPmTimerR3);
|
---|
[1] | 2050 | }
|
---|
| 2051 | return rc;
|
---|
| 2052 | }
|
---|
| 2053 |
|
---|
| 2054 | /**
|
---|
[25966] | 2055 | * @interface_method_impl{PDMIBASE,pfnQueryInterface}
|
---|
[1] | 2056 | */
|
---|
[25966] | 2057 | static DECLCALLBACK(void *) acpiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
|
---|
[1] | 2058 | {
|
---|
[25966] | 2059 | ACPIState *pThis = RT_FROM_MEMBER(pInterface, ACPIState, IBase);
|
---|
[25985] | 2060 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
|
---|
[25984] | 2061 | PDMIBASE_RETURN_INTERFACE(pszIID, PDMIACPIPORT, &pThis->IACPIPort);
|
---|
[25966] | 2062 | return NULL;
|
---|
[1] | 2063 | }
|
---|
| 2064 |
|
---|
| 2065 | /**
|
---|
[37444] | 2066 | * Calculate the check sum for some ACPI data before planting it.
|
---|
| 2067 | *
|
---|
| 2068 | * All the bytes must add up to 0.
|
---|
| 2069 | *
|
---|
| 2070 | * @returns check sum.
|
---|
| 2071 | * @param pvSrc What to check sum.
|
---|
| 2072 | * @param cbData The amount of data to checksum.
|
---|
[1] | 2073 | */
|
---|
[37444] | 2074 | static uint8_t acpiChecksum(const void * const pvSrc, size_t cbData)
|
---|
| 2075 | {
|
---|
| 2076 | uint8_t const *pbSrc = (uint8_t const *)pvSrc;
|
---|
| 2077 | uint8_t uSum = 0;
|
---|
| 2078 | for (size_t i = 0; i < cbData; ++i)
|
---|
| 2079 | uSum += pbSrc[i];
|
---|
| 2080 | return -uSum;
|
---|
| 2081 | }
|
---|
| 2082 |
|
---|
| 2083 | /**
|
---|
| 2084 | * Prepare a ACPI table header.
|
---|
| 2085 | */
|
---|
[40019] | 2086 | static void acpiPrepareHeader(ACPIState *pThis, ACPITBLHEADER *header,
|
---|
| 2087 | const char au8Signature[4],
|
---|
[37444] | 2088 | uint32_t u32Length, uint8_t u8Revision)
|
---|
| 2089 | {
|
---|
| 2090 | memcpy(header->au8Signature, au8Signature, 4);
|
---|
| 2091 | header->u32Length = RT_H2LE_U32(u32Length);
|
---|
| 2092 | header->u8Revision = u8Revision;
|
---|
[40019] | 2093 | memcpy(header->au8OemId, pThis->au8OemId, 6);
|
---|
[37444] | 2094 | memcpy(header->au8OemTabId, "VBOX", 4);
|
---|
| 2095 | memcpy(header->au8OemTabId+4, au8Signature, 4);
|
---|
| 2096 | header->u32OemRevision = RT_H2LE_U32(1);
|
---|
[40019] | 2097 | memcpy(header->au8CreatorId, pThis->au8CreatorId, 4);
|
---|
| 2098 | header->u32CreatorRev = pThis->u32CreatorRev;
|
---|
[37444] | 2099 | }
|
---|
| 2100 |
|
---|
| 2101 | /**
|
---|
| 2102 | * Initialize a generic address structure (ACPIGENADDR).
|
---|
| 2103 | */
|
---|
| 2104 | static void acpiWriteGenericAddr(ACPIGENADDR *g, uint8_t u8AddressSpaceId,
|
---|
| 2105 | uint8_t u8RegisterBitWidth, uint8_t u8RegisterBitOffset,
|
---|
| 2106 | uint8_t u8AccessSize, uint64_t u64Address)
|
---|
| 2107 | {
|
---|
| 2108 | g->u8AddressSpaceId = u8AddressSpaceId;
|
---|
| 2109 | g->u8RegisterBitWidth = u8RegisterBitWidth;
|
---|
| 2110 | g->u8RegisterBitOffset = u8RegisterBitOffset;
|
---|
| 2111 | g->u8AccessSize = u8AccessSize;
|
---|
| 2112 | g->u64Address = RT_H2LE_U64(u64Address);
|
---|
| 2113 | }
|
---|
| 2114 |
|
---|
| 2115 | /**
|
---|
| 2116 | * Wrapper around PDMDevHlpPhysWrite used when planting ACPI tables.
|
---|
| 2117 | */
|
---|
[37446] | 2118 | static void acpiPhyscpy(ACPIState *pThis, RTGCPHYS32 dst, const void * const src, size_t size)
|
---|
[37444] | 2119 | {
|
---|
[37446] | 2120 | PDMDevHlpPhysWrite(pThis->pDevIns, dst, src, size);
|
---|
[37444] | 2121 | }
|
---|
| 2122 |
|
---|
| 2123 | /**
|
---|
| 2124 | * Plant the Differentiated System Description Table (DSDT).
|
---|
| 2125 | */
|
---|
[37446] | 2126 | static void acpiSetupDSDT(ACPIState *pThis, RTGCPHYS32 addr,
|
---|
[37444] | 2127 | void* pPtr, size_t uDsdtLen)
|
---|
| 2128 | {
|
---|
[37446] | 2129 | acpiPhyscpy(pThis, addr, pPtr, uDsdtLen);
|
---|
[37444] | 2130 | }
|
---|
| 2131 |
|
---|
| 2132 | /**
|
---|
| 2133 | * Plan the Secondary System Description Table (SSDT).
|
---|
| 2134 | */
|
---|
[37446] | 2135 | static void acpiSetupSSDT(ACPIState *pThis, RTGCPHYS32 addr,
|
---|
[37444] | 2136 | void* pPtr, size_t uSsdtLen)
|
---|
| 2137 | {
|
---|
[37446] | 2138 | acpiPhyscpy(pThis, addr, pPtr, uSsdtLen);
|
---|
[37444] | 2139 | }
|
---|
| 2140 |
|
---|
| 2141 | /**
|
---|
| 2142 | * Plant the Firmware ACPI Control Structure (FACS).
|
---|
| 2143 | */
|
---|
[37446] | 2144 | static void acpiSetupFACS(ACPIState *pThis, RTGCPHYS32 addr)
|
---|
[37444] | 2145 | {
|
---|
| 2146 | ACPITBLFACS facs;
|
---|
| 2147 |
|
---|
| 2148 | memset(&facs, 0, sizeof(facs));
|
---|
| 2149 | memcpy(facs.au8Signature, "FACS", 4);
|
---|
| 2150 | facs.u32Length = RT_H2LE_U32(sizeof(ACPITBLFACS));
|
---|
| 2151 | facs.u32HWSignature = RT_H2LE_U32(0);
|
---|
| 2152 | facs.u32FWVector = RT_H2LE_U32(0);
|
---|
| 2153 | facs.u32GlobalLock = RT_H2LE_U32(0);
|
---|
| 2154 | facs.u32Flags = RT_H2LE_U32(0);
|
---|
| 2155 | facs.u64X_FWVector = RT_H2LE_U64(0);
|
---|
| 2156 | facs.u8Version = 1;
|
---|
| 2157 |
|
---|
[37446] | 2158 | acpiPhyscpy(pThis, addr, (const uint8_t *)&facs, sizeof(facs));
|
---|
[37444] | 2159 | }
|
---|
| 2160 |
|
---|
| 2161 | /**
|
---|
| 2162 | * Plant the Fixed ACPI Description Table (FADT aka FACP).
|
---|
| 2163 | */
|
---|
[37446] | 2164 | static void acpiSetupFADT(ACPIState *pThis, RTGCPHYS32 GCPhysAcpi1, RTGCPHYS32 GCPhysAcpi2, RTGCPHYS32 GCPhysFacs, RTGCPHYS GCPhysDsdt)
|
---|
[37444] | 2165 | {
|
---|
| 2166 | ACPITBLFADT fadt;
|
---|
| 2167 |
|
---|
| 2168 | /* First the ACPI version 2+ version of the structure. */
|
---|
| 2169 | memset(&fadt, 0, sizeof(fadt));
|
---|
[40019] | 2170 | acpiPrepareHeader(pThis, &fadt.header, "FACP", sizeof(fadt), 4);
|
---|
[37444] | 2171 | fadt.u32FACS = RT_H2LE_U32(GCPhysFacs);
|
---|
| 2172 | fadt.u32DSDT = RT_H2LE_U32(GCPhysDsdt);
|
---|
| 2173 | fadt.u8IntModel = 0; /* dropped from the ACPI 2.0 spec. */
|
---|
| 2174 | fadt.u8PreferredPMProfile = 0; /* unspecified */
|
---|
| 2175 | fadt.u16SCIInt = RT_H2LE_U16(SCI_INT);
|
---|
| 2176 | fadt.u32SMICmd = RT_H2LE_U32(SMI_CMD);
|
---|
| 2177 | fadt.u8AcpiEnable = ACPI_ENABLE;
|
---|
| 2178 | fadt.u8AcpiDisable = ACPI_DISABLE;
|
---|
| 2179 | fadt.u8S4BIOSReq = 0;
|
---|
| 2180 | fadt.u8PStateCnt = 0;
|
---|
[37446] | 2181 | fadt.u32PM1aEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
|
---|
| 2182 | fadt.u32PM1bEVTBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
|
---|
| 2183 | fadt.u32PM1aCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
|
---|
| 2184 | fadt.u32PM1bCTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
|
---|
| 2185 | fadt.u32PM2CTLBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
|
---|
| 2186 | fadt.u32PMTMRBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM_TMR_OFFSET));
|
---|
| 2187 | fadt.u32GPE0BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE0_OFFSET));
|
---|
| 2188 | fadt.u32GPE1BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE1_OFFSET));
|
---|
[37444] | 2189 | fadt.u8PM1EVTLEN = 4;
|
---|
| 2190 | fadt.u8PM1CTLLEN = 2;
|
---|
| 2191 | fadt.u8PM2CTLLEN = 0;
|
---|
| 2192 | fadt.u8PMTMLEN = 4;
|
---|
| 2193 | fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
|
---|
| 2194 | fadt.u8GPE1BLKLEN = GPE1_BLK_LEN;
|
---|
| 2195 | fadt.u8GPE1BASE = GPE1_BASE;
|
---|
| 2196 | fadt.u8CSTCNT = 0;
|
---|
| 2197 | fadt.u16PLVL2LAT = RT_H2LE_U16(P_LVL2_LAT);
|
---|
| 2198 | fadt.u16PLVL3LAT = RT_H2LE_U16(P_LVL3_LAT);
|
---|
| 2199 | fadt.u16FlushSize = RT_H2LE_U16(FLUSH_SIZE);
|
---|
| 2200 | fadt.u16FlushStride = RT_H2LE_U16(FLUSH_STRIDE);
|
---|
| 2201 | fadt.u8DutyOffset = 0;
|
---|
| 2202 | fadt.u8DutyWidth = 0;
|
---|
| 2203 | fadt.u8DayAlarm = 0;
|
---|
| 2204 | fadt.u8MonAlarm = 0;
|
---|
| 2205 | fadt.u8Century = 0;
|
---|
| 2206 | fadt.u16IAPCBOOTARCH = RT_H2LE_U16(IAPC_BOOT_ARCH_LEGACY_DEV | IAPC_BOOT_ARCH_8042);
|
---|
| 2207 | /** @note WBINVD is required for ACPI versions newer than 1.0 */
|
---|
| 2208 | fadt.u32Flags = RT_H2LE_U32( FADT_FL_WBINVD
|
---|
| 2209 | | FADT_FL_FIX_RTC
|
---|
| 2210 | | FADT_FL_TMR_VAL_EXT
|
---|
| 2211 | | FADT_FL_RESET_REG_SUP);
|
---|
| 2212 |
|
---|
| 2213 | /* We have to force physical APIC mode or Linux can't use more than 8 CPUs */
|
---|
[37446] | 2214 | if (pThis->fCpuHotPlug)
|
---|
[37444] | 2215 | fadt.u32Flags |= RT_H2LE_U32(FADT_FL_FORCE_APIC_PHYS_DEST_MODE);
|
---|
| 2216 |
|
---|
| 2217 | acpiWriteGenericAddr(&fadt.ResetReg, 1, 8, 0, 1, ACPI_RESET_BLK);
|
---|
| 2218 | fadt.u8ResetVal = ACPI_RESET_REG_VAL;
|
---|
| 2219 | fadt.u64XFACS = RT_H2LE_U64((uint64_t)GCPhysFacs);
|
---|
| 2220 | fadt.u64XDSDT = RT_H2LE_U64((uint64_t)GCPhysDsdt);
|
---|
[37446] | 2221 | acpiWriteGenericAddr(&fadt.X_PM1aEVTBLK, 1, 32, 0, 2, acpiCalcPmPort(pThis, PM1a_EVT_OFFSET));
|
---|
| 2222 | acpiWriteGenericAddr(&fadt.X_PM1bEVTBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_EVT_OFFSET));
|
---|
| 2223 | acpiWriteGenericAddr(&fadt.X_PM1aCTLBLK, 1, 16, 0, 2, acpiCalcPmPort(pThis, PM1a_CTL_OFFSET));
|
---|
| 2224 | acpiWriteGenericAddr(&fadt.X_PM1bCTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM1b_CTL_OFFSET));
|
---|
| 2225 | acpiWriteGenericAddr(&fadt.X_PM2CTLBLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, PM2_CTL_OFFSET));
|
---|
| 2226 | acpiWriteGenericAddr(&fadt.X_PMTMRBLK, 1, 32, 0, 3, acpiCalcPmPort(pThis, PM_TMR_OFFSET));
|
---|
| 2227 | acpiWriteGenericAddr(&fadt.X_GPE0BLK, 1, 16, 0, 1, acpiCalcPmPort(pThis, GPE0_OFFSET));
|
---|
| 2228 | acpiWriteGenericAddr(&fadt.X_GPE1BLK, 0, 0, 0, 0, acpiCalcPmPort(pThis, GPE1_OFFSET));
|
---|
[37444] | 2229 | fadt.header.u8Checksum = acpiChecksum(&fadt, sizeof(fadt));
|
---|
[37446] | 2230 | acpiPhyscpy(pThis, GCPhysAcpi2, &fadt, sizeof(fadt));
|
---|
[37444] | 2231 |
|
---|
| 2232 | /* Now the ACPI 1.0 version. */
|
---|
| 2233 | fadt.header.u32Length = ACPITBLFADT_VERSION1_SIZE;
|
---|
| 2234 | fadt.u8IntModel = INT_MODEL_DUAL_PIC;
|
---|
| 2235 | fadt.header.u8Checksum = 0; /* Must be zeroed before recalculating checksum! */
|
---|
| 2236 | fadt.header.u8Checksum = acpiChecksum(&fadt, ACPITBLFADT_VERSION1_SIZE);
|
---|
[37446] | 2237 | acpiPhyscpy(pThis, GCPhysAcpi1, &fadt, ACPITBLFADT_VERSION1_SIZE);
|
---|
[37444] | 2238 | }
|
---|
| 2239 |
|
---|
| 2240 | /**
|
---|
| 2241 | * Plant the root System Description Table.
|
---|
| 2242 | *
|
---|
| 2243 | * The RSDT and XSDT tables are basically identical. The only difference is 32
|
---|
| 2244 | * vs 64 bits addresses for description headers. RSDT is for ACPI 1.0. XSDT for
|
---|
| 2245 | * ACPI 2.0 and up.
|
---|
| 2246 | */
|
---|
[37446] | 2247 | static int acpiSetupRSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
|
---|
[37444] | 2248 | {
|
---|
| 2249 | ACPITBLRSDT *rsdt;
|
---|
| 2250 | const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(rsdt->u32Entry[0]);
|
---|
| 2251 |
|
---|
| 2252 | rsdt = (ACPITBLRSDT*)RTMemAllocZ(size);
|
---|
| 2253 | if (!rsdt)
|
---|
[37446] | 2254 | return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_NO_TMP_MEMORY, N_("Cannot allocate RSDT"));
|
---|
[37444] | 2255 |
|
---|
[40019] | 2256 | acpiPrepareHeader(pThis, &rsdt->header, "RSDT", (uint32_t)size, 1);
|
---|
[37444] | 2257 | for (unsigned int i = 0; i < nb_entries; ++i)
|
---|
| 2258 | {
|
---|
| 2259 | rsdt->u32Entry[i] = RT_H2LE_U32(addrs[i]);
|
---|
| 2260 | Log(("Setup RSDT: [%d] = %x\n", i, rsdt->u32Entry[i]));
|
---|
| 2261 | }
|
---|
| 2262 | rsdt->header.u8Checksum = acpiChecksum(rsdt, size);
|
---|
[37446] | 2263 | acpiPhyscpy(pThis, addr, rsdt, size);
|
---|
[37444] | 2264 | RTMemFree(rsdt);
|
---|
| 2265 | return VINF_SUCCESS;
|
---|
| 2266 | }
|
---|
| 2267 |
|
---|
| 2268 | /**
|
---|
| 2269 | * Plant the Extended System Description Table.
|
---|
| 2270 | */
|
---|
[37446] | 2271 | static int acpiSetupXSDT(ACPIState *pThis, RTGCPHYS32 addr, unsigned int nb_entries, uint32_t *addrs)
|
---|
[37444] | 2272 | {
|
---|
| 2273 | ACPITBLXSDT *xsdt;
|
---|
| 2274 | const size_t size = sizeof(ACPITBLHEADER) + nb_entries * sizeof(xsdt->u64Entry[0]);
|
---|
| 2275 |
|
---|
| 2276 | xsdt = (ACPITBLXSDT*)RTMemAllocZ(size);
|
---|
| 2277 | if (!xsdt)
|
---|
| 2278 | return VERR_NO_TMP_MEMORY;
|
---|
| 2279 |
|
---|
[40019] | 2280 | acpiPrepareHeader(pThis, &xsdt->header, "XSDT", (uint32_t)size, 1 /* according to ACPI 3.0 specs */);
|
---|
| 2281 |
|
---|
| 2282 | if (pThis->fUseCust)
|
---|
| 2283 | memcpy(xsdt->header.au8OemTabId, pThis->au8OemTabId, 8);
|
---|
| 2284 |
|
---|
[37444] | 2285 | for (unsigned int i = 0; i < nb_entries; ++i)
|
---|
| 2286 | {
|
---|
| 2287 | xsdt->u64Entry[i] = RT_H2LE_U64((uint64_t)addrs[i]);
|
---|
| 2288 | Log(("Setup XSDT: [%d] = %RX64\n", i, xsdt->u64Entry[i]));
|
---|
| 2289 | }
|
---|
| 2290 | xsdt->header.u8Checksum = acpiChecksum(xsdt, size);
|
---|
[37446] | 2291 | acpiPhyscpy(pThis, addr, xsdt, size);
|
---|
[37444] | 2292 | RTMemFree(xsdt);
|
---|
| 2293 | return VINF_SUCCESS;
|
---|
| 2294 | }
|
---|
| 2295 |
|
---|
| 2296 | /**
|
---|
| 2297 | * Plant the Root System Description Pointer (RSDP).
|
---|
| 2298 | */
|
---|
[40019] | 2299 | static void acpiSetupRSDP(ACPIState *pThis, ACPITBLRSDP *rsdp, RTGCPHYS32 GCPhysRsdt, RTGCPHYS GCPhysXsdt)
|
---|
[37444] | 2300 | {
|
---|
| 2301 | memset(rsdp, 0, sizeof(*rsdp));
|
---|
| 2302 |
|
---|
| 2303 | /* ACPI 1.0 part (RSDT */
|
---|
| 2304 | memcpy(rsdp->au8Signature, "RSD PTR ", 8);
|
---|
[40019] | 2305 | memcpy(rsdp->au8OemId, pThis->au8OemId, 6);
|
---|
[37444] | 2306 | rsdp->u8Revision = ACPI_REVISION;
|
---|
| 2307 | rsdp->u32RSDT = RT_H2LE_U32(GCPhysRsdt);
|
---|
| 2308 | rsdp->u8Checksum = acpiChecksum(rsdp, RT_OFFSETOF(ACPITBLRSDP, u32Length));
|
---|
| 2309 |
|
---|
| 2310 | /* ACPI 2.0 part (XSDT) */
|
---|
| 2311 | rsdp->u32Length = RT_H2LE_U32(sizeof(ACPITBLRSDP));
|
---|
| 2312 | rsdp->u64XSDT = RT_H2LE_U64(GCPhysXsdt);
|
---|
| 2313 | rsdp->u8ExtChecksum = acpiChecksum(rsdp, sizeof(ACPITBLRSDP));
|
---|
| 2314 | }
|
---|
| 2315 |
|
---|
| 2316 | /**
|
---|
| 2317 | * Plant the Multiple APIC Description Table (MADT).
|
---|
| 2318 | *
|
---|
| 2319 | * @note APIC without IO-APIC hangs Windows Vista therefore we setup both.
|
---|
| 2320 | *
|
---|
| 2321 | * @todo All hardcoded, should set this up based on the actual VM config!!!!!
|
---|
| 2322 | */
|
---|
[37446] | 2323 | static void acpiSetupMADT(ACPIState *pThis, RTGCPHYS32 addr)
|
---|
[37444] | 2324 | {
|
---|
[37446] | 2325 | uint16_t cpus = pThis->cCpus;
|
---|
[37444] | 2326 | AcpiTableMADT madt(cpus, NUMBER_OF_IRQ_SOURCE_OVERRIDES);
|
---|
| 2327 |
|
---|
[40019] | 2328 | acpiPrepareHeader(pThis, madt.header_addr(), "APIC", madt.size(), 2);
|
---|
[37444] | 2329 |
|
---|
| 2330 | *madt.u32LAPIC_addr() = RT_H2LE_U32(0xfee00000);
|
---|
| 2331 | *madt.u32Flags_addr() = RT_H2LE_U32(PCAT_COMPAT);
|
---|
| 2332 |
|
---|
| 2333 | /* LAPICs records */
|
---|
| 2334 | ACPITBLLAPIC* lapic = madt.LApics_addr();
|
---|
| 2335 | for (uint16_t i = 0; i < cpus; i++)
|
---|
| 2336 | {
|
---|
| 2337 | lapic->u8Type = 0;
|
---|
| 2338 | lapic->u8Length = sizeof(ACPITBLLAPIC);
|
---|
| 2339 | lapic->u8ProcId = i;
|
---|
| 2340 | /** Must match numbering convention in MPTABLES */
|
---|
| 2341 | lapic->u8ApicId = i;
|
---|
[37446] | 2342 | lapic->u32Flags = VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, i) ? RT_H2LE_U32(LAPIC_ENABLED) : 0;
|
---|
[37444] | 2343 | lapic++;
|
---|
| 2344 | }
|
---|
| 2345 |
|
---|
| 2346 | /* IO-APIC record */
|
---|
| 2347 | ACPITBLIOAPIC* ioapic = madt.IOApic_addr();
|
---|
| 2348 | ioapic->u8Type = 1;
|
---|
| 2349 | ioapic->u8Length = sizeof(ACPITBLIOAPIC);
|
---|
| 2350 | /** Must match MP tables ID */
|
---|
| 2351 | ioapic->u8IOApicId = cpus;
|
---|
| 2352 | ioapic->u8Reserved = 0;
|
---|
| 2353 | ioapic->u32Address = RT_H2LE_U32(0xfec00000);
|
---|
| 2354 | ioapic->u32GSIB = RT_H2LE_U32(0);
|
---|
| 2355 |
|
---|
| 2356 | /* Interrupt Source Overrides */
|
---|
| 2357 | /* Flags:
|
---|
| 2358 | bits[3:2]:
|
---|
| 2359 | 00 conforms to the bus
|
---|
| 2360 | 01 edge-triggered
|
---|
| 2361 | 10 reserved
|
---|
| 2362 | 11 level-triggered
|
---|
| 2363 | bits[1:0]
|
---|
| 2364 | 00 conforms to the bus
|
---|
| 2365 | 01 active-high
|
---|
| 2366 | 10 reserved
|
---|
| 2367 | 11 active-low */
|
---|
| 2368 | /* If changing, also update PDMIsaSetIrq() and MPS */
|
---|
| 2369 | ACPITBLISO* isos = madt.ISO_addr();
|
---|
| 2370 | /* Timer interrupt rule IRQ0 to GSI2 */
|
---|
| 2371 | isos[0].u8Type = 2;
|
---|
| 2372 | isos[0].u8Length = sizeof(ACPITBLISO);
|
---|
| 2373 | isos[0].u8Bus = 0; /* Must be 0 */
|
---|
| 2374 | isos[0].u8Source = 0; /* IRQ0 */
|
---|
| 2375 | isos[0].u32GSI = 2; /* connected to pin 2 */
|
---|
| 2376 | isos[0].u16Flags = 0; /* conform to the bus */
|
---|
| 2377 |
|
---|
| 2378 | /* ACPI interrupt rule - IRQ9 to GSI9 */
|
---|
| 2379 | isos[1].u8Type = 2;
|
---|
| 2380 | isos[1].u8Length = sizeof(ACPITBLISO);
|
---|
| 2381 | isos[1].u8Bus = 0; /* Must be 0 */
|
---|
| 2382 | isos[1].u8Source = 9; /* IRQ9 */
|
---|
| 2383 | isos[1].u32GSI = 9; /* connected to pin 9 */
|
---|
| 2384 | isos[1].u16Flags = 0xd; /* active high, level triggered */
|
---|
| 2385 | Assert(NUMBER_OF_IRQ_SOURCE_OVERRIDES == 2);
|
---|
| 2386 |
|
---|
| 2387 | madt.header_addr()->u8Checksum = acpiChecksum(madt.data(), madt.size());
|
---|
[37446] | 2388 | acpiPhyscpy(pThis, addr, madt.data(), madt.size());
|
---|
[37444] | 2389 | }
|
---|
| 2390 |
|
---|
| 2391 | /**
|
---|
| 2392 | * Plant the High Performance Event Timer (HPET) descriptor.
|
---|
| 2393 | */
|
---|
[37446] | 2394 | static void acpiSetupHPET(ACPIState *pThis, RTGCPHYS32 addr)
|
---|
[37444] | 2395 | {
|
---|
| 2396 | ACPITBLHPET hpet;
|
---|
| 2397 |
|
---|
| 2398 | memset(&hpet, 0, sizeof(hpet));
|
---|
| 2399 |
|
---|
[40019] | 2400 | acpiPrepareHeader(pThis, &hpet.aHeader, "HPET", sizeof(hpet), 1);
|
---|
[37444] | 2401 | /* Keep base address consistent with appropriate DSDT entry (vbox.dsl) */
|
---|
| 2402 | acpiWriteGenericAddr(&hpet.HpetAddr,
|
---|
| 2403 | 0 /* Memory address space */,
|
---|
| 2404 | 64 /* Register bit width */,
|
---|
| 2405 | 0 /* Bit offset */,
|
---|
| 2406 | 0, /* Register access size, is it correct? */
|
---|
| 2407 | 0xfed00000 /* Address */);
|
---|
| 2408 |
|
---|
| 2409 | hpet.u32Id = 0x8086a201; /* must match what HPET ID returns, is it correct ? */
|
---|
| 2410 | hpet.u32Number = 0;
|
---|
| 2411 | hpet.u32MinTick = 4096;
|
---|
| 2412 | hpet.u8Attributes = 0;
|
---|
| 2413 |
|
---|
| 2414 | hpet.aHeader.u8Checksum = acpiChecksum(&hpet, sizeof(hpet));
|
---|
| 2415 |
|
---|
[37446] | 2416 | acpiPhyscpy(pThis, addr, (const uint8_t *)&hpet, sizeof(hpet));
|
---|
[37444] | 2417 | }
|
---|
| 2418 |
|
---|
| 2419 |
|
---|
[40019] | 2420 | /** Custom Description Table */
|
---|
| 2421 | static void acpiSetupCUST(ACPIState *pThis, RTGCPHYS32 addr)
|
---|
| 2422 | {
|
---|
| 2423 | ACPITBLCUST cust;
|
---|
| 2424 |
|
---|
| 2425 | /* First the ACPI version 1 version of the structure. */
|
---|
| 2426 | memset(&cust, 0, sizeof(cust));
|
---|
| 2427 | acpiPrepareHeader(pThis, &cust.header, "CUST", sizeof(cust), 1);
|
---|
| 2428 |
|
---|
| 2429 | memcpy(cust.header.au8OemTabId, pThis->au8OemTabId, 8);
|
---|
| 2430 | cust.header.u32OemRevision = RT_H2LE_U32(pThis->u32OemRevision);
|
---|
| 2431 | cust.header.u8Checksum = acpiChecksum((uint8_t *)&cust, sizeof(cust));
|
---|
| 2432 |
|
---|
| 2433 | acpiPhyscpy(pThis, addr, pThis->pu8CustBin, pThis->cbCustBin);
|
---|
| 2434 | }
|
---|
| 2435 |
|
---|
[37444] | 2436 | /**
|
---|
| 2437 | * Used by acpiPlantTables to plant a MMCONFIG PCI config space access (MCFG)
|
---|
| 2438 | * descriptor.
|
---|
| 2439 | *
|
---|
| 2440 | * @param pThis The ACPI instance.
|
---|
| 2441 | * @param GCPhysDst Where to plant it.
|
---|
| 2442 | */
|
---|
| 2443 | static void acpiSetupMCFG(ACPIState *pThis, RTGCPHYS32 GCPhysDst)
|
---|
| 2444 | {
|
---|
| 2445 | struct
|
---|
| 2446 | {
|
---|
| 2447 | ACPITBLMCFG hdr;
|
---|
| 2448 | ACPITBLMCFGENTRY entry;
|
---|
| 2449 | } tbl;
|
---|
| 2450 | uint8_t u8StartBus = 0;
|
---|
| 2451 | uint8_t u8EndBus = (pThis->u64PciConfigMMioLength >> 20) - 1;
|
---|
| 2452 |
|
---|
| 2453 | RT_ZERO(tbl);
|
---|
| 2454 |
|
---|
[40019] | 2455 | acpiPrepareHeader(pThis, &tbl.hdr.aHeader, "MCFG", sizeof(tbl), 1);
|
---|
[37444] | 2456 | tbl.entry.u64BaseAddress = pThis->u64PciConfigMMioAddress;
|
---|
| 2457 | tbl.entry.u8StartBus = u8StartBus;
|
---|
| 2458 | tbl.entry.u8EndBus = u8EndBus;
|
---|
| 2459 | // u16PciSegmentGroup must match _SEG in ACPI table
|
---|
| 2460 |
|
---|
| 2461 | tbl.hdr.aHeader.u8Checksum = acpiChecksum(&tbl, sizeof(tbl));
|
---|
| 2462 |
|
---|
| 2463 | acpiPhyscpy(pThis, GCPhysDst, (const uint8_t *)&tbl, sizeof(tbl));
|
---|
| 2464 | }
|
---|
| 2465 |
|
---|
| 2466 | /**
|
---|
| 2467 | * Used by acpiPlantTables and acpiConstruct.
|
---|
| 2468 | *
|
---|
| 2469 | * @returns Guest memory address.
|
---|
| 2470 | */
|
---|
| 2471 | static uint32_t find_rsdp_space(void)
|
---|
| 2472 | {
|
---|
| 2473 | return 0xe0000;
|
---|
| 2474 | }
|
---|
| 2475 |
|
---|
| 2476 | /**
|
---|
| 2477 | * Create the ACPI tables in guest memory.
|
---|
| 2478 | */
|
---|
[37446] | 2479 | static int acpiPlantTables(ACPIState *pThis)
|
---|
[1] | 2480 | {
|
---|
[7072] | 2481 | int rc;
|
---|
[26057] | 2482 | RTGCPHYS32 GCPhysCur, GCPhysRsdt, GCPhysXsdt, GCPhysFadtAcpi1, GCPhysFadtAcpi2, GCPhysFacs, GCPhysDsdt;
|
---|
[37444] | 2483 | RTGCPHYS32 GCPhysHpet = 0;
|
---|
| 2484 | RTGCPHYS32 GCPhysApic = 0;
|
---|
| 2485 | RTGCPHYS32 GCPhysSsdt = 0;
|
---|
| 2486 | RTGCPHYS32 GCPhysMcfg = 0;
|
---|
[40019] | 2487 | RTGCPHYS32 GCPhysCust = 0;
|
---|
[7072] | 2488 | uint32_t addend = 0;
|
---|
[34425] | 2489 | RTGCPHYS32 aGCPhysRsdt[8];
|
---|
| 2490 | RTGCPHYS32 aGCPhysXsdt[8];
|
---|
[37444] | 2491 | uint32_t cAddr;
|
---|
| 2492 | uint32_t iMadt = 0;
|
---|
| 2493 | uint32_t iHpet = 0;
|
---|
| 2494 | uint32_t iSsdt = 0;
|
---|
| 2495 | uint32_t iMcfg = 0;
|
---|
[40019] | 2496 | uint32_t iCust = 0;
|
---|
[26057] | 2497 | size_t cbRsdt = sizeof(ACPITBLHEADER);
|
---|
| 2498 | size_t cbXsdt = sizeof(ACPITBLHEADER);
|
---|
[1] | 2499 |
|
---|
[26057] | 2500 | cAddr = 1; /* FADT */
|
---|
[37446] | 2501 | if (pThis->u8UseIOApic)
|
---|
[26057] | 2502 | iMadt = cAddr++; /* MADT */
|
---|
[1] | 2503 |
|
---|
[37446] | 2504 | if (pThis->fUseHpet)
|
---|
[26057] | 2505 | iHpet = cAddr++; /* HPET */
|
---|
[25928] | 2506 |
|
---|
[37446] | 2507 | if (pThis->fUseMcfg)
|
---|
[32591] | 2508 | iMcfg = cAddr++; /* MCFG */
|
---|
| 2509 |
|
---|
[40019] | 2510 | if (pThis->fUseCust)
|
---|
| 2511 | iCust = cAddr++; /* CUST */
|
---|
| 2512 |
|
---|
[26183] | 2513 | iSsdt = cAddr++; /* SSDT */
|
---|
| 2514 |
|
---|
[34425] | 2515 | Assert(cAddr < RT_ELEMENTS(aGCPhysRsdt));
|
---|
| 2516 | Assert(cAddr < RT_ELEMENTS(aGCPhysXsdt));
|
---|
| 2517 |
|
---|
[26057] | 2518 | cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
|
---|
| 2519 | cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
|
---|
[1] | 2520 |
|
---|
[37446] | 2521 | rc = CFGMR3QueryU64(pThis->pDevIns->pCfg, "RamSize", &pThis->u64RamSize);
|
---|
[17572] | 2522 | if (RT_FAILURE(rc))
|
---|
[37446] | 2523 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
[26057] | 2524 | N_("Configuration error: Querying \"RamSize\" as integer failed"));
|
---|
[1] | 2525 |
|
---|
[17542] | 2526 | uint32_t cbRamHole;
|
---|
[37446] | 2527 | rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
|
---|
[17572] | 2528 | if (RT_FAILURE(rc))
|
---|
[37446] | 2529 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
[17572] | 2530 | N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
|
---|
[17590] | 2531 |
|
---|
| 2532 | /*
|
---|
[26057] | 2533 | * Calculate the sizes for the high and low regions.
|
---|
[17590] | 2534 | */
|
---|
[17542] | 2535 | const uint64_t offRamHole = _4G - cbRamHole;
|
---|
[37446] | 2536 | pThis->cbRamHigh = offRamHole < pThis->u64RamSize ? pThis->u64RamSize - offRamHole : 0;
|
---|
| 2537 | uint64_t cbRamLow = offRamHole < pThis->u64RamSize ? offRamHole : pThis->u64RamSize;
|
---|
[17590] | 2538 | if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
|
---|
| 2539 | {
|
---|
[17597] | 2540 | /* Note: This is also enforced by DevPcBios.cpp. */
|
---|
[17590] | 2541 | LogRel(("DevACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
|
---|
| 2542 | cbRamLow = UINT32_C(0xffe00000);
|
---|
| 2543 | }
|
---|
[37446] | 2544 | pThis->cbRamLow = (uint32_t)cbRamLow;
|
---|
[17542] | 2545 |
|
---|
[26057] | 2546 | GCPhysCur = 0;
|
---|
| 2547 | GCPhysRsdt = GCPhysCur;
|
---|
[25928] | 2548 |
|
---|
[26057] | 2549 | GCPhysCur = RT_ALIGN_32(GCPhysCur + cbRsdt, 16);
|
---|
| 2550 | GCPhysXsdt = GCPhysCur;
|
---|
[25928] | 2551 |
|
---|
[26057] | 2552 | GCPhysCur = RT_ALIGN_32(GCPhysCur + cbXsdt, 16);
|
---|
| 2553 | GCPhysFadtAcpi1 = GCPhysCur;
|
---|
[25928] | 2554 |
|
---|
[26057] | 2555 | GCPhysCur = RT_ALIGN_32(GCPhysCur + ACPITBLFADT_VERSION1_SIZE, 16);
|
---|
| 2556 | GCPhysFadtAcpi2 = GCPhysCur;
|
---|
[25928] | 2557 |
|
---|
[26057] | 2558 | GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFADT), 64);
|
---|
| 2559 | GCPhysFacs = GCPhysCur;
|
---|
[25928] | 2560 |
|
---|
[26057] | 2561 | GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLFACS), 16);
|
---|
[37446] | 2562 | if (pThis->u8UseIOApic)
|
---|
[1] | 2563 | {
|
---|
[26057] | 2564 | GCPhysApic = GCPhysCur;
|
---|
[37446] | 2565 | GCPhysCur = RT_ALIGN_32(GCPhysCur + AcpiTableMADT::sizeFor(pThis, NUMBER_OF_IRQ_SOURCE_OVERRIDES), 16);
|
---|
[1] | 2566 | }
|
---|
[37446] | 2567 | if (pThis->fUseHpet)
|
---|
[1] | 2568 | {
|
---|
[26057] | 2569 | GCPhysHpet = GCPhysCur;
|
---|
| 2570 | GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLHPET), 16);
|
---|
[1] | 2571 | }
|
---|
[37446] | 2572 | if (pThis->fUseMcfg)
|
---|
[32591] | 2573 | {
|
---|
| 2574 | GCPhysMcfg = GCPhysCur;
|
---|
| 2575 | /* Assume one entry */
|
---|
| 2576 | GCPhysCur = RT_ALIGN_32(GCPhysCur + sizeof(ACPITBLMCFG) + sizeof(ACPITBLMCFGENTRY), 16);
|
---|
| 2577 | }
|
---|
[40019] | 2578 | if (pThis->fUseCust)
|
---|
| 2579 | {
|
---|
| 2580 | GCPhysCust = GCPhysCur;
|
---|
| 2581 | GCPhysCur = RT_ALIGN_32(GCPhysCur + pThis->cbCustBin, 16);
|
---|
| 2582 | }
|
---|
[26183] | 2583 |
|
---|
[37444] | 2584 | void *pvSsdtCode = NULL;
|
---|
[26183] | 2585 | size_t cbSsdtSize = 0;
|
---|
[37446] | 2586 | rc = acpiPrepareSsdt(pThis->pDevIns, &pvSsdtCode, &cbSsdtSize);
|
---|
[26183] | 2587 | if (RT_FAILURE(rc))
|
---|
| 2588 | return rc;
|
---|
| 2589 |
|
---|
| 2590 | GCPhysSsdt = GCPhysCur;
|
---|
| 2591 | GCPhysCur = RT_ALIGN_32(GCPhysCur + cbSsdtSize, 16);
|
---|
| 2592 |
|
---|
[26057] | 2593 | GCPhysDsdt = GCPhysCur;
|
---|
[1] | 2594 |
|
---|
[37444] | 2595 | void *pvDsdtCode = NULL;
|
---|
[26057] | 2596 | size_t cbDsdtSize = 0;
|
---|
[37446] | 2597 | rc = acpiPrepareDsdt(pThis->pDevIns, &pvDsdtCode, &cbDsdtSize);
|
---|
[20400] | 2598 | if (RT_FAILURE(rc))
|
---|
| 2599 | return rc;
|
---|
| 2600 |
|
---|
[26057] | 2601 | GCPhysCur = RT_ALIGN_32(GCPhysCur + cbDsdtSize, 16);
|
---|
[26183] | 2602 |
|
---|
[26057] | 2603 | if (GCPhysCur > 0x10000)
|
---|
[37446] | 2604 | return PDMDEV_SET_ERROR(pThis->pDevIns, VERR_TOO_MUCH_DATA,
|
---|
[26057] | 2605 | N_("Error: ACPI tables bigger than 64KB"));
|
---|
[1] | 2606 |
|
---|
| 2607 | Log(("RSDP 0x%08X\n", find_rsdp_space()));
|
---|
[37446] | 2608 | addend = pThis->cbRamLow - 0x10000;
|
---|
[26057] | 2609 | Log(("RSDT 0x%08X XSDT 0x%08X\n", GCPhysRsdt + addend, GCPhysXsdt + addend));
|
---|
| 2610 | Log(("FACS 0x%08X FADT (1.0) 0x%08X, FADT (2+) 0x%08X\n", GCPhysFacs + addend, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend));
|
---|
| 2611 | Log(("DSDT 0x%08X", GCPhysDsdt + addend));
|
---|
[37446] | 2612 | if (pThis->u8UseIOApic)
|
---|
[26057] | 2613 | Log((" MADT 0x%08X", GCPhysApic + addend));
|
---|
[37446] | 2614 | if (pThis->fUseHpet)
|
---|
[26057] | 2615 | Log((" HPET 0x%08X", GCPhysHpet + addend));
|
---|
[37446] | 2616 | if (pThis->fUseMcfg)
|
---|
[32591] | 2617 | Log((" MCFG 0x%08X", GCPhysMcfg + addend));
|
---|
[40019] | 2618 | if (pThis->fUseCust)
|
---|
| 2619 | Log((" CUST 0x%08X", GCPhysCust + addend));
|
---|
[26183] | 2620 | Log((" SSDT 0x%08X", GCPhysSsdt + addend));
|
---|
[26057] | 2621 | Log(("\n"));
|
---|
| 2622 |
|
---|
[40019] | 2623 | acpiSetupRSDP(pThis, (ACPITBLRSDP *)pThis->au8RSDPPage, GCPhysRsdt + addend, GCPhysXsdt + addend);
|
---|
[37446] | 2624 | acpiSetupDSDT(pThis, GCPhysDsdt + addend, pvDsdtCode, cbDsdtSize);
|
---|
| 2625 | acpiCleanupDsdt(pThis->pDevIns, pvDsdtCode);
|
---|
| 2626 | acpiSetupFACS(pThis, GCPhysFacs + addend);
|
---|
| 2627 | acpiSetupFADT(pThis, GCPhysFadtAcpi1 + addend, GCPhysFadtAcpi2 + addend, GCPhysFacs + addend, GCPhysDsdt + addend);
|
---|
[1] | 2628 |
|
---|
[26057] | 2629 | aGCPhysRsdt[0] = GCPhysFadtAcpi1 + addend;
|
---|
| 2630 | aGCPhysXsdt[0] = GCPhysFadtAcpi2 + addend;
|
---|
[37446] | 2631 | if (pThis->u8UseIOApic)
|
---|
[1] | 2632 | {
|
---|
[37446] | 2633 | acpiSetupMADT(pThis, GCPhysApic + addend);
|
---|
[26057] | 2634 | aGCPhysRsdt[iMadt] = GCPhysApic + addend;
|
---|
| 2635 | aGCPhysXsdt[iMadt] = GCPhysApic + addend;
|
---|
[1] | 2636 | }
|
---|
[37446] | 2637 | if (pThis->fUseHpet)
|
---|
[25928] | 2638 | {
|
---|
[37446] | 2639 | acpiSetupHPET(pThis, GCPhysHpet + addend);
|
---|
[26057] | 2640 | aGCPhysRsdt[iHpet] = GCPhysHpet + addend;
|
---|
| 2641 | aGCPhysXsdt[iHpet] = GCPhysHpet + addend;
|
---|
[25928] | 2642 | }
|
---|
[37446] | 2643 | if (pThis->fUseMcfg)
|
---|
[32591] | 2644 | {
|
---|
[37446] | 2645 | acpiSetupMCFG(pThis, GCPhysMcfg + addend);
|
---|
[32591] | 2646 | aGCPhysRsdt[iMcfg] = GCPhysMcfg + addend;
|
---|
| 2647 | aGCPhysXsdt[iMcfg] = GCPhysMcfg + addend;
|
---|
| 2648 | }
|
---|
[40019] | 2649 | if (pThis->fUseCust)
|
---|
| 2650 | {
|
---|
| 2651 | acpiSetupCUST(pThis, GCPhysCust + addend);
|
---|
| 2652 | aGCPhysRsdt[iCust] = GCPhysCust + addend;
|
---|
| 2653 | aGCPhysXsdt[iCust] = GCPhysCust + addend;
|
---|
| 2654 | }
|
---|
[32591] | 2655 |
|
---|
[37446] | 2656 | acpiSetupSSDT(pThis, GCPhysSsdt + addend, pvSsdtCode, cbSsdtSize);
|
---|
| 2657 | acpiCleanupSsdt(pThis->pDevIns, pvSsdtCode);
|
---|
[26183] | 2658 | aGCPhysRsdt[iSsdt] = GCPhysSsdt + addend;
|
---|
| 2659 | aGCPhysXsdt[iSsdt] = GCPhysSsdt + addend;
|
---|
[1] | 2660 |
|
---|
[37446] | 2661 | rc = acpiSetupRSDT(pThis, GCPhysRsdt + addend, cAddr, aGCPhysRsdt);
|
---|
[11208] | 2662 | if (RT_FAILURE(rc))
|
---|
[1] | 2663 | return rc;
|
---|
[37446] | 2664 | return acpiSetupXSDT(pThis, GCPhysXsdt + addend, cAddr, aGCPhysXsdt);
|
---|
[1] | 2665 | }
|
---|
| 2666 |
|
---|
[37444] | 2667 | /**
|
---|
| 2668 | * @callback_method_impl{FNPCICONFIGREAD}
|
---|
| 2669 | */
|
---|
| 2670 | static DECLCALLBACK(uint32_t) acpiPciConfigRead(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb)
|
---|
[21855] | 2671 | {
|
---|
[21820] | 2672 | PPDMDEVINS pDevIns = pPciDev->pDevIns;
|
---|
[37444] | 2673 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
[21820] | 2674 |
|
---|
[21855] | 2675 | Log2(("acpi: PCI config read: 0x%x (%d)\n", Address, cb));
|
---|
[21820] | 2676 | return pThis->pfnAcpiPciConfigRead(pPciDev, Address, cb);
|
---|
| 2677 | }
|
---|
| 2678 |
|
---|
[37444] | 2679 | /**
|
---|
| 2680 | * @callback_method_impl{FNPCICONFIGWRITE}
|
---|
| 2681 | */
|
---|
| 2682 | static DECLCALLBACK(void) acpiPciConfigWrite(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb)
|
---|
[21820] | 2683 | {
|
---|
[21829] | 2684 | PPDMDEVINS pDevIns = pPciDev->pDevIns;
|
---|
| 2685 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
[21820] | 2686 |
|
---|
[21855] | 2687 | Log2(("acpi: PCI config write: 0x%x -> 0x%x (%d)\n", u32Value, Address, cb));
|
---|
[37444] | 2688 | DEVACPI_LOCK_R3(pThis);
|
---|
[34035] | 2689 |
|
---|
[34494] | 2690 | if (Address == VBOX_PCI_INTERRUPT_LINE)
|
---|
[34035] | 2691 | {
|
---|
[34494] | 2692 | Log(("acpi: ignore interrupt line settings: %d, we'll use hardcoded value %d\n", u32Value, SCI_INT));
|
---|
| 2693 | u32Value = SCI_INT;
|
---|
[34035] | 2694 | }
|
---|
| 2695 |
|
---|
[21837] | 2696 | pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
|
---|
[21820] | 2697 |
|
---|
[21837] | 2698 | /* PMREGMISC written */
|
---|
[21820] | 2699 | if (Address == 0x80)
|
---|
| 2700 | {
|
---|
[21837] | 2701 | /* Check Power Management IO Space Enable (PMIOSE) bit */
|
---|
| 2702 | if (pPciDev->config[0x80] & 0x1)
|
---|
[21820] | 2703 | {
|
---|
[37444] | 2704 | RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
|
---|
| 2705 | NewIoPortBase &= 0xffc0;
|
---|
[21820] | 2706 |
|
---|
[37444] | 2707 | int rc = acpiUpdatePmHandlers(pThis, NewIoPortBase);
|
---|
[25226] | 2708 | AssertRC(rc);
|
---|
[21820] | 2709 | }
|
---|
| 2710 | }
|
---|
[37444] | 2711 |
|
---|
| 2712 | DEVACPI_UNLOCK(pThis);
|
---|
[21820] | 2713 | }
|
---|
| 2714 |
|
---|
[25817] | 2715 | /**
|
---|
| 2716 | * Attach a new CPU.
|
---|
| 2717 | *
|
---|
| 2718 | * @returns VBox status code.
|
---|
| 2719 | * @param pDevIns The device instance.
|
---|
| 2720 | * @param iLUN The logical unit which is being attached.
|
---|
| 2721 | * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
|
---|
| 2722 | *
|
---|
| 2723 | * @remarks This code path is not used during construction.
|
---|
| 2724 | */
|
---|
| 2725 | static DECLCALLBACK(int) acpiAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
|
---|
| 2726 | {
|
---|
[37446] | 2727 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
[25817] | 2728 | LogFlow(("acpiAttach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
|
---|
| 2729 |
|
---|
[25845] | 2730 | AssertMsgReturn(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
|
---|
| 2731 | ("Hot-plug flag is not set\n"),
|
---|
| 2732 | VERR_NOT_SUPPORTED);
|
---|
[25855] | 2733 | AssertReturn(iLUN < VMM_MAX_CPU_COUNT, VERR_PDM_NO_SUCH_LUN);
|
---|
[25845] | 2734 |
|
---|
[25817] | 2735 | /* Check if it was already attached */
|
---|
[37444] | 2736 | int rc = VINF_SUCCESS;
|
---|
[37446] | 2737 | DEVACPI_LOCK_R3(pThis);
|
---|
| 2738 | if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
|
---|
[37444] | 2739 | {
|
---|
| 2740 | PPDMIBASE IBaseTmp;
|
---|
[37446] | 2741 | rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->IBase, &IBaseTmp, "ACPI CPU");
|
---|
[37444] | 2742 | if (RT_SUCCESS(rc))
|
---|
| 2743 | {
|
---|
| 2744 | /* Enable the CPU */
|
---|
[37446] | 2745 | VMCPUSET_ADD(&pThis->CpuSetAttached, iLUN);
|
---|
[25817] | 2746 |
|
---|
[37444] | 2747 | /*
|
---|
| 2748 | * Lock the CPU because we don't know if the guest will use it or not.
|
---|
| 2749 | * Prevents ejection while the CPU is still used
|
---|
| 2750 | */
|
---|
[37446] | 2751 | VMCPUSET_ADD(&pThis->CpuSetLocked, iLUN);
|
---|
| 2752 | pThis->u32CpuEventType = CPU_EVENT_TYPE_ADD;
|
---|
| 2753 | pThis->u32CpuEvent = iLUN;
|
---|
[25817] | 2754 |
|
---|
[37444] | 2755 | /* Notify the guest */
|
---|
[37446] | 2756 | update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
|
---|
[37444] | 2757 | }
|
---|
[25817] | 2758 | }
|
---|
[37446] | 2759 | DEVACPI_UNLOCK(pThis);
|
---|
[25817] | 2760 | return rc;
|
---|
| 2761 | }
|
---|
| 2762 |
|
---|
| 2763 | /**
|
---|
| 2764 | * Detach notification.
|
---|
| 2765 | *
|
---|
| 2766 | * @param pDevIns The device instance.
|
---|
| 2767 | * @param iLUN The logical unit which is being detached.
|
---|
| 2768 | * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
|
---|
| 2769 | */
|
---|
| 2770 | static DECLCALLBACK(void) acpiDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
|
---|
| 2771 | {
|
---|
[37446] | 2772 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
[25817] | 2773 |
|
---|
| 2774 | LogFlow(("acpiDetach: pDevIns=%p iLUN=%u fFlags=%#x\n", pDevIns, iLUN, fFlags));
|
---|
| 2775 |
|
---|
[25845] | 2776 | AssertMsgReturnVoid(!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
|
---|
| 2777 | ("Hot-plug flag is not set\n"));
|
---|
| 2778 |
|
---|
[25817] | 2779 | /* Check if it was already detached */
|
---|
[37446] | 2780 | DEVACPI_LOCK_R3(pThis);
|
---|
| 2781 | if (VMCPUSET_IS_PRESENT(&pThis->CpuSetAttached, iLUN))
|
---|
[25817] | 2782 | {
|
---|
[37446] | 2783 | if (!VMCPUSET_IS_PRESENT(&pThis->CpuSetLocked, iLUN))
|
---|
[37444] | 2784 | {
|
---|
| 2785 | /* Disable the CPU */
|
---|
[37446] | 2786 | VMCPUSET_DEL(&pThis->CpuSetAttached, iLUN);
|
---|
| 2787 | pThis->u32CpuEventType = CPU_EVENT_TYPE_REMOVE;
|
---|
| 2788 | pThis->u32CpuEvent = iLUN;
|
---|
[25838] | 2789 |
|
---|
[37444] | 2790 | /* Notify the guest */
|
---|
[37446] | 2791 | update_gpe0(pThis, pThis->gpe0_sts | 0x2, pThis->gpe0_en);
|
---|
[37444] | 2792 | }
|
---|
| 2793 | else
|
---|
| 2794 | AssertMsgFailed(("CPU is still locked by the guest\n"));
|
---|
[25817] | 2795 | }
|
---|
[37446] | 2796 | DEVACPI_UNLOCK(pThis);
|
---|
[25817] | 2797 | }
|
---|
| 2798 |
|
---|
[32189] | 2799 | /**
|
---|
| 2800 | * @interface_method_impl{PDMDEVREG,pfnResume}
|
---|
| 2801 | */
|
---|
| 2802 | static DECLCALLBACK(void) acpiResume(PPDMDEVINS pDevIns)
|
---|
| 2803 | {
|
---|
| 2804 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
| 2805 | if (pThis->fSetWakeupOnResume)
|
---|
| 2806 | {
|
---|
| 2807 | Log(("acpiResume: setting WAK_STS\n"));
|
---|
| 2808 | pThis->fSetWakeupOnResume = false;
|
---|
| 2809 | pThis->pm1a_sts |= WAK_STS;
|
---|
| 2810 | }
|
---|
| 2811 | }
|
---|
| 2812 |
|
---|
| 2813 | /**
|
---|
| 2814 | * @interface_method_impl{PDMDEVREG,pfnReset}
|
---|
| 2815 | */
|
---|
[24078] | 2816 | static DECLCALLBACK(void) acpiReset(PPDMDEVINS pDevIns)
|
---|
| 2817 | {
|
---|
[37444] | 2818 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
[24078] | 2819 |
|
---|
[37526] | 2820 | TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
|
---|
[37444] | 2821 | pThis->pm1a_en = 0;
|
---|
| 2822 | pThis->pm1a_sts = 0;
|
---|
| 2823 | pThis->pm1a_ctl = 0;
|
---|
| 2824 | pThis->u64PmTimerInitial = TMTimerGet(pThis->pPmTimerR3);
|
---|
| 2825 | acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
|
---|
| 2826 | pThis->uBatteryIndex = 0;
|
---|
| 2827 | pThis->uSystemInfoIndex = 0;
|
---|
| 2828 | pThis->gpe0_en = 0;
|
---|
| 2829 | pThis->gpe0_sts = 0;
|
---|
| 2830 | pThis->uSleepState = 0;
|
---|
[37526] | 2831 | TMTimerUnlock(pThis->pPmTimerR3);
|
---|
[24078] | 2832 |
|
---|
| 2833 | /** @todo Should we really reset PM base? */
|
---|
[37444] | 2834 | acpiUpdatePmHandlers(pThis, PM_PORT_BASE);
|
---|
[24078] | 2835 |
|
---|
[37444] | 2836 | acpiPlantTables(pThis);
|
---|
[24078] | 2837 | }
|
---|
| 2838 |
|
---|
[1] | 2839 | /**
|
---|
[32189] | 2840 | * @interface_method_impl{PDMDEVREG,pfnRelocate}
|
---|
[24078] | 2841 | */
|
---|
| 2842 | static DECLCALLBACK(void) acpiRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
|
---|
| 2843 | {
|
---|
[37444] | 2844 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
| 2845 | pThis->pPmTimerRC = TMTimerRCPtr(pThis->pPmTimerR3);
|
---|
[39091] | 2846 | NOREF(offDelta);
|
---|
[24078] | 2847 | }
|
---|
| 2848 |
|
---|
| 2849 | /**
|
---|
[40019] | 2850 | * @interface_methid_impl{PDMDEVREG,pfnDestruct}
|
---|
| 2851 | */
|
---|
| 2852 | static DECLCALLBACK(int) acpiDestruct(PPDMDEVINS pDevIns)
|
---|
| 2853 | {
|
---|
| 2854 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
| 2855 | if (pThis->pu8CustBin)
|
---|
| 2856 | {
|
---|
| 2857 | MMR3HeapFree(pThis->pu8CustBin);
|
---|
| 2858 | pThis->pu8CustBin = NULL;
|
---|
| 2859 | }
|
---|
| 2860 | return VINF_SUCCESS;
|
---|
| 2861 | }
|
---|
| 2862 |
|
---|
| 2863 | /**
|
---|
[26160] | 2864 | * @interface_method_impl{PDMDEVREG,pfnConstruct}
|
---|
[1] | 2865 | */
|
---|
[26173] | 2866 | static DECLCALLBACK(int) acpiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
|
---|
[1] | 2867 | {
|
---|
[37446] | 2868 | ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
|
---|
[26001] | 2869 | PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
|
---|
[1] | 2870 |
|
---|
[37444] | 2871 | /*
|
---|
| 2872 | * Init data and set defaults.
|
---|
| 2873 | */
|
---|
| 2874 | /** @todo move more of the code up! */
|
---|
| 2875 |
|
---|
[37446] | 2876 | pThis->pDevIns = pDevIns;
|
---|
| 2877 | VMCPUSET_EMPTY(&pThis->CpuSetAttached);
|
---|
| 2878 | VMCPUSET_EMPTY(&pThis->CpuSetLocked);
|
---|
| 2879 | pThis->idCpuLockCheck = UINT32_C(0xffffffff);
|
---|
| 2880 | pThis->u32CpuEventType = 0;
|
---|
| 2881 | pThis->u32CpuEvent = UINT32_C(0xffffffff);
|
---|
| 2882 |
|
---|
| 2883 | /* The first CPU can't be attached/detached */
|
---|
| 2884 | VMCPUSET_ADD(&pThis->CpuSetAttached, 0);
|
---|
| 2885 | VMCPUSET_ADD(&pThis->CpuSetLocked, 0);
|
---|
| 2886 |
|
---|
| 2887 | /* IBase */
|
---|
| 2888 | pThis->IBase.pfnQueryInterface = acpiQueryInterface;
|
---|
| 2889 | /* IACPIPort */
|
---|
| 2890 | pThis->IACPIPort.pfnSleepButtonPress = acpiPort_SleepButtonPress;
|
---|
| 2891 | pThis->IACPIPort.pfnPowerButtonPress = acpiPort_PowerButtonPress;
|
---|
| 2892 | pThis->IACPIPort.pfnGetPowerButtonHandled = acpiPort_GetPowerButtonHandled;
|
---|
| 2893 | pThis->IACPIPort.pfnGetGuestEnteredACPIMode = acpiPort_GetGuestEnteredACPIMode;
|
---|
| 2894 | pThis->IACPIPort.pfnGetCpuStatus = acpiPort_GetCpuStatus;
|
---|
| 2895 |
|
---|
| 2896 | /* Set the default critical section to NOP (related to the PM timer). */
|
---|
[37466] | 2897 | int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
|
---|
[37444] | 2898 | AssertRCReturn(rc, rc);
|
---|
| 2899 |
|
---|
[37466] | 2900 | rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "acpi%u", iInstance);
|
---|
| 2901 | AssertRCReturn(rc, rc);
|
---|
| 2902 |
|
---|
[37444] | 2903 | /*
|
---|
| 2904 | * Validate and read the configuration.
|
---|
| 2905 | */
|
---|
[26173] | 2906 | if (!CFGMR3AreValuesValid(pCfg,
|
---|
[17572] | 2907 | "RamSize\0"
|
---|
| 2908 | "RamHoleSize\0"
|
---|
| 2909 | "IOAPIC\0"
|
---|
| 2910 | "NumCPUs\0"
|
---|
| 2911 | "GCEnabled\0"
|
---|
| 2912 | "R0Enabled\0"
|
---|
| 2913 | "HpetEnabled\0"
|
---|
[32591] | 2914 | "McfgEnabled\0"
|
---|
[32637] | 2915 | "McfgBase\0"
|
---|
| 2916 | "McfgLength\0"
|
---|
[17572] | 2917 | "SmcEnabled\0"
|
---|
| 2918 | "FdcEnabled\0"
|
---|
[19007] | 2919 | "ShowRtc\0"
|
---|
| 2920 | "ShowCpu\0"
|
---|
[28487] | 2921 | "NicPciAddress\0"
|
---|
[31519] | 2922 | "AudioPciAddress\0"
|
---|
[32471] | 2923 | "IocPciAddress\0"
|
---|
[32477] | 2924 | "HostBusPciAddress\0"
|
---|
[31963] | 2925 | "EnableSuspendToDisk\0"
|
---|
| 2926 | "PowerS1Enabled\0"
|
---|
| 2927 | "PowerS4Enabled\0"
|
---|
[25838] | 2928 | "CpuHotPlug\0"
|
---|
| 2929 | "AmlFilePath\0"
|
---|
[35746] | 2930 | "Serial0IoPortBase\0"
|
---|
| 2931 | "Serial1IoPortBase\0"
|
---|
| 2932 | "Serial0Irq\0"
|
---|
| 2933 | "Serial1Irq\0"
|
---|
[40019] | 2934 | "AcpiOemId\0"
|
---|
| 2935 | "AcpiCreatorId\0"
|
---|
| 2936 | "AcpiCreatorRev\0"
|
---|
| 2937 | "CustomTable\0"
|
---|
| 2938 | "SLICTable\0"
|
---|
[17572] | 2939 | ))
|
---|
[1] | 2940 | return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
|
---|
| 2941 | N_("Configuration error: Invalid config key for ACPI device"));
|
---|
| 2942 |
|
---|
| 2943 | /* query whether we are supposed to present an IOAPIC */
|
---|
[37446] | 2944 | rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8UseIOApic, 1);
|
---|
[17572] | 2945 | if (RT_FAILURE(rc))
|
---|
[1] | 2946 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
[6300] | 2947 | N_("Configuration error: Failed to read \"IOAPIC\""));
|
---|
[1] | 2948 |
|
---|
[37446] | 2949 | rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
|
---|
[12311] | 2950 | if (RT_FAILURE(rc))
|
---|
| 2951 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2952 | N_("Configuration error: Querying \"NumCPUs\" as integer failed"));
|
---|
| 2953 |
|
---|
[10372] | 2954 | /* query whether we are supposed to present an FDC controller */
|
---|
[37446] | 2955 | rc = CFGMR3QueryBoolDef(pCfg, "FdcEnabled", &pThis->fUseFdc, true);
|
---|
[17572] | 2956 | if (RT_FAILURE(rc))
|
---|
[10372] | 2957 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2958 | N_("Configuration error: Failed to read \"FdcEnabled\""));
|
---|
| 2959 |
|
---|
[16170] | 2960 | /* query whether we are supposed to present HPET */
|
---|
[37446] | 2961 | rc = CFGMR3QueryBoolDef(pCfg, "HpetEnabled", &pThis->fUseHpet, false);
|
---|
[16170] | 2962 | if (RT_FAILURE(rc))
|
---|
| 2963 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2964 | N_("Configuration error: Failed to read \"HpetEnabled\""));
|
---|
[33540] | 2965 | /* query MCFG configuration */
|
---|
[37446] | 2966 | rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pThis->u64PciConfigMMioAddress, 0);
|
---|
[32591] | 2967 | if (RT_FAILURE(rc))
|
---|
| 2968 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2969 | N_("Configuration error: Failed to read \"McfgBase\""));
|
---|
[37446] | 2970 | rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pThis->u64PciConfigMMioLength, 0);
|
---|
[32637] | 2971 | if (RT_FAILURE(rc))
|
---|
| 2972 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2973 | N_("Configuration error: Failed to read \"McfgLength\""));
|
---|
[37446] | 2974 | pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
|
---|
[32591] | 2975 |
|
---|
[40019] | 2976 | /* query whether we are supposed to present custom table */
|
---|
| 2977 | pThis->fUseCust = false;
|
---|
| 2978 |
|
---|
[16170] | 2979 | /* query whether we are supposed to present SMC */
|
---|
[37446] | 2980 | rc = CFGMR3QueryBoolDef(pCfg, "SmcEnabled", &pThis->fUseSmc, false);
|
---|
[16170] | 2981 | if (RT_FAILURE(rc))
|
---|
| 2982 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2983 | N_("Configuration error: Failed to read \"SmcEnabled\""));
|
---|
| 2984 |
|
---|
[19007] | 2985 | /* query whether we are supposed to present RTC object */
|
---|
[37446] | 2986 | rc = CFGMR3QueryBoolDef(pCfg, "ShowRtc", &pThis->fShowRtc, false);
|
---|
[19007] | 2987 | if (RT_FAILURE(rc))
|
---|
| 2988 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 2989 | N_("Configuration error: Failed to read \"ShowRtc\""));
|
---|
| 2990 |
|
---|
| 2991 | /* query whether we are supposed to present CPU objects */
|
---|
[37446] | 2992 | rc = CFGMR3QueryBoolDef(pCfg, "ShowCpu", &pThis->fShowCpu, false);
|
---|
[19007] | 2993 | if (RT_FAILURE(rc))
|
---|
| 2994 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
[21829] | 2995 | N_("Configuration error: Failed to read \"ShowCpu\""));
|
---|
[19007] | 2996 |
|
---|
[28487] | 2997 | /* query primary NIC PCI address */
|
---|
[37446] | 2998 | rc = CFGMR3QueryU32Def(pCfg, "NicPciAddress", &pThis->u32NicPciAddress, 0);
|
---|
[28487] | 2999 | if (RT_FAILURE(rc))
|
---|
| 3000 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3001 | N_("Configuration error: Failed to read \"NicPciAddress\""));
|
---|
| 3002 |
|
---|
[31519] | 3003 | /* query primary NIC PCI address */
|
---|
[37446] | 3004 | rc = CFGMR3QueryU32Def(pCfg, "AudioPciAddress", &pThis->u32AudioPciAddress, 0);
|
---|
[31519] | 3005 | if (RT_FAILURE(rc))
|
---|
| 3006 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3007 | N_("Configuration error: Failed to read \"AudioPciAddress\""));
|
---|
| 3008 |
|
---|
[32471] | 3009 | /* query IO controller (southbridge) PCI address */
|
---|
[37446] | 3010 | rc = CFGMR3QueryU32Def(pCfg, "IocPciAddress", &pThis->u32IocPciAddress, 0);
|
---|
[32471] | 3011 | if (RT_FAILURE(rc))
|
---|
| 3012 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3013 | N_("Configuration error: Failed to read \"IocPciAddress\""));
|
---|
| 3014 |
|
---|
[32477] | 3015 | /* query host bus controller PCI address */
|
---|
[37446] | 3016 | rc = CFGMR3QueryU32Def(pCfg, "HostBusPciAddress", &pThis->u32HbcPciAddress, 0);
|
---|
[32477] | 3017 | if (RT_FAILURE(rc))
|
---|
| 3018 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3019 | N_("Configuration error: Failed to read \"HostBusPciAddress\""));
|
---|
| 3020 |
|
---|
[31963] | 3021 | /* query whether S1 power state should be exposed */
|
---|
[37446] | 3022 | rc = CFGMR3QueryBoolDef(pCfg, "PowerS1Enabled", &pThis->fS1Enabled, false);
|
---|
[31963] | 3023 | if (RT_FAILURE(rc))
|
---|
| 3024 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3025 | N_("Configuration error: Failed to read \"PowerS1Enabled\""));
|
---|
| 3026 |
|
---|
| 3027 | /* query whether S4 power state should be exposed */
|
---|
[37446] | 3028 | rc = CFGMR3QueryBoolDef(pCfg, "PowerS4Enabled", &pThis->fS4Enabled, false);
|
---|
[31963] | 3029 | if (RT_FAILURE(rc))
|
---|
| 3030 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
[35546] | 3031 | N_("Configuration error: Failed to read \"PowerS4Enabled\""));
|
---|
[31963] | 3032 |
|
---|
| 3033 | /* query whether S1 power state should save the VM state */
|
---|
[37446] | 3034 | rc = CFGMR3QueryBoolDef(pCfg, "EnableSuspendToDisk", &pThis->fSuspendToSavedState, false);
|
---|
[31963] | 3035 | if (RT_FAILURE(rc))
|
---|
| 3036 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3037 | N_("Configuration error: Failed to read \"EnableSuspendToDisk\""));
|
---|
| 3038 |
|
---|
[25825] | 3039 | /* query whether we are allow CPU hot plugging */
|
---|
[37446] | 3040 | rc = CFGMR3QueryBoolDef(pCfg, "CpuHotPlug", &pThis->fCpuHotPlug, false);
|
---|
[25817] | 3041 | if (RT_FAILURE(rc))
|
---|
| 3042 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
[25838] | 3043 | N_("Configuration error: Failed to read \"CpuHotPlug\""));
|
---|
[25817] | 3044 |
|
---|
[40019] | 3045 | rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
|
---|
| 3046 | if (RT_FAILURE(rc))
|
---|
[1] | 3047 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
[6300] | 3048 | N_("Configuration error: Failed to read \"GCEnabled\""));
|
---|
[1] | 3049 |
|
---|
[40019] | 3050 | rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
|
---|
| 3051 | if (RT_FAILURE(rc))
|
---|
[1] | 3052 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
[40019] | 3053 | N_("configuration error: failed to read \"R0Enabled\""));
|
---|
[1] | 3054 |
|
---|
[35746] | 3055 | /* query serial info */
|
---|
[37446] | 3056 | rc = CFGMR3QueryU8Def(pCfg, "Serial0Irq", &pThis->uSerial0Irq, 4);
|
---|
[35746] | 3057 | if (RT_FAILURE(rc))
|
---|
| 3058 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3059 | N_("Configuration error: Failed to read \"Serial0Irq\""));
|
---|
| 3060 |
|
---|
[37446] | 3061 | rc = CFGMR3QueryU16Def(pCfg, "Serial0IoPortBase", &pThis->uSerial0IoPortBase, 0x3f8);
|
---|
[35746] | 3062 | if (RT_FAILURE(rc))
|
---|
| 3063 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3064 | N_("Configuration error: Failed to read \"Serial0IoPortBase\""));
|
---|
| 3065 |
|
---|
| 3066 | /* Serial 1 is enabled, get config data */
|
---|
[37446] | 3067 | rc = CFGMR3QueryU8Def(pCfg, "Serial1Irq", &pThis->uSerial1Irq, 3);
|
---|
[35746] | 3068 | if (RT_FAILURE(rc))
|
---|
| 3069 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3070 | N_("Configuration error: Failed to read \"Serial1Irq\""));
|
---|
| 3071 |
|
---|
[37446] | 3072 | rc = CFGMR3QueryU16Def(pCfg, "Serial1IoPortBase", &pThis->uSerial1IoPortBase, 0x2f8);
|
---|
[35746] | 3073 | if (RT_FAILURE(rc))
|
---|
| 3074 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3075 | N_("Configuration error: Failed to read \"Serial1IoPortBase\""));
|
---|
| 3076 |
|
---|
[25817] | 3077 | /* Try to attach the other CPUs */
|
---|
[37446] | 3078 | for (unsigned i = 1; i < pThis->cCpus; i++)
|
---|
[25817] | 3079 | {
|
---|
[37446] | 3080 | if (pThis->fCpuHotPlug)
|
---|
[25820] | 3081 | {
|
---|
| 3082 | PPDMIBASE IBaseTmp;
|
---|
[37446] | 3083 | rc = PDMDevHlpDriverAttach(pDevIns, i, &pThis->IBase, &IBaseTmp, "ACPI CPU");
|
---|
[25817] | 3084 |
|
---|
[25820] | 3085 | if (RT_SUCCESS(rc))
|
---|
| 3086 | {
|
---|
[37446] | 3087 | VMCPUSET_ADD(&pThis->CpuSetAttached, i);
|
---|
| 3088 | VMCPUSET_ADD(&pThis->CpuSetLocked, i);
|
---|
[25820] | 3089 | Log(("acpi: Attached CPU %u\n", i));
|
---|
| 3090 | }
|
---|
| 3091 | else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
|
---|
| 3092 | Log(("acpi: CPU %u not attached yet\n", i));
|
---|
| 3093 | else
|
---|
| 3094 | return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach CPU object\n"));
|
---|
| 3095 | }
|
---|
| 3096 | else
|
---|
[25817] | 3097 | {
|
---|
[25825] | 3098 | /* CPU is always attached if hot-plug is not enabled. */
|
---|
[37446] | 3099 | VMCPUSET_ADD(&pThis->CpuSetAttached, i);
|
---|
| 3100 | VMCPUSET_ADD(&pThis->CpuSetLocked, i);
|
---|
[25817] | 3101 | }
|
---|
| 3102 | }
|
---|
| 3103 |
|
---|
[40019] | 3104 | char *pszOemId = NULL;
|
---|
| 3105 | rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiOemId", &pszOemId, "VBOX ");
|
---|
| 3106 | if (RT_FAILURE(rc))
|
---|
| 3107 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
| 3108 | N_("Configuration error: Querying \"AcpiOemId\" as string failed"));
|
---|
| 3109 | size_t cbOemId = strlen(pszOemId);
|
---|
| 3110 | if (cbOemId > 6)
|
---|
| 3111 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
| 3112 | N_("Configuration error: \"AcpiOemId\" must contain not more than 6 characters"));
|
---|
| 3113 | memset(pThis->au8OemId, ' ', sizeof(pThis->au8OemId));
|
---|
| 3114 | memcpy(pThis->au8OemId, pszOemId, cbOemId);
|
---|
| 3115 | MMR3HeapFree(pszOemId);
|
---|
[25817] | 3116 |
|
---|
[40019] | 3117 | char *pszCreatorId = NULL;
|
---|
| 3118 | rc = CFGMR3QueryStringAllocDef(pThis->pDevIns->pCfg, "AcpiCreatorId", &pszCreatorId, "ASL ");
|
---|
| 3119 | if (RT_FAILURE(rc))
|
---|
| 3120 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
| 3121 | N_("Configuration error: Querying \"AcpiCreatorId\" as string failed"));
|
---|
| 3122 | size_t cbCreatorId = strlen(pszCreatorId);
|
---|
| 3123 | if (cbCreatorId > 4)
|
---|
| 3124 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
| 3125 | N_("Configuration error: \"AcpiCreatorId\" must contain not more than 4 characters"));
|
---|
| 3126 | memset(pThis->au8CreatorId, ' ', sizeof(pThis->au8CreatorId));
|
---|
| 3127 | memcpy(pThis->au8CreatorId, pszCreatorId, cbCreatorId);
|
---|
| 3128 | MMR3HeapFree(pszCreatorId);
|
---|
| 3129 |
|
---|
| 3130 | rc = CFGMR3QueryU32Def(pThis->pDevIns->pCfg, "AcpiCreatorRev", &pThis->u32CreatorRev, RT_H2LE_U32(0x61));
|
---|
| 3131 | if (RT_FAILURE(rc))
|
---|
| 3132 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
| 3133 | N_("Configuration error: Querying \"AcpiCreatorRev\" as integer failed"));
|
---|
| 3134 | pThis->u32OemRevision = RT_H2LE_U32(0x1);
|
---|
| 3135 |
|
---|
| 3136 | /*
|
---|
| 3137 | * Get the custom table binary file name.
|
---|
| 3138 | */
|
---|
| 3139 | char *pszCustBinFile;
|
---|
| 3140 | rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "CustomTable", &pszCustBinFile);
|
---|
| 3141 | if (rc == VERR_CFGM_VALUE_NOT_FOUND)
|
---|
| 3142 | rc = CFGMR3QueryStringAlloc(pThis->pDevIns->pCfg, "SLICTable", &pszCustBinFile);
|
---|
| 3143 | if (rc == VERR_CFGM_VALUE_NOT_FOUND)
|
---|
| 3144 | {
|
---|
| 3145 | pszCustBinFile = NULL;
|
---|
| 3146 | rc = VINF_SUCCESS;
|
---|
| 3147 | }
|
---|
| 3148 | else if (RT_FAILURE(rc))
|
---|
| 3149 | return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
|
---|
| 3150 | N_("Configuration error: Querying \"CustomTable\" as a string failed"));
|
---|
| 3151 | else if (!*pszCustBinFile)
|
---|
| 3152 | {
|
---|
| 3153 | MMR3HeapFree(pszCustBinFile);
|
---|
| 3154 | pszCustBinFile = NULL;
|
---|
| 3155 | }
|
---|
| 3156 |
|
---|
| 3157 | /*
|
---|
| 3158 | * Determine the custom table binary size, open specified ROM file in the process.
|
---|
| 3159 | */
|
---|
| 3160 | if (pszCustBinFile)
|
---|
| 3161 | {
|
---|
| 3162 | RTFILE FileCUSTBin;
|
---|
| 3163 | rc = RTFileOpen(&FileCUSTBin, pszCustBinFile,
|
---|
| 3164 | RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
|
---|
| 3165 | if (RT_SUCCESS(rc))
|
---|
| 3166 | {
|
---|
| 3167 | rc = RTFileGetSize(FileCUSTBin, &pThis->cbCustBin);
|
---|
| 3168 | if (RT_SUCCESS(rc))
|
---|
| 3169 | {
|
---|
| 3170 | /* The following checks should be in sync the AssertReleaseMsg's below. */
|
---|
| 3171 | if ( pThis->cbCustBin > 3072
|
---|
| 3172 | || pThis->cbCustBin < sizeof(ACPITBLHEADER))
|
---|
| 3173 | rc = VERR_TOO_MUCH_DATA;
|
---|
| 3174 |
|
---|
| 3175 | /*
|
---|
| 3176 | * Allocate buffer for the custom table binary data.
|
---|
| 3177 | */
|
---|
| 3178 | pThis->pu8CustBin = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, pThis->cbCustBin);
|
---|
| 3179 | if (pThis->pu8CustBin)
|
---|
| 3180 | {
|
---|
| 3181 | rc = RTFileRead(FileCUSTBin, pThis->pu8CustBin, pThis->cbCustBin, NULL);
|
---|
| 3182 | if (RT_FAILURE(rc))
|
---|
| 3183 | {
|
---|
| 3184 | AssertMsgFailed(("RTFileRead(,,%d,NULL) -> %Rrc\n", pThis->cbCustBin, rc));
|
---|
| 3185 | MMR3HeapFree(pThis->pu8CustBin);
|
---|
| 3186 | pThis->pu8CustBin = NULL;
|
---|
| 3187 | }
|
---|
| 3188 | else
|
---|
| 3189 | {
|
---|
| 3190 | pThis->fUseCust = true;
|
---|
| 3191 | memcpy(&pThis->au8OemId[0], &pThis->pu8CustBin[10], 6);
|
---|
| 3192 | memcpy(&pThis->au8OemTabId[0], &pThis->pu8CustBin[16], 8);
|
---|
| 3193 | memcpy(&pThis->u32OemRevision, &pThis->pu8CustBin[24], 4);
|
---|
| 3194 | memcpy(&pThis->au8CreatorId[0], &pThis->pu8CustBin[28], 4);
|
---|
| 3195 | memcpy(&pThis->u32CreatorRev, &pThis->pu8CustBin[32], 4);
|
---|
| 3196 | LogRel(("Reading custom ACPI table from file '%s' (%d bytes)\n", pszCustBinFile, pThis->cbCustBin));
|
---|
| 3197 | }
|
---|
| 3198 | }
|
---|
| 3199 | else
|
---|
| 3200 | rc = VERR_NO_MEMORY;
|
---|
| 3201 |
|
---|
| 3202 | RTFileClose(FileCUSTBin);
|
---|
| 3203 | }
|
---|
| 3204 | }
|
---|
| 3205 | MMR3HeapFree(pszCustBinFile);
|
---|
| 3206 | if (RT_FAILURE(rc))
|
---|
| 3207 | return PDMDEV_SET_ERROR(pDevIns, rc,
|
---|
| 3208 | N_("Error reading custom ACPI table"));
|
---|
| 3209 | }
|
---|
| 3210 |
|
---|
[21820] | 3211 | /* Set default port base */
|
---|
[37446] | 3212 | pThis->uPmIoPortBase = PM_PORT_BASE;
|
---|
[21820] | 3213 |
|
---|
[26001] | 3214 | /*
|
---|
| 3215 | * FDC and SMC try to use the same non-shareable interrupt (6),
|
---|
[25987] | 3216 | * enable only one device.
|
---|
| 3217 | */
|
---|
[37446] | 3218 | if (pThis->fUseSmc)
|
---|
| 3219 | pThis->fUseFdc = false;
|
---|
[25987] | 3220 |
|
---|
[37446] | 3221 | /*
|
---|
| 3222 | * Plant ACPI tables.
|
---|
| 3223 | */
|
---|
[26057] | 3224 | RTGCPHYS32 GCPhysRsdp = find_rsdp_space();
|
---|
| 3225 | if (!GCPhysRsdp)
|
---|
[1] | 3226 | return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
|
---|
[6300] | 3227 | N_("Can not find space for RSDP. ACPI is disabled"));
|
---|
[1] | 3228 |
|
---|
[37446] | 3229 | rc = acpiPlantTables(pThis);
|
---|
[17572] | 3230 | if (RT_FAILURE(rc))
|
---|
[1] | 3231 | return rc;
|
---|
| 3232 |
|
---|
[37446] | 3233 | rc = PDMDevHlpROMRegister(pDevIns, GCPhysRsdp, 0x1000, pThis->au8RSDPPage, 0x1000,
|
---|
[18143] | 3234 | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "ACPI RSDP");
|
---|
[17572] | 3235 | if (RT_FAILURE(rc))
|
---|
[1] | 3236 | return rc;
|
---|
| 3237 |
|
---|
[37446] | 3238 | /*
|
---|
| 3239 | * Register I/O ports.
|
---|
| 3240 | */
|
---|
| 3241 | rc = acpiRegisterPmHandlers(pThis);
|
---|
[21820] | 3242 | if (RT_FAILURE(rc))
|
---|
| 3243 | return rc;
|
---|
| 3244 |
|
---|
| 3245 | #define R(addr, cnt, writer, reader, description) \
|
---|
[17572] | 3246 | do { \
|
---|
[37446] | 3247 | rc = PDMDevHlpIOPortRegister(pDevIns, addr, cnt, pThis, writer, reader, \
|
---|
[17572] | 3248 | NULL, NULL, description); \
|
---|
| 3249 | if (RT_FAILURE(rc)) \
|
---|
| 3250 | return rc; \
|
---|
[1] | 3251 | } while (0)
|
---|
[17572] | 3252 | R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
|
---|
[1] | 3253 | #ifdef DEBUG_ACPI
|
---|
[17572] | 3254 | R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
|
---|
| 3255 | R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
|
---|
[1] | 3256 | #endif
|
---|
[17572] | 3257 | R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
|
---|
| 3258 | R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
|
---|
| 3259 | R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
|
---|
| 3260 | R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
|
---|
| 3261 | R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
|
---|
[1] | 3262 | #undef R
|
---|
| 3263 |
|
---|
[37446] | 3264 | /*
|
---|
| 3265 | * Create the PM timer.
|
---|
| 3266 | */
|
---|
[37526] | 3267 | PTMTIMER pTimer;
|
---|
[37446] | 3268 | rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, acpiPmTimer, &pThis->dev,
|
---|
[37526] | 3269 | TMTIMER_FLAGS_NO_CRIT_SECT, "ACPI PM Timer", &pTimer);
|
---|
| 3270 | AssertRCReturn(rc, rc);
|
---|
| 3271 | pThis->pPmTimerR3 = pTimer;
|
---|
| 3272 | pThis->pPmTimerR0 = TMTimerR0Ptr(pTimer);
|
---|
| 3273 | pThis->pPmTimerRC = TMTimerRCPtr(pTimer);
|
---|
[1] | 3274 |
|
---|
[37526] | 3275 | rc = TMTimerLock(pTimer, VERR_IGNORED);
|
---|
| 3276 | AssertRCReturn(rc, rc);
|
---|
| 3277 | pThis->u64PmTimerInitial = TMTimerGet(pTimer);
|
---|
[37446] | 3278 | acpiPmTimerReset(pThis, pThis->u64PmTimerInitial);
|
---|
[37526] | 3279 | TMTimerUnlock(pTimer);
|
---|
[1] | 3280 |
|
---|
[37446] | 3281 | /*
|
---|
| 3282 | * Set up the PCI device.
|
---|
| 3283 | */
|
---|
| 3284 | PCIDevSetVendorId(&pThis->dev, 0x8086); /* Intel */
|
---|
| 3285 | PCIDevSetDeviceId(&pThis->dev, 0x7113); /* 82371AB */
|
---|
[1] | 3286 |
|
---|
[21820] | 3287 | /* See p. 50 of PIIX4 manual */
|
---|
[37446] | 3288 | PCIDevSetCommand(&pThis->dev, 0x01);
|
---|
| 3289 | PCIDevSetStatus(&pThis->dev, 0x0280);
|
---|
[1] | 3290 |
|
---|
[37446] | 3291 | PCIDevSetRevisionId(&pThis->dev, 0x08);
|
---|
[1] | 3292 |
|
---|
[37446] | 3293 | PCIDevSetClassProg(&pThis->dev, 0x00);
|
---|
| 3294 | PCIDevSetClassSub(&pThis->dev, 0x80);
|
---|
| 3295 | PCIDevSetClassBase(&pThis->dev, 0x06);
|
---|
[21820] | 3296 |
|
---|
[37446] | 3297 | PCIDevSetHeaderType(&pThis->dev, 0x80);
|
---|
[1] | 3298 |
|
---|
[37446] | 3299 | PCIDevSetBIST(&pThis->dev, 0x00);
|
---|
[1] | 3300 |
|
---|
[37446] | 3301 | PCIDevSetInterruptLine(&pThis->dev, SCI_INT);
|
---|
| 3302 | PCIDevSetInterruptPin (&pThis->dev, 0x01);
|
---|
[21820] | 3303 |
|
---|
[37446] | 3304 | pThis->dev.config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
|
---|
[21820] | 3305 |
|
---|
[25968] | 3306 | #if 0
|
---|
| 3307 | int smb_io_base = 0xb100;
|
---|
| 3308 | dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
|
---|
| 3309 | dev->config[0x90] = smb_io_base >> 8;
|
---|
| 3310 | #endif
|
---|
| 3311 |
|
---|
[37446] | 3312 | rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
|
---|
[17572] | 3313 | if (RT_FAILURE(rc))
|
---|
[1] | 3314 | return rc;
|
---|
| 3315 |
|
---|
[37446] | 3316 | PDMDevHlpPCISetConfigCallbacks(pDevIns, &pThis->dev,
|
---|
| 3317 | acpiPciConfigRead, &pThis->pfnAcpiPciConfigRead,
|
---|
| 3318 | acpiPciConfigWrite, &pThis->pfnAcpiPciConfigWrite);
|
---|
[21820] | 3319 |
|
---|
[37446] | 3320 | /*
|
---|
| 3321 | * Register the saved state.
|
---|
| 3322 | */
|
---|
| 3323 | rc = PDMDevHlpSSMRegister(pDevIns, 6, sizeof(*pThis), acpiSaveState, acpiLoadState);
|
---|
[11208] | 3324 | if (RT_FAILURE(rc))
|
---|
[1] | 3325 | return rc;
|
---|
| 3326 |
|
---|
| 3327 | /*
|
---|
| 3328 | * Get the corresponding connector interface
|
---|
| 3329 | */
|
---|
[37446] | 3330 | rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "ACPI Driver Port");
|
---|
[17572] | 3331 | if (RT_SUCCESS(rc))
|
---|
[1] | 3332 | {
|
---|
[37446] | 3333 | pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIACPICONNECTOR);
|
---|
| 3334 | if (!pThis->pDrv)
|
---|
[1] | 3335 | return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_MISSING_INTERFACE,
|
---|
[6300] | 3336 | N_("LUN #0 doesn't have an ACPI connector interface"));
|
---|
[1] | 3337 | }
|
---|
| 3338 | else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
|
---|
| 3339 | {
|
---|
[17572] | 3340 | Log(("acpi: %s/%d: warning: no driver attached to LUN #0!\n",
|
---|
[26165] | 3341 | pDevIns->pReg->szName, pDevIns->iInstance));
|
---|
[1] | 3342 | rc = VINF_SUCCESS;
|
---|
| 3343 | }
|
---|
| 3344 | else
|
---|
[17572] | 3345 | return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach LUN #0"));
|
---|
[1] | 3346 |
|
---|
| 3347 | return rc;
|
---|
| 3348 | }
|
---|
| 3349 |
|
---|
| 3350 | /**
|
---|
| 3351 | * The device registration structure.
|
---|
| 3352 | */
|
---|
| 3353 | const PDMDEVREG g_DeviceACPI =
|
---|
| 3354 | {
|
---|
| 3355 | /* u32Version */
|
---|
| 3356 | PDM_DEVREG_VERSION,
|
---|
[26165] | 3357 | /* szName */
|
---|
[1] | 3358 | "acpi",
|
---|
[12977] | 3359 | /* szRCMod */
|
---|
[1] | 3360 | "VBoxDDGC.gc",
|
---|
| 3361 | /* szR0Mod */
|
---|
| 3362 | "VBoxDDR0.r0",
|
---|
| 3363 | /* pszDescription */
|
---|
| 3364 | "Advanced Configuration and Power Interface",
|
---|
| 3365 | /* fFlags */
|
---|
[12978] | 3366 | PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
|
---|
[1] | 3367 | /* fClass */
|
---|
| 3368 | PDM_DEVREG_CLASS_ACPI,
|
---|
| 3369 | /* cMaxInstances */
|
---|
[40282] | 3370 | ~0U,
|
---|
[1] | 3371 | /* cbInstance */
|
---|
| 3372 | sizeof(ACPIState),
|
---|
| 3373 | /* pfnConstruct */
|
---|
| 3374 | acpiConstruct,
|
---|
| 3375 | /* pfnDestruct */
|
---|
[40019] | 3376 | acpiDestruct,
|
---|
[1] | 3377 | /* pfnRelocate */
|
---|
| 3378 | acpiRelocate,
|
---|
| 3379 | /* pfnIOCtl */
|
---|
| 3380 | NULL,
|
---|
| 3381 | /* pfnPowerOn */
|
---|
| 3382 | NULL,
|
---|
| 3383 | /* pfnReset */
|
---|
| 3384 | acpiReset,
|
---|
| 3385 | /* pfnSuspend */
|
---|
| 3386 | NULL,
|
---|
| 3387 | /* pfnResume */
|
---|
[32189] | 3388 | acpiResume,
|
---|
[1] | 3389 | /* pfnAttach */
|
---|
[25817] | 3390 | acpiAttach,
|
---|
[1] | 3391 | /* pfnDetach */
|
---|
[25817] | 3392 | acpiDetach,
|
---|
[1] | 3393 | /* pfnQueryInterface. */
|
---|
[12977] | 3394 | NULL,
|
---|
| 3395 | /* pfnInitComplete */
|
---|
| 3396 | NULL,
|
---|
| 3397 | /* pfnPowerOff */
|
---|
| 3398 | NULL,
|
---|
| 3399 | /* pfnSoftReset */
|
---|
| 3400 | NULL,
|
---|
| 3401 | /* u32VersionEnd */
|
---|
| 3402 | PDM_DEVREG_VERSION
|
---|
[1] | 3403 | };
|
---|
| 3404 |
|
---|
| 3405 | #endif /* IN_RING3 */
|
---|
[491] | 3406 | #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
|
---|