VirtualBox

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

Last change on this file since 107834 was 107804, checked in by vboxsync, 4 months ago

Main/src-client/ConsoleImplConfigX86.cpp: Disable unused variable, bugref:3409

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

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