VirtualBox

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

Last change on this file since 101462 was 101462, checked in by vboxsync, 20 months ago

Main/ConsoleImpl: Move the PDM configuration out of the x86 config constructor into a separate method and make use of it from the Armv8 constructor, bugref:10528

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 130.8 KB
Line 
1/* $Id: ConsoleImplConfigX86.cpp 101462 2023-10-17 08:38:52Z 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-2023 Oracle and/or its affiliates.
13 *
14 * This file is part of VirtualBox base platform packages, as
15 * available from https://www.215389.xyz.
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// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
41// header file includes Windows.h.
42#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
43# include <VBox/VBoxNetCfg-win.h>
44#endif
45
46#include "ConsoleImpl.h"
47#include "DisplayImpl.h"
48#include "NvramStoreImpl.h"
49#include "PlatformImpl.h"
50#include "VMMDev.h"
51#include "Global.h"
52#ifdef VBOX_WITH_PCI_PASSTHROUGH
53# include "PCIRawDevImpl.h"
54#endif
55
56// generated header
57#include "SchemaDefs.h"
58
59#include "AutoCaller.h"
60
61#include <iprt/base64.h>
62#include <iprt/buildconfig.h>
63#include <iprt/ctype.h>
64#include <iprt/dir.h>
65#include <iprt/file.h>
66#include <iprt/param.h>
67#include <iprt/path.h>
68#include <iprt/string.h>
69#include <iprt/system.h>
70#if 0 /* enable to play with lots of memory. */
71# include <iprt/env.h>
72#endif
73#include <iprt/stream.h>
74
75#include <iprt/http.h>
76#include <iprt/socket.h>
77#include <iprt/uri.h>
78
79#include <VBox/vmm/vmmr3vtable.h>
80#include <VBox/vmm/vmapi.h>
81#include <VBox/err.h>
82#include <VBox/param.h>
83#include <VBox/settings.h> /* For MachineConfigFile::getHostDefaultAudioDriver(). */
84#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
85#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
86#include <VBox/vmm/pdmdev.h> /* For PDMAPICMODE enum. */
87#include <VBox/vmm/pdmstorageifs.h>
88#include <VBox/vmm/gcm.h>
89#include <VBox/version.h>
90#ifdef VBOX_WITH_GUEST_PROPS
91# include <VBox/HostServices/GuestPropertySvc.h>
92# include <VBox/com/defs.h>
93# include <VBox/com/array.h>
94# include <vector>
95#endif /* VBOX_WITH_GUEST_PROPS */
96#include <VBox/intnet.h>
97
98#include <VBox/com/com.h>
99#include <VBox/com/string.h>
100#include <VBox/com/array.h>
101
102#ifdef VBOX_WITH_NETFLT
103# if defined(RT_OS_SOLARIS)
104# include <zone.h>
105# elif defined(RT_OS_LINUX)
106# include <unistd.h>
107# include <sys/ioctl.h>
108# include <sys/socket.h>
109# include <linux/types.h>
110# include <linux/if.h>
111# elif defined(RT_OS_FREEBSD)
112# include <unistd.h>
113# include <sys/types.h>
114# include <sys/ioctl.h>
115# include <sys/socket.h>
116# include <net/if.h>
117# include <net80211/ieee80211_ioctl.h>
118# endif
119# if defined(RT_OS_WINDOWS)
120# include <iprt/win/ntddndis.h>
121# include <devguid.h>
122# else
123# include <HostNetworkInterfaceImpl.h>
124# include <netif.h>
125# include <stdlib.h>
126# endif
127#endif /* VBOX_WITH_NETFLT */
128
129#ifdef VBOX_WITH_AUDIO_VRDE
130# include "DrvAudioVRDE.h"
131#endif
132#ifdef VBOX_WITH_AUDIO_RECORDING
133# include "DrvAudioRec.h"
134#endif
135#include "NetworkServiceRunner.h"
136#include "BusAssignmentManager.h"
137#ifdef VBOX_WITH_EXTPACK
138# include "ExtPackManagerImpl.h"
139#endif
140
141
142/*********************************************************************************************************************************
143* Internal Functions *
144*********************************************************************************************************************************/
145
146/* Darwin compile kludge */
147#undef PVM
148
149/* Comment out the following line to remove VMWare compatibility hack. */
150#define VMWARE_NET_IN_SLOT_11
151
152/**
153 * Translate IDE StorageControllerType_T to string representation.
154 */
155static const char* controllerString(StorageControllerType_T enmType)
156{
157 switch (enmType)
158 {
159 case StorageControllerType_PIIX3:
160 return "PIIX3";
161 case StorageControllerType_PIIX4:
162 return "PIIX4";
163 case StorageControllerType_ICH6:
164 return "ICH6";
165 default:
166 return "Unknown";
167 }
168}
169
170/**
171 * Simple class for storing network boot information.
172 */
173struct BootNic
174{
175 ULONG mInstance;
176 PCIBusAddress mPCIAddress;
177
178 ULONG mBootPrio;
179 bool operator < (const BootNic &rhs) const
180 {
181 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
182 ULONG rval = rhs.mBootPrio - 1;
183 return lval < rval; /* Zero compares as highest number (lowest prio). */
184 }
185};
186
187/**
188 * @throws HRESULT on extra data retrival error.
189 */
190static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
191{
192 *pfGetKeyFromRealSMC = false;
193
194 /*
195 * The extra data takes precedence (if non-zero).
196 */
197 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
198 if (pStrKey->isNotEmpty())
199 return VINF_SUCCESS;
200
201#ifdef RT_OS_DARWIN
202
203 /*
204 * Work done in EFI/DevSmc
205 */
206 *pfGetKeyFromRealSMC = true;
207 int vrc = VINF_SUCCESS;
208
209#else
210 /*
211 * Is it apple hardware in bootcamp?
212 */
213 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
214 * Currently falling back on the product name. */
215 char szManufacturer[256];
216 szManufacturer[0] = '\0';
217 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
218 if (szManufacturer[0] != '\0')
219 {
220 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
221 || !strcmp(szManufacturer, "Apple Inc.")
222 )
223 *pfGetKeyFromRealSMC = true;
224 }
225 else
226 {
227 char szProdName[256];
228 szProdName[0] = '\0';
229 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
230 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
231 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
232 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
233 )
234 && !strchr(szProdName, ' ') /* no spaces */
235 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
236 )
237 *pfGetKeyFromRealSMC = true;
238 }
239
240 int vrc = VINF_SUCCESS;
241#endif
242
243 return vrc;
244}
245
246
247/*
248 * VC++ 8 / amd64 has some serious trouble with the next functions.
249 * As a temporary measure, we'll drop global optimizations.
250 */
251#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
252# if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100
253# pragma optimize("g", off)
254# endif
255#endif
256
257/** Helper that finds out the next HBA port used
258 */
259static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
260{
261 LONG lNextPortUsed = 30;
262 for (size_t j = 0; j < u32Size; ++j)
263 {
264 if ( aPortUsed[j] > lBaseVal
265 && aPortUsed[j] <= lNextPortUsed)
266 lNextPortUsed = aPortUsed[j];
267 }
268 return lNextPortUsed;
269}
270
271#define MAX_BIOS_LUN_COUNT 4
272
273int Console::SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
274 Bstr controllerName, const char * const s_apszBiosConfig[4])
275{
276 RT_NOREF(pCfg);
277 HRESULT hrc;
278#define MAX_DEVICES 30
279#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
280#define VRC() AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
281
282 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
283 LONG lPortUsed[MAX_DEVICES];
284 uint32_t u32HDCount = 0;
285
286 /* init to max value */
287 lPortLUN[0] = MAX_DEVICES;
288
289 com::SafeIfaceArray<IMediumAttachment> atts;
290 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
291 ComSafeArrayAsOutParam(atts)); H();
292 size_t uNumAttachments = atts.size();
293 if (uNumAttachments > MAX_DEVICES)
294 {
295 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
296 uNumAttachments = MAX_DEVICES;
297 }
298
299 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
300 for (size_t j = 0; j < uNumAttachments; ++j)
301 {
302 IMediumAttachment *pMediumAtt = atts[j];
303 LONG lPortNum = 0;
304 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
305 if (SUCCEEDED(hrc))
306 {
307 DeviceType_T lType;
308 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
309 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
310 {
311 /* find min port number used for HD */
312 if (lPortNum < lPortLUN[0])
313 lPortLUN[0] = lPortNum;
314 lPortUsed[u32HDCount++] = lPortNum;
315 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
316 }
317 }
318 }
319
320
321 /* Pick only the top 4 used HD Ports as CMOS doesn't have space
322 * to save details for all 30 ports
323 */
324 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
325 if (u32HDCount < MAX_BIOS_LUN_COUNT)
326 u32MaxPortCount = u32HDCount;
327 for (size_t j = 1; j < u32MaxPortCount; j++)
328 lPortLUN[j] = GetNextUsedPort(lPortUsed, lPortLUN[j-1], u32HDCount);
329 if (pBiosCfg)
330 {
331 for (size_t j = 0; j < u32MaxPortCount; j++)
332 {
333 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
334 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
335 }
336 }
337 return VINF_SUCCESS;
338}
339
340#ifdef VBOX_WITH_PCI_PASSTHROUGH
341HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
342{
343# ifndef VBOX_WITH_EXTPACK
344 RT_NOREF(pUVM);
345# endif
346 HRESULT hrc = S_OK;
347 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
348
349 SafeIfaceArray<IPCIDeviceAttachment> assignments;
350 ComPtr<IMachine> aMachine = i_machine();
351
352 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
353 if ( hrc != S_OK
354 || assignments.size() < 1)
355 return hrc;
356
357 /*
358 * PCI passthrough is only available if the proper ExtPack is installed.
359 *
360 * Note. Configuring PCI passthrough here and providing messages about
361 * the missing extpack isn't exactly clean, but it is a necessary evil
362 * to patch over legacy compatability issues introduced by the new
363 * distribution model.
364 */
365# ifdef VBOX_WITH_EXTPACK
366 static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";
367 if (!mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName))
368 /* Always fatal! */
369 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
370 N_("Implementation of the PCI passthrough framework not found!\n"
371 "The VM cannot be started. To fix this problem, either "
372 "install the '%s' or disable PCI passthrough via VBoxManage"),
373 s_pszPCIRawExtPackName);
374# endif
375
376 /* Now actually add devices */
377 PCFGMNODE pPCIDevs = NULL;
378
379 if (assignments.size() > 0)
380 {
381 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);
382
383 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
384
385 /* Tell PGM to tell GPCIRaw about guest mappings. */
386 CFGMR3InsertNode(pRoot, "PGM", NULL);
387 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
388
389 /*
390 * Currently, using IOMMU needed for PCI passthrough
391 * requires RAM preallocation.
392 */
393 /** @todo check if we can lift this requirement */
394 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
395 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
396 }
397
398 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
399 {
400 ComPtr<IPCIDeviceAttachment> const assignment = assignments[iDev];
401
402 LONG host;
403 hrc = assignment->COMGETTER(HostAddress)(&host); H();
404 LONG guest;
405 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
406 Bstr bstrDevName;
407 hrc = assignment->COMGETTER(Name)(bstrDevName.asOutParam()); H();
408
409 InsertConfigNodeF(pPCIDevs, &pInst, "%d", iDev);
410 InsertConfigInteger(pInst, "Trusted", 1);
411
412 PCIBusAddress HostPCIAddress(host);
413 Assert(HostPCIAddress.valid());
414 InsertConfigNode(pInst, "Config", &pCfg);
415 InsertConfigString(pCfg, "DeviceName", bstrDevName);
416
417 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
418 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);
419 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);
420 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);
421
422 PCIBusAddress GuestPCIAddress(guest);
423 Assert(GuestPCIAddress.valid());
424 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
425 if (hrc != S_OK)
426 return hrc;
427
428 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);
429 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);
430 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);
431
432 /* the driver */
433 InsertConfigNode(pInst, "LUN#0", &pLunL0);
434 InsertConfigString(pLunL0, "Driver", "pciraw");
435 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
436
437 /* the Main driver */
438 InsertConfigString(pLunL1, "Driver", "MainPciRaw");
439 InsertConfigNode(pLunL1, "Config", &pCfg);
440 PCIRawDev *pMainDev = new PCIRawDev(this);
441# error This is not allowed any more
442 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
443 }
444
445 return hrc;
446}
447#endif
448
449
450/**
451 * Worker for configConstructor.
452 *
453 * @return VBox status code.
454 * @param pUVM The user mode VM handle.
455 * @param pVM The cross context VM handle.
456 * @param pVMM The VMM vtable.
457 * @param pAlock The automatic lock instance. This is for when we have
458 * to leave it in order to avoid deadlocks (ext packs and
459 * more).
460 */
461int Console::i_configConstructorX86(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
462{
463 RT_NOREF(pVM /* when everything is disabled */);
464 ComPtr<IMachine> pMachine = i_machine();
465
466 int vrc;
467 HRESULT hrc;
468 Utf8Str strTmp;
469 Bstr bstr;
470
471#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
472
473 /*
474 * Get necessary objects and frequently used parameters.
475 */
476 ComPtr<IVirtualBox> virtualBox;
477 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
478
479 ComPtr<IHost> host;
480 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
481
482 ComPtr<ISystemProperties> systemProperties;
483 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
484
485 PlatformArchitecture_T platformArchHost;
486 hrc = host->COMGETTER(Architecture)(&platformArchHost); H();
487
488 ComPtr<IFirmwareSettings> firmwareSettings;
489 hrc = pMachine->COMGETTER(FirmwareSettings)(firmwareSettings.asOutParam()); H();
490
491 ComPtr<INvramStore> nvramStore;
492 hrc = pMachine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam()); H();
493
494 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
495 RTUUID HardwareUuid;
496 vrc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
497 AssertRCReturn(vrc, vrc);
498
499 ULONG cRamMBs;
500 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
501#if 0 /* enable to play with lots of memory. */
502 if (RTEnvExist("VBOX_RAM_SIZE"))
503 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
504#endif
505 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
506 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
507 uint64_t uMcfgBase = 0;
508 uint32_t cbMcfgLength = 0;
509
510 ParavirtProvider_T enmParavirtProvider;
511 hrc = pMachine->GetEffectiveParavirtProvider(&enmParavirtProvider); H();
512
513 Bstr strParavirtDebug;
514 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
515
516 BOOL fIOAPIC;
517 uint32_t uIoApicPciAddress = NIL_PCIBDF;
518 hrc = firmwareSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
519
520 ComPtr<IPlatform> platform;
521 pMachine->COMGETTER(Platform)(platform.asOutParam()); H();
522
523#if 1 /* For now we only support running same-same architectures (e.g. x86 VMs on x86 hosts). */
524 PlatformArchitecture_T platformArchMachine;
525 hrc = platform->COMGETTER(Architecture)(&platformArchMachine); H();
526 if (platformArchMachine != platformArchHost)
527 return pVMM->pfnVMR3SetError(pUVM, VERR_PLATFORM_ARCH_NOT_SUPPORTED, RT_SRC_POS,
528 N_("VM platform architecture (%s) not supported on this host (%s)."),
529 Global::stringifyPlatformArchitecture(platformArchMachine),
530 Global::stringifyPlatformArchitecture(platformArchHost));
531#endif
532
533 ChipsetType_T chipsetType;
534 hrc = platform->COMGETTER(ChipsetType)(&chipsetType); H();
535 if (chipsetType == ChipsetType_ICH9)
536 {
537 /* We'd better have 0x10000000 region, to cover 256 buses but this put
538 * too much load on hypervisor heap. Linux 4.8 currently complains with
539 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]
540 * only partially covers this bridge'' */
541 cbMcfgLength = 0x4000000; //0x10000000;
542 cbRamHole += cbMcfgLength;
543 uMcfgBase = _4G - cbRamHole;
544 }
545
546 /* Get the CPU profile name. */
547 Bstr bstrCpuProfile;
548 hrc = pMachine->COMGETTER(CPUProfile)(bstrCpuProfile.asOutParam()); H();
549
550 /* Get the X86 platform object. */
551 ComPtr<IPlatformX86> platformX86;
552 hrc = platform->COMGETTER(X86)(platformX86.asOutParam()); H();
553
554 /* Check if long mode is enabled. */
555 BOOL fIsGuest64Bit;
556 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_LongMode, &fIsGuest64Bit); H();
557
558 /*
559 * Figure out the IOMMU config.
560 */
561#if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL)
562 IommuType_T enmIommuType;
563 hrc = platform->COMGETTER(IommuType)(&enmIommuType); H();
564
565 /* Resolve 'automatic' type to an Intel or AMD IOMMU based on the host CPU. */
566 if (enmIommuType == IommuType_Automatic)
567 {
568 if ( bstrCpuProfile.startsWith("AMD")
569 || bstrCpuProfile.startsWith("Quad-Core AMD")
570 || bstrCpuProfile.startsWith("Hygon"))
571 enmIommuType = IommuType_AMD;
572 else if (bstrCpuProfile.startsWith("Intel"))
573 {
574 if ( bstrCpuProfile.equals("Intel 8086")
575 || bstrCpuProfile.equals("Intel 80186")
576 || bstrCpuProfile.equals("Intel 80286")
577 || bstrCpuProfile.equals("Intel 80386")
578 || bstrCpuProfile.equals("Intel 80486"))
579 enmIommuType = IommuType_None;
580 else
581 enmIommuType = IommuType_Intel;
582 }
583# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
584 else if (ASMIsAmdCpu())
585 enmIommuType = IommuType_AMD;
586 else if (ASMIsIntelCpu())
587 enmIommuType = IommuType_Intel;
588# endif
589 else
590 {
591 /** @todo Should we handle other CPUs like Shanghai, VIA etc. here? */
592 LogRel(("WARNING! Unrecognized CPU type, IOMMU disabled.\n"));
593 enmIommuType = IommuType_None;
594 }
595 }
596
597 if (enmIommuType == IommuType_AMD)
598 {
599# ifdef VBOX_WITH_IOMMU_AMD
600 /*
601 * Reserve the specific PCI address of the "SB I/O APIC" when using
602 * an AMD IOMMU. Required by Linux guests, see @bugref{9654#c23}.
603 */
604 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
605# else
606 LogRel(("WARNING! AMD IOMMU not supported, IOMMU disabled.\n"));
607 enmIommuType = IommuType_None;
608# endif
609 }
610
611 if (enmIommuType == IommuType_Intel)
612 {
613# ifdef VBOX_WITH_IOMMU_INTEL
614 /*
615 * Reserve a unique PCI address for the I/O APIC when using
616 * an Intel IOMMU. For convenience we use the same address as
617 * we do on AMD, see @bugref{9967#c13}.
618 */
619 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
620# else
621 LogRel(("WARNING! Intel IOMMU not supported, IOMMU disabled.\n"));
622 enmIommuType = IommuType_None;
623# endif
624 }
625
626 if ( enmIommuType == IommuType_AMD
627 || enmIommuType == IommuType_Intel)
628 {
629 if (chipsetType != ChipsetType_ICH9)
630 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
631 N_("IOMMU uses MSIs which requires the ICH9 chipset implementation."));
632 if (!fIOAPIC)
633 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
634 N_("IOMMU requires an I/O APIC for remapping interrupts."));
635 }
636#else
637 IommuType_T const enmIommuType = IommuType_None;
638#endif
639
640 /* Instantiate the bus assignment manager. */
641 Assert(enmIommuType != IommuType_Automatic);
642 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, enmIommuType);
643
644 ULONG cCpus = 1;
645 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
646
647 ULONG ulCpuExecutionCap = 100;
648 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
649
650 LogRel(("Guest architecture: x86\n"));
651
652 Bstr osTypeId;
653 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
654 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
655
656 APICMode_T apicMode;
657 hrc = firmwareSettings->COMGETTER(APICMode)(&apicMode); H();
658 uint32_t uFwAPIC;
659 switch (apicMode)
660 {
661 case APICMode_Disabled:
662 uFwAPIC = 0;
663 break;
664 case APICMode_APIC:
665 uFwAPIC = 1;
666 break;
667 case APICMode_X2APIC:
668 uFwAPIC = 2;
669 break;
670 default:
671 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
672 uFwAPIC = 1;
673 break;
674 }
675
676 ComPtr<IGuestOSType> pGuestOSType;
677 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());
678
679 BOOL fOsXGuest = FALSE;
680 BOOL fWinGuest = FALSE;
681 BOOL fOs2Guest = FALSE;
682 BOOL fW9xGuest = FALSE;
683 BOOL fDosGuest = FALSE;
684 if (pGuestOSType.isNotNull())
685 {
686 Bstr guestTypeFamilyId;
687 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
688 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
689 fWinGuest = guestTypeFamilyId == Bstr("Windows");
690 fOs2Guest = osTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("OS2"));
691 fW9xGuest = osTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows9")); /* Does not include Windows Me. */
692 fDosGuest = osTypeId.equals(GUEST_OS_ID_STR_X86("DOS")) || osTypeId.equals(GUEST_OS_ID_STR_X86("Windows31"));
693 }
694
695 ComPtr<IPlatformProperties> platformProperties;
696 virtualBox->GetPlatformProperties(PlatformArchitecture_x86, platformProperties.asOutParam());
697
698 ULONG maxNetworkAdapters;
699 hrc = platformProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
700
701 /*
702 * Get root node first.
703 * This is the only node in the tree.
704 */
705 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRootU(pUVM);
706 Assert(pRoot);
707
708 // catching throws from InsertConfigString and friends.
709 try
710 {
711
712 /*
713 * Set the root (and VMM) level values.
714 */
715 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
716 InsertConfigString(pRoot, "Name", bstr);
717 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
718 InsertConfigInteger(pRoot, "RamSize", cbRam);
719 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
720 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
721 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
722 InsertConfigInteger(pRoot, "TimerMillies", 10);
723
724 BOOL fPageFusion = FALSE;
725 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
726 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
727
728 /* Not necessary, but makes sure this setting ends up in the release log. */
729 ULONG ulBalloonSize = 0;
730 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
731 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
732
733 /*
734 * EM values (before CPUM as it may need to set IemExecutesAll).
735 */
736 PCFGMNODE pEM;
737 InsertConfigNode(pRoot, "EM", &pEM);
738
739 /* Triple fault behavior. */
740 BOOL fTripleFaultReset = false;
741 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_TripleFaultReset, &fTripleFaultReset); H();
742 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
743
744 /*
745 * CPUM values.
746 */
747 PCFGMNODE pCPUM;
748 InsertConfigNode(pRoot, "CPUM", &pCPUM);
749 PCFGMNODE pIsaExts;
750 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);
751
752 /* Host CPUID leaf overrides. */
753 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)
754 {
755 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;
756 hrc = platformX86->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);
757 if (hrc == E_INVALIDARG)
758 break;
759 H();
760 PCFGMNODE pLeaf;
761 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
762 /** @todo Figure out how to tell the VMM about uSubLeaf */
763 InsertConfigInteger(pLeaf, "eax", uEax);
764 InsertConfigInteger(pLeaf, "ebx", uEbx);
765 InsertConfigInteger(pLeaf, "ecx", uEcx);
766 InsertConfigInteger(pLeaf, "edx", uEdx);
767 }
768
769 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
770 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
771 if (osTypeId == GUEST_OS_ID_STR_X86("WindowsNT4"))
772 {
773 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
774 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
775 }
776
777 if (fOsXGuest)
778 {
779 /* Expose extended MWAIT features to Mac OS X guests. */
780 LogRel(("Using MWAIT extensions\n"));
781 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);
782
783 /* Fake the CPU family/model so the guest works. This is partly
784 because older mac releases really doesn't work on newer cpus,
785 and partly because mac os x expects more from systems with newer
786 cpus (MSRs, power features, whatever). */
787 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
788 if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS")
789 || osTypeId == GUEST_OS_ID_STR_X64("MacOS"))
790 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
791 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS106")
792 || osTypeId == GUEST_OS_ID_STR_X64("MacOS106"))
793 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
794 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS107")
795 || osTypeId == GUEST_OS_ID_STR_X64("MacOS107"))
796 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
797 what is required here. */
798 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS108")
799 || osTypeId == GUEST_OS_ID_STR_X64("MacOS108"))
800 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
801 what is required here. */
802 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS109")
803 || osTypeId == GUEST_OS_ID_STR_X64("MacOS109"))
804 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
805 out what is required here. */
806 if (uMaxIntelFamilyModelStep != UINT32_MAX)
807 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
808 }
809
810 /* CPU Portability level, */
811 ULONG uCpuIdPortabilityLevel = 0;
812 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
813 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
814
815 /* Physical Address Extension (PAE) */
816 BOOL fEnablePAE = false;
817 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_PAE, &fEnablePAE); H();
818 fEnablePAE |= fIsGuest64Bit;
819 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
820
821 /* 64-bit guests (long mode) */
822 InsertConfigInteger(pCPUM, "Enable64bit", fIsGuest64Bit);
823
824 /* APIC/X2APIC configuration */
825 BOOL fEnableAPIC = true;
826 BOOL fEnableX2APIC = true;
827 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_APIC, &fEnableAPIC); H();
828 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_X2APIC, &fEnableX2APIC); H();
829 if (fEnableX2APIC)
830 Assert(fEnableAPIC);
831
832 /* CPUM profile name. */
833 InsertConfigString(pCPUM, "GuestCpuName", bstrCpuProfile);
834
835 /*
836 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
837 * correctly. There are way too many #UDs we'll miss using VT-x,
838 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
839 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
840 */
841 if ( bstrCpuProfile.equals("Intel 80386") /* just for now */
842 || bstrCpuProfile.equals("Intel 80286")
843 || bstrCpuProfile.equals("Intel 80186")
844 || bstrCpuProfile.equals("Nec V20")
845 || bstrCpuProfile.equals("Intel 8086") )
846 {
847 InsertConfigInteger(pEM, "IemExecutesAll", true);
848 if (!bstrCpuProfile.equals("Intel 80386"))
849 {
850 fEnableAPIC = false;
851 fIOAPIC = false;
852 }
853 fEnableX2APIC = false;
854 }
855
856 /* Adjust firmware APIC handling to stay within the VCPU limits. */
857 if (uFwAPIC == 2 && !fEnableX2APIC)
858 {
859 if (fEnableAPIC)
860 uFwAPIC = 1;
861 else
862 uFwAPIC = 0;
863 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
864 }
865 else if (uFwAPIC == 1 && !fEnableAPIC)
866 {
867 uFwAPIC = 0;
868 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
869 }
870
871 /* Speculation Control. */
872 BOOL fSpecCtrl = FALSE;
873 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_SpecCtrl, &fSpecCtrl); H();
874 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
875
876 /* Nested VT-x / AMD-V. */
877 BOOL fNestedHWVirt = FALSE;
878 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_HWVirt, &fNestedHWVirt); H();
879 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);
880
881 /*
882 * Hardware virtualization extensions.
883 */
884 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
885 if (!fEnableAPIC)
886 {
887 if (fIsGuest64Bit)
888 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
889 N_("Cannot disable the APIC for a 64-bit guest."));
890 if (cCpus > 1)
891 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
892 N_("Cannot disable the APIC for an SMP guest."));
893 if (fIOAPIC)
894 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
895 N_("Cannot disable the APIC when the I/O APIC is present."));
896 }
897
898 BOOL fHMEnabled;
899 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
900 if (cCpus > 1 && !fHMEnabled)
901 {
902 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
903 fHMEnabled = TRUE;
904 }
905
906 BOOL fHMForced;
907 fHMEnabled = fHMForced = TRUE;
908 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
909 if (!fHMForced) /* No need to query if already forced above. */
910 {
911 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
912 if (fHMForced)
913 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
914 }
915 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
916
917 /* /HM/xyz */
918 PCFGMNODE pHM;
919 InsertConfigNode(pRoot, "HM", &pHM);
920 InsertConfigInteger(pHM, "HMForced", fHMForced);
921 if (fHMEnabled)
922 {
923 /* Indicate whether 64-bit guests are supported or not. */
924 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
925
926 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
927 but that requires quite a bit of API change in Main. */
928 if ( fIOAPIC
929 && ( osTypeId == GUEST_OS_ID_STR_X86("WindowsNT4")
930 || osTypeId == GUEST_OS_ID_STR_X86("Windows2000")
931 || osTypeId == GUEST_OS_ID_STR_X86("WindowsXP")
932 || osTypeId == GUEST_OS_ID_STR_X86("Windows2003")))
933 {
934 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
935 * We may want to consider adding more guest OSes (Solaris) later on.
936 */
937 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
938 }
939 }
940
941 /* HWVirtEx exclusive mode */
942 BOOL fHMExclusive = true;
943 hrc = platformProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
944 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
945
946 /* Nested paging (VT-x/AMD-V) */
947 BOOL fEnableNestedPaging = false;
948 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
949 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
950
951 /* Large pages; requires nested paging */
952 BOOL fEnableLargePages = false;
953 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
954 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
955
956 /* VPID (VT-x) */
957 BOOL fEnableVPID = false;
958 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
959 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
960
961 /* Unrestricted execution aka UX (VT-x) */
962 BOOL fEnableUX = false;
963 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
964 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
965
966 /* Virtualized VMSAVE/VMLOAD (AMD-V) */
967 BOOL fVirtVmsaveVmload = true;
968 hrc = host->GetProcessorFeature(ProcessorFeature_VirtVmsaveVmload, &fVirtVmsaveVmload); H();
969 InsertConfigInteger(pHM, "SvmVirtVmsaveVmload", fVirtVmsaveVmload);
970
971 /* Indirect branch prediction boundraries. */
972 BOOL fIBPBOnVMExit = false;
973 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_IBPBOnVMExit, &fIBPBOnVMExit); H();
974 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);
975
976 BOOL fIBPBOnVMEntry = false;
977 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
978 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
979
980 BOOL fSpecCtrlByHost = false;
981 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_SpecCtrlByHost, &fSpecCtrlByHost); H();
982 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
983
984 BOOL fL1DFlushOnSched = true;
985 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_L1DFlushOnEMTScheduling, &fL1DFlushOnSched); H();
986 InsertConfigInteger(pHM, "L1DFlushOnSched", fL1DFlushOnSched);
987
988 BOOL fL1DFlushOnVMEntry = false;
989 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_L1DFlushOnVMEntry, &fL1DFlushOnVMEntry); H();
990 InsertConfigInteger(pHM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);
991
992 BOOL fMDSClearOnSched = true;
993 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_MDSClearOnEMTScheduling, &fMDSClearOnSched); H();
994 InsertConfigInteger(pHM, "MDSClearOnSched", fMDSClearOnSched);
995
996 BOOL fMDSClearOnVMEntry = false;
997 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_MDSClearOnVMEntry, &fMDSClearOnVMEntry); H();
998 InsertConfigInteger(pHM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);
999
1000 /* Reset overwrite. */
1001 mfTurnResetIntoPowerOff = GetExtraDataBoth(virtualBox, pMachine,
1002 "VBoxInternal2/TurnResetIntoPowerOff", &strTmp)->equals("1");
1003 if (mfTurnResetIntoPowerOff)
1004 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
1005
1006 /* Use NEM rather than HM. */
1007 BOOL fUseNativeApi = false;
1008 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();
1009 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);
1010
1011 /* Enable workaround for missing TLB flush for OS/2 guests, see ticketref:20625. */
1012 if (fOs2Guest)
1013 InsertConfigInteger(pHM, "MissingOS2TlbFlushWorkaround", 1);
1014
1015 /*
1016 * NEM
1017 */
1018 PCFGMNODE pNEM;
1019 InsertConfigNode(pRoot, "NEM", &pNEM);
1020 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);
1021
1022 /*
1023 * Paravirt. provider.
1024 */
1025 PCFGMNODE pParavirtNode;
1026 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1027 const char *pcszParavirtProvider;
1028 bool fGimDeviceNeeded = true;
1029 switch (enmParavirtProvider)
1030 {
1031 case ParavirtProvider_None:
1032 pcszParavirtProvider = "None";
1033 fGimDeviceNeeded = false;
1034 break;
1035
1036 case ParavirtProvider_Minimal:
1037 pcszParavirtProvider = "Minimal";
1038 break;
1039
1040 case ParavirtProvider_HyperV:
1041 pcszParavirtProvider = "HyperV";
1042 break;
1043
1044 case ParavirtProvider_KVM:
1045 pcszParavirtProvider = "KVM";
1046 break;
1047
1048 default:
1049 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));
1050 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1051 enmParavirtProvider);
1052 }
1053 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1054
1055 /*
1056 * Parse paravirt. debug options.
1057 */
1058 bool fGimDebug = false;
1059 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1060 uint32_t uGimDebugPort = 50000;
1061 if (strParavirtDebug.isNotEmpty())
1062 {
1063 /* Hyper-V debug options. */
1064 if (enmParavirtProvider == ParavirtProvider_HyperV)
1065 {
1066 bool fGimHvDebug = false;
1067 com::Utf8Str strGimHvVendor;
1068 bool fGimHvVsIf = false;
1069 bool fGimHvHypercallIf = false;
1070
1071 size_t uPos = 0;
1072 com::Utf8Str strDebugOptions = strParavirtDebug;
1073 com::Utf8Str strKey;
1074 com::Utf8Str strVal;
1075 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1076 {
1077 if (strKey == "enabled")
1078 {
1079 if (strVal.toUInt32() == 1)
1080 {
1081 /* Apply defaults.
1082 The defaults are documented in the user manual,
1083 changes need to be reflected accordingly. */
1084 fGimHvDebug = true;
1085 strGimHvVendor = "Microsoft Hv";
1086 fGimHvVsIf = true;
1087 fGimHvHypercallIf = false;
1088 }
1089 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1090 }
1091 else if (strKey == "address")
1092 strGimDebugAddress = strVal;
1093 else if (strKey == "port")
1094 uGimDebugPort = strVal.toUInt32();
1095 else if (strKey == "vendor")
1096 strGimHvVendor = strVal;
1097 else if (strKey == "vsinterface")
1098 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1099 else if (strKey == "hypercallinterface")
1100 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1101 else
1102 {
1103 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1104 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1105 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1106 strDebugOptions.c_str());
1107 }
1108 }
1109
1110 /* Update HyperV CFGM node with active debug options. */
1111 if (fGimHvDebug)
1112 {
1113 PCFGMNODE pHvNode;
1114 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1115 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1116 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1117 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1118 fGimDebug = true;
1119 }
1120 }
1121 }
1122
1123 /*
1124 * Guest Compatibility Manager.
1125 */
1126 PCFGMNODE pGcmNode;
1127 uint32_t u32FixerSet = 0;
1128 InsertConfigNode(pRoot, "GCM", &pGcmNode);
1129 /* OS/2 and Win9x guests can run DOS apps so they get
1130 * the DOS specific fixes as well.
1131 */
1132 if (fOs2Guest)
1133 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2;
1134 else if (fW9xGuest)
1135 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_WIN9X;
1136 else if (fDosGuest)
1137 u32FixerSet = GCMFIXER_DBZ_DOS;
1138 InsertConfigInteger(pGcmNode, "FixerSet", u32FixerSet);
1139
1140
1141 /*
1142 * MM values.
1143 */
1144 PCFGMNODE pMM;
1145 InsertConfigNode(pRoot, "MM", &pMM);
1146 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1147
1148 /*
1149 * PDM config.
1150 * Load drivers in VBoxC.[so|dll]
1151 */
1152 vrc = i_configPdm(pMachine, pVMM, pUVM, pRoot); VRC();
1153
1154 /*
1155 * Devices
1156 */
1157 PCFGMNODE pDevices = NULL; /* /Devices */
1158 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1159 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1160 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1161 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1162 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1163 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1164 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1165
1166 InsertConfigNode(pRoot, "Devices", &pDevices);
1167
1168 /*
1169 * GIM Device
1170 */
1171 if (fGimDeviceNeeded)
1172 {
1173 InsertConfigNode(pDevices, "GIMDev", &pDev);
1174 InsertConfigNode(pDev, "0", &pInst);
1175 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1176 //InsertConfigNode(pInst, "Config", &pCfg);
1177
1178 if (fGimDebug)
1179 {
1180 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1181 InsertConfigString(pLunL0, "Driver", "UDP");
1182 InsertConfigNode(pLunL0, "Config", &pLunL1);
1183 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1184 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1185 }
1186 }
1187
1188 /*
1189 * PC Arch.
1190 */
1191 InsertConfigNode(pDevices, "pcarch", &pDev);
1192 InsertConfigNode(pDev, "0", &pInst);
1193 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1194 InsertConfigNode(pInst, "Config", &pCfg);
1195
1196 /*
1197 * The time offset
1198 */
1199 LONG64 timeOffset;
1200 hrc = firmwareSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1201 PCFGMNODE pTMNode;
1202 InsertConfigNode(pRoot, "TM", &pTMNode);
1203 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1204
1205 /*
1206 * DMA
1207 */
1208 InsertConfigNode(pDevices, "8237A", &pDev);
1209 InsertConfigNode(pDev, "0", &pInst);
1210 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1211
1212 /*
1213 * PCI buses.
1214 */
1215 uint32_t uIocPCIAddress, uHbcPCIAddress;
1216 switch (chipsetType)
1217 {
1218 default:
1219 AssertFailed();
1220 RT_FALL_THRU();
1221 case ChipsetType_PIIX3:
1222 /* Create the base for adding bridges on demand */
1223 InsertConfigNode(pDevices, "pcibridge", NULL);
1224
1225 InsertConfigNode(pDevices, "pci", &pDev);
1226 uHbcPCIAddress = (0x0 << 16) | 0;
1227 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1228 break;
1229 case ChipsetType_ICH9:
1230 /* Create the base for adding bridges on demand */
1231 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1232
1233 InsertConfigNode(pDevices, "ich9pci", &pDev);
1234 uHbcPCIAddress = (0x1e << 16) | 0;
1235 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1236 break;
1237 }
1238 InsertConfigNode(pDev, "0", &pInst);
1239 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1240 InsertConfigNode(pInst, "Config", &pCfg);
1241 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1242 if (chipsetType == ChipsetType_ICH9)
1243 {
1244 /* Provide MCFG info */
1245 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1246 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1247
1248#ifdef VBOX_WITH_PCI_PASSTHROUGH
1249 /* Add PCI passthrough devices */
1250 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1251#endif
1252
1253 if (enmIommuType == IommuType_AMD)
1254 {
1255 /* AMD IOMMU. */
1256 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1257 InsertConfigNode(pDev, "0", &pInst);
1258 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1259 InsertConfigNode(pInst, "Config", &pCfg);
1260 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1261
1262 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1263 {
1264 PCIBusAddress Address;
1265 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1266 {
1267 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1268 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1269 }
1270 else
1271 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1272 N_("Failed to find PCI address of the assigned IOMMU device!"));
1273 }
1274
1275 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1276 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1277 }
1278 else if (enmIommuType == IommuType_Intel)
1279 {
1280 /* Intel IOMMU. */
1281 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1282 InsertConfigNode(pDev, "0", &pInst);
1283 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1284 InsertConfigNode(pInst, "Config", &pCfg);
1285 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1286
1287 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1288 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1289 }
1290 }
1291
1292 /*
1293 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1294 */
1295
1296 /*
1297 * High Precision Event Timer (HPET)
1298 */
1299 BOOL fHPETEnabled;
1300 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1301 hrc = platformX86->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1302 /* so always enable HPET in extended profile */
1303 fHPETEnabled |= fOsXGuest;
1304 /* HPET is always present on ICH9 */
1305 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1306 if (fHPETEnabled)
1307 {
1308 InsertConfigNode(pDevices, "hpet", &pDev);
1309 InsertConfigNode(pDev, "0", &pInst);
1310 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1311 InsertConfigNode(pInst, "Config", &pCfg);
1312 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1313 }
1314
1315 /*
1316 * System Management Controller (SMC)
1317 */
1318 BOOL fSmcEnabled;
1319 fSmcEnabled = fOsXGuest;
1320 if (fSmcEnabled)
1321 {
1322 InsertConfigNode(pDevices, "smc", &pDev);
1323 InsertConfigNode(pDev, "0", &pInst);
1324 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1325 InsertConfigNode(pInst, "Config", &pCfg);
1326
1327 bool fGetKeyFromRealSMC;
1328 Utf8Str strKey;
1329 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1330 AssertRCReturn(vrc, vrc);
1331
1332 if (!fGetKeyFromRealSMC)
1333 InsertConfigString(pCfg, "DeviceKey", strKey);
1334 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1335 }
1336
1337 /*
1338 * Low Pin Count (LPC) bus
1339 */
1340 BOOL fLpcEnabled;
1341 /** @todo implement appropriate getter */
1342 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1343 if (fLpcEnabled)
1344 {
1345 InsertConfigNode(pDevices, "lpc", &pDev);
1346 InsertConfigNode(pDev, "0", &pInst);
1347 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1348 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1349 }
1350
1351 BOOL fShowRtc;
1352 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1353
1354 /*
1355 * PS/2 keyboard & mouse.
1356 */
1357 InsertConfigNode(pDevices, "pckbd", &pDev);
1358 InsertConfigNode(pDev, "0", &pInst);
1359 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1360 InsertConfigNode(pInst, "Config", &pCfg);
1361
1362 KeyboardHIDType_T aKbdHID;
1363 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1364 if (aKbdHID != KeyboardHIDType_None)
1365 {
1366 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1367 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1368 InsertConfigNode(pLunL0, "Config", &pCfg);
1369 InsertConfigInteger(pCfg, "QueueSize", 64);
1370
1371 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1372 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1373 }
1374
1375 PointingHIDType_T aPointingHID;
1376 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1377 if (aPointingHID != PointingHIDType_None)
1378 {
1379 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1380 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1381 InsertConfigNode(pLunL0, "Config", &pCfg);
1382 InsertConfigInteger(pCfg, "QueueSize", 128);
1383
1384 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1385 InsertConfigString(pLunL1, "Driver", "MainMouse");
1386 }
1387
1388 /*
1389 * i8254 Programmable Interval Timer And Dummy Speaker
1390 */
1391 InsertConfigNode(pDevices, "i8254", &pDev);
1392 InsertConfigNode(pDev, "0", &pInst);
1393 InsertConfigNode(pInst, "Config", &pCfg);
1394#ifdef DEBUG
1395 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1396#endif
1397
1398 /*
1399 * i8259 Programmable Interrupt Controller.
1400 */
1401 InsertConfigNode(pDevices, "i8259", &pDev);
1402 InsertConfigNode(pDev, "0", &pInst);
1403 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1404 InsertConfigNode(pInst, "Config", &pCfg);
1405
1406 /*
1407 * Advanced Programmable Interrupt Controller.
1408 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1409 * thus only single insert
1410 */
1411 if (fEnableAPIC)
1412 {
1413 InsertConfigNode(pDevices, "apic", &pDev);
1414 InsertConfigNode(pDev, "0", &pInst);
1415 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1416 InsertConfigNode(pInst, "Config", &pCfg);
1417 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1418 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1419 if (fEnableX2APIC)
1420 enmAPICMode = PDMAPICMODE_X2APIC;
1421 else if (!fEnableAPIC)
1422 enmAPICMode = PDMAPICMODE_NONE;
1423 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1424 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1425
1426 if (fIOAPIC)
1427 {
1428 /*
1429 * I/O Advanced Programmable Interrupt Controller.
1430 */
1431 InsertConfigNode(pDevices, "ioapic", &pDev);
1432 InsertConfigNode(pDev, "0", &pInst);
1433 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1434 InsertConfigNode(pInst, "Config", &pCfg);
1435 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1436 if (enmIommuType == IommuType_AMD)
1437 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1438 else if (enmIommuType == IommuType_Intel)
1439 {
1440 InsertConfigString(pCfg, "ChipType", "DMAR");
1441 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1442 }
1443 }
1444 }
1445
1446 /*
1447 * RTC MC146818.
1448 */
1449 InsertConfigNode(pDevices, "mc146818", &pDev);
1450 InsertConfigNode(pDev, "0", &pInst);
1451 InsertConfigNode(pInst, "Config", &pCfg);
1452 BOOL fRTCUseUTC;
1453 hrc = platform->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1454 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1455
1456 /*
1457 * VGA.
1458 */
1459 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1460 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1461 GraphicsControllerType_T enmGraphicsController;
1462 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1463 switch (enmGraphicsController)
1464 {
1465 case GraphicsControllerType_Null:
1466 break;
1467#ifdef VBOX_WITH_VMSVGA
1468 case GraphicsControllerType_VMSVGA:
1469 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1470 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1471 RT_FALL_THROUGH();
1472 case GraphicsControllerType_VBoxSVGA:
1473#endif
1474 case GraphicsControllerType_VBoxVGA:
1475 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, firmwareSettings,
1476 RT_BOOL(fHMEnabled));
1477 if (FAILED(vrc))
1478 return vrc;
1479 break;
1480 default:
1481 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1482 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1483 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1484 }
1485
1486 /*
1487 * Firmware.
1488 */
1489 FirmwareType_T eFwType = FirmwareType_BIOS;
1490 hrc = firmwareSettings->COMGETTER(FirmwareType)(&eFwType); H();
1491
1492#ifdef VBOX_WITH_EFI
1493 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1494#else
1495 BOOL fEfiEnabled = false;
1496#endif
1497 if (!fEfiEnabled)
1498 {
1499 /*
1500 * PC Bios.
1501 */
1502 InsertConfigNode(pDevices, "pcbios", &pDev);
1503 InsertConfigNode(pDev, "0", &pInst);
1504 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1505 InsertConfigNode(pInst, "Config", &pBiosCfg);
1506 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1507 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1508 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1509 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1510 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1511 BOOL fPXEDebug;
1512 hrc = firmwareSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1513 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1514 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1515 BOOL fUuidLe;
1516 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1517 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1518 BOOL fAutoSerialNumGen;
1519 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1520 if (fAutoSerialNumGen)
1521 InsertConfigString(pBiosCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1522 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1523 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1524 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1525
1526 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1527 VERR_INVALID_PARAMETER);
1528
1529 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1530 {
1531 DeviceType_T enmBootDevice;
1532 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1533
1534 char szParamName[] = "BootDeviceX";
1535 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1536
1537 const char *pszBootDevice;
1538 switch (enmBootDevice)
1539 {
1540 case DeviceType_Null:
1541 pszBootDevice = "NONE";
1542 break;
1543 case DeviceType_HardDisk:
1544 pszBootDevice = "IDE";
1545 break;
1546 case DeviceType_DVD:
1547 pszBootDevice = "DVD";
1548 break;
1549 case DeviceType_Floppy:
1550 pszBootDevice = "FLOPPY";
1551 break;
1552 case DeviceType_Network:
1553 pszBootDevice = "LAN";
1554 break;
1555 default:
1556 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1557 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1558 N_("Invalid boot device '%d'"), enmBootDevice);
1559 }
1560 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1561 }
1562
1563 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1564 * this is required for Windows 2012 guests. */
1565 if (osTypeId == GUEST_OS_ID_STR_X64("Windows2012"))
1566 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1567 }
1568 else
1569 {
1570 /* Autodetect firmware type, basing on guest type */
1571 if (eFwType == FirmwareType_EFI)
1572 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1573 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1574
1575 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1576#ifdef VBOX_WITH_EFI_IN_DD2
1577 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1578 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"
1579 : "VBoxEFI64.fd";
1580#else
1581 Utf8Str efiRomFile;
1582 vrc = findEfiRom(virtualBox, PlatformArchitecture_x86, eFwType, &efiRomFile);
1583 AssertRCReturn(vrc, vrc);
1584 const char *pszEfiRomFile = efiRomFile.c_str();
1585#endif
1586
1587 /* Get boot args */
1588 Utf8Str bootArgs;
1589 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1590
1591 /* Get device props */
1592 Utf8Str deviceProps;
1593 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1594
1595 /* Get NVRAM file name */
1596 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
1597
1598 BOOL fUuidLe;
1599 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1600
1601 BOOL fAutoSerialNumGen;
1602 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1603
1604 /* Get graphics mode settings */
1605 uint32_t u32GraphicsMode = UINT32_MAX;
1606 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1607 if (strTmp.isEmpty())
1608 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1609 if (!strTmp.isEmpty())
1610 u32GraphicsMode = strTmp.toUInt32();
1611
1612 /* Get graphics resolution settings, with some sanity checking */
1613 Utf8Str strResolution;
1614 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1615 if (!strResolution.isEmpty())
1616 {
1617 size_t pos = strResolution.find("x");
1618 if (pos != strResolution.npos)
1619 {
1620 Utf8Str strH, strV;
1621 strH.assignEx(strResolution, 0, pos);
1622 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1623 uint32_t u32H = strH.toUInt32();
1624 uint32_t u32V = strV.toUInt32();
1625 if (u32H == 0 || u32V == 0)
1626 strResolution.setNull();
1627 }
1628 else
1629 strResolution.setNull();
1630 }
1631 else
1632 {
1633 uint32_t u32H = 0;
1634 uint32_t u32V = 0;
1635 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1636 if (strTmp.isEmpty())
1637 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1638 if (!strTmp.isEmpty())
1639 u32H = strTmp.toUInt32();
1640
1641 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1642 if (strTmp.isEmpty())
1643 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1644 if (!strTmp.isEmpty())
1645 u32V = strTmp.toUInt32();
1646 if (u32H != 0 && u32V != 0)
1647 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
1648 }
1649
1650 /*
1651 * EFI subtree.
1652 */
1653 InsertConfigNode(pDevices, "efi", &pDev);
1654 InsertConfigNode(pDev, "0", &pInst);
1655 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1656 InsertConfigNode(pInst, "Config", &pCfg);
1657 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1658 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1659 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1660 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
1661 InsertConfigString(pCfg, "BootArgs", bootArgs);
1662 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1663 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1664 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1665 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1666 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
1667 if (fAutoSerialNumGen)
1668 InsertConfigString(pCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1669 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1670 InsertConfigString(pCfg, "NvramFile", strNvram);
1671 if (u32GraphicsMode != UINT32_MAX)
1672 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1673 if (!strResolution.isEmpty())
1674 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
1675
1676 /* For OS X guests we'll force passing host's DMI info to the guest */
1677 if (fOsXGuest)
1678 {
1679 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1680 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1681 }
1682
1683 /* Attach the NVRAM storage driver. */
1684 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1685 InsertConfigString(pLunL0, "Driver", "NvramStore");
1686 }
1687
1688 /*
1689 * The USB Controllers.
1690 */
1691 com::SafeIfaceArray<IUSBController> usbCtrls;
1692 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
1693 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
1694 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
1695
1696 if (SUCCEEDED(hrc))
1697 {
1698 for (size_t i = 0; i < usbCtrls.size(); ++i)
1699 {
1700 USBControllerType_T enmCtrlType;
1701 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1702 if (enmCtrlType == USBControllerType_OHCI)
1703 {
1704 fOhciPresent = true;
1705 break;
1706 }
1707 else if (enmCtrlType == USBControllerType_XHCI)
1708 {
1709 fXhciPresent = true;
1710 break;
1711 }
1712 }
1713 }
1714 else if (hrc != E_NOTIMPL)
1715 {
1716 H();
1717 }
1718
1719 /*
1720 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
1721 */
1722 if (fOhciPresent || fXhciPresent)
1723 mfVMHasUsbController = true;
1724
1725 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
1726 if (mfVMHasUsbController)
1727 {
1728 for (size_t i = 0; i < usbCtrls.size(); ++i)
1729 {
1730 USBControllerType_T enmCtrlType;
1731 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1732
1733 if (enmCtrlType == USBControllerType_OHCI)
1734 {
1735 InsertConfigNode(pDevices, "usb-ohci", &pDev);
1736 InsertConfigNode(pDev, "0", &pInst);
1737 InsertConfigNode(pInst, "Config", &pCfg);
1738 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1739 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
1740 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1741 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1742 InsertConfigNode(pLunL0, "Config", &pCfg);
1743
1744 /*
1745 * Attach the status driver.
1746 */
1747 i_attachStatusDriver(pInst, DeviceType_USB);
1748 }
1749#ifdef VBOX_WITH_EHCI
1750 else if (enmCtrlType == USBControllerType_EHCI)
1751 {
1752 InsertConfigNode(pDevices, "usb-ehci", &pDev);
1753 InsertConfigNode(pDev, "0", &pInst);
1754 InsertConfigNode(pInst, "Config", &pCfg);
1755 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1756 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
1757
1758 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1759 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1760 InsertConfigNode(pLunL0, "Config", &pCfg);
1761
1762 /*
1763 * Attach the status driver.
1764 */
1765 i_attachStatusDriver(pInst, DeviceType_USB);
1766 }
1767#endif
1768 else if (enmCtrlType == USBControllerType_XHCI)
1769 {
1770 InsertConfigNode(pDevices, "usb-xhci", &pDev);
1771 InsertConfigNode(pDev, "0", &pInst);
1772 InsertConfigNode(pInst, "Config", &pCfg);
1773 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1774 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
1775
1776 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1777 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1778 InsertConfigNode(pLunL0, "Config", &pCfg);
1779
1780 InsertConfigNode(pInst, "LUN#1", &pLunL1);
1781 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
1782 InsertConfigNode(pLunL1, "Config", &pCfg);
1783
1784 /*
1785 * Attach the status driver.
1786 */
1787 i_attachStatusDriver(pInst, DeviceType_USB, 2);
1788 }
1789 } /* for every USB controller. */
1790
1791
1792 /*
1793 * Virtual USB Devices.
1794 */
1795 InsertConfigNode(pRoot, "USB", &pUsbDevices);
1796
1797#ifdef VBOX_WITH_USB
1798 {
1799 /*
1800 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
1801 * on a per device level now.
1802 */
1803 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
1804 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
1805 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
1806 //InsertConfigInteger(pCfg, "Force11Device", true);
1807 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
1808 // that it's documented somewhere.) Users needing it can use:
1809 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
1810 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
1811 }
1812#endif
1813
1814#ifdef VBOX_WITH_USB_CARDREADER
1815 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
1816 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
1817 if (aEmulatedUSBCardReaderEnabled)
1818 {
1819 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
1820 InsertConfigNode(pDev, "0", &pInst);
1821 InsertConfigNode(pInst, "Config", &pCfg);
1822
1823 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1824# ifdef VBOX_WITH_USB_CARDREADER_TEST
1825 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
1826 InsertConfigNode(pLunL0, "Config", &pCfg);
1827# else
1828 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
1829 InsertConfigNode(pLunL0, "Config", &pCfg);
1830# endif
1831 }
1832#endif
1833
1834 /* Virtual USB Mouse/Tablet */
1835 if ( aPointingHID == PointingHIDType_USBMouse
1836 || aPointingHID == PointingHIDType_USBTablet
1837 || aPointingHID == PointingHIDType_USBMultiTouch
1838 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
1839 {
1840 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
1841 InsertConfigNode(pDev, "0", &pInst);
1842 InsertConfigNode(pInst, "Config", &pCfg);
1843
1844 if (aPointingHID == PointingHIDType_USBMouse)
1845 InsertConfigString(pCfg, "Mode", "relative");
1846 else
1847 InsertConfigString(pCfg, "Mode", "absolute");
1848 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1849 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1850 InsertConfigNode(pLunL0, "Config", &pCfg);
1851 InsertConfigInteger(pCfg, "QueueSize", 128);
1852
1853 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1854 InsertConfigString(pLunL1, "Driver", "MainMouse");
1855 }
1856 if ( aPointingHID == PointingHIDType_USBMultiTouch
1857 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
1858 {
1859 InsertConfigNode(pDev, "1", &pInst);
1860 InsertConfigNode(pInst, "Config", &pCfg);
1861
1862 InsertConfigString(pCfg, "Mode", "multitouch");
1863 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1864 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1865 InsertConfigNode(pLunL0, "Config", &pCfg);
1866 InsertConfigInteger(pCfg, "QueueSize", 128);
1867
1868 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1869 InsertConfigString(pLunL1, "Driver", "MainMouse");
1870 }
1871 if (aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
1872 {
1873 InsertConfigNode(pDev, "2", &pInst);
1874 InsertConfigNode(pInst, "Config", &pCfg);
1875
1876 InsertConfigString(pCfg, "Mode", "touchpad");
1877 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1878 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1879 InsertConfigNode(pLunL0, "Config", &pCfg);
1880 InsertConfigInteger(pCfg, "QueueSize", 128);
1881
1882 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1883 InsertConfigString(pLunL1, "Driver", "MainMouse");
1884 }
1885
1886 /* Virtual USB Keyboard */
1887 if (aKbdHID == KeyboardHIDType_USBKeyboard)
1888 {
1889 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
1890 InsertConfigNode(pDev, "0", &pInst);
1891 InsertConfigNode(pInst, "Config", &pCfg);
1892
1893 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1894 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1895 InsertConfigNode(pLunL0, "Config", &pCfg);
1896 InsertConfigInteger(pCfg, "QueueSize", 64);
1897
1898 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1899 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1900 }
1901 }
1902
1903 /*
1904 * Storage controllers.
1905 */
1906 com::SafeIfaceArray<IStorageController> ctrls;
1907 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
1908 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
1909
1910 bool fFdcEnabled = false;
1911 for (size_t i = 0; i < ctrls.size(); ++i)
1912 {
1913 DeviceType_T *paLedDevType = NULL;
1914
1915 StorageControllerType_T enmCtrlType;
1916 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
1917 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
1918 || enmCtrlType == StorageControllerType_USB);
1919
1920 StorageBus_T enmBus;
1921 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
1922
1923 Bstr controllerName;
1924 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
1925
1926 ULONG ulInstance = 999;
1927 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
1928
1929 BOOL fUseHostIOCache;
1930 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
1931
1932 BOOL fBootable;
1933 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
1934
1935 PCFGMNODE pCtlInst = NULL;
1936 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
1937 if (enmCtrlType != StorageControllerType_USB)
1938 {
1939 /* /Devices/<ctrldev>/ */
1940 pDev = aCtrlNodes[enmCtrlType];
1941 if (!pDev)
1942 {
1943 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
1944 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
1945 }
1946
1947 /* /Devices/<ctrldev>/<instance>/ */
1948 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
1949
1950 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
1951 InsertConfigInteger(pCtlInst, "Trusted", 1);
1952 InsertConfigNode(pCtlInst, "Config", &pCfg);
1953 }
1954
1955 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
1956 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
1957
1958 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
1959 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
1960
1961 switch (enmCtrlType)
1962 {
1963 case StorageControllerType_LsiLogic:
1964 {
1965 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
1966
1967 InsertConfigInteger(pCfg, "Bootable", fBootable);
1968
1969 /* BIOS configuration values, first SCSI controller only. */
1970 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
1971 && !pBusMgr->hasPCIDevice("buslogic", 0)
1972 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
1973 && pBiosCfg)
1974 {
1975 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
1976 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
1977 }
1978
1979 /* Attach the status driver */
1980 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
1981 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
1982 break;
1983 }
1984
1985 case StorageControllerType_BusLogic:
1986 {
1987 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
1988
1989 InsertConfigInteger(pCfg, "Bootable", fBootable);
1990
1991 /* BIOS configuration values, first SCSI controller only. */
1992 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
1993 && !pBusMgr->hasPCIDevice("buslogic", 1)
1994 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
1995 && pBiosCfg)
1996 {
1997 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
1998 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
1999 }
2000
2001 /* Attach the status driver */
2002 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2003 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2004 break;
2005 }
2006
2007 case StorageControllerType_IntelAhci:
2008 {
2009 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2010
2011 ULONG cPorts = 0;
2012 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2013 InsertConfigInteger(pCfg, "PortCount", cPorts);
2014 InsertConfigInteger(pCfg, "Bootable", fBootable);
2015
2016 com::SafeIfaceArray<IMediumAttachment> atts;
2017 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2018 ComSafeArrayAsOutParam(atts)); H();
2019
2020 /* Configure the hotpluggable flag for the port. */
2021 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2022 {
2023 IMediumAttachment *pMediumAtt = atts[idxAtt];
2024
2025 LONG lPortNum = 0;
2026 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2027
2028 BOOL fHotPluggable = FALSE;
2029 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2030 if (SUCCEEDED(hrc))
2031 {
2032 PCFGMNODE pPortCfg;
2033 char szName[24];
2034 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2035
2036 InsertConfigNode(pCfg, szName, &pPortCfg);
2037 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2038 }
2039 }
2040
2041 /* BIOS configuration values, first AHCI controller only. */
2042 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2043 && pBiosCfg)
2044 {
2045 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2046 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2047 }
2048
2049 /* Attach the status driver */
2050 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2051 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2052 break;
2053 }
2054
2055 case StorageControllerType_PIIX3:
2056 case StorageControllerType_PIIX4:
2057 case StorageControllerType_ICH6:
2058 {
2059 /*
2060 * IDE (update this when the main interface changes)
2061 */
2062 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2063 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2064
2065 /* Attach the status driver */
2066 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2067 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2068
2069 /* IDE flavors */
2070 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2071 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2072 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2073 break;
2074 }
2075
2076 case StorageControllerType_I82078:
2077 {
2078 /*
2079 * i82078 Floppy drive controller
2080 */
2081 fFdcEnabled = true;
2082 InsertConfigInteger(pCfg, "IRQ", 6);
2083 InsertConfigInteger(pCfg, "DMA", 2);
2084 InsertConfigInteger(pCfg, "MemMapped", 0 );
2085 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2086
2087 /* Attach the status driver */
2088 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),
2089 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
2090 break;
2091 }
2092
2093 case StorageControllerType_LsiLogicSas:
2094 {
2095 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2096
2097 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2098 InsertConfigInteger(pCfg, "Bootable", fBootable);
2099
2100 /* BIOS configuration values, first SCSI controller only. */
2101 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2102 && !pBusMgr->hasPCIDevice("buslogic", 0)
2103 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2104 && pBiosCfg)
2105 {
2106 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2107 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2108 }
2109
2110 ULONG cPorts = 0;
2111 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2112 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2113
2114 /* Attach the status driver */
2115 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
2116 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2117 break;
2118 }
2119
2120 case StorageControllerType_USB:
2121 {
2122 if (pUsbDevices)
2123 {
2124 /*
2125 * USB MSDs are handled a bit different as the device instance
2126 * doesn't match the storage controller instance but the port.
2127 */
2128 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2129 pCtlInst = pDev;
2130 }
2131 else
2132 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2133 N_("There is no USB controller enabled but there\n"
2134 "is at least one USB storage device configured for this VM.\n"
2135 "To fix this problem either enable the USB controller or remove\n"
2136 "the storage device from the VM"));
2137 break;
2138 }
2139
2140 case StorageControllerType_NVMe:
2141 {
2142 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2143
2144 ULONG cPorts = 0;
2145 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2146 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2147
2148 /* Attach the status driver */
2149 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
2150 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
2151 break;
2152 }
2153
2154 case StorageControllerType_VirtioSCSI:
2155 {
2156 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
2157
2158 ULONG cPorts = 0;
2159 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2160 InsertConfigInteger(pCfg, "NumTargets", cPorts);
2161 InsertConfigInteger(pCfg, "Bootable", fBootable);
2162
2163 /* Attach the status driver */
2164 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
2165 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2166 break;
2167 }
2168
2169 default:
2170 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2171 }
2172
2173 /* Attach the media to the storage controllers. */
2174 com::SafeIfaceArray<IMediumAttachment> atts;
2175 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2176 ComSafeArrayAsOutParam(atts)); H();
2177
2178 /* Builtin I/O cache - per device setting. */
2179 BOOL fBuiltinIOCache = true;
2180 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2181
2182 bool fInsertDiskIntegrityDrv = false;
2183 Bstr strDiskIntegrityFlag;
2184 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2185 strDiskIntegrityFlag.asOutParam());
2186 if ( hrc == S_OK
2187 && strDiskIntegrityFlag == "1")
2188 fInsertDiskIntegrityDrv = true;
2189
2190 for (size_t j = 0; j < atts.size(); ++j)
2191 {
2192 IMediumAttachment *pMediumAtt = atts[j];
2193 vrc = i_configMediumAttachment(pszCtrlDev,
2194 ulInstance,
2195 enmBus,
2196 !!fUseHostIOCache,
2197 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2198 fInsertDiskIntegrityDrv,
2199 false /* fSetupMerge */,
2200 0 /* uMergeSource */,
2201 0 /* uMergeTarget */,
2202 pMediumAtt,
2203 mMachineState,
2204 NULL /* phrc */,
2205 false /* fAttachDetach */,
2206 false /* fForceUnmount */,
2207 false /* fHotplug */,
2208 pUVM,
2209 pVMM,
2210 paLedDevType,
2211 NULL /* ppLunL0 */);
2212 if (RT_FAILURE(vrc))
2213 return vrc;
2214 }
2215 H();
2216 }
2217 H();
2218
2219 /*
2220 * Network adapters
2221 */
2222#ifdef VMWARE_NET_IN_SLOT_11
2223 bool fSwapSlots3and11 = false;
2224#endif
2225 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2226 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2227#ifdef VBOX_WITH_E1000
2228 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2229 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2230#endif
2231#ifdef VBOX_WITH_VIRTIO
2232 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2233 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2234#endif /* VBOX_WITH_VIRTIO */
2235 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
2236 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
2237 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
2238 InsertConfigNode(pDevices, "3c501", &pDev3C501);
2239
2240 std::list<BootNic> llBootNics;
2241 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
2242 {
2243 ComPtr<INetworkAdapter> networkAdapter;
2244 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
2245 BOOL fEnabledNetAdapter = FALSE;
2246 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2247 if (!fEnabledNetAdapter)
2248 continue;
2249
2250 /*
2251 * The virtual hardware type. Create appropriate device first.
2252 */
2253 const char *pszAdapterName = "pcnet";
2254 NetworkAdapterType_T adapterType;
2255 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2256 switch (adapterType)
2257 {
2258 case NetworkAdapterType_Am79C970A:
2259 case NetworkAdapterType_Am79C973:
2260 case NetworkAdapterType_Am79C960:
2261 pDev = pDevPCNet;
2262 break;
2263#ifdef VBOX_WITH_E1000
2264 case NetworkAdapterType_I82540EM:
2265 case NetworkAdapterType_I82543GC:
2266 case NetworkAdapterType_I82545EM:
2267 pDev = pDevE1000;
2268 pszAdapterName = "e1000";
2269 break;
2270#endif
2271#ifdef VBOX_WITH_VIRTIO
2272 case NetworkAdapterType_Virtio:
2273 pDev = pDevVirtioNet;
2274 pszAdapterName = "virtio-net";
2275 break;
2276#endif /* VBOX_WITH_VIRTIO */
2277 case NetworkAdapterType_NE1000:
2278 case NetworkAdapterType_NE2000:
2279 case NetworkAdapterType_WD8003:
2280 case NetworkAdapterType_WD8013:
2281 case NetworkAdapterType_ELNK2:
2282 pDev = pDevDP8390;
2283 break;
2284 case NetworkAdapterType_ELNK1:
2285 pDev = pDev3C501;
2286 break;
2287 default:
2288 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
2289 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2290 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
2291 }
2292
2293 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
2294 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2295 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2296 * next 4 get 16..19. */
2297 int iPCIDeviceNo;
2298 switch (uInstance)
2299 {
2300 case 0:
2301 iPCIDeviceNo = 3;
2302 break;
2303 case 1: case 2: case 3:
2304 iPCIDeviceNo = uInstance - 1 + 8;
2305 break;
2306 case 4: case 5: case 6: case 7:
2307 iPCIDeviceNo = uInstance - 4 + 16;
2308 break;
2309 default:
2310 /* auto assignment */
2311 iPCIDeviceNo = -1;
2312 break;
2313 }
2314#ifdef VMWARE_NET_IN_SLOT_11
2315 /*
2316 * Dirty hack for PCI slot compatibility with VMWare,
2317 * it assigns slot 0x11 to the first network controller.
2318 */
2319 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2320 {
2321 iPCIDeviceNo = 0x11;
2322 fSwapSlots3and11 = true;
2323 }
2324 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2325 iPCIDeviceNo = 3;
2326#endif
2327 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2328 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2329
2330 InsertConfigNode(pInst, "Config", &pCfg);
2331#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2332 if (pDev == pDevPCNet)
2333 InsertConfigInteger(pCfg, "R0Enabled", false);
2334#endif
2335 /*
2336 * Collect information needed for network booting and add it to the list.
2337 */
2338 BootNic nic;
2339
2340 nic.mInstance = uInstance;
2341 /* Could be updated by reference, if auto assigned */
2342 nic.mPCIAddress = PCIAddr;
2343
2344 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2345
2346 llBootNics.push_back(nic);
2347
2348 /*
2349 * The virtual hardware type. PCNet supports three types, E1000 three,
2350 * but VirtIO only one.
2351 */
2352 switch (adapterType)
2353 {
2354 case NetworkAdapterType_Am79C970A:
2355 InsertConfigString(pCfg, "ChipType", "Am79C970A");
2356 break;
2357 case NetworkAdapterType_Am79C973:
2358 InsertConfigString(pCfg, "ChipType", "Am79C973");
2359 break;
2360 case NetworkAdapterType_Am79C960:
2361 InsertConfigString(pCfg, "ChipType", "Am79C960");
2362 break;
2363 case NetworkAdapterType_I82540EM:
2364 InsertConfigInteger(pCfg, "AdapterType", 0);
2365 break;
2366 case NetworkAdapterType_I82543GC:
2367 InsertConfigInteger(pCfg, "AdapterType", 1);
2368 break;
2369 case NetworkAdapterType_I82545EM:
2370 InsertConfigInteger(pCfg, "AdapterType", 2);
2371 break;
2372 case NetworkAdapterType_Virtio:
2373 break;
2374 case NetworkAdapterType_NE1000:
2375 InsertConfigString(pCfg, "DeviceType", "NE1000");
2376 break;
2377 case NetworkAdapterType_NE2000:
2378 InsertConfigString(pCfg, "DeviceType", "NE2000");
2379 break;
2380 case NetworkAdapterType_WD8003:
2381 InsertConfigString(pCfg, "DeviceType", "WD8003");
2382 break;
2383 case NetworkAdapterType_WD8013:
2384 InsertConfigString(pCfg, "DeviceType", "WD8013");
2385 break;
2386 case NetworkAdapterType_ELNK2:
2387 InsertConfigString(pCfg, "DeviceType", "3C503");
2388 break;
2389 case NetworkAdapterType_ELNK1:
2390 break;
2391 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
2392#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
2393 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
2394#endif
2395 }
2396
2397 /*
2398 * Get the MAC address and convert it to binary representation
2399 */
2400 Bstr macAddr;
2401 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2402 Assert(!macAddr.isEmpty());
2403 Utf8Str macAddrUtf8 = macAddr;
2404#ifdef VBOX_WITH_CLOUD_NET
2405 NetworkAttachmentType_T eAttachmentType;
2406 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
2407 if (eAttachmentType == NetworkAttachmentType_Cloud)
2408 {
2409 mGateway.setLocalMacAddress(macAddrUtf8);
2410 /* We'll insert cloud MAC later, when it becomes known. */
2411 }
2412 else
2413 {
2414#endif
2415 char *macStr = (char*)macAddrUtf8.c_str();
2416 Assert(strlen(macStr) == 12);
2417 RTMAC Mac;
2418 RT_ZERO(Mac);
2419 char *pMac = (char*)&Mac;
2420 for (uint32_t i = 0; i < 6; ++i)
2421 {
2422 int c1 = *macStr++ - '0';
2423 if (c1 > 9)
2424 c1 -= 7;
2425 int c2 = *macStr++ - '0';
2426 if (c2 > 9)
2427 c2 -= 7;
2428 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2429 }
2430 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2431#ifdef VBOX_WITH_CLOUD_NET
2432 }
2433#endif
2434 /*
2435 * Check if the cable is supposed to be unplugged
2436 */
2437 BOOL fCableConnected;
2438 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2439 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2440
2441 /*
2442 * Line speed to report from custom drivers
2443 */
2444 ULONG ulLineSpeed;
2445 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2446 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2447
2448 /*
2449 * Attach the status driver.
2450 */
2451 i_attachStatusDriver(pInst, DeviceType_Network);
2452
2453 /*
2454 * Configure the network card now
2455 */
2456 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2457 vrc = i_configNetwork(pszAdapterName,
2458 uInstance,
2459 0,
2460 networkAdapter,
2461 pCfg,
2462 pLunL0,
2463 pInst,
2464 false /*fAttachDetach*/,
2465 fIgnoreConnectFailure,
2466 pUVM,
2467 pVMM);
2468 if (RT_FAILURE(vrc))
2469 return vrc;
2470 }
2471
2472 /*
2473 * Build network boot information and transfer it to the BIOS.
2474 */
2475 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2476 {
2477 llBootNics.sort(); /* Sort the list by boot priority. */
2478
2479 char achBootIdx[] = "0";
2480 unsigned uBootIdx = 0;
2481
2482 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2483 {
2484 /* A NIC with priority 0 is only used if it's first in the list. */
2485 if (it->mBootPrio == 0 && uBootIdx != 0)
2486 break;
2487
2488 PCFGMNODE pNetBtDevCfg;
2489 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2490 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2491 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2492 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2493 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2494 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2495 }
2496 }
2497
2498 /*
2499 * Serial (UART) Ports
2500 */
2501 /* serial enabled mask to be passed to dev ACPI */
2502 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2503 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2504 InsertConfigNode(pDevices, "serial", &pDev);
2505 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2506 {
2507 ComPtr<ISerialPort> serialPort;
2508 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2509 BOOL fEnabledSerPort = FALSE;
2510 if (serialPort)
2511 {
2512 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2513 }
2514 if (!fEnabledSerPort)
2515 {
2516 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
2517 continue;
2518 }
2519
2520 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2521 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2522 InsertConfigNode(pInst, "Config", &pCfg);
2523
2524 ULONG ulIRQ;
2525 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2526 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2527 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2528
2529 ULONG ulIOBase;
2530 hrc = serialPort->COMGETTER(IOAddress)(&ulIOBase); H();
2531 InsertConfigInteger(pCfg, "IOAddress", ulIOBase);
2532 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2533
2534 BOOL fServer;
2535 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2536 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2537 UartType_T eUartType;
2538 const char *pszUartType;
2539 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2540 switch (eUartType)
2541 {
2542 case UartType_U16450: pszUartType = "16450"; break;
2543 case UartType_U16750: pszUartType = "16750"; break;
2544 default: AssertFailed(); RT_FALL_THRU();
2545 case UartType_U16550A: pszUartType = "16550A"; break;
2546 }
2547 InsertConfigString(pCfg, "UartType", pszUartType);
2548
2549 PortMode_T eHostMode;
2550 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2551
2552 m_aeSerialPortMode[ulInstance] = eHostMode;
2553 if (eHostMode != PortMode_Disconnected)
2554 {
2555 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2556 if (RT_FAILURE(vrc))
2557 return vrc;
2558 }
2559 }
2560
2561 /*
2562 * Parallel (LPT) Ports
2563 */
2564 /* parallel enabled mask to be passed to dev ACPI */
2565 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2566 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2567 InsertConfigNode(pDevices, "parallel", &pDev);
2568 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2569 {
2570 ComPtr<IParallelPort> parallelPort;
2571 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2572 BOOL fEnabledParPort = FALSE;
2573 if (parallelPort)
2574 {
2575 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2576 }
2577 if (!fEnabledParPort)
2578 continue;
2579
2580 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2581 InsertConfigNode(pInst, "Config", &pCfg);
2582
2583 ULONG ulIRQ;
2584 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2585 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2586 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2587 ULONG ulIOBase;
2588 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2589 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2590 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2591
2592 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2593 if (!bstr.isEmpty())
2594 {
2595 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2596 InsertConfigString(pLunL0, "Driver", "HostParallel");
2597 InsertConfigNode(pLunL0, "Config", &pLunL1);
2598 InsertConfigString(pLunL1, "DevicePath", bstr);
2599 }
2600 }
2601
2602 vrc = i_configVmmDev(pMachine, pBusMgr, pDevices); VRC();
2603
2604 /*
2605 * Audio configuration.
2606 */
2607 bool fAudioEnabled = false;
2608 vrc = i_configAudioCtrl(virtualBox, pMachine, pBusMgr, pDevices,
2609 fOsXGuest, &fAudioEnabled); VRC();
2610
2611#if defined(VBOX_WITH_TPM)
2612 /*
2613 * Configure the Trusted Platform Module.
2614 */
2615 ComObjPtr<ITrustedPlatformModule> ptrTpm;
2616 TpmType_T enmTpmType = TpmType_None;
2617
2618 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
2619 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
2620 if (enmTpmType != TpmType_None)
2621 {
2622 InsertConfigNode(pDevices, "tpm", &pDev);
2623 InsertConfigNode(pDev, "0", &pInst);
2624 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2625 InsertConfigNode(pInst, "Config", &pCfg);
2626 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2627
2628 switch (enmTpmType)
2629 {
2630 case TpmType_v1_2:
2631 case TpmType_v2_0:
2632 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");
2633 InsertConfigNode(pLunL0, "Config", &pCfg);
2634 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);
2635 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2636 InsertConfigString(pLunL1, "Driver", "NvramStore");
2637 break;
2638 case TpmType_Host:
2639#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
2640 InsertConfigString(pLunL0, "Driver", "TpmHost");
2641 InsertConfigNode(pLunL0, "Config", &pCfg);
2642#endif
2643 break;
2644 case TpmType_Swtpm:
2645 hrc = ptrTpm->COMGETTER(Location)(bstr.asOutParam()); H();
2646 InsertConfigString(pLunL0, "Driver", "TpmEmu");
2647 InsertConfigNode(pLunL0, "Config", &pCfg);
2648 InsertConfigString(pCfg, "Location", bstr);
2649 break;
2650 default:
2651 AssertFailedBreak();
2652 }
2653 }
2654#endif
2655
2656 /*
2657 * ACPI
2658 */
2659 BOOL fACPI;
2660 hrc = firmwareSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
2661 if (fACPI)
2662 {
2663 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
2664 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
2665 * intelppm driver refuses to register an idle state handler.
2666 * Always show CPU leafs for OS X guests. */
2667 BOOL fShowCpu = fOsXGuest;
2668 if (cCpus > 1 || fIOAPIC)
2669 fShowCpu = true;
2670
2671 BOOL fCpuHotPlug;
2672 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
2673
2674 InsertConfigNode(pDevices, "acpi", &pDev);
2675 InsertConfigNode(pDev, "0", &pInst);
2676 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2677 InsertConfigNode(pInst, "Config", &pCfg);
2678 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
2679
2680 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
2681
2682 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
2683 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
2684 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
2685 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
2686 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
2687 if (fOsXGuest && !llBootNics.empty())
2688 {
2689 BootNic aNic = llBootNics.front();
2690 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
2691 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
2692 }
2693 if (fOsXGuest && fAudioEnabled)
2694 {
2695 PCIBusAddress Address;
2696 if (pBusMgr->findPCIAddress("hda", 0, Address))
2697 {
2698 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
2699 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
2700 }
2701 }
2702 if (fOsXGuest)
2703 {
2704 PCIBusAddress Address;
2705 if (pBusMgr->findPCIAddress("nvme", 0, Address))
2706 {
2707 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
2708 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
2709 }
2710 }
2711 if (enmIommuType == IommuType_AMD)
2712 {
2713 PCIBusAddress Address;
2714 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
2715 {
2716 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
2717 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
2718 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
2719 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
2720 {
2721 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
2722 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
2723 }
2724 else
2725 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2726 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
2727 }
2728 }
2729 else if (enmIommuType == IommuType_Intel)
2730 {
2731 PCIBusAddress Address;
2732 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
2733 {
2734 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
2735 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
2736 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
2737 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
2738 {
2739 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
2740 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
2741 }
2742 else
2743 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2744 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
2745 }
2746 }
2747
2748 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
2749 if (chipsetType == ChipsetType_ICH9)
2750 {
2751 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
2752 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
2753 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */
2754 if (fIsGuest64Bit || fEnablePAE)
2755 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
2756 }
2757 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
2758 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
2759 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
2760
2761 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
2762 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
2763
2764 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
2765 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
2766
2767 if (auSerialIoPortBase[2])
2768 {
2769 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
2770 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
2771 }
2772
2773 if (auSerialIoPortBase[3])
2774 {
2775 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
2776 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
2777 }
2778
2779 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
2780 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
2781
2782 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
2783 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
2784
2785#if defined(VBOX_WITH_TPM)
2786 switch (enmTpmType)
2787 {
2788 case TpmType_v1_2:
2789 InsertConfigString(pCfg, "TpmMode", "tis1.2");
2790 break;
2791 case TpmType_v2_0:
2792 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
2793 break;
2794 /** @todo Host and swtpm. */
2795 default:
2796 break;
2797 }
2798#endif
2799
2800 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2801 InsertConfigString(pLunL0, "Driver", "ACPIHost");
2802 InsertConfigNode(pLunL0, "Config", &pCfg);
2803
2804 /* Attach the dummy CPU drivers */
2805 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
2806 {
2807 BOOL fCpuAttached = true;
2808
2809 if (fCpuHotPlug)
2810 {
2811 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
2812 }
2813
2814 if (fCpuAttached)
2815 {
2816 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
2817 InsertConfigString(pLunL0, "Driver", "ACPICpu");
2818 InsertConfigNode(pLunL0, "Config", &pCfg);
2819 }
2820 }
2821 }
2822
2823 /*
2824 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
2825 */
2826 {
2827 PCFGMNODE pDbgf;
2828 InsertConfigNode(pRoot, "DBGF", &pDbgf);
2829
2830 /* Paths to search for debug info and such things. */
2831 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
2832 Utf8Str strSettingsPath(bstr);
2833 bstr.setNull();
2834 strSettingsPath.stripFilename();
2835 strSettingsPath.append("/");
2836
2837 char szHomeDir[RTPATH_MAX + 1];
2838 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
2839 if (RT_FAILURE(vrc2))
2840 szHomeDir[0] = '\0';
2841 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
2842
2843
2844 Utf8Str strPath;
2845 strPath.append(strSettingsPath).append("debug/;");
2846 strPath.append(strSettingsPath).append(";");
2847 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
2848 strPath.append(szHomeDir);
2849
2850 InsertConfigString(pDbgf, "Path", strPath.c_str());
2851
2852 /* Tracing configuration. */
2853 BOOL fTracingEnabled;
2854 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
2855 if (fTracingEnabled)
2856 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
2857
2858 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
2859 if (fTracingEnabled)
2860 InsertConfigString(pDbgf, "TracingConfig", bstr);
2861
2862 /* Debugger console config. */
2863 PCFGMNODE pDbgc;
2864 InsertConfigNode(pRoot, "DBGC", &pDbgc);
2865
2866 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
2867 Utf8Str strVBoxHome = bstr;
2868 bstr.setNull();
2869 if (strVBoxHome.isNotEmpty())
2870 strVBoxHome.append("/");
2871 else
2872 {
2873 strVBoxHome = szHomeDir;
2874 strVBoxHome.append("/.vbox");
2875 }
2876
2877 Utf8Str strFile(strVBoxHome);
2878 strFile.append("dbgc-history");
2879 InsertConfigString(pDbgc, "HistoryFile", strFile);
2880
2881 strFile = strSettingsPath;
2882 strFile.append("dbgc-init");
2883 InsertConfigString(pDbgc, "LocalInitScript", strFile);
2884
2885 strFile = strVBoxHome;
2886 strFile.append("dbgc-init");
2887 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
2888
2889 /*
2890 * Configure guest debug settings.
2891 */
2892 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
2893 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
2894
2895 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
2896 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
2897 if (enmGstDbgProvider != GuestDebugProvider_None)
2898 {
2899 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
2900 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
2901 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
2902 Utf8Str strAddress = bstr;
2903 bstr.setNull();
2904
2905 ULONG ulPort = 0;
2906 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
2907
2908 PCFGMNODE pDbgSettings;
2909 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
2910 InsertConfigString(pDbgSettings, "Address", strAddress);
2911 InsertConfigInteger(pDbgSettings, "Port", ulPort);
2912
2913 switch (enmGstDbgProvider)
2914 {
2915 case GuestDebugProvider_Native:
2916 InsertConfigString(pDbgSettings, "StubType", "Native");
2917 break;
2918 case GuestDebugProvider_GDB:
2919 InsertConfigString(pDbgSettings, "StubType", "Gdb");
2920 break;
2921 case GuestDebugProvider_KD:
2922 InsertConfigString(pDbgSettings, "StubType", "Kd");
2923 break;
2924 default:
2925 AssertFailed();
2926 break;
2927 }
2928
2929 switch (enmGstDbgIoProvider)
2930 {
2931 case GuestDebugIoProvider_TCP:
2932 InsertConfigString(pDbgSettings, "Provider", "tcp");
2933 break;
2934 case GuestDebugIoProvider_UDP:
2935 InsertConfigString(pDbgSettings, "Provider", "udp");
2936 break;
2937 case GuestDebugIoProvider_IPC:
2938 InsertConfigString(pDbgSettings, "Provider", "ipc");
2939 break;
2940 default:
2941 AssertFailed();
2942 break;
2943 }
2944 }
2945 }
2946 }
2947 catch (ConfigError &x)
2948 {
2949 // InsertConfig threw something:
2950 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
2951 return x.m_vrc;
2952 }
2953 catch (HRESULT hrcXcpt)
2954 {
2955 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2956 }
2957
2958#ifdef VBOX_WITH_EXTPACK
2959 /*
2960 * Call the extension pack hooks if everything went well thus far.
2961 */
2962 if (RT_SUCCESS(vrc))
2963 {
2964 pAlock->release();
2965 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);
2966 pAlock->acquire();
2967 }
2968#endif
2969
2970 /*
2971 * Apply the CFGM overlay.
2972 */
2973 if (RT_SUCCESS(vrc))
2974 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
2975
2976 /*
2977 * Dump all extradata API settings tweaks, both global and per VM.
2978 */
2979 if (RT_SUCCESS(vrc))
2980 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
2981
2982#undef H
2983
2984 pAlock->release(); /* Avoid triggering the lock order inversion check. */
2985
2986 /*
2987 * Register VM state change handler.
2988 */
2989 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
2990 AssertRC(vrc2);
2991 if (RT_SUCCESS(vrc))
2992 vrc = vrc2;
2993
2994 /*
2995 * Register VM runtime error handler.
2996 */
2997 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
2998 AssertRC(vrc2);
2999 if (RT_SUCCESS(vrc))
3000 vrc = vrc2;
3001
3002 pAlock->acquire();
3003
3004 LogFlowFunc(("vrc = %Rrc\n", vrc));
3005 LogFlowFuncLeave();
3006
3007 return vrc;
3008}
3009
3010
3011int Console::i_configGraphicsController(PCFGMNODE pDevices,
3012 const GraphicsControllerType_T enmGraphicsController,
3013 BusAssignmentManager *pBusMgr,
3014 const ComPtr<IMachine> &ptrMachine,
3015 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
3016 const ComPtr<IFirmwareSettings> &ptrFirmwareSettings,
3017 bool fHMEnabled)
3018{
3019 // InsertConfig* throws
3020 try
3021 {
3022 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3023 HRESULT hrc;
3024 Bstr bstr;
3025 const char *pcszDevice = "vga";
3026
3027#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3028 InsertConfigNode(pDevices, pcszDevice, &pDev);
3029 InsertConfigNode(pDev, "0", &pInst);
3030 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3031
3032 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3033 InsertConfigNode(pInst, "Config", &pCfg);
3034 ULONG cVRamMBs;
3035 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
3036 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3037 ULONG cMonitorCount;
3038 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
3039 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3040#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3041 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3042#else
3043 NOREF(fHMEnabled);
3044#endif
3045 BOOL f3DEnabled;
3046 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3047 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3048
3049 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
3050
3051#ifdef VBOX_WITH_VMSVGA
3052 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
3053 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
3054 {
3055 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3056 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3057 {
3058 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
3059 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
3060 }
3061# ifdef VBOX_WITH_VMSVGA3D
3062 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3063# else
3064 LogRel(("VMSVGA3d not available in this build!\n"));
3065# endif /* VBOX_WITH_VMSVGA3D */
3066 }
3067#else
3068 RT_NOREF(enmGraphicsController);
3069#endif /* VBOX_WITH_VMSVGA */
3070
3071 /* Custom VESA mode list */
3072 unsigned cModes = 0;
3073 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3074 {
3075 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3076 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3077 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3078 if (bstr.isEmpty())
3079 break;
3080 InsertConfigString(pCfg, szExtraDataKey, bstr);
3081 ++cModes;
3082 }
3083 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3084
3085 /* VESA height reduction */
3086 ULONG ulHeightReduction;
3087 IFramebuffer *pFramebuffer = NULL;
3088 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3089 if (SUCCEEDED(hrc) && pFramebuffer)
3090 {
3091 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3092 pFramebuffer->Release();
3093 pFramebuffer = NULL;
3094 }
3095 else
3096 {
3097 /* If framebuffer is not available, there is no height reduction. */
3098 ulHeightReduction = 0;
3099 }
3100 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3101
3102 /*
3103 * BIOS logo
3104 */
3105 BOOL fFadeIn;
3106 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3107 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3108 BOOL fFadeOut;
3109 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3110 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3111 ULONG logoDisplayTime;
3112 hrc = ptrFirmwareSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3113 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3114 Bstr bstrLogoImagePath;
3115 hrc = ptrFirmwareSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
3116 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
3117
3118 /*
3119 * Boot menu
3120 */
3121 FirmwareBootMenuMode_T enmBootMenuMode;
3122 int iShowBootMenu;
3123 hrc = ptrFirmwareSettings->COMGETTER(BootMenuMode)(&enmBootMenuMode); H();
3124 switch (enmBootMenuMode)
3125 {
3126 case FirmwareBootMenuMode_Disabled: iShowBootMenu = 0; break;
3127 case FirmwareBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3128 default: iShowBootMenu = 2; break;
3129 }
3130 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3131
3132 /* Attach the display. */
3133 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3134 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3135 InsertConfigNode(pLunL0, "Config", &pCfg);
3136 }
3137 catch (ConfigError &x)
3138 {
3139 // InsertConfig threw something:
3140 return x.m_vrc;
3141 }
3142
3143#undef H
3144
3145 return VINF_SUCCESS;
3146}
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