VirtualBox

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

Last change on this file since 101464 was 101464, checked in by vboxsync, 19 months ago

Main/ConsoleImpl: Move the guest debug configuration out of the x86 config constructor into a separate method in order to be able to use it from the Armv8 variant later on, bugref:10528

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