VirtualBox

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

Last change on this file since 101014 was 101014, checked in by vboxsync, 21 months ago

Main/src-client/ConsoleImplConfig*: Polishing. More obvious buffer limit and error checking.

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

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