[24706] | 1 | /* $Id: DevFwCommon.cpp 102788 2024-01-08 16:31:52Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[25048] | 3 | * FwCommon - Shared firmware code (used by DevPcBios & DevEFI).
|
---|
[24706] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2009-2023 Oracle and/or its affiliates.
|
---|
[24706] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[24706] | 26 | */
|
---|
| 27 |
|
---|
[57358] | 28 |
|
---|
| 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[25048] | 32 | #define LOG_GROUP LOG_GROUP_DEV
|
---|
[35346] | 33 | #include <VBox/vmm/pdmdev.h>
|
---|
[24706] | 34 |
|
---|
| 35 | #include <VBox/log.h>
|
---|
[25048] | 36 | #include <VBox/err.h>
|
---|
| 37 | #include <VBox/param.h>
|
---|
| 38 |
|
---|
[29250] | 39 | #include <iprt/asm.h>
|
---|
[24706] | 40 | #include <iprt/assert.h>
|
---|
| 41 | #include <iprt/buildconfig.h>
|
---|
| 42 | #include <iprt/file.h>
|
---|
[25048] | 43 | #include <iprt/mem.h>
|
---|
[24706] | 44 | #include <iprt/string.h>
|
---|
| 45 | #include <iprt/uuid.h>
|
---|
[26601] | 46 | #include <iprt/system.h>
|
---|
[44821] | 47 | #include <iprt/cdefs.h>
|
---|
[100542] | 48 | #include <iprt/alloca.h>
|
---|
[24706] | 49 |
|
---|
[35353] | 50 | #include "VBoxDD.h"
|
---|
| 51 | #include "VBoxDD2.h"
|
---|
[24706] | 52 | #include "DevFwCommon.h"
|
---|
| 53 |
|
---|
[25048] | 54 |
|
---|
[57358] | 55 | /*********************************************************************************************************************************
|
---|
| 56 | * Defined Constants And Macros *
|
---|
| 57 | *********************************************************************************************************************************/
|
---|
[25162] | 58 |
|
---|
| 59 | /*
|
---|
| 60 | * Default DMI data (legacy).
|
---|
[40019] | 61 | * Don't change this information otherwise Windows guests might demand re-activation!
|
---|
[25162] | 62 | */
|
---|
[40019] | 63 |
|
---|
| 64 | /* type 0 -- DMI BIOS information */
|
---|
[48755] | 65 | static const int32_t g_iDefDmiBIOSReleaseMajor = 0;
|
---|
| 66 | static const int32_t g_iDefDmiBIOSReleaseMinor = 0;
|
---|
| 67 | static const int32_t g_iDefDmiBIOSFirmwareMajor = 0;
|
---|
| 68 | static const int32_t g_iDefDmiBIOSFirmwareMinor = 0;
|
---|
| 69 | static const char *g_pszDefDmiBIOSVendor = "innotek GmbH";
|
---|
| 70 | static const char *g_pszDefDmiBIOSVersion = "VirtualBox";
|
---|
| 71 | static const char *g_pszDefDmiBIOSReleaseDate = "12/01/2006";
|
---|
[40019] | 72 | /* type 1 -- DMI system information */
|
---|
[48755] | 73 | static const char *g_pszDefDmiSystemVendor = "innotek GmbH";
|
---|
| 74 | static const char *g_pszDefDmiSystemProduct = "VirtualBox";
|
---|
| 75 | static const char *g_pszDefDmiSystemVersion = "1.2";
|
---|
| 76 | static const char *g_pszDefDmiSystemSerial = "0";
|
---|
| 77 | static const char *g_pszDefDmiSystemSKU = "";
|
---|
| 78 | static const char *g_pszDefDmiSystemFamily = "Virtual Machine";
|
---|
[40019] | 79 | /* type 2 -- DMI board information */
|
---|
[48755] | 80 | static const char *g_pszDefDmiBoardVendor = "Oracle Corporation";
|
---|
| 81 | static const char *g_pszDefDmiBoardProduct = "VirtualBox";
|
---|
| 82 | static const char *g_pszDefDmiBoardVersion = "1.2";
|
---|
| 83 | static const char *g_pszDefDmiBoardSerial = "0";
|
---|
| 84 | static const char *g_pszDefDmiBoardAssetTag = "";
|
---|
| 85 | static const char *g_pszDefDmiBoardLocInChass = "";
|
---|
| 86 | static const int32_t g_iDefDmiBoardBoardType = 0x0A; /* Motherboard */
|
---|
[40019] | 87 | /* type 3 -- DMI chassis information */
|
---|
[48755] | 88 | static const char *g_pszDefDmiChassisVendor = "Oracle Corporation";
|
---|
| 89 | static const int32_t g_iDefDmiChassisType = 0x01; /* ''other'', no chassis lock present */
|
---|
| 90 | static const char *g_pszDefDmiChassisVersion = "";
|
---|
| 91 | static const char *g_pszDefDmiChassisSerial = "";
|
---|
| 92 | static const char *g_pszDefDmiChassisAssetTag = "";
|
---|
[40019] | 93 | /* type 4 -- DMI processor information */
|
---|
[48755] | 94 | static const char *g_pszDefDmiProcManufacturer= "GenuineIntel";
|
---|
| 95 | static const char *g_pszDefDmiProcVersion = "Pentium(R) III";
|
---|
[25162] | 96 |
|
---|
[48755] | 97 | /** The host DMI system product value, for DmiUseHostInfo=1. */
|
---|
[26617] | 98 | static char g_szHostDmiSystemProduct[64];
|
---|
[48755] | 99 | /** The host DMI system version value, for DmiUseHostInfo=1. */
|
---|
[26617] | 100 | static char g_szHostDmiSystemVersion[64];
|
---|
[25162] | 101 |
|
---|
[26617] | 102 |
|
---|
[57358] | 103 | /*********************************************************************************************************************************
|
---|
| 104 | * Structures and Typedefs *
|
---|
| 105 | *********************************************************************************************************************************/
|
---|
[24706] | 106 | #pragma pack(1)
|
---|
| 107 |
|
---|
[25025] | 108 | typedef struct SMBIOSHDR
|
---|
| 109 | {
|
---|
| 110 | uint8_t au8Signature[4];
|
---|
| 111 | uint8_t u8Checksum;
|
---|
| 112 | uint8_t u8Eps;
|
---|
| 113 | uint8_t u8VersionMajor;
|
---|
| 114 | uint8_t u8VersionMinor;
|
---|
| 115 | uint16_t u16MaxStructureSize;
|
---|
| 116 | uint8_t u8EntryPointRevision;
|
---|
| 117 | uint8_t u8Pad[5];
|
---|
| 118 | } *SMBIOSHDRPTR;
|
---|
| 119 | AssertCompileSize(SMBIOSHDR, 16);
|
---|
| 120 |
|
---|
| 121 | typedef struct DMIMAINHDR
|
---|
| 122 | {
|
---|
| 123 | uint8_t au8Signature[5];
|
---|
| 124 | uint8_t u8Checksum;
|
---|
| 125 | uint16_t u16TablesLength;
|
---|
| 126 | uint32_t u32TableBase;
|
---|
| 127 | uint16_t u16TableEntries;
|
---|
[25058] | 128 | uint8_t u8TableVersion;
|
---|
[25025] | 129 | } *DMIMAINHDRPTR;
|
---|
[25058] | 130 | AssertCompileSize(DMIMAINHDR, 15);
|
---|
[25025] | 131 |
|
---|
[71061] | 132 | AssertCompile(sizeof(SMBIOSHDR) + sizeof(DMIMAINHDR) <= VBOX_DMI_HDR_SIZE);
|
---|
| 133 |
|
---|
[24706] | 134 | /** DMI header */
|
---|
| 135 | typedef struct DMIHDR
|
---|
| 136 | {
|
---|
| 137 | uint8_t u8Type;
|
---|
| 138 | uint8_t u8Length;
|
---|
| 139 | uint16_t u16Handle;
|
---|
| 140 | } *PDMIHDR;
|
---|
| 141 | AssertCompileSize(DMIHDR, 4);
|
---|
| 142 |
|
---|
| 143 | /** DMI BIOS information (Type 0) */
|
---|
| 144 | typedef struct DMIBIOSINF
|
---|
| 145 | {
|
---|
| 146 | DMIHDR header;
|
---|
| 147 | uint8_t u8Vendor;
|
---|
| 148 | uint8_t u8Version;
|
---|
| 149 | uint16_t u16Start;
|
---|
| 150 | uint8_t u8Release;
|
---|
| 151 | uint8_t u8ROMSize;
|
---|
| 152 | uint64_t u64Characteristics;
|
---|
| 153 | uint8_t u8CharacteristicsByte1;
|
---|
| 154 | uint8_t u8CharacteristicsByte2;
|
---|
| 155 | uint8_t u8ReleaseMajor;
|
---|
| 156 | uint8_t u8ReleaseMinor;
|
---|
| 157 | uint8_t u8FirmwareMajor;
|
---|
| 158 | uint8_t u8FirmwareMinor;
|
---|
| 159 | } *PDMIBIOSINF;
|
---|
| 160 | AssertCompileSize(DMIBIOSINF, 0x18);
|
---|
| 161 |
|
---|
| 162 | /** DMI system information (Type 1) */
|
---|
| 163 | typedef struct DMISYSTEMINF
|
---|
| 164 | {
|
---|
| 165 | DMIHDR header;
|
---|
| 166 | uint8_t u8Manufacturer;
|
---|
| 167 | uint8_t u8ProductName;
|
---|
| 168 | uint8_t u8Version;
|
---|
| 169 | uint8_t u8SerialNumber;
|
---|
| 170 | uint8_t au8Uuid[16];
|
---|
| 171 | uint8_t u8WakeupType;
|
---|
| 172 | uint8_t u8SKUNumber;
|
---|
| 173 | uint8_t u8Family;
|
---|
| 174 | } *PDMISYSTEMINF;
|
---|
| 175 | AssertCompileSize(DMISYSTEMINF, 0x1b);
|
---|
| 176 |
|
---|
[27363] | 177 | /** DMI board (or module) information (Type 2) */
|
---|
| 178 | typedef struct DMIBOARDINF
|
---|
| 179 | {
|
---|
| 180 | DMIHDR header;
|
---|
| 181 | uint8_t u8Manufacturer;
|
---|
| 182 | uint8_t u8Product;
|
---|
| 183 | uint8_t u8Version;
|
---|
| 184 | uint8_t u8SerialNumber;
|
---|
| 185 | uint8_t u8AssetTag;
|
---|
| 186 | uint8_t u8FeatureFlags;
|
---|
[40019] | 187 | uint8_t u8LocationInChass;
|
---|
[27363] | 188 | uint16_t u16ChassisHandle;
|
---|
| 189 | uint8_t u8BoardType;
|
---|
| 190 | uint8_t u8cObjectHandles;
|
---|
| 191 | } *PDMIBOARDINF;
|
---|
| 192 | AssertCompileSize(DMIBOARDINF, 0x0f);
|
---|
| 193 |
|
---|
[24706] | 194 | /** DMI system enclosure or chassis type (Type 3) */
|
---|
| 195 | typedef struct DMICHASSIS
|
---|
| 196 | {
|
---|
| 197 | DMIHDR header;
|
---|
| 198 | uint8_t u8Manufacturer;
|
---|
| 199 | uint8_t u8Type;
|
---|
| 200 | uint8_t u8Version;
|
---|
| 201 | uint8_t u8SerialNumber;
|
---|
| 202 | uint8_t u8AssetTag;
|
---|
| 203 | uint8_t u8BootupState;
|
---|
| 204 | uint8_t u8PowerSupplyState;
|
---|
| 205 | uint8_t u8ThermalState;
|
---|
| 206 | uint8_t u8SecurityStatus;
|
---|
| 207 | /* v2.3+, currently not supported */
|
---|
| 208 | uint32_t u32OEMdefined;
|
---|
| 209 | uint8_t u8Height;
|
---|
| 210 | uint8_t u8NumPowerChords;
|
---|
| 211 | uint8_t u8ContElems;
|
---|
| 212 | uint8_t u8ContElemRecLen;
|
---|
| 213 | } *PDMICHASSIS;
|
---|
| 214 | AssertCompileSize(DMICHASSIS, 0x15);
|
---|
| 215 |
|
---|
| 216 | /** DMI processor information (Type 4) */
|
---|
| 217 | typedef struct DMIPROCESSORINF
|
---|
| 218 | {
|
---|
| 219 | DMIHDR header;
|
---|
| 220 | uint8_t u8SocketDesignation;
|
---|
| 221 | uint8_t u8ProcessorType;
|
---|
| 222 | uint8_t u8ProcessorFamily;
|
---|
| 223 | uint8_t u8ProcessorManufacturer;
|
---|
[39707] | 224 | uint64_t u64ProcessorID;
|
---|
[24706] | 225 | uint8_t u8ProcessorVersion;
|
---|
| 226 | uint8_t u8Voltage;
|
---|
| 227 | uint16_t u16ExternalClock;
|
---|
| 228 | uint16_t u16MaxSpeed;
|
---|
| 229 | uint16_t u16CurrentSpeed;
|
---|
| 230 | uint8_t u8Status;
|
---|
| 231 | uint8_t u8ProcessorUpgrade;
|
---|
[39707] | 232 | /* v2.1+ */
|
---|
[24706] | 233 | uint16_t u16L1CacheHandle;
|
---|
| 234 | uint16_t u16L2CacheHandle;
|
---|
| 235 | uint16_t u16L3CacheHandle;
|
---|
[39707] | 236 | /* v2.3+ */
|
---|
[24706] | 237 | uint8_t u8SerialNumber;
|
---|
| 238 | uint8_t u8AssetTag;
|
---|
| 239 | uint8_t u8PartNumber;
|
---|
[39707] | 240 | /* v2.5+ */
|
---|
[24706] | 241 | uint8_t u8CoreCount;
|
---|
| 242 | uint8_t u8CoreEnabled;
|
---|
| 243 | uint8_t u8ThreadCount;
|
---|
| 244 | uint16_t u16ProcessorCharacteristics;
|
---|
[39707] | 245 | /* v2.6+ */
|
---|
[24706] | 246 | uint16_t u16ProcessorFamily2;
|
---|
| 247 | } *PDMIPROCESSORINF;
|
---|
| 248 | AssertCompileSize(DMIPROCESSORINF, 0x2a);
|
---|
| 249 |
|
---|
| 250 | /** DMI OEM strings (Type 11) */
|
---|
| 251 | typedef struct DMIOEMSTRINGS
|
---|
| 252 | {
|
---|
| 253 | DMIHDR header;
|
---|
| 254 | uint8_t u8Count;
|
---|
| 255 | uint8_t u8VBoxVersion;
|
---|
| 256 | uint8_t u8VBoxRevision;
|
---|
| 257 | } *PDMIOEMSTRINGS;
|
---|
| 258 | AssertCompileSize(DMIOEMSTRINGS, 0x7);
|
---|
| 259 |
|
---|
[44820] | 260 | /** DMI OEM-specific table (Type 128) */
|
---|
| 261 | typedef struct DMIOEMSPECIFIC
|
---|
| 262 | {
|
---|
| 263 | DMIHDR header;
|
---|
| 264 | uint32_t u32CpuFreqKHz;
|
---|
| 265 | } *PDMIOEMSPECIFIC;
|
---|
| 266 | AssertCompileSize(DMIOEMSPECIFIC, 0x8);
|
---|
| 267 |
|
---|
[28568] | 268 | /** Physical memory array (Type 16) */
|
---|
| 269 | typedef struct DMIRAMARRAY
|
---|
| 270 | {
|
---|
| 271 | DMIHDR header;
|
---|
| 272 | uint8_t u8Location;
|
---|
| 273 | uint8_t u8Use;
|
---|
| 274 | uint8_t u8MemErrorCorrection;
|
---|
| 275 | uint32_t u32MaxCapacity;
|
---|
| 276 | uint16_t u16MemErrorHandle;
|
---|
| 277 | uint16_t u16NumberOfMemDevices;
|
---|
| 278 | } *PDMIRAMARRAY;
|
---|
| 279 | AssertCompileSize(DMIRAMARRAY, 15);
|
---|
| 280 |
|
---|
| 281 | /** DMI Memory Device (Type 17) */
|
---|
| 282 | typedef struct DMIMEMORYDEV
|
---|
| 283 | {
|
---|
| 284 | DMIHDR header;
|
---|
| 285 | uint16_t u16PhysMemArrayHandle;
|
---|
| 286 | uint16_t u16MemErrHandle;
|
---|
| 287 | uint16_t u16TotalWidth;
|
---|
| 288 | uint16_t u16DataWidth;
|
---|
| 289 | uint16_t u16Size;
|
---|
| 290 | uint8_t u8FormFactor;
|
---|
| 291 | uint8_t u8DeviceSet;
|
---|
| 292 | uint8_t u8DeviceLocator;
|
---|
| 293 | uint8_t u8BankLocator;
|
---|
| 294 | uint8_t u8MemoryType;
|
---|
| 295 | uint16_t u16TypeDetail;
|
---|
| 296 | uint16_t u16Speed;
|
---|
| 297 | uint8_t u8Manufacturer;
|
---|
| 298 | uint8_t u8SerialNumber;
|
---|
| 299 | uint8_t u8AssetTag;
|
---|
| 300 | uint8_t u8PartNumber;
|
---|
| 301 | /* v2.6+ */
|
---|
| 302 | uint8_t u8Attributes;
|
---|
[83133] | 303 | /* v2.7+ */
|
---|
| 304 | uint32_t u32ExtendedSize;
|
---|
| 305 | uint16_t u16CfgSpeed; /* Configured speed in MT/sec. */
|
---|
[28568] | 306 | } *PDMIMEMORYDEV;
|
---|
[83133] | 307 | AssertCompileSize(DMIMEMORYDEV, 34);
|
---|
[28568] | 308 |
|
---|
[24706] | 309 | /** MPS floating pointer structure */
|
---|
| 310 | typedef struct MPSFLOATPTR
|
---|
| 311 | {
|
---|
| 312 | uint8_t au8Signature[4];
|
---|
| 313 | uint32_t u32MPSAddr;
|
---|
| 314 | uint8_t u8Length;
|
---|
| 315 | uint8_t u8SpecRev;
|
---|
| 316 | uint8_t u8Checksum;
|
---|
| 317 | uint8_t au8Feature[5];
|
---|
| 318 | } *PMPSFLOATPTR;
|
---|
| 319 | AssertCompileSize(MPSFLOATPTR, 16);
|
---|
| 320 |
|
---|
| 321 | /** MPS config table header */
|
---|
| 322 | typedef struct MPSCFGTBLHEADER
|
---|
| 323 | {
|
---|
| 324 | uint8_t au8Signature[4];
|
---|
| 325 | uint16_t u16Length;
|
---|
| 326 | uint8_t u8SpecRev;
|
---|
| 327 | uint8_t u8Checksum;
|
---|
| 328 | uint8_t au8OemId[8];
|
---|
| 329 | uint8_t au8ProductId[12];
|
---|
| 330 | uint32_t u32OemTablePtr;
|
---|
| 331 | uint16_t u16OemTableSize;
|
---|
| 332 | uint16_t u16EntryCount;
|
---|
| 333 | uint32_t u32AddrLocalApic;
|
---|
| 334 | uint16_t u16ExtTableLength;
|
---|
[26939] | 335 | uint8_t u8ExtTableChecksum;
|
---|
[24706] | 336 | uint8_t u8Reserved;
|
---|
| 337 | } *PMPSCFGTBLHEADER;
|
---|
| 338 | AssertCompileSize(MPSCFGTBLHEADER, 0x2c);
|
---|
| 339 |
|
---|
| 340 | /** MPS processor entry */
|
---|
| 341 | typedef struct MPSPROCENTRY
|
---|
| 342 | {
|
---|
| 343 | uint8_t u8EntryType;
|
---|
| 344 | uint8_t u8LocalApicId;
|
---|
| 345 | uint8_t u8LocalApicVersion;
|
---|
| 346 | uint8_t u8CPUFlags;
|
---|
| 347 | uint32_t u32CPUSignature;
|
---|
| 348 | uint32_t u32CPUFeatureFlags;
|
---|
| 349 | uint32_t u32Reserved[2];
|
---|
| 350 | } *PMPSPROCENTRY;
|
---|
| 351 | AssertCompileSize(MPSPROCENTRY, 20);
|
---|
| 352 |
|
---|
| 353 | /** MPS bus entry */
|
---|
| 354 | typedef struct MPSBUSENTRY
|
---|
| 355 | {
|
---|
| 356 | uint8_t u8EntryType;
|
---|
| 357 | uint8_t u8BusId;
|
---|
| 358 | uint8_t au8BusTypeStr[6];
|
---|
| 359 | } *PMPSBUSENTRY;
|
---|
| 360 | AssertCompileSize(MPSBUSENTRY, 8);
|
---|
| 361 |
|
---|
| 362 | /** MPS I/O-APIC entry */
|
---|
| 363 | typedef struct MPSIOAPICENTRY
|
---|
| 364 | {
|
---|
| 365 | uint8_t u8EntryType;
|
---|
| 366 | uint8_t u8Id;
|
---|
| 367 | uint8_t u8Version;
|
---|
| 368 | uint8_t u8Flags;
|
---|
| 369 | uint32_t u32Addr;
|
---|
| 370 | } *PMPSIOAPICENTRY;
|
---|
| 371 | AssertCompileSize(MPSIOAPICENTRY, 8);
|
---|
| 372 |
|
---|
| 373 | /** MPS I/O-Interrupt entry */
|
---|
| 374 | typedef struct MPSIOINTERRUPTENTRY
|
---|
| 375 | {
|
---|
| 376 | uint8_t u8EntryType;
|
---|
| 377 | uint8_t u8Type;
|
---|
| 378 | uint16_t u16Flags;
|
---|
| 379 | uint8_t u8SrcBusId;
|
---|
| 380 | uint8_t u8SrcBusIrq;
|
---|
| 381 | uint8_t u8DstIOAPICId;
|
---|
| 382 | uint8_t u8DstIOAPICInt;
|
---|
| 383 | } *PMPSIOIRQENTRY;
|
---|
| 384 | AssertCompileSize(MPSIOINTERRUPTENTRY, 8);
|
---|
| 385 |
|
---|
| 386 | #pragma pack()
|
---|
| 387 |
|
---|
| 388 |
|
---|
| 389 | /**
|
---|
| 390 | * Calculate a simple checksum for the MPS table.
|
---|
| 391 | *
|
---|
[64369] | 392 | * @param au8Data data
|
---|
| 393 | * @param u32Length size of data
|
---|
[24706] | 394 | */
|
---|
[25048] | 395 | static uint8_t fwCommonChecksum(const uint8_t * const au8Data, uint32_t u32Length)
|
---|
[24706] | 396 | {
|
---|
| 397 | uint8_t u8Sum = 0;
|
---|
| 398 | for (size_t i = 0; i < u32Length; ++i)
|
---|
| 399 | u8Sum += au8Data[i];
|
---|
| 400 | return -u8Sum;
|
---|
| 401 | }
|
---|
| 402 |
|
---|
[28424] | 403 | #if 0 /* unused */
|
---|
[26601] | 404 | static bool fwCommonChecksumOk(const uint8_t * const au8Data, uint32_t u32Length)
|
---|
[25058] | 405 | {
|
---|
| 406 | uint8_t u8Sum = 0;
|
---|
| 407 | for (size_t i = 0; i < u32Length; i++)
|
---|
| 408 | u8Sum += au8Data[i];
|
---|
| 409 | return (u8Sum == 0);
|
---|
| 410 | }
|
---|
[28424] | 411 | #endif
|
---|
[26617] | 412 |
|
---|
[28424] | 413 | /**
|
---|
| 414 | * Try fetch the DMI strings from the system.
|
---|
[26601] | 415 | */
|
---|
| 416 | static void fwCommonUseHostDMIStrings(void)
|
---|
| 417 | {
|
---|
| 418 | int rc;
|
---|
[25058] | 419 |
|
---|
[26601] | 420 | rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME,
|
---|
[26617] | 421 | g_szHostDmiSystemProduct, sizeof(g_szHostDmiSystemProduct));
|
---|
| 422 | if (RT_SUCCESS(rc))
|
---|
[26601] | 423 | {
|
---|
[48755] | 424 | g_pszDefDmiSystemProduct = g_szHostDmiSystemProduct;
|
---|
[26617] | 425 | LogRel(("DMI: Using DmiSystemProduct from host: %s\n", g_szHostDmiSystemProduct));
|
---|
[26601] | 426 | }
|
---|
[25058] | 427 |
|
---|
[26601] | 428 | rc = RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_VERSION,
|
---|
[26617] | 429 | g_szHostDmiSystemVersion, sizeof(g_szHostDmiSystemVersion));
|
---|
| 430 | if (RT_SUCCESS(rc))
|
---|
[26601] | 431 | {
|
---|
[48755] | 432 | g_pszDefDmiSystemVersion = g_szHostDmiSystemVersion;
|
---|
[26617] | 433 | LogRel(("DMI: Using DmiSystemVersion from host: %s\n", g_szHostDmiSystemVersion));
|
---|
[26601] | 434 | }
|
---|
| 435 | }
|
---|
| 436 |
|
---|
[24706] | 437 | /**
|
---|
[100542] | 438 | * Replace the DmiSystemUuid placeholder with the actual value.
|
---|
| 439 | *
|
---|
| 440 | * @param pszBuf Buffer
|
---|
| 441 | * @param cbBuf Size of buffer
|
---|
| 442 | * @param pcszPlaceholder Pointer to placeholder, must be in pszBuf
|
---|
| 443 | * @param cbPlaceholder Length of placeholder
|
---|
| 444 | * @param pcszDmiSystemUuid DmiSystemUuid value
|
---|
| 445 | */
|
---|
| 446 | static void fwUseDmiSystemUuidInString(char *pszBuf, size_t cbBuf,
|
---|
| 447 | const char *pcszPlaceholder, size_t cbPlaceholder,
|
---|
| 448 | const char *pcszDmiSystemUuid)
|
---|
| 449 | {
|
---|
| 450 | size_t const cbPrefix = pcszPlaceholder - pszBuf;
|
---|
| 451 | size_t const cbUuid = strlen(pcszDmiSystemUuid);
|
---|
| 452 | size_t const cbSuffix = strlen(pcszPlaceholder + cbPlaceholder);
|
---|
| 453 | if (cbPrefix + cbUuid + cbSuffix < cbBuf)
|
---|
| 454 | {
|
---|
| 455 | /* Everything fits, no truncation. */
|
---|
| 456 | memmove(pszBuf + cbPrefix + cbUuid, pcszPlaceholder + cbPlaceholder, cbSuffix + 1); \
|
---|
| 457 | memcpy(pszBuf + cbPrefix, pcszDmiSystemUuid, cbUuid); \
|
---|
| 458 | }
|
---|
| 459 | else if (cbPrefix + cbUuid < cbBuf)
|
---|
| 460 | {
|
---|
| 461 | /* Prefix + DmiSystemUuid fits, truncate suffix. */
|
---|
| 462 | memmove(pszBuf + cbPrefix + cbUuid, pcszPlaceholder + cbPlaceholder, cbBuf - cbPrefix - cbUuid - 1); \
|
---|
| 463 | memcpy(pszBuf + cbPrefix, pcszDmiSystemUuid, cbUuid); \
|
---|
| 464 | pszBuf[cbBuf] = '\0';
|
---|
| 465 | }
|
---|
| 466 | else
|
---|
| 467 | {
|
---|
| 468 | /* Prefix fits, truncate DmiSystemUuid. */
|
---|
| 469 | memcpy(pszBuf + cbPrefix, pcszDmiSystemUuid, cbBuf - cbPrefix - 1); \
|
---|
| 470 | pszBuf[cbBuf] = '\0';
|
---|
| 471 | }
|
---|
| 472 | }
|
---|
| 473 |
|
---|
| 474 | /**
|
---|
[24706] | 475 | * Construct the DMI table.
|
---|
| 476 | *
|
---|
| 477 | * @returns VBox status code.
|
---|
[25048] | 478 | * @param pDevIns The device instance.
|
---|
| 479 | * @param pTable Where to create the DMI table.
|
---|
[26728] | 480 | * @param cbMax The maximum size of the DMI table.
|
---|
[25048] | 481 | * @param pUuid Pointer to the UUID to use if the DmiUuid
|
---|
| 482 | * configuration string isn't present.
|
---|
[26173] | 483 | * @param pCfg The handle to our config node.
|
---|
[44820] | 484 | * @param cCpus Number of VCPUs.
|
---|
| 485 | * @param pcbDmiTables Size of DMI data in bytes.
|
---|
[81925] | 486 | * @param pcDmiTables Number of DMI tables.
|
---|
[83032] | 487 | * @param fUefi Flag whether the UEFI specification is supported.
|
---|
[24706] | 488 | */
|
---|
[81925] | 489 | int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, PCRTUUID pUuid, PCFGMNODE pCfg, uint16_t cCpus,
|
---|
[83032] | 490 | uint16_t *pcbDmiTables, uint16_t *pcDmiTables, bool fUefi)
|
---|
[24706] | 491 | {
|
---|
[81919] | 492 | PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
|
---|
| 493 |
|
---|
[48755] | 494 | /*
|
---|
| 495 | * CFGM Hint!
|
---|
| 496 | *
|
---|
| 497 | * The macros below makes it a bit hard to figure out the config options
|
---|
| 498 | * available here. To get a quick hint, take a look a the CFGM
|
---|
| 499 | * validation in the calling code (DevEFI.cpp and DevPcBios.cpp).
|
---|
| 500 | *
|
---|
| 501 | * 32-bit signed integer CFGM options are read by DMI_READ_CFG_S32, the 2nd
|
---|
| 502 | * parameter is the CFGM value name.
|
---|
| 503 | *
|
---|
| 504 | * Strings are read by DMI_READ_CFG_STR and DMI_READ_CFG_STR_DEF, the 2nd parameter is
|
---|
| 505 | * the CFGM value name.
|
---|
| 506 | */
|
---|
| 507 | #define DMI_CHECK_SIZE(cbWant) \
|
---|
[25162] | 508 | { \
|
---|
| 509 | size_t cbNeed = (size_t)(pszStr + cbWant - (char *)pTable) + 5; /* +1 for strtab terminator +4 for end-of-table entry */ \
|
---|
| 510 | if (cbNeed > cbMax) \
|
---|
[24706] | 511 | { \
|
---|
[25162] | 512 | if (fHideErrors) \
|
---|
| 513 | { \
|
---|
| 514 | LogRel(("One of the DMI strings is too long -- using default DMI data!\n")); \
|
---|
| 515 | continue; \
|
---|
| 516 | } \
|
---|
[24706] | 517 | return PDMDevHlpVMSetError(pDevIns, VERR_TOO_MUCH_DATA, RT_SRC_POS, \
|
---|
[25162] | 518 | N_("One of the DMI strings is too long. Check all bios/Dmi* configuration entries. At least %zu bytes are needed but there is no space for more than %d bytes"), cbNeed, cbMax); \
|
---|
[24706] | 519 | } \
|
---|
[25162] | 520 | }
|
---|
| 521 |
|
---|
[48755] | 522 | #define DMI_READ_CFG_STR_DEF(variable, name, default_value) \
|
---|
[25162] | 523 | { \
|
---|
| 524 | if (fForceDefault) \
|
---|
| 525 | pszTmp = default_value; \
|
---|
[24706] | 526 | else \
|
---|
| 527 | { \
|
---|
[81919] | 528 | rc = pHlp->pfnCFGMQueryStringDef(pCfg, name, szBuf, sizeof(szBuf), default_value); \
|
---|
[25162] | 529 | if (RT_FAILURE(rc)) \
|
---|
| 530 | { \
|
---|
| 531 | if (fHideErrors) \
|
---|
| 532 | { \
|
---|
| 533 | LogRel(("Configuration error: Querying \"" name "\" as a string failed -- using default DMI data!\n")); \
|
---|
| 534 | continue; \
|
---|
| 535 | } \
|
---|
| 536 | return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
|
---|
| 537 | N_("Configuration error: Querying \"" name "\" as a string failed")); \
|
---|
| 538 | } \
|
---|
[93952] | 539 | if (!strcmp(szBuf, "<EMPTY>")) \
|
---|
[25162] | 540 | pszTmp = ""; \
|
---|
[100542] | 541 | else if ((pszTmp = RTStrStr(szBuf, "<DmiSystemUuid>"))) \
|
---|
| 542 | { \
|
---|
| 543 | char *pszUuid = pszDmiSystemUuid; \
|
---|
| 544 | if (!pszUuid) \
|
---|
| 545 | { \
|
---|
| 546 | pszUuid = (char *)alloca(RTUUID_STR_LENGTH); \
|
---|
| 547 | RTUuidToStr(pUuid, pszUuid, RTUUID_STR_LENGTH); \
|
---|
| 548 | } \
|
---|
| 549 | fwUseDmiSystemUuidInString(szBuf, sizeof(szBuf), pszTmp, 15, pszUuid); \
|
---|
| 550 | pszTmp = szBuf; \
|
---|
| 551 | } \
|
---|
[25162] | 552 | else \
|
---|
| 553 | pszTmp = szBuf; \
|
---|
[24706] | 554 | } \
|
---|
[25162] | 555 | if (!pszTmp[0]) \
|
---|
| 556 | variable = 0; /* empty string */ \
|
---|
| 557 | else \
|
---|
| 558 | { \
|
---|
| 559 | variable = iStrNr++; \
|
---|
[93952] | 560 | size_t const cbStr = strlen(pszTmp) + 1; \
|
---|
| 561 | DMI_CHECK_SIZE(cbStr); \
|
---|
| 562 | pszStr = (char *)mempcpy(pszStr, pszTmp, cbStr); \
|
---|
[25162] | 563 | } \
|
---|
| 564 | }
|
---|
[24706] | 565 |
|
---|
[48755] | 566 | #define DMI_READ_CFG_STR(variable, name) \
|
---|
| 567 | DMI_READ_CFG_STR_DEF(variable, # name, g_pszDef ## name)
|
---|
[24706] | 568 |
|
---|
[48755] | 569 | #define DMI_READ_CFG_S32(variable, name) \
|
---|
[25162] | 570 | { \
|
---|
| 571 | if (fForceDefault) \
|
---|
[48755] | 572 | variable = g_iDef ## name; \
|
---|
[25162] | 573 | else \
|
---|
| 574 | { \
|
---|
[81919] | 575 | rc = pHlp->pfnCFGMQueryS32Def(pCfg, # name, & variable, g_iDef ## name); \
|
---|
[25162] | 576 | if (RT_FAILURE(rc)) \
|
---|
| 577 | { \
|
---|
| 578 | if (fHideErrors) \
|
---|
| 579 | { \
|
---|
| 580 | LogRel(("Configuration error: Querying \"" # name "\" as an int failed -- using default DMI data!\n")); \
|
---|
| 581 | continue; \
|
---|
| 582 | } \
|
---|
| 583 | return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, \
|
---|
| 584 | N_("Configuration error: Querying \"" # name "\" as an int failed")); \
|
---|
| 585 | } \
|
---|
| 586 | } \
|
---|
| 587 | }
|
---|
| 588 |
|
---|
[93952] | 589 | #define DMI_START_STRUCT(a_pTbl) do { \
|
---|
| 590 | pszStr = (char *)((a_pTbl) + 1); \
|
---|
| 591 | iStrNr = 1; \
|
---|
| 592 | } while (0)
|
---|
[28568] | 593 |
|
---|
[93952] | 594 | #if 0 /* GCC 11.2.1 barfs on this: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=] */
|
---|
| 595 | # define DMI_TERM_STRUCT do { \
|
---|
[26728] | 596 | *pszStr++ = '\0'; /* terminate set of text strings */ \
|
---|
| 597 | if (iStrNr == 1) \
|
---|
| 598 | *pszStr++ = '\0'; /* terminate a structure without strings */ \
|
---|
[93952] | 599 | } while (0)
|
---|
| 600 | #else
|
---|
| 601 | # define DMI_TERM_STRUCT do { \
|
---|
| 602 | size_t const cbToZero = iStrNr == 1 ? 2 : 1; \
|
---|
| 603 | pszStr = (char *)memset(pszStr, 0, cbToZero) + cbToZero; \
|
---|
| 604 | } while (0)
|
---|
| 605 | #endif
|
---|
[26728] | 606 |
|
---|
[25162] | 607 | bool fForceDefault = false;
|
---|
| 608 | #ifdef VBOX_BIOS_DMI_FALLBACK
|
---|
[24706] | 609 | /*
|
---|
[25162] | 610 | * There will be two passes. If an error occurs during the first pass, a
|
---|
| 611 | * message will be written to the release log and we fall back to default
|
---|
| 612 | * DMI data and start a second pass.
|
---|
[24706] | 613 | */
|
---|
[25162] | 614 | bool fHideErrors = true;
|
---|
| 615 | #else
|
---|
| 616 | /*
|
---|
| 617 | * There will be one pass, every error is fatal and will prevent the VM
|
---|
| 618 | * from starting.
|
---|
| 619 | */
|
---|
| 620 | bool fHideErrors = false;
|
---|
| 621 | #endif
|
---|
[24706] | 622 |
|
---|
[26601] | 623 | uint8_t fDmiUseHostInfo;
|
---|
[81919] | 624 | int rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DmiUseHostInfo", &fDmiUseHostInfo, 0);
|
---|
[26601] | 625 | if (RT_FAILURE (rc))
|
---|
[81919] | 626 | return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiUseHostInfo\""));
|
---|
[26601] | 627 |
|
---|
| 628 | /* Sync up with host default DMI values */
|
---|
| 629 | if (fDmiUseHostInfo)
|
---|
| 630 | fwCommonUseHostDMIStrings();
|
---|
| 631 |
|
---|
[28580] | 632 | uint8_t fDmiExposeMemoryTable;
|
---|
[81919] | 633 | rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DmiExposeMemoryTable", &fDmiExposeMemoryTable, 0);
|
---|
[28569] | 634 | if (RT_FAILURE (rc))
|
---|
[81919] | 635 | return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiExposeMemoryTable\""));
|
---|
[39707] | 636 | uint8_t fDmiExposeProcessorInf;
|
---|
[81919] | 637 | rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DmiExposeProcInf", &fDmiExposeProcessorInf, 0);
|
---|
[39707] | 638 | if (RT_FAILURE (rc))
|
---|
[81919] | 639 | return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"DmiExposeProcInf\""));
|
---|
[28569] | 640 |
|
---|
[25162] | 641 | for (;; fForceDefault = true, fHideErrors = false)
|
---|
| 642 | {
|
---|
| 643 | int iStrNr;
|
---|
| 644 | char szBuf[256];
|
---|
| 645 | char *pszStr = (char *)pTable;
|
---|
| 646 | char szDmiSystemUuid[64];
|
---|
| 647 | char *pszDmiSystemUuid;
|
---|
| 648 | const char *pszTmp;
|
---|
[24706] | 649 |
|
---|
[25162] | 650 | if (fForceDefault)
|
---|
| 651 | pszDmiSystemUuid = NULL;
|
---|
| 652 | else
|
---|
[24706] | 653 | {
|
---|
[81919] | 654 | rc = pHlp->pfnCFGMQueryString(pCfg, "DmiSystemUuid", szDmiSystemUuid, sizeof(szDmiSystemUuid));
|
---|
[25162] | 655 | if (rc == VERR_CFGM_VALUE_NOT_FOUND)
|
---|
| 656 | pszDmiSystemUuid = NULL;
|
---|
| 657 | else if (RT_FAILURE(rc))
|
---|
| 658 | {
|
---|
| 659 | if (fHideErrors)
|
---|
| 660 | {
|
---|
| 661 | LogRel(("Configuration error: Querying \"DmiSystemUuid\" as a string failed, using default DMI data\n"));
|
---|
| 662 | continue;
|
---|
| 663 | }
|
---|
| 664 | return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
|
---|
| 665 | N_("Configuration error: Querying \"DmiSystemUuid\" as a string failed"));
|
---|
| 666 | }
|
---|
| 667 | else
|
---|
| 668 | pszDmiSystemUuid = szDmiSystemUuid;
|
---|
[24706] | 669 | }
|
---|
| 670 |
|
---|
[25162] | 671 | /*********************************
|
---|
| 672 | * DMI BIOS information (Type 0) *
|
---|
| 673 | *********************************/
|
---|
| 674 | PDMIBIOSINF pBIOSInf = (PDMIBIOSINF)pszStr;
|
---|
[48755] | 675 | DMI_CHECK_SIZE(sizeof(*pBIOSInf));
|
---|
[24706] | 676 |
|
---|
[25162] | 677 | pszStr = (char *)&pBIOSInf->u8ReleaseMajor;
|
---|
| 678 | pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8ReleaseMajor);
|
---|
[24706] | 679 |
|
---|
[25162] | 680 | /* don't set these fields by default for legacy compatibility */
|
---|
| 681 | int iDmiBIOSReleaseMajor, iDmiBIOSReleaseMinor;
|
---|
[48755] | 682 | DMI_READ_CFG_S32(iDmiBIOSReleaseMajor, DmiBIOSReleaseMajor);
|
---|
| 683 | DMI_READ_CFG_S32(iDmiBIOSReleaseMinor, DmiBIOSReleaseMinor);
|
---|
[25162] | 684 | if (iDmiBIOSReleaseMajor != 0 || iDmiBIOSReleaseMinor != 0)
|
---|
| 685 | {
|
---|
| 686 | pszStr = (char *)&pBIOSInf->u8FirmwareMajor;
|
---|
| 687 | pBIOSInf->header.u8Length = RT_OFFSETOF(DMIBIOSINF, u8FirmwareMajor);
|
---|
| 688 | pBIOSInf->u8ReleaseMajor = iDmiBIOSReleaseMajor;
|
---|
| 689 | pBIOSInf->u8ReleaseMinor = iDmiBIOSReleaseMinor;
|
---|
[24706] | 690 |
|
---|
[25162] | 691 | int iDmiBIOSFirmwareMajor, iDmiBIOSFirmwareMinor;
|
---|
[48755] | 692 | DMI_READ_CFG_S32(iDmiBIOSFirmwareMajor, DmiBIOSFirmwareMajor);
|
---|
| 693 | DMI_READ_CFG_S32(iDmiBIOSFirmwareMinor, DmiBIOSFirmwareMinor);
|
---|
[25162] | 694 | if (iDmiBIOSFirmwareMajor != 0 || iDmiBIOSFirmwareMinor != 0)
|
---|
| 695 | {
|
---|
| 696 | pszStr = (char *)(pBIOSInf + 1);
|
---|
| 697 | pBIOSInf->header.u8Length = sizeof(DMIBIOSINF);
|
---|
| 698 | pBIOSInf->u8FirmwareMajor = iDmiBIOSFirmwareMajor;
|
---|
| 699 | pBIOSInf->u8FirmwareMinor = iDmiBIOSFirmwareMinor;
|
---|
| 700 | }
|
---|
| 701 | }
|
---|
[24706] | 702 |
|
---|
[25162] | 703 | iStrNr = 1;
|
---|
| 704 | pBIOSInf->header.u8Type = 0; /* BIOS Information */
|
---|
| 705 | pBIOSInf->header.u16Handle = 0x0000;
|
---|
[48755] | 706 | DMI_READ_CFG_STR(pBIOSInf->u8Vendor, DmiBIOSVendor);
|
---|
| 707 | DMI_READ_CFG_STR(pBIOSInf->u8Version, DmiBIOSVersion);
|
---|
[25162] | 708 | pBIOSInf->u16Start = 0xE000;
|
---|
[48755] | 709 | DMI_READ_CFG_STR(pBIOSInf->u8Release, DmiBIOSReleaseDate);
|
---|
[25162] | 710 | pBIOSInf->u8ROMSize = 1; /* 128K */
|
---|
| 711 | pBIOSInf->u64Characteristics = RT_BIT(4) /* ISA is supported */
|
---|
| 712 | | RT_BIT(7) /* PCI is supported */
|
---|
| 713 | | RT_BIT(15) /* Boot from CD is supported */
|
---|
| 714 | | RT_BIT(16) /* Selectable Boot is supported */
|
---|
| 715 | | RT_BIT(27) /* Int 9h, 8042 Keyboard services supported */
|
---|
| 716 | | RT_BIT(30) /* Int 10h, CGA/Mono Video Services supported */
|
---|
| 717 | /* any more?? */
|
---|
| 718 | ;
|
---|
| 719 | pBIOSInf->u8CharacteristicsByte1 = RT_BIT(0) /* ACPI is supported */
|
---|
| 720 | /* any more?? */
|
---|
| 721 | ;
|
---|
[102788] | 722 | pBIOSInf->u8CharacteristicsByte2 = RT_BIT(2) /* Enable targeted content distribution, needed by Windows to populate registry, see
|
---|
| 723 | https://download.microsoft.com/download/5/D/6/5D6EAF2B-7DDF-476B-93DC-7CF0072878E6/SMBIOS.doc */
|
---|
| 724 | | fUefi ? RT_BIT(3) : 0
|
---|
[25162] | 725 | /* any more?? */
|
---|
| 726 | ;
|
---|
[48755] | 727 | DMI_TERM_STRUCT;
|
---|
[25219] | 728 |
|
---|
[25162] | 729 | /***********************************
|
---|
| 730 | * DMI system information (Type 1) *
|
---|
| 731 | ***********************************/
|
---|
| 732 | PDMISYSTEMINF pSystemInf = (PDMISYSTEMINF)pszStr;
|
---|
[48755] | 733 | DMI_CHECK_SIZE(sizeof(*pSystemInf));
|
---|
| 734 | DMI_START_STRUCT(pSystemInf);
|
---|
[25162] | 735 | pSystemInf->header.u8Type = 1; /* System Information */
|
---|
| 736 | pSystemInf->header.u8Length = sizeof(*pSystemInf);
|
---|
| 737 | pSystemInf->header.u16Handle = 0x0001;
|
---|
[48755] | 738 | DMI_READ_CFG_STR(pSystemInf->u8Manufacturer, DmiSystemVendor);
|
---|
| 739 | DMI_READ_CFG_STR(pSystemInf->u8ProductName, DmiSystemProduct);
|
---|
| 740 | DMI_READ_CFG_STR(pSystemInf->u8Version, DmiSystemVersion);
|
---|
| 741 | DMI_READ_CFG_STR(pSystemInf->u8SerialNumber, DmiSystemSerial);
|
---|
[25219] | 742 |
|
---|
[25162] | 743 | RTUUID uuid;
|
---|
| 744 | if (pszDmiSystemUuid)
|
---|
| 745 | {
|
---|
| 746 | rc = RTUuidFromStr(&uuid, pszDmiSystemUuid);
|
---|
| 747 | if (RT_FAILURE(rc))
|
---|
[25191] | 748 | {
|
---|
| 749 | if (fHideErrors)
|
---|
| 750 | {
|
---|
| 751 | LogRel(("Configuration error: Invalid UUID for DMI tables specified, using default DMI data\n"));
|
---|
| 752 | continue;
|
---|
| 753 | }
|
---|
[25162] | 754 | return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
|
---|
[25191] | 755 | N_("Configuration error: Invalid UUID for DMI tables specified"));
|
---|
| 756 | }
|
---|
[25162] | 757 | uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
|
---|
| 758 | uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
|
---|
| 759 | uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
|
---|
| 760 | pUuid = &uuid;
|
---|
| 761 | }
|
---|
| 762 | memcpy(pSystemInf->au8Uuid, pUuid, sizeof(RTUUID));
|
---|
[25219] | 763 |
|
---|
[25162] | 764 | pSystemInf->u8WakeupType = 6; /* Power Switch */
|
---|
[48755] | 765 | DMI_READ_CFG_STR(pSystemInf->u8SKUNumber, DmiSystemSKU);
|
---|
| 766 | DMI_READ_CFG_STR(pSystemInf->u8Family, DmiSystemFamily);
|
---|
| 767 | DMI_TERM_STRUCT;
|
---|
[25219] | 768 |
|
---|
[40019] | 769 | /**********************************
|
---|
| 770 | * DMI board information (Type 2) *
|
---|
| 771 | **********************************/
|
---|
| 772 | PDMIBOARDINF pBoardInf = (PDMIBOARDINF)pszStr;
|
---|
[48755] | 773 | DMI_CHECK_SIZE(sizeof(*pBoardInf));
|
---|
| 774 | DMI_START_STRUCT(pBoardInf);
|
---|
[40019] | 775 | int iDmiBoardBoardType;
|
---|
| 776 | pBoardInf->header.u8Type = 2; /* Board Information */
|
---|
| 777 | pBoardInf->header.u8Length = sizeof(*pBoardInf);
|
---|
| 778 | pBoardInf->header.u16Handle = 0x0008;
|
---|
[48755] | 779 | DMI_READ_CFG_STR(pBoardInf->u8Manufacturer, DmiBoardVendor);
|
---|
| 780 | DMI_READ_CFG_STR(pBoardInf->u8Product, DmiBoardProduct);
|
---|
| 781 | DMI_READ_CFG_STR(pBoardInf->u8Version, DmiBoardVersion);
|
---|
| 782 | DMI_READ_CFG_STR(pBoardInf->u8SerialNumber, DmiBoardSerial);
|
---|
| 783 | DMI_READ_CFG_STR(pBoardInf->u8AssetTag, DmiBoardAssetTag);
|
---|
[40019] | 784 | pBoardInf->u8FeatureFlags = RT_BIT(0) /* hosting board, e.g. motherboard */
|
---|
| 785 | ;
|
---|
[48755] | 786 | DMI_READ_CFG_STR(pBoardInf->u8LocationInChass, DmiBoardLocInChass);
|
---|
[40019] | 787 | pBoardInf->u16ChassisHandle = 0x0003; /* see type 3 */
|
---|
[48755] | 788 | DMI_READ_CFG_S32(iDmiBoardBoardType, DmiBoardBoardType);
|
---|
[40019] | 789 | pBoardInf->u8BoardType = iDmiBoardBoardType;
|
---|
| 790 | pBoardInf->u8cObjectHandles = 0;
|
---|
| 791 |
|
---|
[48755] | 792 | DMI_TERM_STRUCT;
|
---|
[40019] | 793 |
|
---|
[25162] | 794 | /********************************************
|
---|
| 795 | * DMI System Enclosure or Chassis (Type 3) *
|
---|
| 796 | ********************************************/
|
---|
| 797 | PDMICHASSIS pChassis = (PDMICHASSIS)pszStr;
|
---|
[48755] | 798 | DMI_CHECK_SIZE(sizeof(*pChassis));
|
---|
[93952] | 799 | pszStr = (char *)&pChassis->u32OEMdefined;
|
---|
[25162] | 800 | iStrNr = 1;
|
---|
[24706] | 801 | #ifdef VBOX_WITH_DMI_CHASSIS
|
---|
[25162] | 802 | pChassis->header.u8Type = 3; /* System Enclosure or Chassis */
|
---|
[24706] | 803 | #else
|
---|
[25162] | 804 | pChassis->header.u8Type = 0x7e; /* inactive */
|
---|
[24706] | 805 | #endif
|
---|
[25162] | 806 | pChassis->header.u8Length = RT_OFFSETOF(DMICHASSIS, u32OEMdefined);
|
---|
| 807 | pChassis->header.u16Handle = 0x0003;
|
---|
[48755] | 808 | DMI_READ_CFG_STR(pChassis->u8Manufacturer, DmiChassisVendor);
|
---|
[46355] | 809 | int iDmiChassisType;
|
---|
[48755] | 810 | DMI_READ_CFG_S32(iDmiChassisType, DmiChassisType);
|
---|
[46355] | 811 | pChassis->u8Type = iDmiChassisType;
|
---|
[48755] | 812 | DMI_READ_CFG_STR(pChassis->u8Version, DmiChassisVersion);
|
---|
| 813 | DMI_READ_CFG_STR(pChassis->u8SerialNumber, DmiChassisSerial);
|
---|
| 814 | DMI_READ_CFG_STR(pChassis->u8AssetTag, DmiChassisAssetTag);
|
---|
[25162] | 815 | pChassis->u8BootupState = 0x03; /* safe */
|
---|
| 816 | pChassis->u8PowerSupplyState = 0x03; /* safe */
|
---|
| 817 | pChassis->u8ThermalState = 0x03; /* safe */
|
---|
| 818 | pChassis->u8SecurityStatus = 0x03; /* none XXX */
|
---|
[24706] | 819 | # if 0
|
---|
[25162] | 820 | /* v2.3+, currently not supported */
|
---|
| 821 | pChassis->u32OEMdefined = 0;
|
---|
| 822 | pChassis->u8Height = 0; /* unspecified */
|
---|
| 823 | pChassis->u8NumPowerChords = 0; /* unspecified */
|
---|
| 824 | pChassis->u8ContElems = 0; /* no contained elements */
|
---|
| 825 | pChassis->u8ContElemRecLen = 0; /* no contained elements */
|
---|
[24706] | 826 | # endif
|
---|
[48755] | 827 | DMI_TERM_STRUCT;
|
---|
[25219] | 828 |
|
---|
[39707] | 829 | /**************************************
|
---|
| 830 | * DMI Processor Information (Type 4) *
|
---|
| 831 | **************************************/
|
---|
| 832 |
|
---|
| 833 | /*
|
---|
| 834 | * This is just a dummy processor. Should we expose the real guest CPU features
|
---|
| 835 | * here? Accessing this information at this point is difficult.
|
---|
| 836 | */
|
---|
| 837 | char szSocket[32];
|
---|
| 838 | PDMIPROCESSORINF pProcessorInf = (PDMIPROCESSORINF)pszStr;
|
---|
[48755] | 839 | DMI_CHECK_SIZE(sizeof(*pProcessorInf));
|
---|
| 840 | DMI_START_STRUCT(pProcessorInf);
|
---|
[39707] | 841 | if (fDmiExposeProcessorInf)
|
---|
| 842 | pProcessorInf->header.u8Type = 4; /* Processor Information */
|
---|
| 843 | else
|
---|
| 844 | pProcessorInf->header.u8Type = 126; /* inactive structure */
|
---|
| 845 | pProcessorInf->header.u8Length = sizeof(*pProcessorInf);
|
---|
| 846 | pProcessorInf->header.u16Handle = 0x0007;
|
---|
| 847 | RTStrPrintf(szSocket, sizeof(szSocket), "Socket #%u", 0);
|
---|
| 848 | pProcessorInf->u8SocketDesignation = iStrNr++;
|
---|
[28569] | 849 | {
|
---|
[93953] | 850 | size_t const cbStr = strlen(szSocket) + 1;
|
---|
[93952] | 851 | DMI_CHECK_SIZE(cbStr);
|
---|
| 852 | pszStr = (char *)mempcpy(pszStr, szSocket, cbStr);
|
---|
[39707] | 853 | }
|
---|
| 854 | pProcessorInf->u8ProcessorType = 0x03; /* Central Processor */
|
---|
| 855 | pProcessorInf->u8ProcessorFamily = 0xB1; /* Pentium III with Intel SpeedStep(TM) */
|
---|
[48755] | 856 | DMI_READ_CFG_STR(pProcessorInf->u8ProcessorManufacturer, DmiProcManufacturer);
|
---|
[28568] | 857 |
|
---|
[39707] | 858 | pProcessorInf->u64ProcessorID = UINT64_C(0x0FEBFBFF00010676);
|
---|
| 859 | /* Ext Family ID = 0
|
---|
| 860 | * Ext Model ID = 2
|
---|
| 861 | * Processor Type = 0
|
---|
| 862 | * Family ID = 6
|
---|
| 863 | * Model = 7
|
---|
| 864 | * Stepping = 6
|
---|
| 865 | * Features: FPU, VME, DE, PSE, TSC, MSR, PAE, MCE, CX8,
|
---|
| 866 | * APIC, SEP, MTRR, PGE, MCA, CMOV, PAT, PSE-36,
|
---|
| 867 | * CFLSH, DS, ACPI, MMX, FXSR, SSE, SSE2, SS */
|
---|
[48755] | 868 | DMI_READ_CFG_STR(pProcessorInf->u8ProcessorVersion, DmiProcVersion);
|
---|
[39707] | 869 | pProcessorInf->u8Voltage = 0x02; /* 3.3V */
|
---|
| 870 | pProcessorInf->u16ExternalClock = 0x00; /* unknown */
|
---|
| 871 | pProcessorInf->u16MaxSpeed = 3000; /* 3GHz */
|
---|
| 872 | pProcessorInf->u16CurrentSpeed = 3000; /* 3GHz */
|
---|
| 873 | pProcessorInf->u8Status = RT_BIT(6) /* CPU socket populated */
|
---|
| 874 | | RT_BIT(0) /* CPU enabled */
|
---|
| 875 | ;
|
---|
| 876 | pProcessorInf->u8ProcessorUpgrade = 0x04; /* ZIF Socket */
|
---|
[44752] | 877 | pProcessorInf->u16L1CacheHandle = 0xFFFF; /* not specified */
|
---|
| 878 | pProcessorInf->u16L2CacheHandle = 0xFFFF; /* not specified */
|
---|
| 879 | pProcessorInf->u16L3CacheHandle = 0xFFFF; /* not specified */
|
---|
[39707] | 880 | pProcessorInf->u8SerialNumber = 0; /* not specified */
|
---|
| 881 | pProcessorInf->u8AssetTag = 0; /* not specified */
|
---|
| 882 | pProcessorInf->u8PartNumber = 0; /* not specified */
|
---|
| 883 | pProcessorInf->u8CoreCount = cCpus; /* */
|
---|
| 884 | pProcessorInf->u8CoreEnabled = cCpus;
|
---|
| 885 | pProcessorInf->u8ThreadCount = 1;
|
---|
[48947] | 886 | pProcessorInf->u16ProcessorCharacteristics
|
---|
[39707] | 887 | = RT_BIT(2); /* 64-bit capable */
|
---|
| 888 | pProcessorInf->u16ProcessorFamily2 = 0;
|
---|
[48755] | 889 | DMI_TERM_STRUCT;
|
---|
[28568] | 890 |
|
---|
[39707] | 891 | /***************************************
|
---|
| 892 | * DMI Physical Memory Array (Type 16) *
|
---|
| 893 | ***************************************/
|
---|
[91897] | 894 | uint64_t const cbRamSize = PDMDevHlpMMPhysGetRamSize(pDevIns);
|
---|
[28568] | 895 |
|
---|
[39707] | 896 | PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr;
|
---|
[48755] | 897 | DMI_CHECK_SIZE(sizeof(*pMemArray));
|
---|
| 898 | DMI_START_STRUCT(pMemArray);
|
---|
[39707] | 899 | if (fDmiExposeMemoryTable)
|
---|
| 900 | pMemArray->header.u8Type = 16; /* Physical Memory Array */
|
---|
| 901 | else
|
---|
| 902 | pMemArray->header.u8Type = 126; /* inactive structure */
|
---|
| 903 | pMemArray->header.u8Length = sizeof(*pMemArray);
|
---|
| 904 | pMemArray->header.u16Handle = 0x0005;
|
---|
| 905 | pMemArray->u8Location = 0x03; /* Motherboard */
|
---|
| 906 | pMemArray->u8Use = 0x03; /* System memory */
|
---|
| 907 | pMemArray->u8MemErrorCorrection = 0x01; /* Other */
|
---|
[65850] | 908 | if (cbRamSize / _1K > INT32_MAX)
|
---|
| 909 | {
|
---|
| 910 | /** @todo 2TB-1K limit. In such cases we probably need to provide multiple type-16 descriptors.
|
---|
| 911 | * Or use 0x8000'0000 = 'capacity unknown'? */
|
---|
| 912 | AssertLogRelMsgFailed(("DMI: RAM size %#RX64 does not fit into type-16 descriptor, clipping to %#RX64\n",
|
---|
| 913 | cbRamSize, (uint64_t)INT32_MAX * _1K));
|
---|
| 914 | pMemArray->u32MaxCapacity = INT32_MAX;
|
---|
| 915 | }
|
---|
| 916 | else
|
---|
| 917 | pMemArray->u32MaxCapacity = (int32_t)(cbRamSize / _1K); /* RAM size in K */
|
---|
[39707] | 918 | pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */
|
---|
| 919 | pMemArray->u16NumberOfMemDevices = 1;
|
---|
[48755] | 920 | DMI_TERM_STRUCT;
|
---|
[28568] | 921 |
|
---|
[39707] | 922 | /***************************************
|
---|
| 923 | * DMI Memory Device (Type 17) *
|
---|
| 924 | ***************************************/
|
---|
| 925 | PDMIMEMORYDEV pMemDev = (PDMIMEMORYDEV)pszStr;
|
---|
[48755] | 926 | DMI_CHECK_SIZE(sizeof(*pMemDev));
|
---|
| 927 | DMI_START_STRUCT(pMemDev);
|
---|
[39707] | 928 | if (fDmiExposeMemoryTable)
|
---|
| 929 | pMemDev->header.u8Type = 17; /* Memory Device */
|
---|
| 930 | else
|
---|
| 931 | pMemDev->header.u8Type = 126; /* inactive structure */
|
---|
| 932 | pMemDev->header.u8Length = sizeof(*pMemDev);
|
---|
| 933 | pMemDev->header.u16Handle = 0x0006;
|
---|
| 934 | pMemDev->u16PhysMemArrayHandle = 0x0005; /* handle of array we belong to */
|
---|
| 935 | pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */
|
---|
| 936 | pMemDev->u16TotalWidth = 0xffff; /* Unknown */
|
---|
| 937 | pMemDev->u16DataWidth = 0xffff; /* Unknown */
|
---|
[65850] | 938 | int16_t u16RamSizeM;
|
---|
[83133] | 939 | int32_t u32ExtRamSizeM = 0;
|
---|
[65850] | 940 | if (cbRamSize / _1M > INT16_MAX)
|
---|
| 941 | {
|
---|
[83134] | 942 | /* The highest bit of u16Size must be 0 to specify 'MB' units / 1 would be 'KB'.
|
---|
[93528] | 943 | * SMBIOS 2.7 introduced a 32-bit extended size. If module size is 32GB or greater,
|
---|
[83133] | 944 | * the old u16Size is set to 7FFFh; old parsers will see 32GB-1MB, new parsers will
|
---|
| 945 | * look at new u32ExtendedSize which can represent at least 128TB. OS X 10.14+ looks
|
---|
| 946 | * at the extended size.
|
---|
| 947 | */
|
---|
[85948] | 948 | LogRel(("DMI: RAM size %#RX64 too big for one type-17 descriptor, clipping to %#RX64\n",
|
---|
| 949 | cbRamSize, (uint64_t)INT16_MAX * _1M));
|
---|
[65850] | 950 | u16RamSizeM = INT16_MAX;
|
---|
[83133] | 951 | if (cbRamSize / _1M >= 0x8000000) {
|
---|
| 952 | AssertLogRelMsgFailed(("DMI: RAM size %#RX64 too big for one type-17 descriptor, clipping to %#RX64\n",
|
---|
| 953 | cbRamSize, (uint64_t)INT32_MAX * _1M));
|
---|
| 954 | u32ExtRamSizeM = 0x8000000; /* 128TB */
|
---|
| 955 | }
|
---|
| 956 | else
|
---|
| 957 | u32ExtRamSizeM = cbRamSize / _1M;
|
---|
[65850] | 958 | }
|
---|
| 959 | else
|
---|
| 960 | u16RamSizeM = (uint16_t)(cbRamSize / _1M);
|
---|
[39707] | 961 | if (u16RamSizeM == 0)
|
---|
| 962 | u16RamSizeM = 0x400; /* 1G */
|
---|
| 963 | pMemDev->u16Size = u16RamSizeM; /* RAM size */
|
---|
[83133] | 964 | pMemDev->u32ExtendedSize = u32ExtRamSizeM;
|
---|
[39707] | 965 | pMemDev->u8FormFactor = 0x09; /* DIMM */
|
---|
| 966 | pMemDev->u8DeviceSet = 0x00; /* Not part of a device set */
|
---|
[48755] | 967 | DMI_READ_CFG_STR_DEF(pMemDev->u8DeviceLocator, " ", "DIMM 0");
|
---|
| 968 | DMI_READ_CFG_STR_DEF(pMemDev->u8BankLocator, " ", "Bank 0");
|
---|
[39707] | 969 | pMemDev->u8MemoryType = 0x03; /* DRAM */
|
---|
| 970 | pMemDev->u16TypeDetail = 0; /* Nothing special */
|
---|
| 971 | pMemDev->u16Speed = 1600; /* Unknown, shall be speed in MHz */
|
---|
[48755] | 972 | DMI_READ_CFG_STR(pMemDev->u8Manufacturer, DmiSystemVendor);
|
---|
| 973 | DMI_READ_CFG_STR_DEF(pMemDev->u8SerialNumber, " ", "00000000");
|
---|
| 974 | DMI_READ_CFG_STR_DEF(pMemDev->u8AssetTag, " ", "00000000");
|
---|
| 975 | DMI_READ_CFG_STR_DEF(pMemDev->u8PartNumber, " ", "00000000");
|
---|
[39707] | 976 | pMemDev->u8Attributes = 0; /* Unknown */
|
---|
[48755] | 977 | DMI_TERM_STRUCT;
|
---|
[28568] | 978 |
|
---|
[25162] | 979 | /*****************************
|
---|
| 980 | * DMI OEM strings (Type 11) *
|
---|
| 981 | *****************************/
|
---|
| 982 | PDMIOEMSTRINGS pOEMStrings = (PDMIOEMSTRINGS)pszStr;
|
---|
[48755] | 983 | DMI_CHECK_SIZE(sizeof(*pOEMStrings));
|
---|
| 984 | DMI_START_STRUCT(pOEMStrings);
|
---|
[24706] | 985 | #ifdef VBOX_WITH_DMI_OEMSTRINGS
|
---|
[25162] | 986 | pOEMStrings->header.u8Type = 0xb; /* OEM Strings */
|
---|
[24706] | 987 | #else
|
---|
[39707] | 988 | pOEMStrings->header.u8Type = 126; /* inactive structure */
|
---|
[24706] | 989 | #endif
|
---|
[25162] | 990 | pOEMStrings->header.u8Length = sizeof(*pOEMStrings);
|
---|
| 991 | pOEMStrings->header.u16Handle = 0x0002;
|
---|
| 992 | pOEMStrings->u8Count = 2;
|
---|
[25219] | 993 |
|
---|
[25162] | 994 | char szTmp[64];
|
---|
| 995 | RTStrPrintf(szTmp, sizeof(szTmp), "vboxVer_%u.%u.%u",
|
---|
| 996 | RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
|
---|
[48755] | 997 | DMI_READ_CFG_STR_DEF(pOEMStrings->u8VBoxVersion, "DmiOEMVBoxVer", szTmp);
|
---|
[25162] | 998 | RTStrPrintf(szTmp, sizeof(szTmp), "vboxRev_%u", RTBldCfgRevision());
|
---|
[48755] | 999 | DMI_READ_CFG_STR_DEF(pOEMStrings->u8VBoxRevision, "DmiOEMVBoxRev", szTmp);
|
---|
| 1000 | DMI_TERM_STRUCT;
|
---|
[25219] | 1001 |
|
---|
[44820] | 1002 | /*************************************
|
---|
| 1003 | * DMI OEM specific table (Type 128) *
|
---|
| 1004 | ************************************/
|
---|
| 1005 | PDMIOEMSPECIFIC pOEMSpecific = (PDMIOEMSPECIFIC)pszStr;
|
---|
[48755] | 1006 | DMI_CHECK_SIZE(sizeof(*pOEMSpecific));
|
---|
| 1007 | DMI_START_STRUCT(pOEMSpecific);
|
---|
[44820] | 1008 | pOEMSpecific->header.u8Type = 0x80; /* OEM specific */
|
---|
| 1009 | pOEMSpecific->header.u8Length = sizeof(*pOEMSpecific);
|
---|
[101427] | 1010 | pOEMSpecific->header.u16Handle = 0x0004;
|
---|
[91968] | 1011 | pOEMSpecific->u32CpuFreqKHz = RT_H2LE_U32((uint32_t)((uint64_t)PDMDevHlpTMCpuTicksPerSecond(pDevIns) / 1000));
|
---|
[48755] | 1012 | DMI_TERM_STRUCT;
|
---|
[44820] | 1013 |
|
---|
[25162] | 1014 | /* End-of-table marker - includes padding to account for fixed table size. */
|
---|
| 1015 | PDMIHDR pEndOfTable = (PDMIHDR)pszStr;
|
---|
[40277] | 1016 | pszStr = (char *)(pEndOfTable + 1);
|
---|
[25162] | 1017 | pEndOfTable->u8Type = 0x7f;
|
---|
[40277] | 1018 |
|
---|
| 1019 | pEndOfTable->u8Length = sizeof(*pEndOfTable);
|
---|
[25162] | 1020 | pEndOfTable->u16Handle = 0xFEFF;
|
---|
[40277] | 1021 | *pcbDmiTables = ((uintptr_t)pszStr - (uintptr_t)pTable) + 2;
|
---|
[25219] | 1022 |
|
---|
[44820] | 1023 | /* We currently plant 10 DMI tables. Update this if tables number changed. */
|
---|
[81925] | 1024 | *pcDmiTables = 10;
|
---|
[44820] | 1025 |
|
---|
[48755] | 1026 | /* If more fields are added here, fix the size check in DMI_READ_CFG_STR */
|
---|
[24706] | 1027 |
|
---|
[25162] | 1028 | /* Success! */
|
---|
| 1029 | break;
|
---|
| 1030 | }
|
---|
[24706] | 1031 |
|
---|
[48755] | 1032 | #undef DMI_READ_CFG_STR
|
---|
| 1033 | #undef DMI_READ_CFG_S32
|
---|
| 1034 | #undef DMI_CHECK_SIZE
|
---|
[28424] | 1035 | return VINF_SUCCESS;
|
---|
| 1036 | }
|
---|
[24706] | 1037 |
|
---|
[28424] | 1038 | /**
|
---|
| 1039 | * Construct the SMBIOS and DMI headers table pointer at VM construction and
|
---|
| 1040 | * reset.
|
---|
| 1041 | *
|
---|
[64369] | 1042 | * @param pDevIns The device instance data.
|
---|
[71061] | 1043 | * @param pHdr Pointer to the header destination.
|
---|
[64369] | 1044 | * @param cbDmiTables Size of all DMI tables planted in bytes.
|
---|
| 1045 | * @param cNumDmiTables Number of DMI tables planted.
|
---|
[28424] | 1046 | */
|
---|
[71061] | 1047 | void FwCommonPlantSmbiosAndDmiHdrs(PPDMDEVINS pDevIns, uint8_t *pHdr, uint16_t cbDmiTables, uint16_t cNumDmiTables)
|
---|
[28424] | 1048 | {
|
---|
[71061] | 1049 | RT_NOREF(pDevIns);
|
---|
| 1050 |
|
---|
[28424] | 1051 | struct
|
---|
[25025] | 1052 | {
|
---|
[28424] | 1053 | struct SMBIOSHDR smbios;
|
---|
| 1054 | struct DMIMAINHDR dmi;
|
---|
[43712] | 1055 | }
|
---|
| 1056 | aBiosHeaders =
|
---|
[28424] | 1057 | {
|
---|
| 1058 | // The SMBIOS header
|
---|
[25025] | 1059 | {
|
---|
[28424] | 1060 | { 0x5f, 0x53, 0x4d, 0x5f}, // "_SM_" signature
|
---|
| 1061 | 0x00, // checksum
|
---|
| 1062 | 0x1f, // EPS length, defined by standard
|
---|
| 1063 | VBOX_SMBIOS_MAJOR_VER, // SMBIOS major version
|
---|
| 1064 | VBOX_SMBIOS_MINOR_VER, // SMBIOS minor version
|
---|
| 1065 | VBOX_SMBIOS_MAXSS, // Maximum structure size
|
---|
| 1066 | 0x00, // Entry point revision
|
---|
| 1067 | { 0x00, 0x00, 0x00, 0x00, 0x00 } // padding
|
---|
| 1068 | },
|
---|
| 1069 | // The DMI header
|
---|
| 1070 | {
|
---|
| 1071 | { 0x5f, 0x44, 0x4d, 0x49, 0x5f }, // "_DMI_" signature
|
---|
| 1072 | 0x00, // checksum
|
---|
[43712] | 1073 | 0, // DMI tables length
|
---|
[28424] | 1074 | VBOX_DMI_TABLE_BASE, // DMI tables base
|
---|
[44820] | 1075 | 0, // DMI tables entries
|
---|
[28424] | 1076 | VBOX_DMI_TABLE_VER, // DMI version
|
---|
| 1077 | }
|
---|
| 1078 | };
|
---|
[25025] | 1079 |
|
---|
[43712] | 1080 | aBiosHeaders.dmi.u16TablesLength = cbDmiTables;
|
---|
[44820] | 1081 | aBiosHeaders.dmi.u16TableEntries = cNumDmiTables;
|
---|
[77254] | 1082 | /* NB: The _SM_ table checksum technically covers both the _SM_ part (16 bytes) and the _DMI_ part
|
---|
| 1083 | * (further 15 bytes). However, because the _DMI_ checksum must be zero, the _SM_ checksum can
|
---|
| 1084 | * be calculated independently.
|
---|
| 1085 | */
|
---|
[43712] | 1086 | aBiosHeaders.smbios.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.smbios, sizeof(aBiosHeaders.smbios));
|
---|
| 1087 | aBiosHeaders.dmi.u8Checksum = fwCommonChecksum((uint8_t*)&aBiosHeaders.dmi, sizeof(aBiosHeaders.dmi));
|
---|
[25025] | 1088 |
|
---|
[71061] | 1089 | memcpy(pHdr, &aBiosHeaders, sizeof(aBiosHeaders));
|
---|
[24706] | 1090 | }
|
---|
| 1091 |
|
---|
| 1092 | /**
|
---|
[28203] | 1093 | * Construct the MPS table for implanting as a ROM page.
|
---|
[24706] | 1094 | *
|
---|
[28203] | 1095 | * Only applicable if IOAPIC is active!
|
---|
| 1096 | *
|
---|
[33540] | 1097 | * See ``MultiProcessor Specification Version 1.4 (May 1997)'':
|
---|
[24706] | 1098 | * ``1.3 Scope
|
---|
| 1099 | * ...
|
---|
| 1100 | * The hardware required to implement the MP specification is kept to a
|
---|
| 1101 | * minimum, as follows:
|
---|
| 1102 | * * One or more processors that are Intel architecture instruction set
|
---|
| 1103 | * compatible, such as the CPUs in the Intel486 or Pentium processor
|
---|
| 1104 | * family.
|
---|
| 1105 | * * One or more APICs, such as the Intel 82489DX Advanced Programmable
|
---|
| 1106 | * Interrupt Controller or the integrated APIC, such as that on the
|
---|
[25647] | 1107 | * Intel Pentium 735\\90 and 815\\100 processors, together with a discrete
|
---|
[24706] | 1108 | * I/O APIC unit.''
|
---|
| 1109 | * and later:
|
---|
| 1110 | * ``4.3.3 I/O APIC Entries
|
---|
| 1111 | * The configuration table contains one or more entries for I/O APICs.
|
---|
| 1112 | * ...
|
---|
| 1113 | * I/O APIC FLAGS: EN 3:0 1 If zero, this I/O APIC is unusable, and the
|
---|
| 1114 | * operating system should not attempt to access
|
---|
| 1115 | * this I/O APIC.
|
---|
| 1116 | * At least one I/O APIC must be enabled.''
|
---|
| 1117 | *
|
---|
| 1118 | * @param pDevIns The device instance data.
|
---|
[26728] | 1119 | * @param pTable Where to write the table.
|
---|
| 1120 | * @param cbMax The maximum size of the MPS table.
|
---|
| 1121 | * @param cCpus The number of guest CPUs.
|
---|
[24706] | 1122 | */
|
---|
[26728] | 1123 | void FwCommonPlantMpsTable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, uint16_t cCpus)
|
---|
[24706] | 1124 | {
|
---|
[62890] | 1125 | RT_NOREF1(cbMax);
|
---|
| 1126 |
|
---|
[24706] | 1127 | /* configuration table */
|
---|
| 1128 | PMPSCFGTBLHEADER pCfgTab = (MPSCFGTBLHEADER*)pTable;
|
---|
| 1129 | memcpy(pCfgTab->au8Signature, "PCMP", 4);
|
---|
| 1130 | pCfgTab->u8SpecRev = 4; /* 1.4 */
|
---|
| 1131 | memcpy(pCfgTab->au8OemId, "VBOXCPU ", 8);
|
---|
| 1132 | memcpy(pCfgTab->au8ProductId, "VirtualBox ", 12);
|
---|
| 1133 | pCfgTab->u32OemTablePtr = 0;
|
---|
| 1134 | pCfgTab->u16OemTableSize = 0;
|
---|
[39274] | 1135 | pCfgTab->u16EntryCount = 0; /* Incremented as we go. */
|
---|
[24706] | 1136 | pCfgTab->u32AddrLocalApic = 0xfee00000;
|
---|
| 1137 | pCfgTab->u16ExtTableLength = 0;
|
---|
[26939] | 1138 | pCfgTab->u8ExtTableChecksum = 0;
|
---|
[24706] | 1139 | pCfgTab->u8Reserved = 0;
|
---|
| 1140 |
|
---|
| 1141 | uint32_t u32Eax, u32Ebx, u32Ecx, u32Edx;
|
---|
| 1142 | uint32_t u32CPUSignature = 0x0520; /* default: Pentium 100 */
|
---|
| 1143 | uint32_t u32FeatureFlags = 0x0001; /* default: FPU */
|
---|
| 1144 | PDMDevHlpGetCpuId(pDevIns, 0, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
|
---|
| 1145 | if (u32Eax >= 1)
|
---|
| 1146 | {
|
---|
| 1147 | PDMDevHlpGetCpuId(pDevIns, 1, &u32Eax, &u32Ebx, &u32Ecx, &u32Edx);
|
---|
| 1148 | u32CPUSignature = u32Eax & 0xfff;
|
---|
| 1149 | /* Local APIC will be enabled later so override it here. Since we provide
|
---|
| 1150 | * an MP table we have an IOAPIC and therefore a Local APIC. */
|
---|
| 1151 | u32FeatureFlags = u32Edx | X86_CPUID_FEATURE_EDX_APIC;
|
---|
| 1152 | }
|
---|
| 1153 | /* Construct MPS table for each VCPU. */
|
---|
| 1154 | PMPSPROCENTRY pProcEntry = (PMPSPROCENTRY)(pCfgTab+1);
|
---|
[25048] | 1155 | for (int i = 0; i < cCpus; i++)
|
---|
[24706] | 1156 | {
|
---|
| 1157 | pProcEntry->u8EntryType = 0; /* processor entry */
|
---|
[26940] | 1158 | pProcEntry->u8LocalApicId = i;
|
---|
[26939] | 1159 | pProcEntry->u8LocalApicVersion = 0x14;
|
---|
[24706] | 1160 | pProcEntry->u8CPUFlags = (i == 0 ? 2 /* bootstrap processor */ : 0 /* application processor */) | 1 /* enabled */;
|
---|
| 1161 | pProcEntry->u32CPUSignature = u32CPUSignature;
|
---|
| 1162 | pProcEntry->u32CPUFeatureFlags = u32FeatureFlags;
|
---|
| 1163 | pProcEntry->u32Reserved[0] =
|
---|
| 1164 | pProcEntry->u32Reserved[1] = 0;
|
---|
| 1165 | pProcEntry++;
|
---|
[39274] | 1166 | pCfgTab->u16EntryCount++;
|
---|
[24706] | 1167 | }
|
---|
| 1168 |
|
---|
[39264] | 1169 | uint32_t iBusIdIsa = 0;
|
---|
| 1170 | uint32_t iBusIdPci0 = 1;
|
---|
[26939] | 1171 |
|
---|
[24706] | 1172 | /* ISA bus */
|
---|
[25305] | 1173 | PMPSBUSENTRY pBusEntry = (PMPSBUSENTRY)pProcEntry;
|
---|
[24706] | 1174 | pBusEntry->u8EntryType = 1; /* bus entry */
|
---|
[26939] | 1175 | pBusEntry->u8BusId = iBusIdIsa; /* this ID is referenced by the interrupt entries */
|
---|
[24706] | 1176 | memcpy(pBusEntry->au8BusTypeStr, "ISA ", 6);
|
---|
[26939] | 1177 | pBusEntry++;
|
---|
[39274] | 1178 | pCfgTab->u16EntryCount++;
|
---|
[24706] | 1179 |
|
---|
[26939] | 1180 | /* PCI bus */
|
---|
| 1181 | pBusEntry->u8EntryType = 1; /* bus entry */
|
---|
| 1182 | pBusEntry->u8BusId = iBusIdPci0; /* this ID can be referenced by the interrupt entries */
|
---|
| 1183 | memcpy(pBusEntry->au8BusTypeStr, "PCI ", 6);
|
---|
[59281] | 1184 | pBusEntry++;
|
---|
[39274] | 1185 | pCfgTab->u16EntryCount++;
|
---|
[24706] | 1186 |
|
---|
[26939] | 1187 |
|
---|
[24706] | 1188 | /* I/O-APIC.
|
---|
| 1189 | * MP spec: "The configuration table contains one or more entries for I/O APICs.
|
---|
| 1190 | * ... At least one I/O APIC must be enabled." */
|
---|
[59281] | 1191 | PMPSIOAPICENTRY pIOAPICEntry = (PMPSIOAPICENTRY)(pBusEntry);
|
---|
[26939] | 1192 | uint16_t iApicId = 0;
|
---|
[24706] | 1193 | pIOAPICEntry->u8EntryType = 2; /* I/O-APIC entry */
|
---|
[26939] | 1194 | pIOAPICEntry->u8Id = iApicId; /* this ID is referenced by the interrupt entries */
|
---|
[24706] | 1195 | pIOAPICEntry->u8Version = 0x11;
|
---|
| 1196 | pIOAPICEntry->u8Flags = 1 /* enable */;
|
---|
| 1197 | pIOAPICEntry->u32Addr = 0xfec00000;
|
---|
[39274] | 1198 | pCfgTab->u16EntryCount++;
|
---|
[24706] | 1199 |
|
---|
[26939] | 1200 | /* Interrupt tables */
|
---|
| 1201 | /* Bus vectors */
|
---|
[39274] | 1202 | /* Note: The PIC is currently not routed to the I/O APIC. Therefore we skip
|
---|
| 1203 | * pin 0 on the I/O APIC.
|
---|
| 1204 | */
|
---|
[24706] | 1205 | PMPSIOIRQENTRY pIrqEntry = (PMPSIOIRQENTRY)(pIOAPICEntry+1);
|
---|
[39274] | 1206 | for (int iPin = 1; iPin < 16; iPin++, pIrqEntry++)
|
---|
[24706] | 1207 | {
|
---|
| 1208 | pIrqEntry->u8EntryType = 3; /* I/O interrupt entry */
|
---|
[26939] | 1209 | /*
|
---|
| 1210 | * 0 - INT, vectored interrupt,
|
---|
| 1211 | * 3 - ExtINT, vectored interrupt provided by PIC
|
---|
| 1212 | * As we emulate system with both APIC and PIC, it's needed for their coexistence.
|
---|
| 1213 | */
|
---|
| 1214 | pIrqEntry->u8Type = (iPin == 0) ? 3 : 0;
|
---|
| 1215 | pIrqEntry->u16Flags = 0; /* polarity of APIC I/O input signal = conforms to bus,
|
---|
| 1216 | trigger mode = conforms to bus */
|
---|
| 1217 | pIrqEntry->u8SrcBusId = iBusIdIsa; /* ISA bus */
|
---|
| 1218 | /* IRQ0 mapped to pin 2, other are identity mapped */
|
---|
| 1219 | /* If changing, also update PDMIsaSetIrq() and MADT */
|
---|
| 1220 | pIrqEntry->u8SrcBusIrq = (iPin == 2) ? 0 : iPin; /* IRQ on the bus */
|
---|
[33540] | 1221 | pIrqEntry->u8DstIOAPICId = iApicId; /* destination IO-APIC */
|
---|
[26939] | 1222 | pIrqEntry->u8DstIOAPICInt = iPin; /* pin on destination IO-APIC */
|
---|
[39274] | 1223 | pCfgTab->u16EntryCount++;
|
---|
[24706] | 1224 | }
|
---|
[26939] | 1225 | /* Local delivery */
|
---|
| 1226 | pIrqEntry->u8EntryType = 4; /* Local interrupt entry */
|
---|
| 1227 | pIrqEntry->u8Type = 3; /* ExtINT */
|
---|
| 1228 | pIrqEntry->u16Flags = (1 << 2) | 1; /* active-high, edge-triggered */
|
---|
| 1229 | pIrqEntry->u8SrcBusId = iBusIdIsa;
|
---|
| 1230 | pIrqEntry->u8SrcBusIrq = 0;
|
---|
| 1231 | pIrqEntry->u8DstIOAPICId = 0xff;
|
---|
| 1232 | pIrqEntry->u8DstIOAPICInt = 0;
|
---|
| 1233 | pIrqEntry++;
|
---|
[39274] | 1234 | pCfgTab->u16EntryCount++;
|
---|
| 1235 | pIrqEntry->u8EntryType = 4; /* Local interrupt entry */
|
---|
| 1236 | pIrqEntry->u8Type = 1; /* NMI */
|
---|
| 1237 | pIrqEntry->u16Flags = (1 << 2) | 1; /* active-high, edge-triggered */
|
---|
| 1238 | pIrqEntry->u8SrcBusId = iBusIdIsa;
|
---|
| 1239 | pIrqEntry->u8SrcBusIrq = 0;
|
---|
| 1240 | pIrqEntry->u8DstIOAPICId = 0xff;
|
---|
| 1241 | pIrqEntry->u8DstIOAPICInt = 1;
|
---|
| 1242 | pIrqEntry++;
|
---|
| 1243 | pCfgTab->u16EntryCount++;
|
---|
[24706] | 1244 |
|
---|
| 1245 | pCfgTab->u16Length = (uint8_t*)pIrqEntry - pTable;
|
---|
[25048] | 1246 | pCfgTab->u8Checksum = fwCommonChecksum(pTable, pCfgTab->u16Length);
|
---|
[24706] | 1247 |
|
---|
[26728] | 1248 | AssertMsg(pCfgTab->u16Length < cbMax,
|
---|
[24706] | 1249 | ("VBOX_MPS_TABLE_SIZE=%d, maximum allowed size is %d",
|
---|
[26728] | 1250 | pCfgTab->u16Length, cbMax));
|
---|
[28203] | 1251 | }
|
---|
[24706] | 1252 |
|
---|
[28203] | 1253 | /**
|
---|
| 1254 | * Construct the MPS table pointer at VM construction and reset.
|
---|
| 1255 | *
|
---|
| 1256 | * Only applicable if IOAPIC is active!
|
---|
| 1257 | *
|
---|
[73142] | 1258 | * @param pDevIns The device instance data.
|
---|
| 1259 | * @param u32MpTableAddr The MP table physical address.
|
---|
[28203] | 1260 | */
|
---|
[73142] | 1261 | void FwCommonPlantMpsFloatPtr(PPDMDEVINS pDevIns, uint32_t u32MpTableAddr)
|
---|
[28203] | 1262 | {
|
---|
[24706] | 1263 | MPSFLOATPTR floatPtr;
|
---|
| 1264 | floatPtr.au8Signature[0] = '_';
|
---|
| 1265 | floatPtr.au8Signature[1] = 'M';
|
---|
| 1266 | floatPtr.au8Signature[2] = 'P';
|
---|
| 1267 | floatPtr.au8Signature[3] = '_';
|
---|
[73142] | 1268 | floatPtr.u32MPSAddr = u32MpTableAddr;
|
---|
[24706] | 1269 | floatPtr.u8Length = 1; /* structure size in paragraphs */
|
---|
| 1270 | floatPtr.u8SpecRev = 4; /* MPS revision 1.4 */
|
---|
| 1271 | floatPtr.u8Checksum = 0;
|
---|
| 1272 | floatPtr.au8Feature[0] = 0;
|
---|
| 1273 | floatPtr.au8Feature[1] = 0;
|
---|
| 1274 | floatPtr.au8Feature[2] = 0;
|
---|
| 1275 | floatPtr.au8Feature[3] = 0;
|
---|
| 1276 | floatPtr.au8Feature[4] = 0;
|
---|
[25048] | 1277 | floatPtr.u8Checksum = fwCommonChecksum((uint8_t*)&floatPtr, 16);
|
---|
[28203] | 1278 | PDMDevHlpPhysWrite(pDevIns, 0x9fff0, &floatPtr, 16);
|
---|
[24706] | 1279 | }
|
---|
[48755] | 1280 |
|
---|