VirtualBox

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

最後變更 在這個檔案從100325是 99913,由 vboxsync 提交於 23 月 前

Main/src-client/ConsoleImpl: Add some _very_ basic config code to run an ARMv8 based guest inside the main VirtualBox frontend, can be activated by a CFGM key, bugref:10384

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

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