VirtualBox

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

Last change on this file since 105010 was 104844, checked in by vboxsync, 6 months ago

DevVGA,DevPCI,Main: Increased the max VRAM size to 1GB. Experimental. [fix] bugref:10687

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