VirtualBox

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

Last change on this file since 101459 was 101459, checked in by vboxsync, 14 months ago

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

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