VirtualBox

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

Last change on this file since 101458 was 101458, checked in by vboxsync, 20 months ago

Main/ConsoleImpl: Move the audio controller configuration out of the x86 config constructor into a separate method in order to be able to use it from the Armv8 variant later on, bugref:10528

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

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