VirtualBox

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

Last change on this file since 101381 was 101381, checked in by vboxsync, 8 months ago

Main: More guest OS id marking. bugref:10384

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

© 2023 Oracle
ContactPrivacy policyTerms of Use