VirtualBox

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

Last change on this file since 107402 was 107267, checked in by vboxsync, 6 weeks ago

Main/API,UI: bugref:10810 Based on Brent's patch, added UsbNet support into Main API and UI

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 85.7 KB
Line 
1/* $Id: ConsoleImplConfigX86.cpp 107267 2024-12-10 07:37:35Z 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;
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 /*
995 * Paravirt. provider.
996 */
997 PCFGMNODE pParavirtNode;
998 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
999 const char *pcszParavirtProvider;
1000 bool fGimDeviceNeeded = true;
1001 switch (enmParavirtProvider)
1002 {
1003 case ParavirtProvider_None:
1004 pcszParavirtProvider = "None";
1005 fGimDeviceNeeded = false;
1006 break;
1007
1008 case ParavirtProvider_Minimal:
1009 pcszParavirtProvider = "Minimal";
1010 break;
1011
1012 case ParavirtProvider_HyperV:
1013 pcszParavirtProvider = "HyperV";
1014 break;
1015
1016 case ParavirtProvider_KVM:
1017 pcszParavirtProvider = "KVM";
1018 break;
1019
1020 default:
1021 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));
1022 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1023 enmParavirtProvider);
1024 }
1025 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1026
1027 /*
1028 * Parse paravirt. debug options.
1029 */
1030 bool fGimDebug = false;
1031 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1032 uint32_t uGimDebugPort = 50000;
1033 if (strParavirtDebug.isNotEmpty())
1034 {
1035 /* Hyper-V debug options. */
1036 if (enmParavirtProvider == ParavirtProvider_HyperV)
1037 {
1038 bool fGimHvDebug = false;
1039 com::Utf8Str strGimHvVendor;
1040 bool fGimHvVsIf = false;
1041 bool fGimHvHypercallIf = false;
1042
1043 size_t uPos = 0;
1044 com::Utf8Str strDebugOptions = strParavirtDebug;
1045 com::Utf8Str strKey;
1046 com::Utf8Str strVal;
1047 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1048 {
1049 if (strKey == "enabled")
1050 {
1051 if (strVal.toUInt32() == 1)
1052 {
1053 /* Apply defaults.
1054 The defaults are documented in the user manual,
1055 changes need to be reflected accordingly. */
1056 fGimHvDebug = true;
1057 strGimHvVendor = "Microsoft Hv";
1058 fGimHvVsIf = true;
1059 fGimHvHypercallIf = false;
1060 }
1061 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1062 }
1063 else if (strKey == "address")
1064 strGimDebugAddress = strVal;
1065 else if (strKey == "port")
1066 uGimDebugPort = strVal.toUInt32();
1067 else if (strKey == "vendor")
1068 strGimHvVendor = strVal;
1069 else if (strKey == "vsinterface")
1070 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1071 else if (strKey == "hypercallinterface")
1072 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1073 else
1074 {
1075 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1076 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1077 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1078 strDebugOptions.c_str());
1079 }
1080 }
1081
1082 /* Update HyperV CFGM node with active debug options. */
1083 if (fGimHvDebug)
1084 {
1085 PCFGMNODE pHvNode;
1086 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1087 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1088 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1089 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1090 fGimDebug = true;
1091 }
1092 }
1093 }
1094
1095 /*
1096 * Guest Compatibility Manager.
1097 */
1098 PCFGMNODE pGcmNode;
1099 InsertConfigNode(pRoot, "GCM", &pGcmNode);
1100 /* OS/2 and Win9x guests can run DOS apps so they get the DOS specific
1101 fixes as well. */
1102 if (fDosGuest || fOs2Guest || fW9xGuest)
1103 InsertConfigInteger(pGcmNode, "DivByZeroDOS", 1);
1104 if (fOs2Guest)
1105 InsertConfigInteger(pGcmNode, "DivByZeroOS2", 1);
1106 if (fW9xGuest)
1107 InsertConfigInteger(pGcmNode, "DivByZeroWin9x", 1);
1108 /* MesaVmsvgaDrv (formerly LovelyMesaDrvWorkaround) is set futher down. */
1109
1110 /*
1111 * MM values.
1112 */
1113 PCFGMNODE pMM;
1114 InsertConfigNode(pRoot, "MM", &pMM);
1115 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1116
1117 /*
1118 * PDM config.
1119 * Load drivers in VBoxC.[so|dll]
1120 */
1121 vrc = i_configPdm(pMachine, pVMM, pUVM, pRoot); VRC();
1122
1123 /*
1124 * Devices
1125 */
1126 PCFGMNODE pDevices = NULL; /* /Devices */
1127 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1128 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1129 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1130 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1131 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1132 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1133 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1134
1135 InsertConfigNode(pRoot, "Devices", &pDevices);
1136
1137 /*
1138 * GIM Device
1139 */
1140 if (fGimDeviceNeeded)
1141 {
1142 InsertConfigNode(pDevices, "GIMDev", &pDev);
1143 InsertConfigNode(pDev, "0", &pInst);
1144 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1145 //InsertConfigNode(pInst, "Config", &pCfg);
1146
1147 if (fGimDebug)
1148 {
1149 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1150 InsertConfigString(pLunL0, "Driver", "UDP");
1151 InsertConfigNode(pLunL0, "Config", &pLunL1);
1152 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1153 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1154 }
1155 }
1156
1157 /*
1158 * PC Arch.
1159 */
1160 InsertConfigNode(pDevices, "pcarch", &pDev);
1161 InsertConfigNode(pDev, "0", &pInst);
1162 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1163 InsertConfigNode(pInst, "Config", &pCfg);
1164
1165 /*
1166 * The time offset
1167 */
1168 LONG64 timeOffset;
1169 hrc = firmwareSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1170 PCFGMNODE pTMNode;
1171 InsertConfigNode(pRoot, "TM", &pTMNode);
1172 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1173
1174 /*
1175 * DMA
1176 */
1177 InsertConfigNode(pDevices, "8237A", &pDev);
1178 InsertConfigNode(pDev, "0", &pInst);
1179 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1180
1181 /*
1182 * PCI buses.
1183 */
1184 uint32_t uIocPCIAddress, uHbcPCIAddress;
1185 switch (chipsetType)
1186 {
1187 default:
1188 AssertFailed();
1189 RT_FALL_THRU();
1190 case ChipsetType_PIIX3:
1191 /* Create the base for adding bridges on demand */
1192 InsertConfigNode(pDevices, "pcibridge", NULL);
1193
1194 InsertConfigNode(pDevices, "pci", &pDev);
1195 uHbcPCIAddress = (0x0 << 16) | 0;
1196 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1197 break;
1198 case ChipsetType_ICH9:
1199 /* Create the base for adding bridges on demand */
1200 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1201
1202 InsertConfigNode(pDevices, "ich9pci", &pDev);
1203 uHbcPCIAddress = (0x1e << 16) | 0;
1204 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1205 break;
1206 }
1207 InsertConfigNode(pDev, "0", &pInst);
1208 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1209 InsertConfigNode(pInst, "Config", &pCfg);
1210 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1211 if (chipsetType == ChipsetType_ICH9)
1212 {
1213 /* Provide MCFG info */
1214 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1215 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1216
1217#ifdef VBOX_WITH_PCI_PASSTHROUGH
1218 /* Add PCI passthrough devices */
1219 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1220#endif
1221
1222 if (enmIommuType == IommuType_AMD)
1223 {
1224 /* AMD IOMMU. */
1225 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1226 InsertConfigNode(pDev, "0", &pInst);
1227 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1228 InsertConfigNode(pInst, "Config", &pCfg);
1229 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1230
1231 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1232 {
1233 PCIBusAddress Address;
1234 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1235 {
1236 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1237 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1238 }
1239 else
1240 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1241 N_("Failed to find PCI address of the assigned IOMMU device!"));
1242 }
1243
1244 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1245 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1246 }
1247 else if (enmIommuType == IommuType_Intel)
1248 {
1249 /* Intel IOMMU. */
1250 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1251 InsertConfigNode(pDev, "0", &pInst);
1252 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1253 InsertConfigNode(pInst, "Config", &pCfg);
1254 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1255
1256 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1257 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1258 }
1259 }
1260
1261 /*
1262 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1263 */
1264
1265 /*
1266 * High Precision Event Timer (HPET)
1267 */
1268 BOOL fHPETEnabled;
1269 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1270 hrc = platformX86->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1271 /* so always enable HPET in extended profile */
1272 fHPETEnabled |= fOsXGuest;
1273 /* HPET is always present on ICH9 */
1274 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1275 if (fHPETEnabled)
1276 {
1277 InsertConfigNode(pDevices, "hpet", &pDev);
1278 InsertConfigNode(pDev, "0", &pInst);
1279 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1280 InsertConfigNode(pInst, "Config", &pCfg);
1281 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1282 }
1283
1284 /*
1285 * System Management Controller (SMC)
1286 */
1287 BOOL fSmcEnabled;
1288 fSmcEnabled = fOsXGuest;
1289 if (fSmcEnabled)
1290 {
1291 InsertConfigNode(pDevices, "smc", &pDev);
1292 InsertConfigNode(pDev, "0", &pInst);
1293 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1294 InsertConfigNode(pInst, "Config", &pCfg);
1295
1296 bool fGetKeyFromRealSMC;
1297 Utf8Str strKey;
1298 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1299 AssertRCReturn(vrc, vrc);
1300
1301 if (!fGetKeyFromRealSMC)
1302 InsertConfigString(pCfg, "DeviceKey", strKey);
1303 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1304 }
1305
1306 /*
1307 * Low Pin Count (LPC) bus
1308 */
1309 BOOL fLpcEnabled;
1310 /** @todo implement appropriate getter */
1311 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1312 if (fLpcEnabled)
1313 {
1314 InsertConfigNode(pDevices, "lpc", &pDev);
1315 InsertConfigNode(pDev, "0", &pInst);
1316 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1317 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1318 }
1319
1320 BOOL fShowRtc;
1321 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1322
1323 /*
1324 * PS/2 keyboard & mouse.
1325 */
1326 InsertConfigNode(pDevices, "pckbd", &pDev);
1327 InsertConfigNode(pDev, "0", &pInst);
1328 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1329 InsertConfigNode(pInst, "Config", &pCfg);
1330
1331 KeyboardHIDType_T aKbdHID;
1332 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1333 if (aKbdHID != KeyboardHIDType_None)
1334 {
1335 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1336 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1337 InsertConfigNode(pLunL0, "Config", &pCfg);
1338 InsertConfigInteger(pCfg, "QueueSize", 64);
1339
1340 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1341 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1342 }
1343
1344 PointingHIDType_T aPointingHID;
1345 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1346 if (aPointingHID != PointingHIDType_None)
1347 {
1348 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1349 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1350 InsertConfigNode(pLunL0, "Config", &pCfg);
1351 InsertConfigInteger(pCfg, "QueueSize", 128);
1352
1353 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1354 InsertConfigString(pLunL1, "Driver", "MainMouse");
1355 }
1356
1357 /*
1358 * i8254 Programmable Interval Timer And Dummy Speaker
1359 */
1360 InsertConfigNode(pDevices, "i8254", &pDev);
1361 InsertConfigNode(pDev, "0", &pInst);
1362 InsertConfigNode(pInst, "Config", &pCfg);
1363#ifdef DEBUG
1364 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1365#endif
1366
1367 /*
1368 * i8259 Programmable Interrupt Controller.
1369 */
1370 InsertConfigNode(pDevices, "i8259", &pDev);
1371 InsertConfigNode(pDev, "0", &pInst);
1372 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1373 InsertConfigNode(pInst, "Config", &pCfg);
1374
1375 /*
1376 * Advanced Programmable Interrupt Controller.
1377 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1378 * thus only single insert
1379 */
1380 if (fEnableAPIC)
1381 {
1382 InsertConfigNode(pDevices, "apic", &pDev);
1383 InsertConfigNode(pDev, "0", &pInst);
1384 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1385 InsertConfigNode(pInst, "Config", &pCfg);
1386 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1387 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1388 if (fEnableX2APIC)
1389 enmAPICMode = PDMAPICMODE_X2APIC;
1390 else if (!fEnableAPIC)
1391 enmAPICMode = PDMAPICMODE_NONE;
1392 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1393 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1394
1395 if (fIOAPIC)
1396 {
1397 /*
1398 * I/O Advanced Programmable Interrupt Controller.
1399 */
1400 InsertConfigNode(pDevices, "ioapic", &pDev);
1401 InsertConfigNode(pDev, "0", &pInst);
1402 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1403 InsertConfigNode(pInst, "Config", &pCfg);
1404 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1405 if (enmIommuType == IommuType_AMD)
1406 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1407 else if (enmIommuType == IommuType_Intel)
1408 {
1409 InsertConfigString(pCfg, "ChipType", "DMAR");
1410 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1411 }
1412 }
1413 }
1414
1415 /*
1416 * RTC MC146818.
1417 */
1418 InsertConfigNode(pDevices, "mc146818", &pDev);
1419 InsertConfigNode(pDev, "0", &pInst);
1420 InsertConfigNode(pInst, "Config", &pCfg);
1421 BOOL fRTCUseUTC;
1422 hrc = platform->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1423 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1424
1425 /*
1426 * VGA.
1427 */
1428 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1429 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1430 GraphicsControllerType_T enmGraphicsController;
1431 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1432 switch (enmGraphicsController)
1433 {
1434 case GraphicsControllerType_Null:
1435 break;
1436#ifdef VBOX_WITH_VMSVGA
1437 case GraphicsControllerType_VMSVGA:
1438 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else's logging backdoor. */
1439 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else's logging backdoor. */
1440 InsertConfigInteger(pGcmNode, "MesaVmsvgaDrv", 1); /* hits someone else's logging backdoor. */
1441 RT_FALL_THROUGH();
1442 case GraphicsControllerType_VBoxSVGA:
1443#endif
1444 case GraphicsControllerType_VBoxVGA:
1445 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, firmwareSettings);
1446 if (FAILED(vrc))
1447 return vrc;
1448 break;
1449 default:
1450 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1451 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1452 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1453 }
1454
1455#if defined(VBOX_WITH_TPM)
1456 /*
1457 * Configure the Trusted Platform Module.
1458 */
1459 ComObjPtr<ITrustedPlatformModule> ptrTpm;
1460 TpmType_T enmTpmType = TpmType_None;
1461
1462 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
1463 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
1464 if (enmTpmType != TpmType_None)
1465 {
1466 vrc = i_configTpm(ptrTpm, enmTpmType, pDevices, TPM_MMIO_BASE_DEFAULT, 10 /*uIrq*/,
1467 TPM_PPI_MMIO_BASE_DEFAULT, false /*fCrb*/); VRC();
1468 }
1469#endif
1470
1471 /*
1472 * Firmware.
1473 */
1474 FirmwareType_T eFwType = FirmwareType_BIOS;
1475 hrc = firmwareSettings->COMGETTER(FirmwareType)(&eFwType); H();
1476
1477#ifdef VBOX_WITH_EFI
1478 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1479#else
1480 BOOL fEfiEnabled = false;
1481#endif
1482 if (!fEfiEnabled)
1483 {
1484 /*
1485 * PC Bios.
1486 */
1487 InsertConfigNode(pDevices, "pcbios", &pDev);
1488 InsertConfigNode(pDev, "0", &pInst);
1489 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1490 InsertConfigNode(pInst, "Config", &pBiosCfg);
1491 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1492 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1493 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1494 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1495 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1496 BOOL fPXEDebug;
1497 hrc = firmwareSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1498 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1499 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1500 BOOL fUuidLe;
1501 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1502 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1503 BOOL fAutoSerialNumGen;
1504 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1505 if (fAutoSerialNumGen)
1506 InsertConfigString(pBiosCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1507 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1508 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1509 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1510
1511 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1512 VERR_INVALID_PARAMETER);
1513
1514 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1515 {
1516 DeviceType_T enmBootDevice;
1517 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1518
1519 char szParamName[] = "BootDeviceX";
1520 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1521
1522 const char *pszBootDevice;
1523 switch (enmBootDevice)
1524 {
1525 case DeviceType_Null:
1526 pszBootDevice = "NONE";
1527 break;
1528 case DeviceType_HardDisk:
1529 pszBootDevice = "IDE";
1530 break;
1531 case DeviceType_DVD:
1532 pszBootDevice = "DVD";
1533 break;
1534 case DeviceType_Floppy:
1535 pszBootDevice = "FLOPPY";
1536 break;
1537 case DeviceType_Network:
1538 pszBootDevice = "LAN";
1539 break;
1540 default:
1541 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1542 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1543 N_("Invalid boot device '%d'"), enmBootDevice);
1544 }
1545 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1546 }
1547
1548 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1549 * this is required for Windows 2012 guests. */
1550 if (osTypeId == GUEST_OS_ID_STR_X64("Windows2012"))
1551 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1552 }
1553 else
1554 {
1555 /* Autodetect firmware type, basing on guest type */
1556 if (eFwType == FirmwareType_EFI)
1557 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1558 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1559
1560 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1561#ifdef VBOX_WITH_EFI_IN_DD2
1562 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1563 : eFwType == FirmwareType_EFI32 ? "VBoxEFI-x86.fd"
1564 : "VBoxEFI-amd64.fd";
1565#else
1566 Utf8Str efiRomFile;
1567 vrc = findEfiRom(virtualBox, PlatformArchitecture_x86, eFwType, &efiRomFile);
1568 AssertRCReturn(vrc, vrc);
1569 const char *pszEfiRomFile = efiRomFile.c_str();
1570#endif
1571
1572 /* Get boot args */
1573 Utf8Str bootArgs;
1574 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1575
1576 /* Get device props */
1577 Utf8Str deviceProps;
1578 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1579
1580 /* Get NVRAM file name */
1581 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
1582
1583 BOOL fUuidLe;
1584 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1585
1586 BOOL fAutoSerialNumGen;
1587 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1588
1589 /* Get graphics mode settings */
1590 uint32_t u32GraphicsMode = UINT32_MAX;
1591 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1592 if (strTmp.isEmpty())
1593 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1594 if (!strTmp.isEmpty())
1595 u32GraphicsMode = strTmp.toUInt32();
1596
1597 /* Get graphics resolution settings, with some sanity checking */
1598 Utf8Str strResolution;
1599 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1600 if (!strResolution.isEmpty())
1601 {
1602 size_t pos = strResolution.find("x");
1603 if (pos != strResolution.npos)
1604 {
1605 Utf8Str strH, strV;
1606 strH.assignEx(strResolution, 0, pos);
1607 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1608 uint32_t u32H = strH.toUInt32();
1609 uint32_t u32V = strV.toUInt32();
1610 if (u32H == 0 || u32V == 0)
1611 strResolution.setNull();
1612 }
1613 else
1614 strResolution.setNull();
1615 }
1616 else
1617 {
1618 uint32_t u32H = 0;
1619 uint32_t u32V = 0;
1620 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1621 if (strTmp.isEmpty())
1622 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1623 if (!strTmp.isEmpty())
1624 u32H = strTmp.toUInt32();
1625
1626 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1627 if (strTmp.isEmpty())
1628 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1629 if (!strTmp.isEmpty())
1630 u32V = strTmp.toUInt32();
1631 if (u32H != 0 && u32V != 0)
1632 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
1633 }
1634
1635 /*
1636 * EFI subtree.
1637 */
1638 InsertConfigNode(pDevices, "efi", &pDev);
1639 InsertConfigNode(pDev, "0", &pInst);
1640 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1641 InsertConfigNode(pInst, "Config", &pCfg);
1642 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1643 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1644 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1645 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
1646 InsertConfigString(pCfg, "BootArgs", bootArgs);
1647 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1648 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1649 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1650 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1651 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
1652 if (fAutoSerialNumGen)
1653 InsertConfigString(pCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1654 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1655 InsertConfigString(pCfg, "NvramFile", strNvram);
1656 if (u32GraphicsMode != UINT32_MAX)
1657 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1658 if (!strResolution.isEmpty())
1659 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
1660
1661 /* For OS X guests we'll force passing host's DMI info to the guest */
1662 if (fOsXGuest)
1663 {
1664 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1665 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1666 }
1667
1668#if defined(VBOX_WITH_TPM)
1669 if (enmTpmType != TpmType_None)
1670 InsertConfigInteger(pCfg, "TpmPpiBase", TPM_PPI_MMIO_BASE_DEFAULT);
1671#endif
1672
1673 /* Attach the NVRAM storage driver. */
1674 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1675 InsertConfigString(pLunL0, "Driver", "NvramStore");
1676 }
1677
1678 /*
1679 * The USB Controllers.
1680 */
1681 PCFGMNODE pUsbDevices = NULL;
1682 vrc = i_configUsb(pMachine, pBusMgr, pRoot, pDevices, aKbdHID, aPointingHID, &pUsbDevices);
1683
1684 /*
1685 * Storage controllers.
1686 */
1687 bool fFdcEnabled = false;
1688 vrc = i_configStorageCtrls(pMachine, pBusMgr, pVMM, pUVM,
1689 pDevices, pUsbDevices, pBiosCfg, &fFdcEnabled); VRC();
1690
1691 /*
1692 * Network adapters
1693 */
1694 std::list<BootNic> llBootNics;
1695 vrc = i_configNetworkCtrls(pMachine, platformProperties, chipsetType, pBusMgr,
1696 pVMM, pUVM, pDevices, pUsbDevices, llBootNics); VRC();
1697
1698 /*
1699 * Build network boot information and transfer it to the BIOS.
1700 */
1701 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
1702 {
1703 llBootNics.sort(); /* Sort the list by boot priority. */
1704
1705 char achBootIdx[] = "0";
1706 unsigned uBootIdx = 0;
1707
1708 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
1709 {
1710 /* A NIC with priority 0 is only used if it's first in the list. */
1711 if (it->mBootPrio == 0 && uBootIdx != 0)
1712 break;
1713
1714 PCFGMNODE pNetBtDevCfg;
1715 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
1716 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
1717 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
1718 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
1719 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
1720 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
1721 }
1722 }
1723
1724 /*
1725 * Serial (UART) Ports
1726 */
1727 /* serial enabled mask to be passed to dev ACPI */
1728 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
1729 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
1730 InsertConfigNode(pDevices, "serial", &pDev);
1731 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
1732 {
1733 ComPtr<ISerialPort> serialPort;
1734 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
1735 BOOL fEnabledSerPort = FALSE;
1736 if (serialPort)
1737 {
1738 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
1739 }
1740 if (!fEnabledSerPort)
1741 {
1742 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
1743 continue;
1744 }
1745
1746 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1747 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1748 InsertConfigNode(pInst, "Config", &pCfg);
1749
1750 ULONG ulIRQ;
1751 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
1752 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1753 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
1754
1755 ULONG ulIOBase;
1756 hrc = serialPort->COMGETTER(IOAddress)(&ulIOBase); H();
1757 InsertConfigInteger(pCfg, "IOAddress", ulIOBase);
1758 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
1759
1760 BOOL fServer;
1761 hrc = serialPort->COMGETTER(Server)(&fServer); H();
1762 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
1763 UartType_T eUartType;
1764 const char *pszUartType;
1765 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
1766 switch (eUartType)
1767 {
1768 case UartType_U16450: pszUartType = "16450"; break;
1769 case UartType_U16750: pszUartType = "16750"; break;
1770 default: AssertFailed(); RT_FALL_THRU();
1771 case UartType_U16550A: pszUartType = "16550A"; break;
1772 }
1773 InsertConfigString(pCfg, "UartType", pszUartType);
1774
1775 PortMode_T eHostMode;
1776 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
1777
1778 m_aeSerialPortMode[ulInstance] = eHostMode;
1779 if (eHostMode != PortMode_Disconnected)
1780 {
1781 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
1782 if (RT_FAILURE(vrc))
1783 return vrc;
1784 }
1785 }
1786
1787 /*
1788 * Parallel (LPT) Ports
1789 */
1790 /* parallel enabled mask to be passed to dev ACPI */
1791 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
1792 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
1793 InsertConfigNode(pDevices, "parallel", &pDev);
1794 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
1795 {
1796 ComPtr<IParallelPort> parallelPort;
1797 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
1798 BOOL fEnabledParPort = FALSE;
1799 if (parallelPort)
1800 {
1801 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
1802 }
1803 if (!fEnabledParPort)
1804 continue;
1805
1806 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1807 InsertConfigNode(pInst, "Config", &pCfg);
1808
1809 ULONG ulIRQ;
1810 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
1811 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1812 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
1813 ULONG ulIOBase;
1814 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
1815 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
1816 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
1817
1818 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
1819 if (!bstr.isEmpty())
1820 {
1821 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1822 InsertConfigString(pLunL0, "Driver", "HostParallel");
1823 InsertConfigNode(pLunL0, "Config", &pLunL1);
1824 InsertConfigString(pLunL1, "DevicePath", bstr);
1825 }
1826 }
1827
1828 vrc = i_configVmmDev(pMachine, pBusMgr, pDevices); VRC();
1829
1830 /*
1831 * Audio configuration.
1832 */
1833 bool fAudioEnabled = false;
1834 vrc = i_configAudioCtrl(virtualBox, pMachine, pBusMgr, pDevices,
1835 fOsXGuest, &fAudioEnabled); VRC();
1836
1837 /*
1838 * ACPI
1839 */
1840 BOOL fACPI;
1841 hrc = firmwareSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
1842 if (fACPI)
1843 {
1844 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
1845 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
1846 * intelppm driver refuses to register an idle state handler.
1847 * Always show CPU leafs for OS X guests. */
1848 BOOL fShowCpu = fOsXGuest;
1849 if (cCpus > 1 || fIOAPIC)
1850 fShowCpu = true;
1851
1852 BOOL fCpuHotPlug;
1853 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
1854
1855 InsertConfigNode(pDevices, "acpi", &pDev);
1856 InsertConfigNode(pDev, "0", &pInst);
1857 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1858 InsertConfigNode(pInst, "Config", &pCfg);
1859 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
1860
1861 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1862
1863 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1864 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
1865 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
1866 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
1867 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
1868 if (fOsXGuest && !llBootNics.empty())
1869 {
1870 BootNic aNic = llBootNics.front();
1871 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
1872 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
1873 }
1874 if (fOsXGuest && fAudioEnabled)
1875 {
1876 PCIBusAddress Address;
1877 if (pBusMgr->findPCIAddress("hda", 0, Address))
1878 {
1879 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
1880 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
1881 }
1882 }
1883 if (fOsXGuest)
1884 {
1885 PCIBusAddress Address;
1886 if (pBusMgr->findPCIAddress("nvme", 0, Address))
1887 {
1888 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
1889 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
1890 }
1891 }
1892 if (enmIommuType == IommuType_AMD)
1893 {
1894 PCIBusAddress Address;
1895 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1896 {
1897 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1898 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
1899 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
1900 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
1901 {
1902 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
1903 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
1904 }
1905 else
1906 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1907 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
1908 }
1909 }
1910 else if (enmIommuType == IommuType_Intel)
1911 {
1912 PCIBusAddress Address;
1913 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
1914 {
1915 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1916 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
1917 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
1918 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
1919 {
1920 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
1921 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
1922 }
1923 else
1924 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1925 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
1926 }
1927 }
1928
1929 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
1930 if (chipsetType == ChipsetType_ICH9)
1931 {
1932 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1933 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1934 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */
1935 if (fIsGuest64Bit || fEnablePAE)
1936 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
1937 }
1938 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
1939 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
1940 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
1941
1942 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
1943 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
1944
1945 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
1946 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
1947
1948 if (auSerialIoPortBase[2])
1949 {
1950 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
1951 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
1952 }
1953
1954 if (auSerialIoPortBase[3])
1955 {
1956 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
1957 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
1958 }
1959
1960 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
1961 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
1962
1963 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
1964 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
1965
1966#if defined(VBOX_WITH_TPM)
1967 switch (enmTpmType)
1968 {
1969 case TpmType_v1_2:
1970 InsertConfigString(pCfg, "TpmMode", "tis1.2");
1971 break;
1972 case TpmType_v2_0:
1973 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
1974 break;
1975 /** @todo Host and swtpm. */
1976 default:
1977 break;
1978 }
1979#endif
1980
1981 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1982 InsertConfigString(pLunL0, "Driver", "ACPIHost");
1983 InsertConfigNode(pLunL0, "Config", &pCfg);
1984
1985 /* Attach the dummy CPU drivers */
1986 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
1987 {
1988 BOOL fCpuAttached = true;
1989
1990 if (fCpuHotPlug)
1991 {
1992 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
1993 }
1994
1995 if (fCpuAttached)
1996 {
1997 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
1998 InsertConfigString(pLunL0, "Driver", "ACPICpu");
1999 InsertConfigNode(pLunL0, "Config", &pCfg);
2000 }
2001 }
2002 }
2003
2004 /*
2005 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
2006 */
2007 vrc = i_configGuestDbg(virtualBox, pMachine, pRoot); VRC();
2008 }
2009 catch (ConfigError &x)
2010 {
2011 // InsertConfig threw something:
2012 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
2013 return x.m_vrc;
2014 }
2015 catch (HRESULT hrcXcpt)
2016 {
2017 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2018 }
2019
2020#ifdef VBOX_WITH_EXTPACK
2021 /*
2022 * Call the extension pack hooks if everything went well thus far.
2023 */
2024 if (RT_SUCCESS(vrc))
2025 {
2026 pAlock->release();
2027 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);
2028 pAlock->acquire();
2029 }
2030#endif
2031
2032 /*
2033 * Apply the CFGM overlay.
2034 */
2035 if (RT_SUCCESS(vrc))
2036 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
2037
2038 /*
2039 * Dump all extradata API settings tweaks, both global and per VM.
2040 */
2041 if (RT_SUCCESS(vrc))
2042 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
2043
2044#undef H
2045
2046 pAlock->release(); /* Avoid triggering the lock order inversion check. */
2047
2048 /*
2049 * Register VM state change handler.
2050 */
2051 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
2052 AssertRC(vrc2);
2053 if (RT_SUCCESS(vrc))
2054 vrc = vrc2;
2055
2056 /*
2057 * Register VM runtime error handler.
2058 */
2059 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
2060 AssertRC(vrc2);
2061 if (RT_SUCCESS(vrc))
2062 vrc = vrc2;
2063
2064 pAlock->acquire();
2065
2066 LogFlowFunc(("vrc = %Rrc\n", vrc));
2067 LogFlowFuncLeave();
2068
2069 return vrc;
2070}
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