VirtualBox

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

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

Main: Allow creation of x86 VMs (based on guest OS type or the set architecture) on non-x86 hosts. bugref:10384

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 134.3 KB
Line 
1/* $Id: ConsoleImplConfigX86.cpp 101461 2023-10-17 08:37:28Z 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 PCFGMNODE pPDM;
1153 PCFGMNODE pNode;
1154 PCFGMNODE pMod;
1155 InsertConfigNode(pRoot, "PDM", &pPDM);
1156 InsertConfigNode(pPDM, "Devices", &pNode);
1157 InsertConfigNode(pPDM, "Drivers", &pNode);
1158 InsertConfigNode(pNode, "VBoxC", &pMod);
1159#ifdef VBOX_WITH_XPCOM
1160 // VBoxC is located in the components subdirectory
1161 char szPathVBoxC[RTPATH_MAX];
1162 vrc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX); VRC();
1163 vrc = RTPathAppend(szPathVBoxC, RTPATH_MAX, "/components/VBoxC"); VRC();
1164 InsertConfigString(pMod, "Path", szPathVBoxC);
1165#else
1166 InsertConfigString(pMod, "Path", "VBoxC");
1167#endif
1168
1169
1170 /*
1171 * Block cache settings.
1172 */
1173 PCFGMNODE pPDMBlkCache;
1174 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
1175
1176 /* I/O cache size */
1177 ULONG ioCacheSize = 5;
1178 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
1179 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
1180
1181 /*
1182 * Bandwidth groups.
1183 */
1184 ComPtr<IBandwidthControl> bwCtrl;
1185
1186 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
1187
1188 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
1189 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
1190
1191 PCFGMNODE pAc;
1192 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
1193 PCFGMNODE pAcFile;
1194 InsertConfigNode(pAc, "File", &pAcFile);
1195 PCFGMNODE pAcFileBwGroups;
1196 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
1197#ifdef VBOX_WITH_NETSHAPER
1198 PCFGMNODE pNetworkShaper;
1199 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
1200 PCFGMNODE pNetworkBwGroups;
1201 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
1202#endif /* VBOX_WITH_NETSHAPER */
1203
1204 for (size_t i = 0; i < bwGroups.size(); i++)
1205 {
1206 Bstr strName;
1207 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
1208 if (strName.isEmpty())
1209 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));
1210
1211 BandwidthGroupType_T enmType = BandwidthGroupType_Null;
1212 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
1213 LONG64 cMaxBytesPerSec = 0;
1214 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
1215
1216 if (enmType == BandwidthGroupType_Disk)
1217 {
1218 PCFGMNODE pBwGroup;
1219 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1220 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1221 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
1222 InsertConfigInteger(pBwGroup, "Step", 0);
1223 }
1224#ifdef VBOX_WITH_NETSHAPER
1225 else if (enmType == BandwidthGroupType_Network)
1226 {
1227 /* Network bandwidth groups. */
1228 PCFGMNODE pBwGroup;
1229 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1230 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1231 }
1232#endif /* VBOX_WITH_NETSHAPER */
1233 }
1234
1235 /*
1236 * Devices
1237 */
1238 PCFGMNODE pDevices = NULL; /* /Devices */
1239 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1240 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1241 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1242 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1243 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1244 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1245 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1246
1247 InsertConfigNode(pRoot, "Devices", &pDevices);
1248
1249 /*
1250 * GIM Device
1251 */
1252 if (fGimDeviceNeeded)
1253 {
1254 InsertConfigNode(pDevices, "GIMDev", &pDev);
1255 InsertConfigNode(pDev, "0", &pInst);
1256 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1257 //InsertConfigNode(pInst, "Config", &pCfg);
1258
1259 if (fGimDebug)
1260 {
1261 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1262 InsertConfigString(pLunL0, "Driver", "UDP");
1263 InsertConfigNode(pLunL0, "Config", &pLunL1);
1264 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1265 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1266 }
1267 }
1268
1269 /*
1270 * PC Arch.
1271 */
1272 InsertConfigNode(pDevices, "pcarch", &pDev);
1273 InsertConfigNode(pDev, "0", &pInst);
1274 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1275 InsertConfigNode(pInst, "Config", &pCfg);
1276
1277 /*
1278 * The time offset
1279 */
1280 LONG64 timeOffset;
1281 hrc = firmwareSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1282 PCFGMNODE pTMNode;
1283 InsertConfigNode(pRoot, "TM", &pTMNode);
1284 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1285
1286 /*
1287 * DMA
1288 */
1289 InsertConfigNode(pDevices, "8237A", &pDev);
1290 InsertConfigNode(pDev, "0", &pInst);
1291 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1292
1293 /*
1294 * PCI buses.
1295 */
1296 uint32_t uIocPCIAddress, uHbcPCIAddress;
1297 switch (chipsetType)
1298 {
1299 default:
1300 AssertFailed();
1301 RT_FALL_THRU();
1302 case ChipsetType_PIIX3:
1303 /* Create the base for adding bridges on demand */
1304 InsertConfigNode(pDevices, "pcibridge", NULL);
1305
1306 InsertConfigNode(pDevices, "pci", &pDev);
1307 uHbcPCIAddress = (0x0 << 16) | 0;
1308 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1309 break;
1310 case ChipsetType_ICH9:
1311 /* Create the base for adding bridges on demand */
1312 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1313
1314 InsertConfigNode(pDevices, "ich9pci", &pDev);
1315 uHbcPCIAddress = (0x1e << 16) | 0;
1316 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1317 break;
1318 }
1319 InsertConfigNode(pDev, "0", &pInst);
1320 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1321 InsertConfigNode(pInst, "Config", &pCfg);
1322 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1323 if (chipsetType == ChipsetType_ICH9)
1324 {
1325 /* Provide MCFG info */
1326 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1327 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1328
1329#ifdef VBOX_WITH_PCI_PASSTHROUGH
1330 /* Add PCI passthrough devices */
1331 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1332#endif
1333
1334 if (enmIommuType == IommuType_AMD)
1335 {
1336 /* AMD IOMMU. */
1337 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1338 InsertConfigNode(pDev, "0", &pInst);
1339 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1340 InsertConfigNode(pInst, "Config", &pCfg);
1341 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1342
1343 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1344 {
1345 PCIBusAddress Address;
1346 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1347 {
1348 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1349 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1350 }
1351 else
1352 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1353 N_("Failed to find PCI address of the assigned IOMMU device!"));
1354 }
1355
1356 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1357 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1358 }
1359 else if (enmIommuType == IommuType_Intel)
1360 {
1361 /* Intel IOMMU. */
1362 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1363 InsertConfigNode(pDev, "0", &pInst);
1364 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1365 InsertConfigNode(pInst, "Config", &pCfg);
1366 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1367
1368 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1369 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1370 }
1371 }
1372
1373 /*
1374 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1375 */
1376
1377 /*
1378 * High Precision Event Timer (HPET)
1379 */
1380 BOOL fHPETEnabled;
1381 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1382 hrc = platformX86->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1383 /* so always enable HPET in extended profile */
1384 fHPETEnabled |= fOsXGuest;
1385 /* HPET is always present on ICH9 */
1386 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1387 if (fHPETEnabled)
1388 {
1389 InsertConfigNode(pDevices, "hpet", &pDev);
1390 InsertConfigNode(pDev, "0", &pInst);
1391 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1392 InsertConfigNode(pInst, "Config", &pCfg);
1393 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1394 }
1395
1396 /*
1397 * System Management Controller (SMC)
1398 */
1399 BOOL fSmcEnabled;
1400 fSmcEnabled = fOsXGuest;
1401 if (fSmcEnabled)
1402 {
1403 InsertConfigNode(pDevices, "smc", &pDev);
1404 InsertConfigNode(pDev, "0", &pInst);
1405 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1406 InsertConfigNode(pInst, "Config", &pCfg);
1407
1408 bool fGetKeyFromRealSMC;
1409 Utf8Str strKey;
1410 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1411 AssertRCReturn(vrc, vrc);
1412
1413 if (!fGetKeyFromRealSMC)
1414 InsertConfigString(pCfg, "DeviceKey", strKey);
1415 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1416 }
1417
1418 /*
1419 * Low Pin Count (LPC) bus
1420 */
1421 BOOL fLpcEnabled;
1422 /** @todo implement appropriate getter */
1423 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1424 if (fLpcEnabled)
1425 {
1426 InsertConfigNode(pDevices, "lpc", &pDev);
1427 InsertConfigNode(pDev, "0", &pInst);
1428 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1429 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1430 }
1431
1432 BOOL fShowRtc;
1433 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1434
1435 /*
1436 * PS/2 keyboard & mouse.
1437 */
1438 InsertConfigNode(pDevices, "pckbd", &pDev);
1439 InsertConfigNode(pDev, "0", &pInst);
1440 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1441 InsertConfigNode(pInst, "Config", &pCfg);
1442
1443 KeyboardHIDType_T aKbdHID;
1444 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1445 if (aKbdHID != KeyboardHIDType_None)
1446 {
1447 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1448 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1449 InsertConfigNode(pLunL0, "Config", &pCfg);
1450 InsertConfigInteger(pCfg, "QueueSize", 64);
1451
1452 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1453 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1454 }
1455
1456 PointingHIDType_T aPointingHID;
1457 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1458 if (aPointingHID != PointingHIDType_None)
1459 {
1460 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1461 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1462 InsertConfigNode(pLunL0, "Config", &pCfg);
1463 InsertConfigInteger(pCfg, "QueueSize", 128);
1464
1465 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1466 InsertConfigString(pLunL1, "Driver", "MainMouse");
1467 }
1468
1469 /*
1470 * i8254 Programmable Interval Timer And Dummy Speaker
1471 */
1472 InsertConfigNode(pDevices, "i8254", &pDev);
1473 InsertConfigNode(pDev, "0", &pInst);
1474 InsertConfigNode(pInst, "Config", &pCfg);
1475#ifdef DEBUG
1476 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1477#endif
1478
1479 /*
1480 * i8259 Programmable Interrupt Controller.
1481 */
1482 InsertConfigNode(pDevices, "i8259", &pDev);
1483 InsertConfigNode(pDev, "0", &pInst);
1484 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1485 InsertConfigNode(pInst, "Config", &pCfg);
1486
1487 /*
1488 * Advanced Programmable Interrupt Controller.
1489 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1490 * thus only single insert
1491 */
1492 if (fEnableAPIC)
1493 {
1494 InsertConfigNode(pDevices, "apic", &pDev);
1495 InsertConfigNode(pDev, "0", &pInst);
1496 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1497 InsertConfigNode(pInst, "Config", &pCfg);
1498 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1499 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1500 if (fEnableX2APIC)
1501 enmAPICMode = PDMAPICMODE_X2APIC;
1502 else if (!fEnableAPIC)
1503 enmAPICMode = PDMAPICMODE_NONE;
1504 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1505 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1506
1507 if (fIOAPIC)
1508 {
1509 /*
1510 * I/O Advanced Programmable Interrupt Controller.
1511 */
1512 InsertConfigNode(pDevices, "ioapic", &pDev);
1513 InsertConfigNode(pDev, "0", &pInst);
1514 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1515 InsertConfigNode(pInst, "Config", &pCfg);
1516 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1517 if (enmIommuType == IommuType_AMD)
1518 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1519 else if (enmIommuType == IommuType_Intel)
1520 {
1521 InsertConfigString(pCfg, "ChipType", "DMAR");
1522 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1523 }
1524 }
1525 }
1526
1527 /*
1528 * RTC MC146818.
1529 */
1530 InsertConfigNode(pDevices, "mc146818", &pDev);
1531 InsertConfigNode(pDev, "0", &pInst);
1532 InsertConfigNode(pInst, "Config", &pCfg);
1533 BOOL fRTCUseUTC;
1534 hrc = platform->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1535 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1536
1537 /*
1538 * VGA.
1539 */
1540 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1541 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1542 GraphicsControllerType_T enmGraphicsController;
1543 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1544 switch (enmGraphicsController)
1545 {
1546 case GraphicsControllerType_Null:
1547 break;
1548#ifdef VBOX_WITH_VMSVGA
1549 case GraphicsControllerType_VMSVGA:
1550 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1551 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1552 RT_FALL_THROUGH();
1553 case GraphicsControllerType_VBoxSVGA:
1554#endif
1555 case GraphicsControllerType_VBoxVGA:
1556 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, firmwareSettings,
1557 RT_BOOL(fHMEnabled));
1558 if (FAILED(vrc))
1559 return vrc;
1560 break;
1561 default:
1562 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1563 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1564 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1565 }
1566
1567 /*
1568 * Firmware.
1569 */
1570 FirmwareType_T eFwType = FirmwareType_BIOS;
1571 hrc = firmwareSettings->COMGETTER(FirmwareType)(&eFwType); H();
1572
1573#ifdef VBOX_WITH_EFI
1574 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1575#else
1576 BOOL fEfiEnabled = false;
1577#endif
1578 if (!fEfiEnabled)
1579 {
1580 /*
1581 * PC Bios.
1582 */
1583 InsertConfigNode(pDevices, "pcbios", &pDev);
1584 InsertConfigNode(pDev, "0", &pInst);
1585 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1586 InsertConfigNode(pInst, "Config", &pBiosCfg);
1587 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1588 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1589 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1590 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1591 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1592 BOOL fPXEDebug;
1593 hrc = firmwareSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1594 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1595 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1596 BOOL fUuidLe;
1597 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1598 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1599 BOOL fAutoSerialNumGen;
1600 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1601 if (fAutoSerialNumGen)
1602 InsertConfigString(pBiosCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1603 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1604 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1605 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1606
1607 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1608 VERR_INVALID_PARAMETER);
1609
1610 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1611 {
1612 DeviceType_T enmBootDevice;
1613 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1614
1615 char szParamName[] = "BootDeviceX";
1616 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1617
1618 const char *pszBootDevice;
1619 switch (enmBootDevice)
1620 {
1621 case DeviceType_Null:
1622 pszBootDevice = "NONE";
1623 break;
1624 case DeviceType_HardDisk:
1625 pszBootDevice = "IDE";
1626 break;
1627 case DeviceType_DVD:
1628 pszBootDevice = "DVD";
1629 break;
1630 case DeviceType_Floppy:
1631 pszBootDevice = "FLOPPY";
1632 break;
1633 case DeviceType_Network:
1634 pszBootDevice = "LAN";
1635 break;
1636 default:
1637 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1638 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1639 N_("Invalid boot device '%d'"), enmBootDevice);
1640 }
1641 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1642 }
1643
1644 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1645 * this is required for Windows 2012 guests. */
1646 if (osTypeId == GUEST_OS_ID_STR_X64("Windows2012"))
1647 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1648 }
1649 else
1650 {
1651 /* Autodetect firmware type, basing on guest type */
1652 if (eFwType == FirmwareType_EFI)
1653 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1654 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1655
1656 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1657#ifdef VBOX_WITH_EFI_IN_DD2
1658 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1659 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"
1660 : "VBoxEFI64.fd";
1661#else
1662 Utf8Str efiRomFile;
1663 vrc = findEfiRom(virtualBox, PlatformArchitecture_x86, eFwType, &efiRomFile);
1664 AssertRCReturn(vrc, vrc);
1665 const char *pszEfiRomFile = efiRomFile.c_str();
1666#endif
1667
1668 /* Get boot args */
1669 Utf8Str bootArgs;
1670 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1671
1672 /* Get device props */
1673 Utf8Str deviceProps;
1674 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1675
1676 /* Get NVRAM file name */
1677 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
1678
1679 BOOL fUuidLe;
1680 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1681
1682 BOOL fAutoSerialNumGen;
1683 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1684
1685 /* Get graphics mode settings */
1686 uint32_t u32GraphicsMode = UINT32_MAX;
1687 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1688 if (strTmp.isEmpty())
1689 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1690 if (!strTmp.isEmpty())
1691 u32GraphicsMode = strTmp.toUInt32();
1692
1693 /* Get graphics resolution settings, with some sanity checking */
1694 Utf8Str strResolution;
1695 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1696 if (!strResolution.isEmpty())
1697 {
1698 size_t pos = strResolution.find("x");
1699 if (pos != strResolution.npos)
1700 {
1701 Utf8Str strH, strV;
1702 strH.assignEx(strResolution, 0, pos);
1703 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1704 uint32_t u32H = strH.toUInt32();
1705 uint32_t u32V = strV.toUInt32();
1706 if (u32H == 0 || u32V == 0)
1707 strResolution.setNull();
1708 }
1709 else
1710 strResolution.setNull();
1711 }
1712 else
1713 {
1714 uint32_t u32H = 0;
1715 uint32_t u32V = 0;
1716 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1717 if (strTmp.isEmpty())
1718 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1719 if (!strTmp.isEmpty())
1720 u32H = strTmp.toUInt32();
1721
1722 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1723 if (strTmp.isEmpty())
1724 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1725 if (!strTmp.isEmpty())
1726 u32V = strTmp.toUInt32();
1727 if (u32H != 0 && u32V != 0)
1728 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
1729 }
1730
1731 /*
1732 * EFI subtree.
1733 */
1734 InsertConfigNode(pDevices, "efi", &pDev);
1735 InsertConfigNode(pDev, "0", &pInst);
1736 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1737 InsertConfigNode(pInst, "Config", &pCfg);
1738 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1739 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1740 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1741 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
1742 InsertConfigString(pCfg, "BootArgs", bootArgs);
1743 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1744 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1745 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1746 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1747 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
1748 if (fAutoSerialNumGen)
1749 InsertConfigString(pCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1750 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1751 InsertConfigString(pCfg, "NvramFile", strNvram);
1752 if (u32GraphicsMode != UINT32_MAX)
1753 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1754 if (!strResolution.isEmpty())
1755 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
1756
1757 /* For OS X guests we'll force passing host's DMI info to the guest */
1758 if (fOsXGuest)
1759 {
1760 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1761 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1762 }
1763
1764 /* Attach the NVRAM storage driver. */
1765 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1766 InsertConfigString(pLunL0, "Driver", "NvramStore");
1767 }
1768
1769 /*
1770 * The USB Controllers.
1771 */
1772 com::SafeIfaceArray<IUSBController> usbCtrls;
1773 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
1774 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
1775 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
1776
1777 if (SUCCEEDED(hrc))
1778 {
1779 for (size_t i = 0; i < usbCtrls.size(); ++i)
1780 {
1781 USBControllerType_T enmCtrlType;
1782 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1783 if (enmCtrlType == USBControllerType_OHCI)
1784 {
1785 fOhciPresent = true;
1786 break;
1787 }
1788 else if (enmCtrlType == USBControllerType_XHCI)
1789 {
1790 fXhciPresent = true;
1791 break;
1792 }
1793 }
1794 }
1795 else if (hrc != E_NOTIMPL)
1796 {
1797 H();
1798 }
1799
1800 /*
1801 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
1802 */
1803 if (fOhciPresent || fXhciPresent)
1804 mfVMHasUsbController = true;
1805
1806 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
1807 if (mfVMHasUsbController)
1808 {
1809 for (size_t i = 0; i < usbCtrls.size(); ++i)
1810 {
1811 USBControllerType_T enmCtrlType;
1812 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1813
1814 if (enmCtrlType == USBControllerType_OHCI)
1815 {
1816 InsertConfigNode(pDevices, "usb-ohci", &pDev);
1817 InsertConfigNode(pDev, "0", &pInst);
1818 InsertConfigNode(pInst, "Config", &pCfg);
1819 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1820 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
1821 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1822 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1823 InsertConfigNode(pLunL0, "Config", &pCfg);
1824
1825 /*
1826 * Attach the status driver.
1827 */
1828 i_attachStatusDriver(pInst, DeviceType_USB);
1829 }
1830#ifdef VBOX_WITH_EHCI
1831 else if (enmCtrlType == USBControllerType_EHCI)
1832 {
1833 InsertConfigNode(pDevices, "usb-ehci", &pDev);
1834 InsertConfigNode(pDev, "0", &pInst);
1835 InsertConfigNode(pInst, "Config", &pCfg);
1836 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1837 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
1838
1839 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1840 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1841 InsertConfigNode(pLunL0, "Config", &pCfg);
1842
1843 /*
1844 * Attach the status driver.
1845 */
1846 i_attachStatusDriver(pInst, DeviceType_USB);
1847 }
1848#endif
1849 else if (enmCtrlType == USBControllerType_XHCI)
1850 {
1851 InsertConfigNode(pDevices, "usb-xhci", &pDev);
1852 InsertConfigNode(pDev, "0", &pInst);
1853 InsertConfigNode(pInst, "Config", &pCfg);
1854 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1855 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
1856
1857 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1858 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1859 InsertConfigNode(pLunL0, "Config", &pCfg);
1860
1861 InsertConfigNode(pInst, "LUN#1", &pLunL1);
1862 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
1863 InsertConfigNode(pLunL1, "Config", &pCfg);
1864
1865 /*
1866 * Attach the status driver.
1867 */
1868 i_attachStatusDriver(pInst, DeviceType_USB, 2);
1869 }
1870 } /* for every USB controller. */
1871
1872
1873 /*
1874 * Virtual USB Devices.
1875 */
1876 InsertConfigNode(pRoot, "USB", &pUsbDevices);
1877
1878#ifdef VBOX_WITH_USB
1879 {
1880 /*
1881 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
1882 * on a per device level now.
1883 */
1884 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
1885 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
1886 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
1887 //InsertConfigInteger(pCfg, "Force11Device", true);
1888 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
1889 // that it's documented somewhere.) Users needing it can use:
1890 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
1891 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
1892 }
1893#endif
1894
1895#ifdef VBOX_WITH_USB_CARDREADER
1896 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
1897 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
1898 if (aEmulatedUSBCardReaderEnabled)
1899 {
1900 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
1901 InsertConfigNode(pDev, "0", &pInst);
1902 InsertConfigNode(pInst, "Config", &pCfg);
1903
1904 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1905# ifdef VBOX_WITH_USB_CARDREADER_TEST
1906 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
1907 InsertConfigNode(pLunL0, "Config", &pCfg);
1908# else
1909 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
1910 InsertConfigNode(pLunL0, "Config", &pCfg);
1911# endif
1912 }
1913#endif
1914
1915 /* Virtual USB Mouse/Tablet */
1916 if ( aPointingHID == PointingHIDType_USBMouse
1917 || aPointingHID == PointingHIDType_USBTablet
1918 || aPointingHID == PointingHIDType_USBMultiTouch
1919 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
1920 {
1921 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
1922 InsertConfigNode(pDev, "0", &pInst);
1923 InsertConfigNode(pInst, "Config", &pCfg);
1924
1925 if (aPointingHID == PointingHIDType_USBMouse)
1926 InsertConfigString(pCfg, "Mode", "relative");
1927 else
1928 InsertConfigString(pCfg, "Mode", "absolute");
1929 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1930 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1931 InsertConfigNode(pLunL0, "Config", &pCfg);
1932 InsertConfigInteger(pCfg, "QueueSize", 128);
1933
1934 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1935 InsertConfigString(pLunL1, "Driver", "MainMouse");
1936 }
1937 if ( aPointingHID == PointingHIDType_USBMultiTouch
1938 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
1939 {
1940 InsertConfigNode(pDev, "1", &pInst);
1941 InsertConfigNode(pInst, "Config", &pCfg);
1942
1943 InsertConfigString(pCfg, "Mode", "multitouch");
1944 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1945 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1946 InsertConfigNode(pLunL0, "Config", &pCfg);
1947 InsertConfigInteger(pCfg, "QueueSize", 128);
1948
1949 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1950 InsertConfigString(pLunL1, "Driver", "MainMouse");
1951 }
1952 if (aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)
1953 {
1954 InsertConfigNode(pDev, "2", &pInst);
1955 InsertConfigNode(pInst, "Config", &pCfg);
1956
1957 InsertConfigString(pCfg, "Mode", "touchpad");
1958 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1959 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1960 InsertConfigNode(pLunL0, "Config", &pCfg);
1961 InsertConfigInteger(pCfg, "QueueSize", 128);
1962
1963 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1964 InsertConfigString(pLunL1, "Driver", "MainMouse");
1965 }
1966
1967 /* Virtual USB Keyboard */
1968 if (aKbdHID == KeyboardHIDType_USBKeyboard)
1969 {
1970 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
1971 InsertConfigNode(pDev, "0", &pInst);
1972 InsertConfigNode(pInst, "Config", &pCfg);
1973
1974 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1975 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1976 InsertConfigNode(pLunL0, "Config", &pCfg);
1977 InsertConfigInteger(pCfg, "QueueSize", 64);
1978
1979 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1980 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1981 }
1982 }
1983
1984 /*
1985 * Storage controllers.
1986 */
1987 com::SafeIfaceArray<IStorageController> ctrls;
1988 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
1989 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
1990
1991 bool fFdcEnabled = false;
1992 for (size_t i = 0; i < ctrls.size(); ++i)
1993 {
1994 DeviceType_T *paLedDevType = NULL;
1995
1996 StorageControllerType_T enmCtrlType;
1997 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
1998 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
1999 || enmCtrlType == StorageControllerType_USB);
2000
2001 StorageBus_T enmBus;
2002 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
2003
2004 Bstr controllerName;
2005 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
2006
2007 ULONG ulInstance = 999;
2008 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
2009
2010 BOOL fUseHostIOCache;
2011 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
2012
2013 BOOL fBootable;
2014 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
2015
2016 PCFGMNODE pCtlInst = NULL;
2017 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
2018 if (enmCtrlType != StorageControllerType_USB)
2019 {
2020 /* /Devices/<ctrldev>/ */
2021 pDev = aCtrlNodes[enmCtrlType];
2022 if (!pDev)
2023 {
2024 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
2025 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
2026 }
2027
2028 /* /Devices/<ctrldev>/<instance>/ */
2029 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
2030
2031 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
2032 InsertConfigInteger(pCtlInst, "Trusted", 1);
2033 InsertConfigNode(pCtlInst, "Config", &pCfg);
2034 }
2035
2036 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
2037 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
2038
2039 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
2040 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
2041
2042 switch (enmCtrlType)
2043 {
2044 case StorageControllerType_LsiLogic:
2045 {
2046 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
2047
2048 InsertConfigInteger(pCfg, "Bootable", fBootable);
2049
2050 /* BIOS configuration values, first SCSI controller only. */
2051 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
2052 && !pBusMgr->hasPCIDevice("buslogic", 0)
2053 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2054 && pBiosCfg)
2055 {
2056 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
2057 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2058 }
2059
2060 /* Attach the status driver */
2061 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2062 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2063 break;
2064 }
2065
2066 case StorageControllerType_BusLogic:
2067 {
2068 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
2069
2070 InsertConfigInteger(pCfg, "Bootable", fBootable);
2071
2072 /* BIOS configuration values, first SCSI controller only. */
2073 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2074 && !pBusMgr->hasPCIDevice("buslogic", 1)
2075 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2076 && pBiosCfg)
2077 {
2078 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
2079 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2080 }
2081
2082 /* Attach the status driver */
2083 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2084 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2085 break;
2086 }
2087
2088 case StorageControllerType_IntelAhci:
2089 {
2090 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2091
2092 ULONG cPorts = 0;
2093 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2094 InsertConfigInteger(pCfg, "PortCount", cPorts);
2095 InsertConfigInteger(pCfg, "Bootable", fBootable);
2096
2097 com::SafeIfaceArray<IMediumAttachment> atts;
2098 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2099 ComSafeArrayAsOutParam(atts)); H();
2100
2101 /* Configure the hotpluggable flag for the port. */
2102 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2103 {
2104 IMediumAttachment *pMediumAtt = atts[idxAtt];
2105
2106 LONG lPortNum = 0;
2107 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2108
2109 BOOL fHotPluggable = FALSE;
2110 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2111 if (SUCCEEDED(hrc))
2112 {
2113 PCFGMNODE pPortCfg;
2114 char szName[24];
2115 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2116
2117 InsertConfigNode(pCfg, szName, &pPortCfg);
2118 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2119 }
2120 }
2121
2122 /* BIOS configuration values, first AHCI controller only. */
2123 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2124 && pBiosCfg)
2125 {
2126 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2127 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2128 }
2129
2130 /* Attach the status driver */
2131 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2132 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2133 break;
2134 }
2135
2136 case StorageControllerType_PIIX3:
2137 case StorageControllerType_PIIX4:
2138 case StorageControllerType_ICH6:
2139 {
2140 /*
2141 * IDE (update this when the main interface changes)
2142 */
2143 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2144 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2145
2146 /* Attach the status driver */
2147 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
2148 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2149
2150 /* IDE flavors */
2151 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2152 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2153 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2154 break;
2155 }
2156
2157 case StorageControllerType_I82078:
2158 {
2159 /*
2160 * i82078 Floppy drive controller
2161 */
2162 fFdcEnabled = true;
2163 InsertConfigInteger(pCfg, "IRQ", 6);
2164 InsertConfigInteger(pCfg, "DMA", 2);
2165 InsertConfigInteger(pCfg, "MemMapped", 0 );
2166 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2167
2168 /* Attach the status driver */
2169 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),
2170 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
2171 break;
2172 }
2173
2174 case StorageControllerType_LsiLogicSas:
2175 {
2176 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2177
2178 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2179 InsertConfigInteger(pCfg, "Bootable", fBootable);
2180
2181 /* BIOS configuration values, first SCSI controller only. */
2182 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2183 && !pBusMgr->hasPCIDevice("buslogic", 0)
2184 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2185 && pBiosCfg)
2186 {
2187 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2188 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2189 }
2190
2191 ULONG cPorts = 0;
2192 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2193 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2194
2195 /* Attach the status driver */
2196 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
2197 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2198 break;
2199 }
2200
2201 case StorageControllerType_USB:
2202 {
2203 if (pUsbDevices)
2204 {
2205 /*
2206 * USB MSDs are handled a bit different as the device instance
2207 * doesn't match the storage controller instance but the port.
2208 */
2209 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2210 pCtlInst = pDev;
2211 }
2212 else
2213 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2214 N_("There is no USB controller enabled but there\n"
2215 "is at least one USB storage device configured for this VM.\n"
2216 "To fix this problem either enable the USB controller or remove\n"
2217 "the storage device from the VM"));
2218 break;
2219 }
2220
2221 case StorageControllerType_NVMe:
2222 {
2223 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2224
2225 ULONG cPorts = 0;
2226 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2227 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2228
2229 /* Attach the status driver */
2230 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
2231 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
2232 break;
2233 }
2234
2235 case StorageControllerType_VirtioSCSI:
2236 {
2237 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
2238
2239 ULONG cPorts = 0;
2240 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2241 InsertConfigInteger(pCfg, "NumTargets", cPorts);
2242 InsertConfigInteger(pCfg, "Bootable", fBootable);
2243
2244 /* Attach the status driver */
2245 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
2246 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
2247 break;
2248 }
2249
2250 default:
2251 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2252 }
2253
2254 /* Attach the media to the storage controllers. */
2255 com::SafeIfaceArray<IMediumAttachment> atts;
2256 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2257 ComSafeArrayAsOutParam(atts)); H();
2258
2259 /* Builtin I/O cache - per device setting. */
2260 BOOL fBuiltinIOCache = true;
2261 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2262
2263 bool fInsertDiskIntegrityDrv = false;
2264 Bstr strDiskIntegrityFlag;
2265 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2266 strDiskIntegrityFlag.asOutParam());
2267 if ( hrc == S_OK
2268 && strDiskIntegrityFlag == "1")
2269 fInsertDiskIntegrityDrv = true;
2270
2271 for (size_t j = 0; j < atts.size(); ++j)
2272 {
2273 IMediumAttachment *pMediumAtt = atts[j];
2274 vrc = i_configMediumAttachment(pszCtrlDev,
2275 ulInstance,
2276 enmBus,
2277 !!fUseHostIOCache,
2278 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2279 fInsertDiskIntegrityDrv,
2280 false /* fSetupMerge */,
2281 0 /* uMergeSource */,
2282 0 /* uMergeTarget */,
2283 pMediumAtt,
2284 mMachineState,
2285 NULL /* phrc */,
2286 false /* fAttachDetach */,
2287 false /* fForceUnmount */,
2288 false /* fHotplug */,
2289 pUVM,
2290 pVMM,
2291 paLedDevType,
2292 NULL /* ppLunL0 */);
2293 if (RT_FAILURE(vrc))
2294 return vrc;
2295 }
2296 H();
2297 }
2298 H();
2299
2300 /*
2301 * Network adapters
2302 */
2303#ifdef VMWARE_NET_IN_SLOT_11
2304 bool fSwapSlots3and11 = false;
2305#endif
2306 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2307 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2308#ifdef VBOX_WITH_E1000
2309 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2310 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2311#endif
2312#ifdef VBOX_WITH_VIRTIO
2313 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2314 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2315#endif /* VBOX_WITH_VIRTIO */
2316 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
2317 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
2318 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
2319 InsertConfigNode(pDevices, "3c501", &pDev3C501);
2320
2321 std::list<BootNic> llBootNics;
2322 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
2323 {
2324 ComPtr<INetworkAdapter> networkAdapter;
2325 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
2326 BOOL fEnabledNetAdapter = FALSE;
2327 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2328 if (!fEnabledNetAdapter)
2329 continue;
2330
2331 /*
2332 * The virtual hardware type. Create appropriate device first.
2333 */
2334 const char *pszAdapterName = "pcnet";
2335 NetworkAdapterType_T adapterType;
2336 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2337 switch (adapterType)
2338 {
2339 case NetworkAdapterType_Am79C970A:
2340 case NetworkAdapterType_Am79C973:
2341 case NetworkAdapterType_Am79C960:
2342 pDev = pDevPCNet;
2343 break;
2344#ifdef VBOX_WITH_E1000
2345 case NetworkAdapterType_I82540EM:
2346 case NetworkAdapterType_I82543GC:
2347 case NetworkAdapterType_I82545EM:
2348 pDev = pDevE1000;
2349 pszAdapterName = "e1000";
2350 break;
2351#endif
2352#ifdef VBOX_WITH_VIRTIO
2353 case NetworkAdapterType_Virtio:
2354 pDev = pDevVirtioNet;
2355 pszAdapterName = "virtio-net";
2356 break;
2357#endif /* VBOX_WITH_VIRTIO */
2358 case NetworkAdapterType_NE1000:
2359 case NetworkAdapterType_NE2000:
2360 case NetworkAdapterType_WD8003:
2361 case NetworkAdapterType_WD8013:
2362 case NetworkAdapterType_ELNK2:
2363 pDev = pDevDP8390;
2364 break;
2365 case NetworkAdapterType_ELNK1:
2366 pDev = pDev3C501;
2367 break;
2368 default:
2369 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
2370 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2371 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
2372 }
2373
2374 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
2375 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2376 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2377 * next 4 get 16..19. */
2378 int iPCIDeviceNo;
2379 switch (uInstance)
2380 {
2381 case 0:
2382 iPCIDeviceNo = 3;
2383 break;
2384 case 1: case 2: case 3:
2385 iPCIDeviceNo = uInstance - 1 + 8;
2386 break;
2387 case 4: case 5: case 6: case 7:
2388 iPCIDeviceNo = uInstance - 4 + 16;
2389 break;
2390 default:
2391 /* auto assignment */
2392 iPCIDeviceNo = -1;
2393 break;
2394 }
2395#ifdef VMWARE_NET_IN_SLOT_11
2396 /*
2397 * Dirty hack for PCI slot compatibility with VMWare,
2398 * it assigns slot 0x11 to the first network controller.
2399 */
2400 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2401 {
2402 iPCIDeviceNo = 0x11;
2403 fSwapSlots3and11 = true;
2404 }
2405 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2406 iPCIDeviceNo = 3;
2407#endif
2408 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2409 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2410
2411 InsertConfigNode(pInst, "Config", &pCfg);
2412#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2413 if (pDev == pDevPCNet)
2414 InsertConfigInteger(pCfg, "R0Enabled", false);
2415#endif
2416 /*
2417 * Collect information needed for network booting and add it to the list.
2418 */
2419 BootNic nic;
2420
2421 nic.mInstance = uInstance;
2422 /* Could be updated by reference, if auto assigned */
2423 nic.mPCIAddress = PCIAddr;
2424
2425 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2426
2427 llBootNics.push_back(nic);
2428
2429 /*
2430 * The virtual hardware type. PCNet supports three types, E1000 three,
2431 * but VirtIO only one.
2432 */
2433 switch (adapterType)
2434 {
2435 case NetworkAdapterType_Am79C970A:
2436 InsertConfigString(pCfg, "ChipType", "Am79C970A");
2437 break;
2438 case NetworkAdapterType_Am79C973:
2439 InsertConfigString(pCfg, "ChipType", "Am79C973");
2440 break;
2441 case NetworkAdapterType_Am79C960:
2442 InsertConfigString(pCfg, "ChipType", "Am79C960");
2443 break;
2444 case NetworkAdapterType_I82540EM:
2445 InsertConfigInteger(pCfg, "AdapterType", 0);
2446 break;
2447 case NetworkAdapterType_I82543GC:
2448 InsertConfigInteger(pCfg, "AdapterType", 1);
2449 break;
2450 case NetworkAdapterType_I82545EM:
2451 InsertConfigInteger(pCfg, "AdapterType", 2);
2452 break;
2453 case NetworkAdapterType_Virtio:
2454 break;
2455 case NetworkAdapterType_NE1000:
2456 InsertConfigString(pCfg, "DeviceType", "NE1000");
2457 break;
2458 case NetworkAdapterType_NE2000:
2459 InsertConfigString(pCfg, "DeviceType", "NE2000");
2460 break;
2461 case NetworkAdapterType_WD8003:
2462 InsertConfigString(pCfg, "DeviceType", "WD8003");
2463 break;
2464 case NetworkAdapterType_WD8013:
2465 InsertConfigString(pCfg, "DeviceType", "WD8013");
2466 break;
2467 case NetworkAdapterType_ELNK2:
2468 InsertConfigString(pCfg, "DeviceType", "3C503");
2469 break;
2470 case NetworkAdapterType_ELNK1:
2471 break;
2472 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
2473#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
2474 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
2475#endif
2476 }
2477
2478 /*
2479 * Get the MAC address and convert it to binary representation
2480 */
2481 Bstr macAddr;
2482 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2483 Assert(!macAddr.isEmpty());
2484 Utf8Str macAddrUtf8 = macAddr;
2485#ifdef VBOX_WITH_CLOUD_NET
2486 NetworkAttachmentType_T eAttachmentType;
2487 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
2488 if (eAttachmentType == NetworkAttachmentType_Cloud)
2489 {
2490 mGateway.setLocalMacAddress(macAddrUtf8);
2491 /* We'll insert cloud MAC later, when it becomes known. */
2492 }
2493 else
2494 {
2495#endif
2496 char *macStr = (char*)macAddrUtf8.c_str();
2497 Assert(strlen(macStr) == 12);
2498 RTMAC Mac;
2499 RT_ZERO(Mac);
2500 char *pMac = (char*)&Mac;
2501 for (uint32_t i = 0; i < 6; ++i)
2502 {
2503 int c1 = *macStr++ - '0';
2504 if (c1 > 9)
2505 c1 -= 7;
2506 int c2 = *macStr++ - '0';
2507 if (c2 > 9)
2508 c2 -= 7;
2509 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2510 }
2511 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2512#ifdef VBOX_WITH_CLOUD_NET
2513 }
2514#endif
2515 /*
2516 * Check if the cable is supposed to be unplugged
2517 */
2518 BOOL fCableConnected;
2519 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2520 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2521
2522 /*
2523 * Line speed to report from custom drivers
2524 */
2525 ULONG ulLineSpeed;
2526 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2527 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2528
2529 /*
2530 * Attach the status driver.
2531 */
2532 i_attachStatusDriver(pInst, DeviceType_Network);
2533
2534 /*
2535 * Configure the network card now
2536 */
2537 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2538 vrc = i_configNetwork(pszAdapterName,
2539 uInstance,
2540 0,
2541 networkAdapter,
2542 pCfg,
2543 pLunL0,
2544 pInst,
2545 false /*fAttachDetach*/,
2546 fIgnoreConnectFailure,
2547 pUVM,
2548 pVMM);
2549 if (RT_FAILURE(vrc))
2550 return vrc;
2551 }
2552
2553 /*
2554 * Build network boot information and transfer it to the BIOS.
2555 */
2556 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2557 {
2558 llBootNics.sort(); /* Sort the list by boot priority. */
2559
2560 char achBootIdx[] = "0";
2561 unsigned uBootIdx = 0;
2562
2563 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2564 {
2565 /* A NIC with priority 0 is only used if it's first in the list. */
2566 if (it->mBootPrio == 0 && uBootIdx != 0)
2567 break;
2568
2569 PCFGMNODE pNetBtDevCfg;
2570 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2571 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2572 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2573 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2574 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2575 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2576 }
2577 }
2578
2579 /*
2580 * Serial (UART) Ports
2581 */
2582 /* serial enabled mask to be passed to dev ACPI */
2583 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2584 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2585 InsertConfigNode(pDevices, "serial", &pDev);
2586 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2587 {
2588 ComPtr<ISerialPort> serialPort;
2589 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2590 BOOL fEnabledSerPort = FALSE;
2591 if (serialPort)
2592 {
2593 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2594 }
2595 if (!fEnabledSerPort)
2596 {
2597 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
2598 continue;
2599 }
2600
2601 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2602 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2603 InsertConfigNode(pInst, "Config", &pCfg);
2604
2605 ULONG ulIRQ;
2606 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2607 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2608 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2609
2610 ULONG ulIOBase;
2611 hrc = serialPort->COMGETTER(IOAddress)(&ulIOBase); H();
2612 InsertConfigInteger(pCfg, "IOAddress", ulIOBase);
2613 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2614
2615 BOOL fServer;
2616 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2617 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2618 UartType_T eUartType;
2619 const char *pszUartType;
2620 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2621 switch (eUartType)
2622 {
2623 case UartType_U16450: pszUartType = "16450"; break;
2624 case UartType_U16750: pszUartType = "16750"; break;
2625 default: AssertFailed(); RT_FALL_THRU();
2626 case UartType_U16550A: pszUartType = "16550A"; break;
2627 }
2628 InsertConfigString(pCfg, "UartType", pszUartType);
2629
2630 PortMode_T eHostMode;
2631 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2632
2633 m_aeSerialPortMode[ulInstance] = eHostMode;
2634 if (eHostMode != PortMode_Disconnected)
2635 {
2636 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2637 if (RT_FAILURE(vrc))
2638 return vrc;
2639 }
2640 }
2641
2642 /*
2643 * Parallel (LPT) Ports
2644 */
2645 /* parallel enabled mask to be passed to dev ACPI */
2646 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2647 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2648 InsertConfigNode(pDevices, "parallel", &pDev);
2649 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2650 {
2651 ComPtr<IParallelPort> parallelPort;
2652 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2653 BOOL fEnabledParPort = FALSE;
2654 if (parallelPort)
2655 {
2656 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2657 }
2658 if (!fEnabledParPort)
2659 continue;
2660
2661 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2662 InsertConfigNode(pInst, "Config", &pCfg);
2663
2664 ULONG ulIRQ;
2665 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2666 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2667 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2668 ULONG ulIOBase;
2669 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2670 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2671 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2672
2673 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2674 if (!bstr.isEmpty())
2675 {
2676 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2677 InsertConfigString(pLunL0, "Driver", "HostParallel");
2678 InsertConfigNode(pLunL0, "Config", &pLunL1);
2679 InsertConfigString(pLunL1, "DevicePath", bstr);
2680 }
2681 }
2682
2683 vrc = i_configVmmDev(pMachine, pBusMgr, pDevices); VRC();
2684
2685 /*
2686 * Audio configuration.
2687 */
2688 bool fAudioEnabled = false;
2689 vrc = i_configAudioCtrl(virtualBox, pMachine, pBusMgr, pDevices,
2690 fOsXGuest, &fAudioEnabled); VRC();
2691
2692#if defined(VBOX_WITH_TPM)
2693 /*
2694 * Configure the Trusted Platform Module.
2695 */
2696 ComObjPtr<ITrustedPlatformModule> ptrTpm;
2697 TpmType_T enmTpmType = TpmType_None;
2698
2699 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
2700 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
2701 if (enmTpmType != TpmType_None)
2702 {
2703 InsertConfigNode(pDevices, "tpm", &pDev);
2704 InsertConfigNode(pDev, "0", &pInst);
2705 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2706 InsertConfigNode(pInst, "Config", &pCfg);
2707 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2708
2709 switch (enmTpmType)
2710 {
2711 case TpmType_v1_2:
2712 case TpmType_v2_0:
2713 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");
2714 InsertConfigNode(pLunL0, "Config", &pCfg);
2715 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);
2716 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2717 InsertConfigString(pLunL1, "Driver", "NvramStore");
2718 break;
2719 case TpmType_Host:
2720#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
2721 InsertConfigString(pLunL0, "Driver", "TpmHost");
2722 InsertConfigNode(pLunL0, "Config", &pCfg);
2723#endif
2724 break;
2725 case TpmType_Swtpm:
2726 hrc = ptrTpm->COMGETTER(Location)(bstr.asOutParam()); H();
2727 InsertConfigString(pLunL0, "Driver", "TpmEmu");
2728 InsertConfigNode(pLunL0, "Config", &pCfg);
2729 InsertConfigString(pCfg, "Location", bstr);
2730 break;
2731 default:
2732 AssertFailedBreak();
2733 }
2734 }
2735#endif
2736
2737 /*
2738 * ACPI
2739 */
2740 BOOL fACPI;
2741 hrc = firmwareSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
2742 if (fACPI)
2743 {
2744 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
2745 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
2746 * intelppm driver refuses to register an idle state handler.
2747 * Always show CPU leafs for OS X guests. */
2748 BOOL fShowCpu = fOsXGuest;
2749 if (cCpus > 1 || fIOAPIC)
2750 fShowCpu = true;
2751
2752 BOOL fCpuHotPlug;
2753 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
2754
2755 InsertConfigNode(pDevices, "acpi", &pDev);
2756 InsertConfigNode(pDev, "0", &pInst);
2757 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2758 InsertConfigNode(pInst, "Config", &pCfg);
2759 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
2760
2761 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
2762
2763 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
2764 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
2765 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
2766 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
2767 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
2768 if (fOsXGuest && !llBootNics.empty())
2769 {
2770 BootNic aNic = llBootNics.front();
2771 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
2772 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
2773 }
2774 if (fOsXGuest && fAudioEnabled)
2775 {
2776 PCIBusAddress Address;
2777 if (pBusMgr->findPCIAddress("hda", 0, Address))
2778 {
2779 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
2780 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
2781 }
2782 }
2783 if (fOsXGuest)
2784 {
2785 PCIBusAddress Address;
2786 if (pBusMgr->findPCIAddress("nvme", 0, Address))
2787 {
2788 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
2789 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
2790 }
2791 }
2792 if (enmIommuType == IommuType_AMD)
2793 {
2794 PCIBusAddress Address;
2795 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
2796 {
2797 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
2798 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
2799 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
2800 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
2801 {
2802 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
2803 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
2804 }
2805 else
2806 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2807 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
2808 }
2809 }
2810 else if (enmIommuType == IommuType_Intel)
2811 {
2812 PCIBusAddress Address;
2813 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
2814 {
2815 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
2816 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
2817 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
2818 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
2819 {
2820 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
2821 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
2822 }
2823 else
2824 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2825 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
2826 }
2827 }
2828
2829 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
2830 if (chipsetType == ChipsetType_ICH9)
2831 {
2832 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
2833 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
2834 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */
2835 if (fIsGuest64Bit || fEnablePAE)
2836 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
2837 }
2838 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
2839 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
2840 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
2841
2842 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
2843 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
2844
2845 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
2846 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
2847
2848 if (auSerialIoPortBase[2])
2849 {
2850 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
2851 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
2852 }
2853
2854 if (auSerialIoPortBase[3])
2855 {
2856 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
2857 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
2858 }
2859
2860 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
2861 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
2862
2863 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
2864 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
2865
2866#if defined(VBOX_WITH_TPM)
2867 switch (enmTpmType)
2868 {
2869 case TpmType_v1_2:
2870 InsertConfigString(pCfg, "TpmMode", "tis1.2");
2871 break;
2872 case TpmType_v2_0:
2873 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
2874 break;
2875 /** @todo Host and swtpm. */
2876 default:
2877 break;
2878 }
2879#endif
2880
2881 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2882 InsertConfigString(pLunL0, "Driver", "ACPIHost");
2883 InsertConfigNode(pLunL0, "Config", &pCfg);
2884
2885 /* Attach the dummy CPU drivers */
2886 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
2887 {
2888 BOOL fCpuAttached = true;
2889
2890 if (fCpuHotPlug)
2891 {
2892 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
2893 }
2894
2895 if (fCpuAttached)
2896 {
2897 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
2898 InsertConfigString(pLunL0, "Driver", "ACPICpu");
2899 InsertConfigNode(pLunL0, "Config", &pCfg);
2900 }
2901 }
2902 }
2903
2904 /*
2905 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
2906 */
2907 {
2908 PCFGMNODE pDbgf;
2909 InsertConfigNode(pRoot, "DBGF", &pDbgf);
2910
2911 /* Paths to search for debug info and such things. */
2912 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
2913 Utf8Str strSettingsPath(bstr);
2914 bstr.setNull();
2915 strSettingsPath.stripFilename();
2916 strSettingsPath.append("/");
2917
2918 char szHomeDir[RTPATH_MAX + 1];
2919 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
2920 if (RT_FAILURE(vrc2))
2921 szHomeDir[0] = '\0';
2922 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
2923
2924
2925 Utf8Str strPath;
2926 strPath.append(strSettingsPath).append("debug/;");
2927 strPath.append(strSettingsPath).append(";");
2928 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
2929 strPath.append(szHomeDir);
2930
2931 InsertConfigString(pDbgf, "Path", strPath.c_str());
2932
2933 /* Tracing configuration. */
2934 BOOL fTracingEnabled;
2935 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
2936 if (fTracingEnabled)
2937 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
2938
2939 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
2940 if (fTracingEnabled)
2941 InsertConfigString(pDbgf, "TracingConfig", bstr);
2942
2943 BOOL fAllowTracingToAccessVM;
2944 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
2945 if (fAllowTracingToAccessVM)
2946 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
2947
2948 /* Debugger console config. */
2949 PCFGMNODE pDbgc;
2950 InsertConfigNode(pRoot, "DBGC", &pDbgc);
2951
2952 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
2953 Utf8Str strVBoxHome = bstr;
2954 bstr.setNull();
2955 if (strVBoxHome.isNotEmpty())
2956 strVBoxHome.append("/");
2957 else
2958 {
2959 strVBoxHome = szHomeDir;
2960 strVBoxHome.append("/.vbox");
2961 }
2962
2963 Utf8Str strFile(strVBoxHome);
2964 strFile.append("dbgc-history");
2965 InsertConfigString(pDbgc, "HistoryFile", strFile);
2966
2967 strFile = strSettingsPath;
2968 strFile.append("dbgc-init");
2969 InsertConfigString(pDbgc, "LocalInitScript", strFile);
2970
2971 strFile = strVBoxHome;
2972 strFile.append("dbgc-init");
2973 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
2974
2975 /*
2976 * Configure guest debug settings.
2977 */
2978 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
2979 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
2980
2981 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
2982 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
2983 if (enmGstDbgProvider != GuestDebugProvider_None)
2984 {
2985 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
2986 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
2987 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
2988 Utf8Str strAddress = bstr;
2989 bstr.setNull();
2990
2991 ULONG ulPort = 0;
2992 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
2993
2994 PCFGMNODE pDbgSettings;
2995 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
2996 InsertConfigString(pDbgSettings, "Address", strAddress);
2997 InsertConfigInteger(pDbgSettings, "Port", ulPort);
2998
2999 switch (enmGstDbgProvider)
3000 {
3001 case GuestDebugProvider_Native:
3002 InsertConfigString(pDbgSettings, "StubType", "Native");
3003 break;
3004 case GuestDebugProvider_GDB:
3005 InsertConfigString(pDbgSettings, "StubType", "Gdb");
3006 break;
3007 case GuestDebugProvider_KD:
3008 InsertConfigString(pDbgSettings, "StubType", "Kd");
3009 break;
3010 default:
3011 AssertFailed();
3012 break;
3013 }
3014
3015 switch (enmGstDbgIoProvider)
3016 {
3017 case GuestDebugIoProvider_TCP:
3018 InsertConfigString(pDbgSettings, "Provider", "tcp");
3019 break;
3020 case GuestDebugIoProvider_UDP:
3021 InsertConfigString(pDbgSettings, "Provider", "udp");
3022 break;
3023 case GuestDebugIoProvider_IPC:
3024 InsertConfigString(pDbgSettings, "Provider", "ipc");
3025 break;
3026 default:
3027 AssertFailed();
3028 break;
3029 }
3030 }
3031 }
3032 }
3033 catch (ConfigError &x)
3034 {
3035 // InsertConfig threw something:
3036 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
3037 return x.m_vrc;
3038 }
3039 catch (HRESULT hrcXcpt)
3040 {
3041 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3042 }
3043
3044#ifdef VBOX_WITH_EXTPACK
3045 /*
3046 * Call the extension pack hooks if everything went well thus far.
3047 */
3048 if (RT_SUCCESS(vrc))
3049 {
3050 pAlock->release();
3051 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);
3052 pAlock->acquire();
3053 }
3054#endif
3055
3056 /*
3057 * Apply the CFGM overlay.
3058 */
3059 if (RT_SUCCESS(vrc))
3060 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3061
3062 /*
3063 * Dump all extradata API settings tweaks, both global and per VM.
3064 */
3065 if (RT_SUCCESS(vrc))
3066 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3067
3068#undef H
3069
3070 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3071
3072 /*
3073 * Register VM state change handler.
3074 */
3075 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3076 AssertRC(vrc2);
3077 if (RT_SUCCESS(vrc))
3078 vrc = vrc2;
3079
3080 /*
3081 * Register VM runtime error handler.
3082 */
3083 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3084 AssertRC(vrc2);
3085 if (RT_SUCCESS(vrc))
3086 vrc = vrc2;
3087
3088 pAlock->acquire();
3089
3090 LogFlowFunc(("vrc = %Rrc\n", vrc));
3091 LogFlowFuncLeave();
3092
3093 return vrc;
3094}
3095
3096
3097int Console::i_configGraphicsController(PCFGMNODE pDevices,
3098 const GraphicsControllerType_T enmGraphicsController,
3099 BusAssignmentManager *pBusMgr,
3100 const ComPtr<IMachine> &ptrMachine,
3101 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
3102 const ComPtr<IFirmwareSettings> &ptrFirmwareSettings,
3103 bool fHMEnabled)
3104{
3105 // InsertConfig* throws
3106 try
3107 {
3108 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3109 HRESULT hrc;
3110 Bstr bstr;
3111 const char *pcszDevice = "vga";
3112
3113#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3114 InsertConfigNode(pDevices, pcszDevice, &pDev);
3115 InsertConfigNode(pDev, "0", &pInst);
3116 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3117
3118 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3119 InsertConfigNode(pInst, "Config", &pCfg);
3120 ULONG cVRamMBs;
3121 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
3122 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3123 ULONG cMonitorCount;
3124 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
3125 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3126#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3127 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3128#else
3129 NOREF(fHMEnabled);
3130#endif
3131 BOOL f3DEnabled;
3132 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3133 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3134
3135 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
3136
3137#ifdef VBOX_WITH_VMSVGA
3138 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
3139 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
3140 {
3141 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3142 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3143 {
3144 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
3145 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
3146 }
3147# ifdef VBOX_WITH_VMSVGA3D
3148 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3149# else
3150 LogRel(("VMSVGA3d not available in this build!\n"));
3151# endif /* VBOX_WITH_VMSVGA3D */
3152 }
3153#else
3154 RT_NOREF(enmGraphicsController);
3155#endif /* VBOX_WITH_VMSVGA */
3156
3157 /* Custom VESA mode list */
3158 unsigned cModes = 0;
3159 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3160 {
3161 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3162 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3163 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3164 if (bstr.isEmpty())
3165 break;
3166 InsertConfigString(pCfg, szExtraDataKey, bstr);
3167 ++cModes;
3168 }
3169 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3170
3171 /* VESA height reduction */
3172 ULONG ulHeightReduction;
3173 IFramebuffer *pFramebuffer = NULL;
3174 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3175 if (SUCCEEDED(hrc) && pFramebuffer)
3176 {
3177 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3178 pFramebuffer->Release();
3179 pFramebuffer = NULL;
3180 }
3181 else
3182 {
3183 /* If framebuffer is not available, there is no height reduction. */
3184 ulHeightReduction = 0;
3185 }
3186 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3187
3188 /*
3189 * BIOS logo
3190 */
3191 BOOL fFadeIn;
3192 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3193 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3194 BOOL fFadeOut;
3195 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3196 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3197 ULONG logoDisplayTime;
3198 hrc = ptrFirmwareSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3199 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3200 Bstr bstrLogoImagePath;
3201 hrc = ptrFirmwareSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
3202 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
3203
3204 /*
3205 * Boot menu
3206 */
3207 FirmwareBootMenuMode_T enmBootMenuMode;
3208 int iShowBootMenu;
3209 hrc = ptrFirmwareSettings->COMGETTER(BootMenuMode)(&enmBootMenuMode); H();
3210 switch (enmBootMenuMode)
3211 {
3212 case FirmwareBootMenuMode_Disabled: iShowBootMenu = 0; break;
3213 case FirmwareBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3214 default: iShowBootMenu = 2; break;
3215 }
3216 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3217
3218 /* Attach the display. */
3219 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3220 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3221 InsertConfigNode(pLunL0, "Config", &pCfg);
3222 }
3223 catch (ConfigError &x)
3224 {
3225 // InsertConfig threw something:
3226 return x.m_vrc;
3227 }
3228
3229#undef H
3230
3231 return VINF_SUCCESS;
3232}
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