VirtualBox

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

最後變更 在這個檔案從101057是 101035,由 vboxsync 提交於 19 月 前

Initial commit (based draft v2 / on patch v5) for implementing platform architecture support for x86 and ARM. bugref:10384

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

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