VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleImplConfigX86.cpp

Last change on this file was 107855, checked in by vboxsync, 4 weeks ago

VMM/NEM,Main: Feed the cpu bug mitigation parameters to both HM and NEM. [bugfix] jiraref:VBP-947

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.2 KB
Line 
1/* $Id: ConsoleImplConfigX86.cpp 107855 2025-01-20 11:23:21Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - VM Configuration Bits.
4 *
5 * @remark We've split out the code that the 64-bit VC++ v8 compiler finds
6 * problematic to optimize so we can disable optimizations and later,
7 * perhaps, find a real solution for it (like rewriting the code and
8 * to stop resemble a tonne of spaghetti).
9 */
10
11/*
12 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
13 *
14 * This file is part of VirtualBox base platform packages, as
15 * available from https://www.virtualbox.org.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation, in version 3 of the
20 * License.
21 *
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, see <https://www.gnu.org/licenses>.
29 *
30 * SPDX-License-Identifier: GPL-3.0-only
31 */
32
33
34/*********************************************************************************************************************************
35* Header Files *
36*********************************************************************************************************************************/
37#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
38#include "LoggingNew.h"
39
40#include "ConsoleImpl.h"
41#include "DisplayImpl.h"
42#include "NvramStoreImpl.h"
43#include "PlatformImpl.h"
44#include "VMMDev.h"
45#include "Global.h"
46#ifdef VBOX_WITH_PCI_PASSTHROUGH
47# include "PCIRawDevImpl.h"
48#endif
49
50// generated header
51#include "SchemaDefs.h"
52
53#include "AutoCaller.h"
54
55#include <iprt/base64.h>
56#include <iprt/buildconfig.h>
57#include <iprt/ctype.h>
58#include <iprt/dir.h>
59#include <iprt/file.h>
60#include <iprt/param.h>
61#include <iprt/path.h>
62#include <iprt/string.h>
63#include <iprt/system.h>
64#if 0 /* enable to play with lots of memory. */
65# include <iprt/env.h>
66#endif
67#include <iprt/stream.h>
68
69#include <iprt/http.h>
70#include <iprt/socket.h>
71#include <iprt/uri.h>
72
73#include <VBox/vmm/vmmr3vtable.h>
74#include <VBox/vmm/vmapi.h>
75#include <VBox/err.h>
76#include <VBox/param.h>
77#include <VBox/settings.h> /* For MachineConfigFile::getHostDefaultAudioDriver(). */
78#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
79#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
80#include <VBox/vmm/pdmapic.h> /* For PDMAPICMODE enum. */
81#include <VBox/vmm/pdmstorageifs.h>
82#include <VBox/version.h>
83
84#include <VBox/com/com.h>
85#include <VBox/com/string.h>
86#include <VBox/com/array.h>
87
88#include "NetworkServiceRunner.h"
89#include "BusAssignmentManager.h"
90#ifdef VBOX_WITH_EXTPACK
91# include "ExtPackManagerImpl.h"
92#endif
93
94/** The TPM MMIO base default. */
95#define TPM_MMIO_BASE_DEFAULT UINT64_C(0xfed40000)
96/** The TPM PPI MMIO base default (compatible with qemu). */
97#define TPM_PPI_MMIO_BASE_DEFAULT UINT64_C(0xfed45000)
98
99
100/*********************************************************************************************************************************
101* Internal Functions *
102*********************************************************************************************************************************/
103
104/* Darwin compile kludge */
105#undef PVM
106
107/**
108 * @throws HRESULT on extra data retrival error.
109 */
110static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
111{
112 *pfGetKeyFromRealSMC = false;
113
114 /*
115 * The extra data takes precedence (if non-zero).
116 */
117 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
118 if (pStrKey->isNotEmpty())
119 return VINF_SUCCESS;
120
121#ifdef RT_OS_DARWIN
122
123 /*
124 * Work done in EFI/DevSmc
125 */
126 *pfGetKeyFromRealSMC = true;
127 int vrc = VINF_SUCCESS;
128
129#else
130 /*
131 * Is it apple hardware in bootcamp?
132 */
133 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
134 * Currently falling back on the product name. */
135 char szManufacturer[256];
136 szManufacturer[0] = '\0';
137 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
138 if (szManufacturer[0] != '\0')
139 {
140 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
141 || !strcmp(szManufacturer, "Apple Inc.")
142 )
143 *pfGetKeyFromRealSMC = true;
144 }
145 else
146 {
147 char szProdName[256];
148 szProdName[0] = '\0';
149 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
150 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
151 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
152 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
153 )
154 && !strchr(szProdName, ' ') /* no spaces */
155 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
156 )
157 *pfGetKeyFromRealSMC = true;
158 }
159
160 int vrc = VINF_SUCCESS;
161#endif
162
163 return vrc;
164}
165
166
167/*
168 * VC++ 8 / amd64 has some serious trouble with the next functions.
169 * As a temporary measure, we'll drop global optimizations.
170 */
171#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
172# if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100
173# pragma optimize("g", off)
174# endif
175#endif
176
177/** Helper that finds out the next HBA port used
178 */
179static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
180{
181 LONG lNextPortUsed = 30;
182 for (size_t j = 0; j < u32Size; ++j)
183 {
184 if ( aPortUsed[j] > lBaseVal
185 && aPortUsed[j] <= lNextPortUsed)
186 lNextPortUsed = aPortUsed[j];
187 }
188 return lNextPortUsed;
189}
190
191#define MAX_BIOS_LUN_COUNT 4
192
193int Console::SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
194 Bstr controllerName, const char * const s_apszBiosConfig[4])
195{
196 RT_NOREF(pCfg);
197 HRESULT hrc;
198#define MAX_DEVICES 30
199#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
200#define VRC() AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
201
202 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
203 LONG lPortUsed[MAX_DEVICES];
204 uint32_t u32HDCount = 0;
205
206 /* init to max value */
207 lPortLUN[0] = MAX_DEVICES;
208
209 com::SafeIfaceArray<IMediumAttachment> atts;
210 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
211 ComSafeArrayAsOutParam(atts)); H();
212 size_t uNumAttachments = atts.size();
213 if (uNumAttachments > MAX_DEVICES)
214 {
215 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
216 uNumAttachments = MAX_DEVICES;
217 }
218
219 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
220 for (size_t j = 0; j < uNumAttachments; ++j)
221 {
222 IMediumAttachment *pMediumAtt = atts[j];
223 LONG lPortNum = 0;
224 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
225 if (SUCCEEDED(hrc))
226 {
227 DeviceType_T lType;
228 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
229 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
230 {
231 /* find min port number used for HD */
232 if (lPortNum < lPortLUN[0])
233 lPortLUN[0] = lPortNum;
234 lPortUsed[u32HDCount++] = lPortNum;
235 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
236 }
237 }
238 }
239
240
241 /* Pick only the top 4 used HD Ports as CMOS doesn't have space
242 * to save details for all 30 ports
243 */
244 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
245 if (u32HDCount < MAX_BIOS_LUN_COUNT)
246 u32MaxPortCount = u32HDCount;
247 for (size_t j = 1; j < u32MaxPortCount; j++)
248 lPortLUN[j] = GetNextUsedPort(lPortUsed, lPortLUN[j-1], u32HDCount);
249 if (pBiosCfg)
250 {
251 for (size_t j = 0; j < u32MaxPortCount; j++)
252 {
253 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
254 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
255 }
256 }
257 return VINF_SUCCESS;
258}
259
260#ifdef VBOX_WITH_PCI_PASSTHROUGH
261HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
262{
263# ifndef VBOX_WITH_EXTPACK
264 RT_NOREF(pUVM);
265# endif
266 HRESULT hrc = S_OK;
267 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
268
269 SafeIfaceArray<IPCIDeviceAttachment> assignments;
270 ComPtr<IMachine> aMachine = i_machine();
271
272 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
273 if ( hrc != S_OK
274 || assignments.size() < 1)
275 return hrc;
276
277 /*
278 * PCI passthrough is only available if the proper ExtPack is installed.
279 *
280 * Note. Configuring PCI passthrough here and providing messages about
281 * the missing extpack isn't exactly clean, but it is a necessary evil
282 * to patch over legacy compatability issues introduced by the new
283 * distribution model.
284 */
285# ifdef VBOX_WITH_EXTPACK
286 static const char *s_pszPCIRawExtPackName = VBOX_PUEL_PRODUCT;
287 if ( !mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName)
288 && !mptrExtPackManager->i_isExtPackUsable("Oracle VM VirtualBox Extension Pack")) /* Legacy name -- see @bugref{10690}. */
289 /* Always fatal! */
290 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
291 N_("Implementation of the PCI passthrough framework not found!\n"
292 "The VM cannot be started. To fix this problem, either "
293 "install the '%s' or disable PCI passthrough via VBoxManage"),
294 s_pszPCIRawExtPackName);
295# endif
296
297 /* Now actually add devices */
298 PCFGMNODE pPCIDevs = NULL;
299
300 if (assignments.size() > 0)
301 {
302 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);
303
304 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
305
306 /* Tell PGM to tell GPCIRaw about guest mappings. */
307 CFGMR3InsertNode(pRoot, "PGM", NULL);
308 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
309
310 /*
311 * Currently, using IOMMU needed for PCI passthrough
312 * requires RAM preallocation.
313 */
314 /** @todo check if we can lift this requirement */
315 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
316 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
317 }
318
319 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
320 {
321 ComPtr<IPCIDeviceAttachment> const assignment = assignments[iDev];
322
323 LONG host;
324 hrc = assignment->COMGETTER(HostAddress)(&host); H();
325 LONG guest;
326 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
327 Bstr bstrDevName;
328 hrc = assignment->COMGETTER(Name)(bstrDevName.asOutParam()); H();
329
330 InsertConfigNodeF(pPCIDevs, &pInst, "%d", iDev);
331 InsertConfigInteger(pInst, "Trusted", 1);
332
333 PCIBusAddress HostPCIAddress(host);
334 Assert(HostPCIAddress.valid());
335 InsertConfigNode(pInst, "Config", &pCfg);
336 InsertConfigString(pCfg, "DeviceName", bstrDevName);
337
338 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
339 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);
340 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);
341 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);
342
343 PCIBusAddress GuestPCIAddress(guest);
344 Assert(GuestPCIAddress.valid());
345 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
346 if (hrc != S_OK)
347 return hrc;
348
349 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);
350 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);
351 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);
352
353 /* the driver */
354 InsertConfigNode(pInst, "LUN#0", &pLunL0);
355 InsertConfigString(pLunL0, "Driver", "pciraw");
356 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
357
358 /* the Main driver */
359 InsertConfigString(pLunL1, "Driver", "MainPciRaw");
360 InsertConfigNode(pLunL1, "Config", &pCfg);
361 PCIRawDev *pMainDev = new PCIRawDev(this);
362# error This is not allowed any more
363 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
364 }
365
366 return hrc;
367}
368#endif
369
370
371/**
372 * Worker for configConstructor.
373 *
374 * @return VBox status code.
375 * @param pUVM The user mode VM handle.
376 * @param pVM The cross context VM handle.
377 * @param pVMM The VMM vtable.
378 * @param pAlock The automatic lock instance. This is for when we have
379 * to leave it in order to avoid deadlocks (ext packs and
380 * more).
381 */
382int Console::i_configConstructorX86(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
383{
384 RT_NOREF(pVM /* when everything is disabled */);
385 ComPtr<IMachine> pMachine = i_machine();
386
387 int vrc;
388 HRESULT hrc;
389 Utf8Str strTmp;
390 Bstr bstr;
391
392#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
393
394 /*
395 * Get necessary objects and frequently used parameters.
396 */
397 ComPtr<IVirtualBox> virtualBox;
398 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
399
400 ComPtr<IHost> host;
401 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
402
403 ComPtr<ISystemProperties> systemProperties;
404 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
405
406 ComPtr<IFirmwareSettings> firmwareSettings;
407 hrc = pMachine->COMGETTER(FirmwareSettings)(firmwareSettings.asOutParam()); H();
408
409 ComPtr<INvramStore> nvramStore;
410 hrc = pMachine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam()); H();
411
412 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
413 RTUUID HardwareUuid;
414 vrc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
415 AssertRCReturn(vrc, vrc);
416
417 ULONG cRamMBs;
418 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
419#if 0 /* enable to play with lots of memory. */
420 if (RTEnvExist("VBOX_RAM_SIZE"))
421 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
422#endif
423 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
424 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
425 uint64_t uMcfgBase = 0;
426 uint32_t cbMcfgLength = 0;
427
428 ParavirtProvider_T enmParavirtProvider;
429 hrc = pMachine->GetEffectiveParavirtProvider(&enmParavirtProvider); H();
430
431 Bstr strParavirtDebug;
432 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
433
434 BOOL fIOAPIC;
435 uint32_t uIoApicPciAddress = NIL_PCIBDF;
436 hrc = firmwareSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
437
438 ComPtr<IPlatform> platform;
439 pMachine->COMGETTER(Platform)(platform.asOutParam()); H();
440
441 /* We have to increase the RAM hole if lots of VRAM is assigned. We stupidly
442 have to do this before the MCFG region is subtracted, even if there
443 should be ample space for it after the VRAM due to alignment. See
444 assumptions in ich9pciFakePCIBIOS(). */
445 ComPtr<IGraphicsAdapter> ptrGraphicsAdapter;
446 hrc = pMachine->COMGETTER(GraphicsAdapter)(ptrGraphicsAdapter.asOutParam()); H();
447 ULONG cVRamMBs = 0;
448 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
449 if (cVRamMBs > 256)
450 {
451 uint32_t cVRamMBsPowerOfTwo = RT_MIN(cVRamMBs, 1024); /* 1GB is the absolute max given PCI alignment. */
452 if (!RT_IS_POWER_OF_TWO(cVRamMBsPowerOfTwo))
453 cVRamMBsPowerOfTwo = RT_BIT_32(ASMBitLastSetU32(cVRamMBsPowerOfTwo)); /* returns [1..32] */
454 if (cbRamHole / _1M < cVRamMBsPowerOfTwo * 2)
455 {
456 cbRamHole = cVRamMBsPowerOfTwo * 2 * _1M; /* We must double the VRAM size due to PCI alignment. */
457/** @todo sort out the MCFG placement to better use available physical memory. */
458 //if (uMcfgBase)
459 // uMcfgBase = _4G - cbRamHole + cVRamMBsPowerOfTwo * _1M;
460 }
461 }
462
463 ChipsetType_T chipsetType;
464 hrc = platform->COMGETTER(ChipsetType)(&chipsetType); H();
465 if (chipsetType == ChipsetType_ICH9)
466 {
467 /* We'd better have 0x10000000 region, to cover 256 buses but this put
468 * too much load on hypervisor heap. Linux 4.8 currently complains with
469 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]
470 * only partially covers this bridge'' */
471 cbMcfgLength = 0x4000000; //0x10000000;
472 cbRamHole += cbMcfgLength;
473 uMcfgBase = _4G - cbRamHole;
474 }
475
476 /* Get the CPU profile name. */
477 Bstr bstrCpuProfile;
478 hrc = pMachine->COMGETTER(CPUProfile)(bstrCpuProfile.asOutParam()); H();
479
480 /* Get the X86 platform object. */
481 ComPtr<IPlatformX86> platformX86;
482 hrc = platform->COMGETTER(X86)(platformX86.asOutParam()); H();
483
484 /* Check if long mode is enabled. */
485 BOOL fIsGuest64Bit;
486 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_LongMode, &fIsGuest64Bit); H();
487
488 /*
489 * Figure out the IOMMU config.
490 */
491#if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL)
492 IommuType_T enmIommuType;
493 hrc = platform->COMGETTER(IommuType)(&enmIommuType); H();
494
495 /* Resolve 'automatic' type to an Intel or AMD IOMMU based on the host CPU. */
496 if (enmIommuType == IommuType_Automatic)
497 {
498 if ( bstrCpuProfile.startsWith("AMD")
499 || bstrCpuProfile.startsWith("Quad-Core AMD")
500 || bstrCpuProfile.startsWith("Hygon"))
501 enmIommuType = IommuType_AMD;
502 else if (bstrCpuProfile.startsWith("Intel"))
503 {
504 if ( bstrCpuProfile.equals("Intel 8086")
505 || bstrCpuProfile.equals("Intel 80186")
506 || bstrCpuProfile.equals("Intel 80286")
507 || bstrCpuProfile.equals("Intel 80386")
508 || bstrCpuProfile.equals("Intel 80486"))
509 enmIommuType = IommuType_None;
510 else
511 enmIommuType = IommuType_Intel;
512 }
513# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
514 else if (ASMIsAmdCpu())
515 enmIommuType = IommuType_AMD;
516 else if (ASMIsIntelCpu())
517 enmIommuType = IommuType_Intel;
518# endif
519 else
520 {
521 /** @todo Should we handle other CPUs like Shanghai, VIA etc. here? */
522 LogRel(("WARNING! Unrecognized CPU type, IOMMU disabled.\n"));
523 enmIommuType = IommuType_None;
524 }
525 }
526
527 if (enmIommuType == IommuType_AMD)
528 {
529# ifdef VBOX_WITH_IOMMU_AMD
530 /*
531 * Reserve the specific PCI address of the "SB I/O APIC" when using
532 * an AMD IOMMU. Required by Linux guests, see @bugref{9654#c23}.
533 */
534 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
535# else
536 LogRel(("WARNING! AMD IOMMU not supported, IOMMU disabled.\n"));
537 enmIommuType = IommuType_None;
538# endif
539 }
540
541 if (enmIommuType == IommuType_Intel)
542 {
543# ifdef VBOX_WITH_IOMMU_INTEL
544 /*
545 * Reserve a unique PCI address for the I/O APIC when using
546 * an Intel IOMMU. For convenience we use the same address as
547 * we do on AMD, see @bugref{9967#c13}.
548 */
549 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
550# else
551 LogRel(("WARNING! Intel IOMMU not supported, IOMMU disabled.\n"));
552 enmIommuType = IommuType_None;
553# endif
554 }
555
556 if ( enmIommuType == IommuType_AMD
557 || enmIommuType == IommuType_Intel)
558 {
559 if (chipsetType != ChipsetType_ICH9)
560 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
561 N_("IOMMU uses MSIs which requires the ICH9 chipset implementation."));
562 if (!fIOAPIC)
563 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
564 N_("IOMMU requires an I/O APIC for remapping interrupts."));
565 }
566#else
567 IommuType_T const enmIommuType = IommuType_None;
568#endif
569
570 /* Instantiate the bus assignment manager. */
571 Assert(enmIommuType != IommuType_Automatic);
572 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, enmIommuType);
573
574 ULONG cCpus = 1;
575 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
576
577 ULONG ulCpuExecutionCap = 100;
578 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
579
580 VMExecutionEngine_T enmExecEngine = VMExecutionEngine_NotSet;
581 hrc = pMachine->COMGETTER(VMExecutionEngine)(&enmExecEngine); H();
582
583 LogRel(("Guest architecture: x86\n"));
584
585 Bstr osTypeId;
586 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
587 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
588
589 APICMode_T apicMode;
590 hrc = firmwareSettings->COMGETTER(APICMode)(&apicMode); H();
591 uint32_t uFwAPIC;
592 switch (apicMode)
593 {
594 case APICMode_Disabled:
595 uFwAPIC = 0;
596 break;
597 case APICMode_APIC:
598 uFwAPIC = 1;
599 break;
600 case APICMode_X2APIC:
601 uFwAPIC = 2;
602 break;
603 default:
604 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
605 uFwAPIC = 1;
606 break;
607 }
608
609 ComPtr<IGuestOSType> pGuestOSType;
610 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());
611
612 BOOL fOsXGuest = FALSE;
613 /*BOOL fWinGuest = FALSE; unused*/
614 BOOL fOs2Guest = FALSE;
615 BOOL fW9xGuest = FALSE;
616 BOOL fDosGuest = FALSE;
617 if (pGuestOSType.isNotNull())
618 {
619 Bstr guestTypeFamilyId;
620 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
621 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
622 /*fWinGuest = guestTypeFamilyId == Bstr("Windows");*/
623 fOs2Guest = osTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("OS2"));
624 fW9xGuest = osTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows9")); /* Does not include Windows Me. */
625 fDosGuest = osTypeId.equals(GUEST_OS_ID_STR_X86("DOS")) || osTypeId.equals(GUEST_OS_ID_STR_X86("Windows31"));
626 }
627
628 ComPtr<IPlatformProperties> platformProperties;
629 virtualBox->GetPlatformProperties(PlatformArchitecture_x86, platformProperties.asOutParam());
630
631 /*
632 * Get root node first.
633 * This is the only node in the tree.
634 */
635 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRootU(pUVM);
636 Assert(pRoot);
637
638 // catching throws from InsertConfigString and friends.
639 try
640 {
641
642 /*
643 * Set the root (and VMM) level values.
644 */
645 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
646 InsertConfigString(pRoot, "Name", bstr);
647 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
648 InsertConfigInteger(pRoot, "RamSize", cbRam);
649 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
650 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
651 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
652 InsertConfigInteger(pRoot, "TimerMillies", 10);
653
654 BOOL fPageFusion = FALSE;
655 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
656 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
657
658 /* Not necessary, but makes sure this setting ends up in the release log. */
659 ULONG ulBalloonSize = 0;
660 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
661 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
662
663 /*
664 * EM values (before CPUM as it may need to set IemExecutesAll).
665 */
666 PCFGMNODE pEM;
667 InsertConfigNode(pRoot, "EM", &pEM);
668
669 /* Triple fault behavior. */
670 BOOL fTripleFaultReset = false;
671 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_TripleFaultReset, &fTripleFaultReset); H();
672 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
673
674 /*
675 * CPUM values.
676 */
677 PCFGMNODE pCPUM;
678 InsertConfigNode(pRoot, "CPUM", &pCPUM);
679 PCFGMNODE pIsaExts;
680 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);
681
682 /* Host CPUID leaf overrides. */
683 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)
684 {
685 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;
686 hrc = platformX86->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);
687 if (hrc == E_INVALIDARG)
688 break;
689 H();
690 PCFGMNODE pLeaf;
691 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
692 /** @todo Figure out how to tell the VMM about uSubLeaf */
693 InsertConfigInteger(pLeaf, "eax", uEax);
694 InsertConfigInteger(pLeaf, "ebx", uEbx);
695 InsertConfigInteger(pLeaf, "ecx", uEcx);
696 InsertConfigInteger(pLeaf, "edx", uEdx);
697 }
698
699 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
700 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
701 if (osTypeId == GUEST_OS_ID_STR_X86("WindowsNT4"))
702 {
703 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
704 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
705 }
706
707 if (fOsXGuest)
708 {
709 /* Expose extended MWAIT features to Mac OS X guests. */
710 LogRel(("Using MWAIT extensions\n"));
711 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);
712
713 /* Fake the CPU family/model so the guest works. This is partly
714 because older mac releases really doesn't work on newer cpus,
715 and partly because mac os x expects more from systems with newer
716 cpus (MSRs, power features, whatever). */
717 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
718 if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS")
719 || osTypeId == GUEST_OS_ID_STR_X64("MacOS"))
720 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
721 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS106")
722 || osTypeId == GUEST_OS_ID_STR_X64("MacOS106"))
723 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
724 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS107")
725 || osTypeId == GUEST_OS_ID_STR_X64("MacOS107"))
726 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
727 what is required here. */
728 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS108")
729 || osTypeId == GUEST_OS_ID_STR_X64("MacOS108"))
730 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
731 what is required here. */
732 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS109")
733 || osTypeId == GUEST_OS_ID_STR_X64("MacOS109"))
734 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
735 out what is required here. */
736 if (uMaxIntelFamilyModelStep != UINT32_MAX)
737 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
738 }
739
740 /* CPU Portability level, */
741 ULONG uCpuIdPortabilityLevel = 0;
742 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
743 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
744
745 /* Physical Address Extension (PAE) */
746 BOOL fEnablePAE = false;
747 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_PAE, &fEnablePAE); H();
748 fEnablePAE |= fIsGuest64Bit;
749 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
750
751 /* 64-bit guests (long mode) */
752 InsertConfigInteger(pCPUM, "Enable64bit", fIsGuest64Bit);
753
754 /* APIC/X2APIC configuration */
755 BOOL fEnableAPIC = true;
756 BOOL fEnableX2APIC = true;
757 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_APIC, &fEnableAPIC); H();
758 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_X2APIC, &fEnableX2APIC); H();
759 if (fEnableX2APIC)
760 Assert(fEnableAPIC);
761
762 /* CPUM profile name. */
763 InsertConfigString(pCPUM, "GuestCpuName", bstrCpuProfile);
764
765 /*
766 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
767 * correctly. There are way too many #UDs we'll miss using VT-x,
768 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
769 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
770 */
771 if ( bstrCpuProfile.equals("Intel 80386") /* just for now */
772 || bstrCpuProfile.equals("Intel 80286")
773 || bstrCpuProfile.equals("Intel 80186")
774 || bstrCpuProfile.equals("Nec V20")
775 || bstrCpuProfile.equals("Intel 8086") )
776 {
777 InsertConfigInteger(pEM, "IemExecutesAll", true);
778 if (!bstrCpuProfile.equals("Intel 80386"))
779 {
780 fEnableAPIC = false;
781 fIOAPIC = false;
782 }
783 fEnableX2APIC = false;
784 }
785
786 /* Adjust firmware APIC handling to stay within the VCPU limits. */
787 if (uFwAPIC == 2 && !fEnableX2APIC)
788 {
789 if (fEnableAPIC)
790 uFwAPIC = 1;
791 else
792 uFwAPIC = 0;
793 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
794 }
795 else if (uFwAPIC == 1 && !fEnableAPIC)
796 {
797 uFwAPIC = 0;
798 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
799 }
800
801 /* Speculation Control. */
802 BOOL fSpecCtrl = FALSE;
803 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_SpecCtrl, &fSpecCtrl); H();
804 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
805
806 /* Nested VT-x / AMD-V. */
807 BOOL fNestedHWVirt = FALSE;
808 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_HWVirt, &fNestedHWVirt); H();
809 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);
810
811 /*
812 * Hardware virtualization extensions.
813 */
814 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
815 if (!fEnableAPIC)
816 {
817 if (fIsGuest64Bit)
818 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
819 N_("Cannot disable the APIC for a 64-bit guest."));
820 if (cCpus > 1)
821 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
822 N_("Cannot disable the APIC for an SMP guest."));
823 if (fIOAPIC)
824 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
825 N_("Cannot disable the APIC when the I/O APIC is present."));
826 }
827
828 BOOL fHMEnabled;
829 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
830 if (cCpus > 1 && !fHMEnabled)
831 {
832 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
833 fHMEnabled = TRUE;
834 }
835
836 BOOL fHMForced;
837 fHMEnabled = fHMForced = TRUE;
838 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
839 if (!fHMForced) /* No need to query if already forced above. */
840 {
841 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
842 if (fHMForced)
843 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
844 }
845 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
846
847 /* /HM/xyz */
848 PCFGMNODE pHM;
849 InsertConfigNode(pRoot, "HM", &pHM);
850 InsertConfigInteger(pHM, "HMForced", fHMForced);
851 if (fHMEnabled)
852 {
853 /* Indicate whether 64-bit guests are supported or not. */
854 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
855
856 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
857 but that requires quite a bit of API change in Main. */
858 if ( fIOAPIC
859 && ( osTypeId == GUEST_OS_ID_STR_X86("WindowsNT4")
860 || osTypeId == GUEST_OS_ID_STR_X86("Windows2000")
861 || osTypeId == GUEST_OS_ID_STR_X86("WindowsXP")
862 || osTypeId == GUEST_OS_ID_STR_X86("Windows2003")))
863 {
864 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
865 * We may want to consider adding more guest OSes (Solaris) later on.
866 */
867 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
868 }
869 }
870
871 /*
872 * Set VM execution engine.
873 */
874 /** @todo r=aeichner Maybe provide a better VMM API for this instead of the different CFGM knobs. */
875 LogRel(("Using execution engine %u\n", enmExecEngine));
876 switch (enmExecEngine)
877 {
878 case VMExecutionEngine_HwVirt:
879 InsertConfigInteger(pEM, "IemExecutesAll", 0);
880 InsertConfigInteger(pEM, "IemRecompiled", 0);
881 InsertConfigInteger(pHM, "UseNEMInstead", 0);
882 InsertConfigInteger(pHM, "FallbackToNEM", 0);
883 InsertConfigInteger(pHM, "FallbackToIEM", 0);
884 break;
885 case VMExecutionEngine_NativeApi:
886 InsertConfigInteger(pEM, "IemExecutesAll", 0);
887 InsertConfigInteger(pEM, "IemRecompiled", 0);
888 InsertConfigInteger(pHM, "UseNEMInstead", 1);
889 InsertConfigInteger(pHM, "FallbackToNEM", 1);
890 InsertConfigInteger(pHM, "FallbackToIEM", 0);
891 break;
892 case VMExecutionEngine_Interpreter:
893 case VMExecutionEngine_Recompiler:
894 InsertConfigInteger(pEM, "IemExecutesAll", 1);
895 InsertConfigInteger(pEM, "IemRecompiled", enmExecEngine == VMExecutionEngine_Recompiler);
896 InsertConfigInteger(pHM, "UseNEMInstead", 0);
897 InsertConfigInteger(pHM, "FallbackToNEM", 0);
898 InsertConfigInteger(pHM, "FallbackToIEM", 1);
899 break;
900 case VMExecutionEngine_Default:
901 break; /* Nothing to do, let VMM decide. */
902 default:
903 AssertLogRelFailed();
904 }
905
906 /* HWVirtEx exclusive mode */
907 BOOL fHMExclusive = true;
908 hrc = platformProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
909 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
910
911 /* Nested paging (VT-x/AMD-V) */
912 BOOL fEnableNestedPaging = false;
913 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
914 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
915
916 /* Large pages; requires nested paging */
917 BOOL fEnableLargePages = false;
918 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
919 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
920
921 /* VPID (VT-x) */
922 BOOL fEnableVPID = false;
923 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
924 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
925
926 /* Unrestricted execution aka UX (VT-x) */
927 BOOL fEnableUX = false;
928 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
929 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
930
931 /* Virtualized VMSAVE/VMLOAD (AMD-V) */
932 BOOL fVirtVmsaveVmload = true;
933 hrc = host->GetProcessorFeature(ProcessorFeature_VirtVmsaveVmload, &fVirtVmsaveVmload); H();
934 InsertConfigInteger(pHM, "SvmVirtVmsaveVmload", fVirtVmsaveVmload);
935
936 /* Indirect branch prediction boundraries. */
937 BOOL fIBPBOnVMExit = false;
938 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_IBPBOnVMExit, &fIBPBOnVMExit); H();
939 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);
940
941 BOOL fIBPBOnVMEntry = false;
942 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
943 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
944
945 BOOL fSpecCtrlByHost = false;
946 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_SpecCtrlByHost, &fSpecCtrlByHost); H();
947 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
948
949 BOOL fL1DFlushOnSched = true;
950 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_L1DFlushOnEMTScheduling, &fL1DFlushOnSched); H();
951 InsertConfigInteger(pHM, "L1DFlushOnSched", fL1DFlushOnSched);
952
953 BOOL fL1DFlushOnVMEntry = false;
954 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_L1DFlushOnVMEntry, &fL1DFlushOnVMEntry); H();
955 InsertConfigInteger(pHM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);
956
957 BOOL fMDSClearOnSched = true;
958 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_MDSClearOnEMTScheduling, &fMDSClearOnSched); H();
959 InsertConfigInteger(pHM, "MDSClearOnSched", fMDSClearOnSched);
960
961 BOOL fMDSClearOnVMEntry = false;
962 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_MDSClearOnVMEntry, &fMDSClearOnVMEntry); H();
963 InsertConfigInteger(pHM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);
964
965 /* Reset overwrite. */
966 mfTurnResetIntoPowerOff = GetExtraDataBoth(virtualBox, pMachine,
967 "VBoxInternal2/TurnResetIntoPowerOff", &strTmp)->equals("1");
968 if (mfTurnResetIntoPowerOff)
969 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
970
971 /** @todo This is a bit redundant but in order to avoid forcing setting version bumps later on
972 * and don't magically change behavior of old VMs we have to keep this for now. As soon as the user sets
973 * the execution to anything else than Default the execution engine setting takes precedence.
974 */
975 if (enmExecEngine == VMExecutionEngine_Default)
976 {
977 /* Use NEM rather than HM. */
978 BOOL fUseNativeApi = false;
979 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();
980 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);
981 }
982
983 /* Enable workaround for missing TLB flush for OS/2 guests, see ticketref:20625. */
984 if (fOs2Guest)
985 InsertConfigInteger(pHM, "MissingOS2TlbFlushWorkaround", 1);
986
987 /*
988 * NEM
989 */
990 PCFGMNODE pNEM;
991 InsertConfigNode(pRoot, "NEM", &pNEM);
992 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);
993
994#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
995 InsertConfigInteger(pNEM, "IBPBOnVMExit", fIBPBOnVMExit);
996 InsertConfigInteger(pNEM, "IBPBOnVMEntry", fIBPBOnVMEntry);
997 InsertConfigInteger(pNEM, "L1DFlushOnSched", fL1DFlushOnSched);
998 InsertConfigInteger(pNEM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);
999 InsertConfigInteger(pNEM, "MDSClearOnSched", fMDSClearOnSched);
1000 InsertConfigInteger(pNEM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);
1001#endif
1002
1003 /*
1004 * Paravirt. provider.
1005 */
1006 PCFGMNODE pParavirtNode;
1007 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1008 const char *pcszParavirtProvider;
1009 bool fGimDeviceNeeded = true;
1010 switch (enmParavirtProvider)
1011 {
1012 case ParavirtProvider_None:
1013 pcszParavirtProvider = "None";
1014 fGimDeviceNeeded = false;
1015 break;
1016
1017 case ParavirtProvider_Minimal:
1018 pcszParavirtProvider = "Minimal";
1019 break;
1020
1021 case ParavirtProvider_HyperV:
1022 pcszParavirtProvider = "HyperV";
1023 break;
1024
1025 case ParavirtProvider_KVM:
1026 pcszParavirtProvider = "KVM";
1027 break;
1028
1029 default:
1030 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));
1031 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1032 enmParavirtProvider);
1033 }
1034 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1035
1036 /*
1037 * Parse paravirt. debug options.
1038 */
1039 bool fGimDebug = false;
1040 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1041 uint32_t uGimDebugPort = 50000;
1042 if (strParavirtDebug.isNotEmpty())
1043 {
1044 /* Hyper-V debug options. */
1045 if (enmParavirtProvider == ParavirtProvider_HyperV)
1046 {
1047 bool fGimHvDebug = false;
1048 com::Utf8Str strGimHvVendor;
1049 bool fGimHvVsIf = false;
1050 bool fGimHvHypercallIf = false;
1051
1052 size_t uPos = 0;
1053 com::Utf8Str strDebugOptions = strParavirtDebug;
1054 com::Utf8Str strKey;
1055 com::Utf8Str strVal;
1056 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1057 {
1058 if (strKey == "enabled")
1059 {
1060 if (strVal.toUInt32() == 1)
1061 {
1062 /* Apply defaults.
1063 The defaults are documented in the user manual,
1064 changes need to be reflected accordingly. */
1065 fGimHvDebug = true;
1066 strGimHvVendor = "Microsoft Hv";
1067 fGimHvVsIf = true;
1068 fGimHvHypercallIf = false;
1069 }
1070 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1071 }
1072 else if (strKey == "address")
1073 strGimDebugAddress = strVal;
1074 else if (strKey == "port")
1075 uGimDebugPort = strVal.toUInt32();
1076 else if (strKey == "vendor")
1077 strGimHvVendor = strVal;
1078 else if (strKey == "vsinterface")
1079 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1080 else if (strKey == "hypercallinterface")
1081 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1082 else
1083 {
1084 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1085 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1086 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1087 strDebugOptions.c_str());
1088 }
1089 }
1090
1091 /* Update HyperV CFGM node with active debug options. */
1092 if (fGimHvDebug)
1093 {
1094 PCFGMNODE pHvNode;
1095 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1096 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1097 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1098 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1099 fGimDebug = true;
1100 }
1101 }
1102 }
1103
1104 /*
1105 * Guest Compatibility Manager.
1106 */
1107 PCFGMNODE pGcmNode;
1108 InsertConfigNode(pRoot, "GCM", &pGcmNode);
1109 /* OS/2 and Win9x guests can run DOS apps so they get the DOS specific
1110 fixes as well. */
1111 if (fDosGuest || fOs2Guest || fW9xGuest)
1112 InsertConfigInteger(pGcmNode, "DivByZeroDOS", 1);
1113 if (fOs2Guest)
1114 InsertConfigInteger(pGcmNode, "DivByZeroOS2", 1);
1115 if (fW9xGuest)
1116 InsertConfigInteger(pGcmNode, "DivByZeroWin9x", 1);
1117 /* MesaVmsvgaDrv (formerly LovelyMesaDrvWorkaround) is set futher down. */
1118
1119 /*
1120 * MM values.
1121 */
1122 PCFGMNODE pMM;
1123 InsertConfigNode(pRoot, "MM", &pMM);
1124 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1125
1126 /*
1127 * PDM config.
1128 * Load drivers in VBoxC.[so|dll]
1129 */
1130 vrc = i_configPdm(pMachine, pVMM, pUVM, pRoot); VRC();
1131
1132 /*
1133 * Devices
1134 */
1135 PCFGMNODE pDevices = NULL; /* /Devices */
1136 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1137 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1138 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1139 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1140 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1141 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1142 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1143
1144 InsertConfigNode(pRoot, "Devices", &pDevices);
1145
1146 /*
1147 * GIM Device
1148 */
1149 if (fGimDeviceNeeded)
1150 {
1151 InsertConfigNode(pDevices, "GIMDev", &pDev);
1152 InsertConfigNode(pDev, "0", &pInst);
1153 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1154 //InsertConfigNode(pInst, "Config", &pCfg);
1155
1156 if (fGimDebug)
1157 {
1158 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1159 InsertConfigString(pLunL0, "Driver", "UDP");
1160 InsertConfigNode(pLunL0, "Config", &pLunL1);
1161 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1162 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1163 }
1164 }
1165
1166 /*
1167 * PC Arch.
1168 */
1169 InsertConfigNode(pDevices, "pcarch", &pDev);
1170 InsertConfigNode(pDev, "0", &pInst);
1171 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1172 InsertConfigNode(pInst, "Config", &pCfg);
1173
1174 /*
1175 * The time offset
1176 */
1177 LONG64 timeOffset;
1178 hrc = firmwareSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1179 PCFGMNODE pTMNode;
1180 InsertConfigNode(pRoot, "TM", &pTMNode);
1181 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1182
1183 /*
1184 * DMA
1185 */
1186 InsertConfigNode(pDevices, "8237A", &pDev);
1187 InsertConfigNode(pDev, "0", &pInst);
1188 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1189
1190 /*
1191 * PCI buses.
1192 */
1193 uint32_t uIocPCIAddress, uHbcPCIAddress;
1194 switch (chipsetType)
1195 {
1196 default:
1197 AssertFailed();
1198 RT_FALL_THRU();
1199 case ChipsetType_PIIX3:
1200 /* Create the base for adding bridges on demand */
1201 InsertConfigNode(pDevices, "pcibridge", NULL);
1202
1203 InsertConfigNode(pDevices, "pci", &pDev);
1204 uHbcPCIAddress = (0x0 << 16) | 0;
1205 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1206 break;
1207 case ChipsetType_ICH9:
1208 /* Create the base for adding bridges on demand */
1209 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1210
1211 InsertConfigNode(pDevices, "ich9pci", &pDev);
1212 uHbcPCIAddress = (0x1e << 16) | 0;
1213 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1214 break;
1215 }
1216 InsertConfigNode(pDev, "0", &pInst);
1217 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1218 InsertConfigNode(pInst, "Config", &pCfg);
1219 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1220 if (chipsetType == ChipsetType_ICH9)
1221 {
1222 /* Provide MCFG info */
1223 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1224 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1225
1226#ifdef VBOX_WITH_PCI_PASSTHROUGH
1227 /* Add PCI passthrough devices */
1228 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1229#endif
1230
1231 if (enmIommuType == IommuType_AMD)
1232 {
1233 /* AMD IOMMU. */
1234 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1235 InsertConfigNode(pDev, "0", &pInst);
1236 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1237 InsertConfigNode(pInst, "Config", &pCfg);
1238 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1239
1240 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1241 {
1242 PCIBusAddress Address;
1243 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1244 {
1245 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1246 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1247 }
1248 else
1249 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1250 N_("Failed to find PCI address of the assigned IOMMU device!"));
1251 }
1252
1253 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1254 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1255 }
1256 else if (enmIommuType == IommuType_Intel)
1257 {
1258 /* Intel IOMMU. */
1259 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1260 InsertConfigNode(pDev, "0", &pInst);
1261 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1262 InsertConfigNode(pInst, "Config", &pCfg);
1263 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1264
1265 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1266 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1267 }
1268 }
1269
1270 /*
1271 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1272 */
1273
1274 /*
1275 * High Precision Event Timer (HPET)
1276 */
1277 BOOL fHPETEnabled;
1278 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1279 hrc = platformX86->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1280 /* so always enable HPET in extended profile */
1281 fHPETEnabled |= fOsXGuest;
1282 /* HPET is always present on ICH9 */
1283 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1284 if (fHPETEnabled)
1285 {
1286 InsertConfigNode(pDevices, "hpet", &pDev);
1287 InsertConfigNode(pDev, "0", &pInst);
1288 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1289 InsertConfigNode(pInst, "Config", &pCfg);
1290 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1291 }
1292
1293 /*
1294 * System Management Controller (SMC)
1295 */
1296 BOOL fSmcEnabled;
1297 fSmcEnabled = fOsXGuest;
1298 if (fSmcEnabled)
1299 {
1300 InsertConfigNode(pDevices, "smc", &pDev);
1301 InsertConfigNode(pDev, "0", &pInst);
1302 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1303 InsertConfigNode(pInst, "Config", &pCfg);
1304
1305 bool fGetKeyFromRealSMC;
1306 Utf8Str strKey;
1307 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1308 AssertRCReturn(vrc, vrc);
1309
1310 if (!fGetKeyFromRealSMC)
1311 InsertConfigString(pCfg, "DeviceKey", strKey);
1312 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1313 }
1314
1315 /*
1316 * Low Pin Count (LPC) bus
1317 */
1318 BOOL fLpcEnabled;
1319 /** @todo implement appropriate getter */
1320 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1321 if (fLpcEnabled)
1322 {
1323 InsertConfigNode(pDevices, "lpc", &pDev);
1324 InsertConfigNode(pDev, "0", &pInst);
1325 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1326 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1327 }
1328
1329 BOOL fShowRtc;
1330 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1331
1332 /*
1333 * PS/2 keyboard & mouse.
1334 */
1335 InsertConfigNode(pDevices, "pckbd", &pDev);
1336 InsertConfigNode(pDev, "0", &pInst);
1337 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1338 InsertConfigNode(pInst, "Config", &pCfg);
1339
1340 KeyboardHIDType_T aKbdHID;
1341 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1342 if (aKbdHID != KeyboardHIDType_None)
1343 {
1344 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1345 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1346 InsertConfigNode(pLunL0, "Config", &pCfg);
1347 InsertConfigInteger(pCfg, "QueueSize", 64);
1348
1349 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1350 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1351 }
1352
1353 PointingHIDType_T aPointingHID;
1354 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1355 if (aPointingHID != PointingHIDType_None)
1356 {
1357 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1358 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1359 InsertConfigNode(pLunL0, "Config", &pCfg);
1360 InsertConfigInteger(pCfg, "QueueSize", 128);
1361
1362 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1363 InsertConfigString(pLunL1, "Driver", "MainMouse");
1364 }
1365
1366 /*
1367 * i8254 Programmable Interval Timer And Dummy Speaker
1368 */
1369 InsertConfigNode(pDevices, "i8254", &pDev);
1370 InsertConfigNode(pDev, "0", &pInst);
1371 InsertConfigNode(pInst, "Config", &pCfg);
1372#ifdef DEBUG
1373 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1374#endif
1375
1376 /*
1377 * i8259 Programmable Interrupt Controller.
1378 */
1379 InsertConfigNode(pDevices, "i8259", &pDev);
1380 InsertConfigNode(pDev, "0", &pInst);
1381 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1382 InsertConfigNode(pInst, "Config", &pCfg);
1383
1384 /*
1385 * Advanced Programmable Interrupt Controller.
1386 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1387 * thus only single insert
1388 */
1389 if (fEnableAPIC)
1390 {
1391 InsertConfigNode(pDevices, "apic", &pDev);
1392 InsertConfigNode(pDev, "0", &pInst);
1393 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1394 InsertConfigNode(pInst, "Config", &pCfg);
1395 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1396 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1397 if (fEnableX2APIC)
1398 enmAPICMode = PDMAPICMODE_X2APIC;
1399 else if (!fEnableAPIC)
1400 enmAPICMode = PDMAPICMODE_NONE;
1401 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1402 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1403
1404 if (fIOAPIC)
1405 {
1406 /*
1407 * I/O Advanced Programmable Interrupt Controller.
1408 */
1409 InsertConfigNode(pDevices, "ioapic", &pDev);
1410 InsertConfigNode(pDev, "0", &pInst);
1411 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1412 InsertConfigNode(pInst, "Config", &pCfg);
1413 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1414 if (enmIommuType == IommuType_AMD)
1415 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1416 else if (enmIommuType == IommuType_Intel)
1417 {
1418 InsertConfigString(pCfg, "ChipType", "DMAR");
1419 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1420 }
1421 }
1422 }
1423
1424 /*
1425 * RTC MC146818.
1426 */
1427 InsertConfigNode(pDevices, "mc146818", &pDev);
1428 InsertConfigNode(pDev, "0", &pInst);
1429 InsertConfigNode(pInst, "Config", &pCfg);
1430 BOOL fRTCUseUTC;
1431 hrc = platform->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1432 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1433
1434 /*
1435 * VGA.
1436 */
1437 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1438 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1439 GraphicsControllerType_T enmGraphicsController;
1440 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1441 switch (enmGraphicsController)
1442 {
1443 case GraphicsControllerType_Null:
1444 break;
1445#ifdef VBOX_WITH_VMSVGA
1446 case GraphicsControllerType_VMSVGA:
1447 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else's logging backdoor. */
1448 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else's logging backdoor. */
1449 InsertConfigInteger(pGcmNode, "MesaVmsvgaDrv", 1); /* hits someone else's logging backdoor. */
1450 RT_FALL_THROUGH();
1451 case GraphicsControllerType_VBoxSVGA:
1452#endif
1453 case GraphicsControllerType_VBoxVGA:
1454 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, firmwareSettings);
1455 if (FAILED(vrc))
1456 return vrc;
1457 break;
1458 default:
1459 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1460 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1461 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1462 }
1463
1464#if defined(VBOX_WITH_TPM)
1465 /*
1466 * Configure the Trusted Platform Module.
1467 */
1468 ComObjPtr<ITrustedPlatformModule> ptrTpm;
1469 TpmType_T enmTpmType = TpmType_None;
1470
1471 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
1472 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
1473 if (enmTpmType != TpmType_None)
1474 {
1475 vrc = i_configTpm(ptrTpm, enmTpmType, pDevices, TPM_MMIO_BASE_DEFAULT, 10 /*uIrq*/,
1476 TPM_PPI_MMIO_BASE_DEFAULT, false /*fCrb*/); VRC();
1477 }
1478#endif
1479
1480 /*
1481 * Firmware.
1482 */
1483 FirmwareType_T eFwType = FirmwareType_BIOS;
1484 hrc = firmwareSettings->COMGETTER(FirmwareType)(&eFwType); H();
1485
1486#ifdef VBOX_WITH_EFI
1487 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1488#else
1489 BOOL fEfiEnabled = false;
1490#endif
1491 if (!fEfiEnabled)
1492 {
1493 /*
1494 * PC Bios.
1495 */
1496 InsertConfigNode(pDevices, "pcbios", &pDev);
1497 InsertConfigNode(pDev, "0", &pInst);
1498 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1499 InsertConfigNode(pInst, "Config", &pBiosCfg);
1500 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1501 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1502 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1503 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1504 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1505 BOOL fPXEDebug;
1506 hrc = firmwareSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1507 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1508 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1509 BOOL fUuidLe;
1510 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1511 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1512 BOOL fAutoSerialNumGen;
1513 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1514 if (fAutoSerialNumGen)
1515 InsertConfigString(pBiosCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1516 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1517 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1518 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1519
1520 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1521 VERR_INVALID_PARAMETER);
1522
1523 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1524 {
1525 DeviceType_T enmBootDevice;
1526 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1527
1528 char szParamName[] = "BootDeviceX";
1529 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1530
1531 const char *pszBootDevice;
1532 switch (enmBootDevice)
1533 {
1534 case DeviceType_Null:
1535 pszBootDevice = "NONE";
1536 break;
1537 case DeviceType_HardDisk:
1538 pszBootDevice = "IDE";
1539 break;
1540 case DeviceType_DVD:
1541 pszBootDevice = "DVD";
1542 break;
1543 case DeviceType_Floppy:
1544 pszBootDevice = "FLOPPY";
1545 break;
1546 case DeviceType_Network:
1547 pszBootDevice = "LAN";
1548 break;
1549 default:
1550 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1551 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1552 N_("Invalid boot device '%d'"), enmBootDevice);
1553 }
1554 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1555 }
1556
1557 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1558 * this is required for Windows 2012 guests. */
1559 if (osTypeId == GUEST_OS_ID_STR_X64("Windows2012"))
1560 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1561 }
1562 else
1563 {
1564 /* Autodetect firmware type, basing on guest type */
1565 if (eFwType == FirmwareType_EFI)
1566 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1567 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1568
1569 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1570#ifdef VBOX_WITH_EFI_IN_DD2
1571 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1572 : eFwType == FirmwareType_EFI32 ? "VBoxEFI-x86.fd"
1573 : "VBoxEFI-amd64.fd";
1574#else
1575 Utf8Str efiRomFile;
1576 vrc = findEfiRom(virtualBox, PlatformArchitecture_x86, eFwType, &efiRomFile);
1577 AssertRCReturn(vrc, vrc);
1578 const char *pszEfiRomFile = efiRomFile.c_str();
1579#endif
1580
1581 /* Get boot args */
1582 Utf8Str bootArgs;
1583 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1584
1585 /* Get device props */
1586 Utf8Str deviceProps;
1587 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1588
1589 /* Get NVRAM file name */
1590 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
1591
1592 BOOL fUuidLe;
1593 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1594
1595 BOOL fAutoSerialNumGen;
1596 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1597
1598 /* Get graphics mode settings */
1599 uint32_t u32GraphicsMode = UINT32_MAX;
1600 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1601 if (strTmp.isEmpty())
1602 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1603 if (!strTmp.isEmpty())
1604 u32GraphicsMode = strTmp.toUInt32();
1605
1606 /* Get graphics resolution settings, with some sanity checking */
1607 Utf8Str strResolution;
1608 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1609 if (!strResolution.isEmpty())
1610 {
1611 size_t pos = strResolution.find("x");
1612 if (pos != strResolution.npos)
1613 {
1614 Utf8Str strH, strV;
1615 strH.assignEx(strResolution, 0, pos);
1616 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1617 uint32_t u32H = strH.toUInt32();
1618 uint32_t u32V = strV.toUInt32();
1619 if (u32H == 0 || u32V == 0)
1620 strResolution.setNull();
1621 }
1622 else
1623 strResolution.setNull();
1624 }
1625 else
1626 {
1627 uint32_t u32H = 0;
1628 uint32_t u32V = 0;
1629 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1630 if (strTmp.isEmpty())
1631 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1632 if (!strTmp.isEmpty())
1633 u32H = strTmp.toUInt32();
1634
1635 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1636 if (strTmp.isEmpty())
1637 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1638 if (!strTmp.isEmpty())
1639 u32V = strTmp.toUInt32();
1640 if (u32H != 0 && u32V != 0)
1641 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
1642 }
1643
1644 /*
1645 * EFI subtree.
1646 */
1647 InsertConfigNode(pDevices, "efi", &pDev);
1648 InsertConfigNode(pDev, "0", &pInst);
1649 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1650 InsertConfigNode(pInst, "Config", &pCfg);
1651 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1652 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1653 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1654 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
1655 InsertConfigString(pCfg, "BootArgs", bootArgs);
1656 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1657 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1658 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1659 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1660 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
1661 if (fAutoSerialNumGen)
1662 InsertConfigString(pCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1663 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1664 InsertConfigString(pCfg, "NvramFile", strNvram);
1665 if (u32GraphicsMode != UINT32_MAX)
1666 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1667 if (!strResolution.isEmpty())
1668 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
1669
1670 /* For OS X guests we'll force passing host's DMI info to the guest */
1671 if (fOsXGuest)
1672 {
1673 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1674 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1675 }
1676
1677#if defined(VBOX_WITH_TPM)
1678 if (enmTpmType != TpmType_None)
1679 InsertConfigInteger(pCfg, "TpmPpiBase", TPM_PPI_MMIO_BASE_DEFAULT);
1680#endif
1681
1682 /* Attach the NVRAM storage driver. */
1683 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1684 InsertConfigString(pLunL0, "Driver", "NvramStore");
1685 }
1686
1687 /*
1688 * The USB Controllers.
1689 */
1690 PCFGMNODE pUsbDevices = NULL;
1691 vrc = i_configUsb(pMachine, pBusMgr, pRoot, pDevices, aKbdHID, aPointingHID, &pUsbDevices);
1692
1693 /*
1694 * Storage controllers.
1695 */
1696 bool fFdcEnabled = false;
1697 vrc = i_configStorageCtrls(pMachine, pBusMgr, pVMM, pUVM,
1698 pDevices, pUsbDevices, pBiosCfg, &fFdcEnabled); VRC();
1699
1700 /*
1701 * Network adapters
1702 */
1703 std::list<BootNic> llBootNics;
1704 vrc = i_configNetworkCtrls(pMachine, platformProperties, chipsetType, pBusMgr,
1705 pVMM, pUVM, pDevices, pUsbDevices, llBootNics); VRC();
1706
1707 /*
1708 * Build network boot information and transfer it to the BIOS.
1709 */
1710 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
1711 {
1712 llBootNics.sort(); /* Sort the list by boot priority. */
1713
1714 char achBootIdx[] = "0";
1715 unsigned uBootIdx = 0;
1716
1717 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
1718 {
1719 /* A NIC with priority 0 is only used if it's first in the list. */
1720 if (it->mBootPrio == 0 && uBootIdx != 0)
1721 break;
1722
1723 PCFGMNODE pNetBtDevCfg;
1724 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
1725 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
1726 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
1727 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
1728 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
1729 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
1730 }
1731 }
1732
1733 /*
1734 * Serial (UART) Ports
1735 */
1736 /* serial enabled mask to be passed to dev ACPI */
1737 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
1738 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
1739 InsertConfigNode(pDevices, "serial", &pDev);
1740 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
1741 {
1742 ComPtr<ISerialPort> serialPort;
1743 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
1744 BOOL fEnabledSerPort = FALSE;
1745 if (serialPort)
1746 {
1747 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
1748 }
1749 if (!fEnabledSerPort)
1750 {
1751 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
1752 continue;
1753 }
1754
1755 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1756 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1757 InsertConfigNode(pInst, "Config", &pCfg);
1758
1759 ULONG ulIRQ;
1760 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
1761 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1762 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
1763
1764 ULONG ulIOBase;
1765 hrc = serialPort->COMGETTER(IOAddress)(&ulIOBase); H();
1766 InsertConfigInteger(pCfg, "IOAddress", ulIOBase);
1767 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
1768
1769 BOOL fServer;
1770 hrc = serialPort->COMGETTER(Server)(&fServer); H();
1771 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
1772 UartType_T eUartType;
1773 const char *pszUartType;
1774 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
1775 switch (eUartType)
1776 {
1777 case UartType_U16450: pszUartType = "16450"; break;
1778 case UartType_U16750: pszUartType = "16750"; break;
1779 default: AssertFailed(); RT_FALL_THRU();
1780 case UartType_U16550A: pszUartType = "16550A"; break;
1781 }
1782 InsertConfigString(pCfg, "UartType", pszUartType);
1783
1784 PortMode_T eHostMode;
1785 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
1786
1787 m_aeSerialPortMode[ulInstance] = eHostMode;
1788 if (eHostMode != PortMode_Disconnected)
1789 {
1790 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
1791 if (RT_FAILURE(vrc))
1792 return vrc;
1793 }
1794 }
1795
1796 /*
1797 * Parallel (LPT) Ports
1798 */
1799 /* parallel enabled mask to be passed to dev ACPI */
1800 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
1801 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
1802 InsertConfigNode(pDevices, "parallel", &pDev);
1803 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
1804 {
1805 ComPtr<IParallelPort> parallelPort;
1806 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
1807 BOOL fEnabledParPort = FALSE;
1808 if (parallelPort)
1809 {
1810 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
1811 }
1812 if (!fEnabledParPort)
1813 continue;
1814
1815 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1816 InsertConfigNode(pInst, "Config", &pCfg);
1817
1818 ULONG ulIRQ;
1819 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
1820 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1821 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
1822 ULONG ulIOBase;
1823 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
1824 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
1825 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
1826
1827 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
1828 if (!bstr.isEmpty())
1829 {
1830 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1831 InsertConfigString(pLunL0, "Driver", "HostParallel");
1832 InsertConfigNode(pLunL0, "Config", &pLunL1);
1833 InsertConfigString(pLunL1, "DevicePath", bstr);
1834 }
1835 }
1836
1837 vrc = i_configVmmDev(pMachine, pBusMgr, pDevices); VRC();
1838
1839 /*
1840 * Audio configuration.
1841 */
1842 bool fAudioEnabled = false;
1843 vrc = i_configAudioCtrl(virtualBox, pMachine, pBusMgr, pDevices,
1844 fOsXGuest, &fAudioEnabled); VRC();
1845
1846 /*
1847 * ACPI
1848 */
1849 BOOL fACPI;
1850 hrc = firmwareSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
1851 if (fACPI)
1852 {
1853 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
1854 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
1855 * intelppm driver refuses to register an idle state handler.
1856 * Always show CPU leafs for OS X guests. */
1857 BOOL fShowCpu = fOsXGuest;
1858 if (cCpus > 1 || fIOAPIC)
1859 fShowCpu = true;
1860
1861 BOOL fCpuHotPlug;
1862 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
1863
1864 InsertConfigNode(pDevices, "acpi", &pDev);
1865 InsertConfigNode(pDev, "0", &pInst);
1866 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1867 InsertConfigNode(pInst, "Config", &pCfg);
1868 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
1869
1870 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1871
1872 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1873 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
1874 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
1875 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
1876 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
1877 if (fOsXGuest && !llBootNics.empty())
1878 {
1879 BootNic aNic = llBootNics.front();
1880 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
1881 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
1882 }
1883 if (fOsXGuest && fAudioEnabled)
1884 {
1885 PCIBusAddress Address;
1886 if (pBusMgr->findPCIAddress("hda", 0, Address))
1887 {
1888 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
1889 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
1890 }
1891 }
1892 if (fOsXGuest)
1893 {
1894 PCIBusAddress Address;
1895 if (pBusMgr->findPCIAddress("nvme", 0, Address))
1896 {
1897 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
1898 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
1899 }
1900 }
1901 if (enmIommuType == IommuType_AMD)
1902 {
1903 PCIBusAddress Address;
1904 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1905 {
1906 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1907 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
1908 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
1909 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
1910 {
1911 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
1912 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
1913 }
1914 else
1915 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1916 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
1917 }
1918 }
1919 else if (enmIommuType == IommuType_Intel)
1920 {
1921 PCIBusAddress Address;
1922 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
1923 {
1924 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1925 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
1926 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
1927 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
1928 {
1929 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
1930 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
1931 }
1932 else
1933 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1934 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
1935 }
1936 }
1937
1938 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
1939 if (chipsetType == ChipsetType_ICH9)
1940 {
1941 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1942 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1943 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */
1944 if (fIsGuest64Bit || fEnablePAE)
1945 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
1946 }
1947 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
1948 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
1949 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
1950
1951 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
1952 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
1953
1954 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
1955 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
1956
1957 if (auSerialIoPortBase[2])
1958 {
1959 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
1960 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
1961 }
1962
1963 if (auSerialIoPortBase[3])
1964 {
1965 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
1966 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
1967 }
1968
1969 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
1970 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
1971
1972 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
1973 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
1974
1975#if defined(VBOX_WITH_TPM)
1976 switch (enmTpmType)
1977 {
1978 case TpmType_v1_2:
1979 InsertConfigString(pCfg, "TpmMode", "tis1.2");
1980 break;
1981 case TpmType_v2_0:
1982 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
1983 break;
1984 /** @todo Host and swtpm. */
1985 default:
1986 break;
1987 }
1988#endif
1989
1990 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1991 InsertConfigString(pLunL0, "Driver", "ACPIHost");
1992 InsertConfigNode(pLunL0, "Config", &pCfg);
1993
1994 /* Attach the dummy CPU drivers */
1995 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
1996 {
1997 BOOL fCpuAttached = true;
1998
1999 if (fCpuHotPlug)
2000 {
2001 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
2002 }
2003
2004 if (fCpuAttached)
2005 {
2006 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
2007 InsertConfigString(pLunL0, "Driver", "ACPICpu");
2008 InsertConfigNode(pLunL0, "Config", &pCfg);
2009 }
2010 }
2011 }
2012
2013 /*
2014 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
2015 */
2016 vrc = i_configGuestDbg(virtualBox, pMachine, pRoot); VRC();
2017 }
2018 catch (ConfigError &x)
2019 {
2020 // InsertConfig threw something:
2021 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
2022 return x.m_vrc;
2023 }
2024 catch (HRESULT hrcXcpt)
2025 {
2026 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2027 }
2028
2029#ifdef VBOX_WITH_EXTPACK
2030 /*
2031 * Call the extension pack hooks if everything went well thus far.
2032 */
2033 if (RT_SUCCESS(vrc))
2034 {
2035 pAlock->release();
2036 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);
2037 pAlock->acquire();
2038 }
2039#endif
2040
2041 /*
2042 * Apply the CFGM overlay.
2043 */
2044 if (RT_SUCCESS(vrc))
2045 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
2046
2047 /*
2048 * Dump all extradata API settings tweaks, both global and per VM.
2049 */
2050 if (RT_SUCCESS(vrc))
2051 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
2052
2053#undef H
2054
2055 pAlock->release(); /* Avoid triggering the lock order inversion check. */
2056
2057 /*
2058 * Register VM state change handler.
2059 */
2060 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
2061 AssertRC(vrc2);
2062 if (RT_SUCCESS(vrc))
2063 vrc = vrc2;
2064
2065 /*
2066 * Register VM runtime error handler.
2067 */
2068 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
2069 AssertRC(vrc2);
2070 if (RT_SUCCESS(vrc))
2071 vrc = vrc2;
2072
2073 pAlock->acquire();
2074
2075 LogFlowFunc(("vrc = %Rrc\n", vrc));
2076 LogFlowFuncLeave();
2077
2078 return vrc;
2079}
Note: See TracBrowser for help on using the repository browser.

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