VirtualBox

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

Last change on this file since 101465 was 101465, checked in by vboxsync, 19 months ago

Main/ConsoleImpl: Move the storage 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: 101.2 KB
Line 
1/* $Id: ConsoleImplConfigX86.cpp 101465 2023-10-17 09:58: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#include "PlatformImpl.h"
50#include "VMMDev.h"
51#include "Global.h"
52#ifdef VBOX_WITH_PCI_PASSTHROUGH
53# include "PCIRawDevImpl.h"
54#endif
55
56// generated header
57#include "SchemaDefs.h"
58
59#include "AutoCaller.h"
60
61#include <iprt/base64.h>
62#include <iprt/buildconfig.h>
63#include <iprt/ctype.h>
64#include <iprt/dir.h>
65#include <iprt/file.h>
66#include <iprt/param.h>
67#include <iprt/path.h>
68#include <iprt/string.h>
69#include <iprt/system.h>
70#if 0 /* enable to play with lots of memory. */
71# include <iprt/env.h>
72#endif
73#include <iprt/stream.h>
74
75#include <iprt/http.h>
76#include <iprt/socket.h>
77#include <iprt/uri.h>
78
79#include <VBox/vmm/vmmr3vtable.h>
80#include <VBox/vmm/vmapi.h>
81#include <VBox/err.h>
82#include <VBox/param.h>
83#include <VBox/settings.h> /* For MachineConfigFile::getHostDefaultAudioDriver(). */
84#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
85#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
86#include <VBox/vmm/pdmdev.h> /* For PDMAPICMODE enum. */
87#include <VBox/vmm/pdmstorageifs.h>
88#include <VBox/vmm/gcm.h>
89#include <VBox/version.h>
90#ifdef VBOX_WITH_GUEST_PROPS
91# include <VBox/HostServices/GuestPropertySvc.h>
92# include <VBox/com/defs.h>
93# include <VBox/com/array.h>
94# include <vector>
95#endif /* VBOX_WITH_GUEST_PROPS */
96#include <VBox/intnet.h>
97
98#include <VBox/com/com.h>
99#include <VBox/com/string.h>
100#include <VBox/com/array.h>
101
102#ifdef VBOX_WITH_NETFLT
103# if defined(RT_OS_SOLARIS)
104# include <zone.h>
105# elif defined(RT_OS_LINUX)
106# include <unistd.h>
107# include <sys/ioctl.h>
108# include <sys/socket.h>
109# include <linux/types.h>
110# include <linux/if.h>
111# elif defined(RT_OS_FREEBSD)
112# include <unistd.h>
113# include <sys/types.h>
114# include <sys/ioctl.h>
115# include <sys/socket.h>
116# include <net/if.h>
117# include <net80211/ieee80211_ioctl.h>
118# endif
119# if defined(RT_OS_WINDOWS)
120# include <iprt/win/ntddndis.h>
121# include <devguid.h>
122# else
123# include <HostNetworkInterfaceImpl.h>
124# include <netif.h>
125# include <stdlib.h>
126# endif
127#endif /* VBOX_WITH_NETFLT */
128
129#ifdef VBOX_WITH_AUDIO_VRDE
130# include "DrvAudioVRDE.h"
131#endif
132#ifdef VBOX_WITH_AUDIO_RECORDING
133# include "DrvAudioRec.h"
134#endif
135#include "NetworkServiceRunner.h"
136#include "BusAssignmentManager.h"
137#ifdef VBOX_WITH_EXTPACK
138# include "ExtPackManagerImpl.h"
139#endif
140
141
142/*********************************************************************************************************************************
143* Internal Functions *
144*********************************************************************************************************************************/
145
146/* Darwin compile kludge */
147#undef PVM
148
149/* Comment out the following line to remove VMWare compatibility hack. */
150#define VMWARE_NET_IN_SLOT_11
151
152/**
153 * Simple class for storing network boot information.
154 */
155struct BootNic
156{
157 ULONG mInstance;
158 PCIBusAddress mPCIAddress;
159
160 ULONG mBootPrio;
161 bool operator < (const BootNic &rhs) const
162 {
163 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
164 ULONG rval = rhs.mBootPrio - 1;
165 return lval < rval; /* Zero compares as highest number (lowest prio). */
166 }
167};
168
169/**
170 * @throws HRESULT on extra data retrival error.
171 */
172static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
173{
174 *pfGetKeyFromRealSMC = false;
175
176 /*
177 * The extra data takes precedence (if non-zero).
178 */
179 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
180 if (pStrKey->isNotEmpty())
181 return VINF_SUCCESS;
182
183#ifdef RT_OS_DARWIN
184
185 /*
186 * Work done in EFI/DevSmc
187 */
188 *pfGetKeyFromRealSMC = true;
189 int vrc = VINF_SUCCESS;
190
191#else
192 /*
193 * Is it apple hardware in bootcamp?
194 */
195 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
196 * Currently falling back on the product name. */
197 char szManufacturer[256];
198 szManufacturer[0] = '\0';
199 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
200 if (szManufacturer[0] != '\0')
201 {
202 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
203 || !strcmp(szManufacturer, "Apple Inc.")
204 )
205 *pfGetKeyFromRealSMC = true;
206 }
207 else
208 {
209 char szProdName[256];
210 szProdName[0] = '\0';
211 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
212 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
213 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
214 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
215 )
216 && !strchr(szProdName, ' ') /* no spaces */
217 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
218 )
219 *pfGetKeyFromRealSMC = true;
220 }
221
222 int vrc = VINF_SUCCESS;
223#endif
224
225 return vrc;
226}
227
228
229/*
230 * VC++ 8 / amd64 has some serious trouble with the next functions.
231 * As a temporary measure, we'll drop global optimizations.
232 */
233#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
234# if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100
235# pragma optimize("g", off)
236# endif
237#endif
238
239/** Helper that finds out the next HBA port used
240 */
241static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
242{
243 LONG lNextPortUsed = 30;
244 for (size_t j = 0; j < u32Size; ++j)
245 {
246 if ( aPortUsed[j] > lBaseVal
247 && aPortUsed[j] <= lNextPortUsed)
248 lNextPortUsed = aPortUsed[j];
249 }
250 return lNextPortUsed;
251}
252
253#define MAX_BIOS_LUN_COUNT 4
254
255int Console::SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
256 Bstr controllerName, const char * const s_apszBiosConfig[4])
257{
258 RT_NOREF(pCfg);
259 HRESULT hrc;
260#define MAX_DEVICES 30
261#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
262#define VRC() AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
263
264 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
265 LONG lPortUsed[MAX_DEVICES];
266 uint32_t u32HDCount = 0;
267
268 /* init to max value */
269 lPortLUN[0] = MAX_DEVICES;
270
271 com::SafeIfaceArray<IMediumAttachment> atts;
272 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
273 ComSafeArrayAsOutParam(atts)); H();
274 size_t uNumAttachments = atts.size();
275 if (uNumAttachments > MAX_DEVICES)
276 {
277 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
278 uNumAttachments = MAX_DEVICES;
279 }
280
281 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
282 for (size_t j = 0; j < uNumAttachments; ++j)
283 {
284 IMediumAttachment *pMediumAtt = atts[j];
285 LONG lPortNum = 0;
286 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
287 if (SUCCEEDED(hrc))
288 {
289 DeviceType_T lType;
290 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
291 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
292 {
293 /* find min port number used for HD */
294 if (lPortNum < lPortLUN[0])
295 lPortLUN[0] = lPortNum;
296 lPortUsed[u32HDCount++] = lPortNum;
297 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
298 }
299 }
300 }
301
302
303 /* Pick only the top 4 used HD Ports as CMOS doesn't have space
304 * to save details for all 30 ports
305 */
306 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
307 if (u32HDCount < MAX_BIOS_LUN_COUNT)
308 u32MaxPortCount = u32HDCount;
309 for (size_t j = 1; j < u32MaxPortCount; j++)
310 lPortLUN[j] = GetNextUsedPort(lPortUsed, lPortLUN[j-1], u32HDCount);
311 if (pBiosCfg)
312 {
313 for (size_t j = 0; j < u32MaxPortCount; j++)
314 {
315 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
316 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
317 }
318 }
319 return VINF_SUCCESS;
320}
321
322#ifdef VBOX_WITH_PCI_PASSTHROUGH
323HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
324{
325# ifndef VBOX_WITH_EXTPACK
326 RT_NOREF(pUVM);
327# endif
328 HRESULT hrc = S_OK;
329 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
330
331 SafeIfaceArray<IPCIDeviceAttachment> assignments;
332 ComPtr<IMachine> aMachine = i_machine();
333
334 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
335 if ( hrc != S_OK
336 || assignments.size() < 1)
337 return hrc;
338
339 /*
340 * PCI passthrough is only available if the proper ExtPack is installed.
341 *
342 * Note. Configuring PCI passthrough here and providing messages about
343 * the missing extpack isn't exactly clean, but it is a necessary evil
344 * to patch over legacy compatability issues introduced by the new
345 * distribution model.
346 */
347# ifdef VBOX_WITH_EXTPACK
348 static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";
349 if (!mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName))
350 /* Always fatal! */
351 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
352 N_("Implementation of the PCI passthrough framework not found!\n"
353 "The VM cannot be started. To fix this problem, either "
354 "install the '%s' or disable PCI passthrough via VBoxManage"),
355 s_pszPCIRawExtPackName);
356# endif
357
358 /* Now actually add devices */
359 PCFGMNODE pPCIDevs = NULL;
360
361 if (assignments.size() > 0)
362 {
363 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);
364
365 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
366
367 /* Tell PGM to tell GPCIRaw about guest mappings. */
368 CFGMR3InsertNode(pRoot, "PGM", NULL);
369 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
370
371 /*
372 * Currently, using IOMMU needed for PCI passthrough
373 * requires RAM preallocation.
374 */
375 /** @todo check if we can lift this requirement */
376 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
377 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
378 }
379
380 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
381 {
382 ComPtr<IPCIDeviceAttachment> const assignment = assignments[iDev];
383
384 LONG host;
385 hrc = assignment->COMGETTER(HostAddress)(&host); H();
386 LONG guest;
387 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
388 Bstr bstrDevName;
389 hrc = assignment->COMGETTER(Name)(bstrDevName.asOutParam()); H();
390
391 InsertConfigNodeF(pPCIDevs, &pInst, "%d", iDev);
392 InsertConfigInteger(pInst, "Trusted", 1);
393
394 PCIBusAddress HostPCIAddress(host);
395 Assert(HostPCIAddress.valid());
396 InsertConfigNode(pInst, "Config", &pCfg);
397 InsertConfigString(pCfg, "DeviceName", bstrDevName);
398
399 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
400 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);
401 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);
402 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);
403
404 PCIBusAddress GuestPCIAddress(guest);
405 Assert(GuestPCIAddress.valid());
406 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
407 if (hrc != S_OK)
408 return hrc;
409
410 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);
411 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);
412 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);
413
414 /* the driver */
415 InsertConfigNode(pInst, "LUN#0", &pLunL0);
416 InsertConfigString(pLunL0, "Driver", "pciraw");
417 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
418
419 /* the Main driver */
420 InsertConfigString(pLunL1, "Driver", "MainPciRaw");
421 InsertConfigNode(pLunL1, "Config", &pCfg);
422 PCIRawDev *pMainDev = new PCIRawDev(this);
423# error This is not allowed any more
424 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
425 }
426
427 return hrc;
428}
429#endif
430
431
432/**
433 * Worker for configConstructor.
434 *
435 * @return VBox status code.
436 * @param pUVM The user mode VM handle.
437 * @param pVM The cross context VM handle.
438 * @param pVMM The VMM vtable.
439 * @param pAlock The automatic lock instance. This is for when we have
440 * to leave it in order to avoid deadlocks (ext packs and
441 * more).
442 */
443int Console::i_configConstructorX86(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
444{
445 RT_NOREF(pVM /* when everything is disabled */);
446 ComPtr<IMachine> pMachine = i_machine();
447
448 int vrc;
449 HRESULT hrc;
450 Utf8Str strTmp;
451 Bstr bstr;
452
453#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
454
455 /*
456 * Get necessary objects and frequently used parameters.
457 */
458 ComPtr<IVirtualBox> virtualBox;
459 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
460
461 ComPtr<IHost> host;
462 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
463
464 ComPtr<ISystemProperties> systemProperties;
465 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
466
467 PlatformArchitecture_T platformArchHost;
468 hrc = host->COMGETTER(Architecture)(&platformArchHost); H();
469
470 ComPtr<IFirmwareSettings> firmwareSettings;
471 hrc = pMachine->COMGETTER(FirmwareSettings)(firmwareSettings.asOutParam()); H();
472
473 ComPtr<INvramStore> nvramStore;
474 hrc = pMachine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam()); H();
475
476 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
477 RTUUID HardwareUuid;
478 vrc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
479 AssertRCReturn(vrc, vrc);
480
481 ULONG cRamMBs;
482 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
483#if 0 /* enable to play with lots of memory. */
484 if (RTEnvExist("VBOX_RAM_SIZE"))
485 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
486#endif
487 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
488 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
489 uint64_t uMcfgBase = 0;
490 uint32_t cbMcfgLength = 0;
491
492 ParavirtProvider_T enmParavirtProvider;
493 hrc = pMachine->GetEffectiveParavirtProvider(&enmParavirtProvider); H();
494
495 Bstr strParavirtDebug;
496 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
497
498 BOOL fIOAPIC;
499 uint32_t uIoApicPciAddress = NIL_PCIBDF;
500 hrc = firmwareSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
501
502 ComPtr<IPlatform> platform;
503 pMachine->COMGETTER(Platform)(platform.asOutParam()); H();
504
505#if 0 /* For now we only support running same-same architectures (e.g. x86 VMs on x86 hosts). */
506 PlatformArchitecture_T platformArchMachine;
507 hrc = platform->COMGETTER(Architecture)(&platformArchMachine); H();
508 if (platformArchMachine != platformArchHost)
509 return pVMM->pfnVMR3SetError(pUVM, VERR_PLATFORM_ARCH_NOT_SUPPORTED, RT_SRC_POS,
510 N_("VM platform architecture (%s) not supported on this host (%s)."),
511 Global::stringifyPlatformArchitecture(platformArchMachine),
512 Global::stringifyPlatformArchitecture(platformArchHost));
513#endif
514
515 ChipsetType_T chipsetType;
516 hrc = platform->COMGETTER(ChipsetType)(&chipsetType); H();
517 if (chipsetType == ChipsetType_ICH9)
518 {
519 /* We'd better have 0x10000000 region, to cover 256 buses but this put
520 * too much load on hypervisor heap. Linux 4.8 currently complains with
521 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]
522 * only partially covers this bridge'' */
523 cbMcfgLength = 0x4000000; //0x10000000;
524 cbRamHole += cbMcfgLength;
525 uMcfgBase = _4G - cbRamHole;
526 }
527
528 /* Get the CPU profile name. */
529 Bstr bstrCpuProfile;
530 hrc = pMachine->COMGETTER(CPUProfile)(bstrCpuProfile.asOutParam()); H();
531
532 /* Get the X86 platform object. */
533 ComPtr<IPlatformX86> platformX86;
534 hrc = platform->COMGETTER(X86)(platformX86.asOutParam()); H();
535
536 /* Check if long mode is enabled. */
537 BOOL fIsGuest64Bit;
538 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_LongMode, &fIsGuest64Bit); H();
539
540 /*
541 * Figure out the IOMMU config.
542 */
543#if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL)
544 IommuType_T enmIommuType;
545 hrc = platform->COMGETTER(IommuType)(&enmIommuType); H();
546
547 /* Resolve 'automatic' type to an Intel or AMD IOMMU based on the host CPU. */
548 if (enmIommuType == IommuType_Automatic)
549 {
550 if ( bstrCpuProfile.startsWith("AMD")
551 || bstrCpuProfile.startsWith("Quad-Core AMD")
552 || bstrCpuProfile.startsWith("Hygon"))
553 enmIommuType = IommuType_AMD;
554 else if (bstrCpuProfile.startsWith("Intel"))
555 {
556 if ( bstrCpuProfile.equals("Intel 8086")
557 || bstrCpuProfile.equals("Intel 80186")
558 || bstrCpuProfile.equals("Intel 80286")
559 || bstrCpuProfile.equals("Intel 80386")
560 || bstrCpuProfile.equals("Intel 80486"))
561 enmIommuType = IommuType_None;
562 else
563 enmIommuType = IommuType_Intel;
564 }
565# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
566 else if (ASMIsAmdCpu())
567 enmIommuType = IommuType_AMD;
568 else if (ASMIsIntelCpu())
569 enmIommuType = IommuType_Intel;
570# endif
571 else
572 {
573 /** @todo Should we handle other CPUs like Shanghai, VIA etc. here? */
574 LogRel(("WARNING! Unrecognized CPU type, IOMMU disabled.\n"));
575 enmIommuType = IommuType_None;
576 }
577 }
578
579 if (enmIommuType == IommuType_AMD)
580 {
581# ifdef VBOX_WITH_IOMMU_AMD
582 /*
583 * Reserve the specific PCI address of the "SB I/O APIC" when using
584 * an AMD IOMMU. Required by Linux guests, see @bugref{9654#c23}.
585 */
586 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
587# else
588 LogRel(("WARNING! AMD IOMMU not supported, IOMMU disabled.\n"));
589 enmIommuType = IommuType_None;
590# endif
591 }
592
593 if (enmIommuType == IommuType_Intel)
594 {
595# ifdef VBOX_WITH_IOMMU_INTEL
596 /*
597 * Reserve a unique PCI address for the I/O APIC when using
598 * an Intel IOMMU. For convenience we use the same address as
599 * we do on AMD, see @bugref{9967#c13}.
600 */
601 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;
602# else
603 LogRel(("WARNING! Intel IOMMU not supported, IOMMU disabled.\n"));
604 enmIommuType = IommuType_None;
605# endif
606 }
607
608 if ( enmIommuType == IommuType_AMD
609 || enmIommuType == IommuType_Intel)
610 {
611 if (chipsetType != ChipsetType_ICH9)
612 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
613 N_("IOMMU uses MSIs which requires the ICH9 chipset implementation."));
614 if (!fIOAPIC)
615 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
616 N_("IOMMU requires an I/O APIC for remapping interrupts."));
617 }
618#else
619 IommuType_T const enmIommuType = IommuType_None;
620#endif
621
622 /* Instantiate the bus assignment manager. */
623 Assert(enmIommuType != IommuType_Automatic);
624 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, enmIommuType);
625
626 ULONG cCpus = 1;
627 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
628
629 ULONG ulCpuExecutionCap = 100;
630 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
631
632 LogRel(("Guest architecture: x86\n"));
633
634 Bstr osTypeId;
635 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
636 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
637
638 APICMode_T apicMode;
639 hrc = firmwareSettings->COMGETTER(APICMode)(&apicMode); H();
640 uint32_t uFwAPIC;
641 switch (apicMode)
642 {
643 case APICMode_Disabled:
644 uFwAPIC = 0;
645 break;
646 case APICMode_APIC:
647 uFwAPIC = 1;
648 break;
649 case APICMode_X2APIC:
650 uFwAPIC = 2;
651 break;
652 default:
653 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
654 uFwAPIC = 1;
655 break;
656 }
657
658 ComPtr<IGuestOSType> pGuestOSType;
659 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());
660
661 BOOL fOsXGuest = FALSE;
662 BOOL fWinGuest = FALSE;
663 BOOL fOs2Guest = FALSE;
664 BOOL fW9xGuest = FALSE;
665 BOOL fDosGuest = FALSE;
666 if (pGuestOSType.isNotNull())
667 {
668 Bstr guestTypeFamilyId;
669 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
670 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
671 fWinGuest = guestTypeFamilyId == Bstr("Windows");
672 fOs2Guest = osTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("OS2"));
673 fW9xGuest = osTypeId.startsWith(GUEST_OS_ID_STR_PARTIAL("Windows9")); /* Does not include Windows Me. */
674 fDosGuest = osTypeId.equals(GUEST_OS_ID_STR_X86("DOS")) || osTypeId.equals(GUEST_OS_ID_STR_X86("Windows31"));
675 }
676
677 ComPtr<IPlatformProperties> platformProperties;
678 virtualBox->GetPlatformProperties(PlatformArchitecture_x86, platformProperties.asOutParam());
679
680 ULONG maxNetworkAdapters;
681 hrc = platformProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
682
683 /*
684 * Get root node first.
685 * This is the only node in the tree.
686 */
687 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRootU(pUVM);
688 Assert(pRoot);
689
690 // catching throws from InsertConfigString and friends.
691 try
692 {
693
694 /*
695 * Set the root (and VMM) level values.
696 */
697 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
698 InsertConfigString(pRoot, "Name", bstr);
699 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
700 InsertConfigInteger(pRoot, "RamSize", cbRam);
701 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
702 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
703 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
704 InsertConfigInteger(pRoot, "TimerMillies", 10);
705
706 BOOL fPageFusion = FALSE;
707 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
708 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
709
710 /* Not necessary, but makes sure this setting ends up in the release log. */
711 ULONG ulBalloonSize = 0;
712 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
713 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
714
715 /*
716 * EM values (before CPUM as it may need to set IemExecutesAll).
717 */
718 PCFGMNODE pEM;
719 InsertConfigNode(pRoot, "EM", &pEM);
720
721 /* Triple fault behavior. */
722 BOOL fTripleFaultReset = false;
723 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_TripleFaultReset, &fTripleFaultReset); H();
724 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
725
726 /*
727 * CPUM values.
728 */
729 PCFGMNODE pCPUM;
730 InsertConfigNode(pRoot, "CPUM", &pCPUM);
731 PCFGMNODE pIsaExts;
732 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);
733
734 /* Host CPUID leaf overrides. */
735 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)
736 {
737 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;
738 hrc = platformX86->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);
739 if (hrc == E_INVALIDARG)
740 break;
741 H();
742 PCFGMNODE pLeaf;
743 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
744 /** @todo Figure out how to tell the VMM about uSubLeaf */
745 InsertConfigInteger(pLeaf, "eax", uEax);
746 InsertConfigInteger(pLeaf, "ebx", uEbx);
747 InsertConfigInteger(pLeaf, "ecx", uEcx);
748 InsertConfigInteger(pLeaf, "edx", uEdx);
749 }
750
751 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
752 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
753 if (osTypeId == GUEST_OS_ID_STR_X86("WindowsNT4"))
754 {
755 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
756 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
757 }
758
759 if (fOsXGuest)
760 {
761 /* Expose extended MWAIT features to Mac OS X guests. */
762 LogRel(("Using MWAIT extensions\n"));
763 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);
764
765 /* Fake the CPU family/model so the guest works. This is partly
766 because older mac releases really doesn't work on newer cpus,
767 and partly because mac os x expects more from systems with newer
768 cpus (MSRs, power features, whatever). */
769 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
770 if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS")
771 || osTypeId == GUEST_OS_ID_STR_X64("MacOS"))
772 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
773 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS106")
774 || osTypeId == GUEST_OS_ID_STR_X64("MacOS106"))
775 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
776 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS107")
777 || osTypeId == GUEST_OS_ID_STR_X64("MacOS107"))
778 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
779 what is required here. */
780 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS108")
781 || osTypeId == GUEST_OS_ID_STR_X64("MacOS108"))
782 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
783 what is required here. */
784 else if ( osTypeId == GUEST_OS_ID_STR_X86("MacOS109")
785 || osTypeId == GUEST_OS_ID_STR_X64("MacOS109"))
786 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
787 out what is required here. */
788 if (uMaxIntelFamilyModelStep != UINT32_MAX)
789 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
790 }
791
792 /* CPU Portability level, */
793 ULONG uCpuIdPortabilityLevel = 0;
794 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
795 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
796
797 /* Physical Address Extension (PAE) */
798 BOOL fEnablePAE = false;
799 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_PAE, &fEnablePAE); H();
800 fEnablePAE |= fIsGuest64Bit;
801 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
802
803 /* 64-bit guests (long mode) */
804 InsertConfigInteger(pCPUM, "Enable64bit", fIsGuest64Bit);
805
806 /* APIC/X2APIC configuration */
807 BOOL fEnableAPIC = true;
808 BOOL fEnableX2APIC = true;
809 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_APIC, &fEnableAPIC); H();
810 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_X2APIC, &fEnableX2APIC); H();
811 if (fEnableX2APIC)
812 Assert(fEnableAPIC);
813
814 /* CPUM profile name. */
815 InsertConfigString(pCPUM, "GuestCpuName", bstrCpuProfile);
816
817 /*
818 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
819 * correctly. There are way too many #UDs we'll miss using VT-x,
820 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
821 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
822 */
823 if ( bstrCpuProfile.equals("Intel 80386") /* just for now */
824 || bstrCpuProfile.equals("Intel 80286")
825 || bstrCpuProfile.equals("Intel 80186")
826 || bstrCpuProfile.equals("Nec V20")
827 || bstrCpuProfile.equals("Intel 8086") )
828 {
829 InsertConfigInteger(pEM, "IemExecutesAll", true);
830 if (!bstrCpuProfile.equals("Intel 80386"))
831 {
832 fEnableAPIC = false;
833 fIOAPIC = false;
834 }
835 fEnableX2APIC = false;
836 }
837
838 /* Adjust firmware APIC handling to stay within the VCPU limits. */
839 if (uFwAPIC == 2 && !fEnableX2APIC)
840 {
841 if (fEnableAPIC)
842 uFwAPIC = 1;
843 else
844 uFwAPIC = 0;
845 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
846 }
847 else if (uFwAPIC == 1 && !fEnableAPIC)
848 {
849 uFwAPIC = 0;
850 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
851 }
852
853 /* Speculation Control. */
854 BOOL fSpecCtrl = FALSE;
855 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_SpecCtrl, &fSpecCtrl); H();
856 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
857
858 /* Nested VT-x / AMD-V. */
859 BOOL fNestedHWVirt = FALSE;
860 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_HWVirt, &fNestedHWVirt); H();
861 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);
862
863 /*
864 * Hardware virtualization extensions.
865 */
866 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
867 if (!fEnableAPIC)
868 {
869 if (fIsGuest64Bit)
870 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
871 N_("Cannot disable the APIC for a 64-bit guest."));
872 if (cCpus > 1)
873 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
874 N_("Cannot disable the APIC for an SMP guest."));
875 if (fIOAPIC)
876 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
877 N_("Cannot disable the APIC when the I/O APIC is present."));
878 }
879
880 BOOL fHMEnabled;
881 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
882 if (cCpus > 1 && !fHMEnabled)
883 {
884 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
885 fHMEnabled = TRUE;
886 }
887
888 BOOL fHMForced;
889 fHMEnabled = fHMForced = TRUE;
890 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
891 if (!fHMForced) /* No need to query if already forced above. */
892 {
893 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
894 if (fHMForced)
895 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
896 }
897 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
898
899 /* /HM/xyz */
900 PCFGMNODE pHM;
901 InsertConfigNode(pRoot, "HM", &pHM);
902 InsertConfigInteger(pHM, "HMForced", fHMForced);
903 if (fHMEnabled)
904 {
905 /* Indicate whether 64-bit guests are supported or not. */
906 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
907
908 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
909 but that requires quite a bit of API change in Main. */
910 if ( fIOAPIC
911 && ( osTypeId == GUEST_OS_ID_STR_X86("WindowsNT4")
912 || osTypeId == GUEST_OS_ID_STR_X86("Windows2000")
913 || osTypeId == GUEST_OS_ID_STR_X86("WindowsXP")
914 || osTypeId == GUEST_OS_ID_STR_X86("Windows2003")))
915 {
916 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
917 * We may want to consider adding more guest OSes (Solaris) later on.
918 */
919 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
920 }
921 }
922
923 /* HWVirtEx exclusive mode */
924 BOOL fHMExclusive = true;
925 hrc = platformProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
926 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
927
928 /* Nested paging (VT-x/AMD-V) */
929 BOOL fEnableNestedPaging = false;
930 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
931 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
932
933 /* Large pages; requires nested paging */
934 BOOL fEnableLargePages = false;
935 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
936 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
937
938 /* VPID (VT-x) */
939 BOOL fEnableVPID = false;
940 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
941 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
942
943 /* Unrestricted execution aka UX (VT-x) */
944 BOOL fEnableUX = false;
945 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
946 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
947
948 /* Virtualized VMSAVE/VMLOAD (AMD-V) */
949 BOOL fVirtVmsaveVmload = true;
950 hrc = host->GetProcessorFeature(ProcessorFeature_VirtVmsaveVmload, &fVirtVmsaveVmload); H();
951 InsertConfigInteger(pHM, "SvmVirtVmsaveVmload", fVirtVmsaveVmload);
952
953 /* Indirect branch prediction boundraries. */
954 BOOL fIBPBOnVMExit = false;
955 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_IBPBOnVMExit, &fIBPBOnVMExit); H();
956 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);
957
958 BOOL fIBPBOnVMEntry = false;
959 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
960 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
961
962 BOOL fSpecCtrlByHost = false;
963 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_SpecCtrlByHost, &fSpecCtrlByHost); H();
964 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
965
966 BOOL fL1DFlushOnSched = true;
967 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_L1DFlushOnEMTScheduling, &fL1DFlushOnSched); H();
968 InsertConfigInteger(pHM, "L1DFlushOnSched", fL1DFlushOnSched);
969
970 BOOL fL1DFlushOnVMEntry = false;
971 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_L1DFlushOnVMEntry, &fL1DFlushOnVMEntry); H();
972 InsertConfigInteger(pHM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);
973
974 BOOL fMDSClearOnSched = true;
975 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_MDSClearOnEMTScheduling, &fMDSClearOnSched); H();
976 InsertConfigInteger(pHM, "MDSClearOnSched", fMDSClearOnSched);
977
978 BOOL fMDSClearOnVMEntry = false;
979 hrc = platformX86->GetCPUProperty(CPUPropertyTypeX86_MDSClearOnVMEntry, &fMDSClearOnVMEntry); H();
980 InsertConfigInteger(pHM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);
981
982 /* Reset overwrite. */
983 mfTurnResetIntoPowerOff = GetExtraDataBoth(virtualBox, pMachine,
984 "VBoxInternal2/TurnResetIntoPowerOff", &strTmp)->equals("1");
985 if (mfTurnResetIntoPowerOff)
986 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
987
988 /* Use NEM rather than HM. */
989 BOOL fUseNativeApi = false;
990 hrc = platformX86->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();
991 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);
992
993 /* Enable workaround for missing TLB flush for OS/2 guests, see ticketref:20625. */
994 if (fOs2Guest)
995 InsertConfigInteger(pHM, "MissingOS2TlbFlushWorkaround", 1);
996
997 /*
998 * NEM
999 */
1000 PCFGMNODE pNEM;
1001 InsertConfigNode(pRoot, "NEM", &pNEM);
1002 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);
1003
1004 /*
1005 * Paravirt. provider.
1006 */
1007 PCFGMNODE pParavirtNode;
1008 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1009 const char *pcszParavirtProvider;
1010 bool fGimDeviceNeeded = true;
1011 switch (enmParavirtProvider)
1012 {
1013 case ParavirtProvider_None:
1014 pcszParavirtProvider = "None";
1015 fGimDeviceNeeded = false;
1016 break;
1017
1018 case ParavirtProvider_Minimal:
1019 pcszParavirtProvider = "Minimal";
1020 break;
1021
1022 case ParavirtProvider_HyperV:
1023 pcszParavirtProvider = "HyperV";
1024 break;
1025
1026 case ParavirtProvider_KVM:
1027 pcszParavirtProvider = "KVM";
1028 break;
1029
1030 default:
1031 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));
1032 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1033 enmParavirtProvider);
1034 }
1035 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1036
1037 /*
1038 * Parse paravirt. debug options.
1039 */
1040 bool fGimDebug = false;
1041 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1042 uint32_t uGimDebugPort = 50000;
1043 if (strParavirtDebug.isNotEmpty())
1044 {
1045 /* Hyper-V debug options. */
1046 if (enmParavirtProvider == ParavirtProvider_HyperV)
1047 {
1048 bool fGimHvDebug = false;
1049 com::Utf8Str strGimHvVendor;
1050 bool fGimHvVsIf = false;
1051 bool fGimHvHypercallIf = false;
1052
1053 size_t uPos = 0;
1054 com::Utf8Str strDebugOptions = strParavirtDebug;
1055 com::Utf8Str strKey;
1056 com::Utf8Str strVal;
1057 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1058 {
1059 if (strKey == "enabled")
1060 {
1061 if (strVal.toUInt32() == 1)
1062 {
1063 /* Apply defaults.
1064 The defaults are documented in the user manual,
1065 changes need to be reflected accordingly. */
1066 fGimHvDebug = true;
1067 strGimHvVendor = "Microsoft Hv";
1068 fGimHvVsIf = true;
1069 fGimHvHypercallIf = false;
1070 }
1071 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1072 }
1073 else if (strKey == "address")
1074 strGimDebugAddress = strVal;
1075 else if (strKey == "port")
1076 uGimDebugPort = strVal.toUInt32();
1077 else if (strKey == "vendor")
1078 strGimHvVendor = strVal;
1079 else if (strKey == "vsinterface")
1080 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1081 else if (strKey == "hypercallinterface")
1082 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1083 else
1084 {
1085 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1086 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1087 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1088 strDebugOptions.c_str());
1089 }
1090 }
1091
1092 /* Update HyperV CFGM node with active debug options. */
1093 if (fGimHvDebug)
1094 {
1095 PCFGMNODE pHvNode;
1096 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1097 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1098 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1099 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1100 fGimDebug = true;
1101 }
1102 }
1103 }
1104
1105 /*
1106 * Guest Compatibility Manager.
1107 */
1108 PCFGMNODE pGcmNode;
1109 uint32_t u32FixerSet = 0;
1110 InsertConfigNode(pRoot, "GCM", &pGcmNode);
1111 /* OS/2 and Win9x guests can run DOS apps so they get
1112 * the DOS specific fixes as well.
1113 */
1114 if (fOs2Guest)
1115 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2;
1116 else if (fW9xGuest)
1117 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_WIN9X;
1118 else if (fDosGuest)
1119 u32FixerSet = GCMFIXER_DBZ_DOS;
1120 InsertConfigInteger(pGcmNode, "FixerSet", u32FixerSet);
1121
1122
1123 /*
1124 * MM values.
1125 */
1126 PCFGMNODE pMM;
1127 InsertConfigNode(pRoot, "MM", &pMM);
1128 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1129
1130 /*
1131 * PDM config.
1132 * Load drivers in VBoxC.[so|dll]
1133 */
1134 vrc = i_configPdm(pMachine, pVMM, pUVM, pRoot); VRC();
1135
1136 /*
1137 * Devices
1138 */
1139 PCFGMNODE pDevices = NULL; /* /Devices */
1140 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1141 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1142 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1143 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1144 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1145 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1146 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1147
1148 InsertConfigNode(pRoot, "Devices", &pDevices);
1149
1150 /*
1151 * GIM Device
1152 */
1153 if (fGimDeviceNeeded)
1154 {
1155 InsertConfigNode(pDevices, "GIMDev", &pDev);
1156 InsertConfigNode(pDev, "0", &pInst);
1157 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1158 //InsertConfigNode(pInst, "Config", &pCfg);
1159
1160 if (fGimDebug)
1161 {
1162 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1163 InsertConfigString(pLunL0, "Driver", "UDP");
1164 InsertConfigNode(pLunL0, "Config", &pLunL1);
1165 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1166 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1167 }
1168 }
1169
1170 /*
1171 * PC Arch.
1172 */
1173 InsertConfigNode(pDevices, "pcarch", &pDev);
1174 InsertConfigNode(pDev, "0", &pInst);
1175 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1176 InsertConfigNode(pInst, "Config", &pCfg);
1177
1178 /*
1179 * The time offset
1180 */
1181 LONG64 timeOffset;
1182 hrc = firmwareSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1183 PCFGMNODE pTMNode;
1184 InsertConfigNode(pRoot, "TM", &pTMNode);
1185 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1186
1187 /*
1188 * DMA
1189 */
1190 InsertConfigNode(pDevices, "8237A", &pDev);
1191 InsertConfigNode(pDev, "0", &pInst);
1192 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1193
1194 /*
1195 * PCI buses.
1196 */
1197 uint32_t uIocPCIAddress, uHbcPCIAddress;
1198 switch (chipsetType)
1199 {
1200 default:
1201 AssertFailed();
1202 RT_FALL_THRU();
1203 case ChipsetType_PIIX3:
1204 /* Create the base for adding bridges on demand */
1205 InsertConfigNode(pDevices, "pcibridge", NULL);
1206
1207 InsertConfigNode(pDevices, "pci", &pDev);
1208 uHbcPCIAddress = (0x0 << 16) | 0;
1209 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1210 break;
1211 case ChipsetType_ICH9:
1212 /* Create the base for adding bridges on demand */
1213 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1214
1215 InsertConfigNode(pDevices, "ich9pci", &pDev);
1216 uHbcPCIAddress = (0x1e << 16) | 0;
1217 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1218 break;
1219 }
1220 InsertConfigNode(pDev, "0", &pInst);
1221 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1222 InsertConfigNode(pInst, "Config", &pCfg);
1223 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1224 if (chipsetType == ChipsetType_ICH9)
1225 {
1226 /* Provide MCFG info */
1227 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1228 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1229
1230#ifdef VBOX_WITH_PCI_PASSTHROUGH
1231 /* Add PCI passthrough devices */
1232 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1233#endif
1234
1235 if (enmIommuType == IommuType_AMD)
1236 {
1237 /* AMD IOMMU. */
1238 InsertConfigNode(pDevices, "iommu-amd", &pDev);
1239 InsertConfigNode(pDev, "0", &pInst);
1240 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1241 InsertConfigNode(pInst, "Config", &pCfg);
1242 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();
1243
1244 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */
1245 {
1246 PCIBusAddress Address;
1247 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
1248 {
1249 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
1250 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);
1251 }
1252 else
1253 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1254 N_("Failed to find PCI address of the assigned IOMMU device!"));
1255 }
1256
1257 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1258 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1259 }
1260 else if (enmIommuType == IommuType_Intel)
1261 {
1262 /* Intel IOMMU. */
1263 InsertConfigNode(pDevices, "iommu-intel", &pDev);
1264 InsertConfigNode(pDev, "0", &pInst);
1265 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1266 InsertConfigNode(pInst, "Config", &pCfg);
1267 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();
1268
1269 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);
1270 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();
1271 }
1272 }
1273
1274 /*
1275 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1276 */
1277
1278 /*
1279 * High Precision Event Timer (HPET)
1280 */
1281 BOOL fHPETEnabled;
1282 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1283 hrc = platformX86->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1284 /* so always enable HPET in extended profile */
1285 fHPETEnabled |= fOsXGuest;
1286 /* HPET is always present on ICH9 */
1287 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1288 if (fHPETEnabled)
1289 {
1290 InsertConfigNode(pDevices, "hpet", &pDev);
1291 InsertConfigNode(pDev, "0", &pInst);
1292 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1293 InsertConfigNode(pInst, "Config", &pCfg);
1294 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1295 }
1296
1297 /*
1298 * System Management Controller (SMC)
1299 */
1300 BOOL fSmcEnabled;
1301 fSmcEnabled = fOsXGuest;
1302 if (fSmcEnabled)
1303 {
1304 InsertConfigNode(pDevices, "smc", &pDev);
1305 InsertConfigNode(pDev, "0", &pInst);
1306 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1307 InsertConfigNode(pInst, "Config", &pCfg);
1308
1309 bool fGetKeyFromRealSMC;
1310 Utf8Str strKey;
1311 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1312 AssertRCReturn(vrc, vrc);
1313
1314 if (!fGetKeyFromRealSMC)
1315 InsertConfigString(pCfg, "DeviceKey", strKey);
1316 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1317 }
1318
1319 /*
1320 * Low Pin Count (LPC) bus
1321 */
1322 BOOL fLpcEnabled;
1323 /** @todo implement appropriate getter */
1324 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1325 if (fLpcEnabled)
1326 {
1327 InsertConfigNode(pDevices, "lpc", &pDev);
1328 InsertConfigNode(pDev, "0", &pInst);
1329 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1330 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1331 }
1332
1333 BOOL fShowRtc;
1334 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1335
1336 /*
1337 * PS/2 keyboard & mouse.
1338 */
1339 InsertConfigNode(pDevices, "pckbd", &pDev);
1340 InsertConfigNode(pDev, "0", &pInst);
1341 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1342 InsertConfigNode(pInst, "Config", &pCfg);
1343
1344 KeyboardHIDType_T aKbdHID;
1345 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
1346 if (aKbdHID != KeyboardHIDType_None)
1347 {
1348 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1349 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1350 InsertConfigNode(pLunL0, "Config", &pCfg);
1351 InsertConfigInteger(pCfg, "QueueSize", 64);
1352
1353 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1354 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1355 }
1356
1357 PointingHIDType_T aPointingHID;
1358 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1359 if (aPointingHID != PointingHIDType_None)
1360 {
1361 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1362 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1363 InsertConfigNode(pLunL0, "Config", &pCfg);
1364 InsertConfigInteger(pCfg, "QueueSize", 128);
1365
1366 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1367 InsertConfigString(pLunL1, "Driver", "MainMouse");
1368 }
1369
1370 /*
1371 * i8254 Programmable Interval Timer And Dummy Speaker
1372 */
1373 InsertConfigNode(pDevices, "i8254", &pDev);
1374 InsertConfigNode(pDev, "0", &pInst);
1375 InsertConfigNode(pInst, "Config", &pCfg);
1376#ifdef DEBUG
1377 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1378#endif
1379
1380 /*
1381 * i8259 Programmable Interrupt Controller.
1382 */
1383 InsertConfigNode(pDevices, "i8259", &pDev);
1384 InsertConfigNode(pDev, "0", &pInst);
1385 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1386 InsertConfigNode(pInst, "Config", &pCfg);
1387
1388 /*
1389 * Advanced Programmable Interrupt Controller.
1390 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1391 * thus only single insert
1392 */
1393 if (fEnableAPIC)
1394 {
1395 InsertConfigNode(pDevices, "apic", &pDev);
1396 InsertConfigNode(pDev, "0", &pInst);
1397 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1398 InsertConfigNode(pInst, "Config", &pCfg);
1399 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1400 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1401 if (fEnableX2APIC)
1402 enmAPICMode = PDMAPICMODE_X2APIC;
1403 else if (!fEnableAPIC)
1404 enmAPICMode = PDMAPICMODE_NONE;
1405 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1406 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1407
1408 if (fIOAPIC)
1409 {
1410 /*
1411 * I/O Advanced Programmable Interrupt Controller.
1412 */
1413 InsertConfigNode(pDevices, "ioapic", &pDev);
1414 InsertConfigNode(pDev, "0", &pInst);
1415 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1416 InsertConfigNode(pInst, "Config", &pCfg);
1417 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1418 if (enmIommuType == IommuType_AMD)
1419 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1420 else if (enmIommuType == IommuType_Intel)
1421 {
1422 InsertConfigString(pCfg, "ChipType", "DMAR");
1423 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);
1424 }
1425 }
1426 }
1427
1428 /*
1429 * RTC MC146818.
1430 */
1431 InsertConfigNode(pDevices, "mc146818", &pDev);
1432 InsertConfigNode(pDev, "0", &pInst);
1433 InsertConfigNode(pInst, "Config", &pCfg);
1434 BOOL fRTCUseUTC;
1435 hrc = platform->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1436 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1437
1438 /*
1439 * VGA.
1440 */
1441 ComPtr<IGraphicsAdapter> pGraphicsAdapter;
1442 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();
1443 GraphicsControllerType_T enmGraphicsController;
1444 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1445 switch (enmGraphicsController)
1446 {
1447 case GraphicsControllerType_Null:
1448 break;
1449#ifdef VBOX_WITH_VMSVGA
1450 case GraphicsControllerType_VMSVGA:
1451 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1452 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */
1453 RT_FALL_THROUGH();
1454 case GraphicsControllerType_VBoxSVGA:
1455#endif
1456 case GraphicsControllerType_VBoxVGA:
1457 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, firmwareSettings,
1458 RT_BOOL(fHMEnabled));
1459 if (FAILED(vrc))
1460 return vrc;
1461 break;
1462 default:
1463 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1464 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1465 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1466 }
1467
1468 /*
1469 * Firmware.
1470 */
1471 FirmwareType_T eFwType = FirmwareType_BIOS;
1472 hrc = firmwareSettings->COMGETTER(FirmwareType)(&eFwType); H();
1473
1474#ifdef VBOX_WITH_EFI
1475 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1476#else
1477 BOOL fEfiEnabled = false;
1478#endif
1479 if (!fEfiEnabled)
1480 {
1481 /*
1482 * PC Bios.
1483 */
1484 InsertConfigNode(pDevices, "pcbios", &pDev);
1485 InsertConfigNode(pDev, "0", &pInst);
1486 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1487 InsertConfigNode(pInst, "Config", &pBiosCfg);
1488 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1489 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1490 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1491 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1492 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1493 BOOL fPXEDebug;
1494 hrc = firmwareSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1495 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1496 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1497 BOOL fUuidLe;
1498 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1499 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);
1500 BOOL fAutoSerialNumGen;
1501 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1502 if (fAutoSerialNumGen)
1503 InsertConfigString(pBiosCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1504 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1505 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1506 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1507
1508 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1509 VERR_INVALID_PARAMETER);
1510
1511 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1512 {
1513 DeviceType_T enmBootDevice;
1514 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();
1515
1516 char szParamName[] = "BootDeviceX";
1517 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1518
1519 const char *pszBootDevice;
1520 switch (enmBootDevice)
1521 {
1522 case DeviceType_Null:
1523 pszBootDevice = "NONE";
1524 break;
1525 case DeviceType_HardDisk:
1526 pszBootDevice = "IDE";
1527 break;
1528 case DeviceType_DVD:
1529 pszBootDevice = "DVD";
1530 break;
1531 case DeviceType_Floppy:
1532 pszBootDevice = "FLOPPY";
1533 break;
1534 case DeviceType_Network:
1535 pszBootDevice = "LAN";
1536 break;
1537 default:
1538 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));
1539 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1540 N_("Invalid boot device '%d'"), enmBootDevice);
1541 }
1542 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1543 }
1544
1545 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1546 * this is required for Windows 2012 guests. */
1547 if (osTypeId == GUEST_OS_ID_STR_X64("Windows2012"))
1548 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1549 }
1550 else
1551 {
1552 /* Autodetect firmware type, basing on guest type */
1553 if (eFwType == FirmwareType_EFI)
1554 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
1555 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1556
1557 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);
1558#ifdef VBOX_WITH_EFI_IN_DD2
1559 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"
1560 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"
1561 : "VBoxEFI64.fd";
1562#else
1563 Utf8Str efiRomFile;
1564 vrc = findEfiRom(virtualBox, PlatformArchitecture_x86, eFwType, &efiRomFile);
1565 AssertRCReturn(vrc, vrc);
1566 const char *pszEfiRomFile = efiRomFile.c_str();
1567#endif
1568
1569 /* Get boot args */
1570 Utf8Str bootArgs;
1571 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1572
1573 /* Get device props */
1574 Utf8Str deviceProps;
1575 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1576
1577 /* Get NVRAM file name */
1578 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();
1579
1580 BOOL fUuidLe;
1581 hrc = firmwareSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();
1582
1583 BOOL fAutoSerialNumGen;
1584 hrc = firmwareSettings->COMGETTER(AutoSerialNumGen)(&fAutoSerialNumGen); H();
1585
1586 /* Get graphics mode settings */
1587 uint32_t u32GraphicsMode = UINT32_MAX;
1588 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1589 if (strTmp.isEmpty())
1590 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1591 if (!strTmp.isEmpty())
1592 u32GraphicsMode = strTmp.toUInt32();
1593
1594 /* Get graphics resolution settings, with some sanity checking */
1595 Utf8Str strResolution;
1596 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);
1597 if (!strResolution.isEmpty())
1598 {
1599 size_t pos = strResolution.find("x");
1600 if (pos != strResolution.npos)
1601 {
1602 Utf8Str strH, strV;
1603 strH.assignEx(strResolution, 0, pos);
1604 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);
1605 uint32_t u32H = strH.toUInt32();
1606 uint32_t u32V = strV.toUInt32();
1607 if (u32H == 0 || u32V == 0)
1608 strResolution.setNull();
1609 }
1610 else
1611 strResolution.setNull();
1612 }
1613 else
1614 {
1615 uint32_t u32H = 0;
1616 uint32_t u32V = 0;
1617 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1618 if (strTmp.isEmpty())
1619 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1620 if (!strTmp.isEmpty())
1621 u32H = strTmp.toUInt32();
1622
1623 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1624 if (strTmp.isEmpty())
1625 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1626 if (!strTmp.isEmpty())
1627 u32V = strTmp.toUInt32();
1628 if (u32H != 0 && u32V != 0)
1629 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);
1630 }
1631
1632 /*
1633 * EFI subtree.
1634 */
1635 InsertConfigNode(pDevices, "efi", &pDev);
1636 InsertConfigNode(pDev, "0", &pInst);
1637 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1638 InsertConfigNode(pInst, "Config", &pCfg);
1639 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1640 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1641 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1642 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);
1643 InsertConfigString(pCfg, "BootArgs", bootArgs);
1644 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1645 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1646 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1647 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1648 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);
1649 if (fAutoSerialNumGen)
1650 InsertConfigString(pCfg, "DmiSystemSerial", "VirtualBox-<DmiSystemUuid>");
1651 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1652 InsertConfigString(pCfg, "NvramFile", strNvram);
1653 if (u32GraphicsMode != UINT32_MAX)
1654 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1655 if (!strResolution.isEmpty())
1656 InsertConfigString(pCfg, "GraphicsResolution", strResolution);
1657
1658 /* For OS X guests we'll force passing host's DMI info to the guest */
1659 if (fOsXGuest)
1660 {
1661 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1662 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1663 }
1664
1665 /* Attach the NVRAM storage driver. */
1666 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1667 InsertConfigString(pLunL0, "Driver", "NvramStore");
1668 }
1669
1670 /*
1671 * The USB Controllers.
1672 */
1673 PCFGMNODE pUsbDevices = NULL;
1674 vrc = i_configUsb(pMachine, pBusMgr, pRoot, pDevices, aKbdHID, aPointingHID, &pUsbDevices);
1675
1676 /*
1677 * Storage controllers.
1678 */
1679 bool fFdcEnabled = false;
1680 vrc = i_configStorageCtrls(pMachine, pBusMgr, pVMM, pUVM,
1681 pDevices, pUsbDevices, pBiosCfg, &fFdcEnabled); VRC();
1682
1683 /*
1684 * Network adapters
1685 */
1686#ifdef VMWARE_NET_IN_SLOT_11
1687 bool fSwapSlots3and11 = false;
1688#endif
1689 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
1690 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
1691#ifdef VBOX_WITH_E1000
1692 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
1693 InsertConfigNode(pDevices, "e1000", &pDevE1000);
1694#endif
1695#ifdef VBOX_WITH_VIRTIO
1696 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
1697 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
1698#endif /* VBOX_WITH_VIRTIO */
1699 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
1700 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
1701 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
1702 InsertConfigNode(pDevices, "3c501", &pDev3C501);
1703
1704 std::list<BootNic> llBootNics;
1705 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
1706 {
1707 ComPtr<INetworkAdapter> networkAdapter;
1708 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
1709 BOOL fEnabledNetAdapter = FALSE;
1710 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
1711 if (!fEnabledNetAdapter)
1712 continue;
1713
1714 /*
1715 * The virtual hardware type. Create appropriate device first.
1716 */
1717 const char *pszAdapterName = "pcnet";
1718 NetworkAdapterType_T adapterType;
1719 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
1720 switch (adapterType)
1721 {
1722 case NetworkAdapterType_Am79C970A:
1723 case NetworkAdapterType_Am79C973:
1724 case NetworkAdapterType_Am79C960:
1725 pDev = pDevPCNet;
1726 break;
1727#ifdef VBOX_WITH_E1000
1728 case NetworkAdapterType_I82540EM:
1729 case NetworkAdapterType_I82543GC:
1730 case NetworkAdapterType_I82545EM:
1731 pDev = pDevE1000;
1732 pszAdapterName = "e1000";
1733 break;
1734#endif
1735#ifdef VBOX_WITH_VIRTIO
1736 case NetworkAdapterType_Virtio:
1737 pDev = pDevVirtioNet;
1738 pszAdapterName = "virtio-net";
1739 break;
1740#endif /* VBOX_WITH_VIRTIO */
1741 case NetworkAdapterType_NE1000:
1742 case NetworkAdapterType_NE2000:
1743 case NetworkAdapterType_WD8003:
1744 case NetworkAdapterType_WD8013:
1745 case NetworkAdapterType_ELNK2:
1746 pDev = pDevDP8390;
1747 break;
1748 case NetworkAdapterType_ELNK1:
1749 pDev = pDev3C501;
1750 break;
1751 default:
1752 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
1753 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1754 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
1755 }
1756
1757 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
1758 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1759 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
1760 * next 4 get 16..19. */
1761 int iPCIDeviceNo;
1762 switch (uInstance)
1763 {
1764 case 0:
1765 iPCIDeviceNo = 3;
1766 break;
1767 case 1: case 2: case 3:
1768 iPCIDeviceNo = uInstance - 1 + 8;
1769 break;
1770 case 4: case 5: case 6: case 7:
1771 iPCIDeviceNo = uInstance - 4 + 16;
1772 break;
1773 default:
1774 /* auto assignment */
1775 iPCIDeviceNo = -1;
1776 break;
1777 }
1778#ifdef VMWARE_NET_IN_SLOT_11
1779 /*
1780 * Dirty hack for PCI slot compatibility with VMWare,
1781 * it assigns slot 0x11 to the first network controller.
1782 */
1783 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
1784 {
1785 iPCIDeviceNo = 0x11;
1786 fSwapSlots3and11 = true;
1787 }
1788 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
1789 iPCIDeviceNo = 3;
1790#endif
1791 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
1792 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
1793
1794 InsertConfigNode(pInst, "Config", &pCfg);
1795#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
1796 if (pDev == pDevPCNet)
1797 InsertConfigInteger(pCfg, "R0Enabled", false);
1798#endif
1799 /*
1800 * Collect information needed for network booting and add it to the list.
1801 */
1802 BootNic nic;
1803
1804 nic.mInstance = uInstance;
1805 /* Could be updated by reference, if auto assigned */
1806 nic.mPCIAddress = PCIAddr;
1807
1808 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
1809
1810 llBootNics.push_back(nic);
1811
1812 /*
1813 * The virtual hardware type. PCNet supports three types, E1000 three,
1814 * but VirtIO only one.
1815 */
1816 switch (adapterType)
1817 {
1818 case NetworkAdapterType_Am79C970A:
1819 InsertConfigString(pCfg, "ChipType", "Am79C970A");
1820 break;
1821 case NetworkAdapterType_Am79C973:
1822 InsertConfigString(pCfg, "ChipType", "Am79C973");
1823 break;
1824 case NetworkAdapterType_Am79C960:
1825 InsertConfigString(pCfg, "ChipType", "Am79C960");
1826 break;
1827 case NetworkAdapterType_I82540EM:
1828 InsertConfigInteger(pCfg, "AdapterType", 0);
1829 break;
1830 case NetworkAdapterType_I82543GC:
1831 InsertConfigInteger(pCfg, "AdapterType", 1);
1832 break;
1833 case NetworkAdapterType_I82545EM:
1834 InsertConfigInteger(pCfg, "AdapterType", 2);
1835 break;
1836 case NetworkAdapterType_Virtio:
1837 break;
1838 case NetworkAdapterType_NE1000:
1839 InsertConfigString(pCfg, "DeviceType", "NE1000");
1840 break;
1841 case NetworkAdapterType_NE2000:
1842 InsertConfigString(pCfg, "DeviceType", "NE2000");
1843 break;
1844 case NetworkAdapterType_WD8003:
1845 InsertConfigString(pCfg, "DeviceType", "WD8003");
1846 break;
1847 case NetworkAdapterType_WD8013:
1848 InsertConfigString(pCfg, "DeviceType", "WD8013");
1849 break;
1850 case NetworkAdapterType_ELNK2:
1851 InsertConfigString(pCfg, "DeviceType", "3C503");
1852 break;
1853 case NetworkAdapterType_ELNK1:
1854 break;
1855 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
1856#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
1857 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
1858#endif
1859 }
1860
1861 /*
1862 * Get the MAC address and convert it to binary representation
1863 */
1864 Bstr macAddr;
1865 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
1866 Assert(!macAddr.isEmpty());
1867 Utf8Str macAddrUtf8 = macAddr;
1868#ifdef VBOX_WITH_CLOUD_NET
1869 NetworkAttachmentType_T eAttachmentType;
1870 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
1871 if (eAttachmentType == NetworkAttachmentType_Cloud)
1872 {
1873 mGateway.setLocalMacAddress(macAddrUtf8);
1874 /* We'll insert cloud MAC later, when it becomes known. */
1875 }
1876 else
1877 {
1878#endif
1879 char *macStr = (char*)macAddrUtf8.c_str();
1880 Assert(strlen(macStr) == 12);
1881 RTMAC Mac;
1882 RT_ZERO(Mac);
1883 char *pMac = (char*)&Mac;
1884 for (uint32_t i = 0; i < 6; ++i)
1885 {
1886 int c1 = *macStr++ - '0';
1887 if (c1 > 9)
1888 c1 -= 7;
1889 int c2 = *macStr++ - '0';
1890 if (c2 > 9)
1891 c2 -= 7;
1892 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
1893 }
1894 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
1895#ifdef VBOX_WITH_CLOUD_NET
1896 }
1897#endif
1898 /*
1899 * Check if the cable is supposed to be unplugged
1900 */
1901 BOOL fCableConnected;
1902 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
1903 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
1904
1905 /*
1906 * Line speed to report from custom drivers
1907 */
1908 ULONG ulLineSpeed;
1909 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
1910 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
1911
1912 /*
1913 * Attach the status driver.
1914 */
1915 i_attachStatusDriver(pInst, DeviceType_Network);
1916
1917 /*
1918 * Configure the network card now
1919 */
1920 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
1921 vrc = i_configNetwork(pszAdapterName,
1922 uInstance,
1923 0,
1924 networkAdapter,
1925 pCfg,
1926 pLunL0,
1927 pInst,
1928 false /*fAttachDetach*/,
1929 fIgnoreConnectFailure,
1930 pUVM,
1931 pVMM);
1932 if (RT_FAILURE(vrc))
1933 return vrc;
1934 }
1935
1936 /*
1937 * Build network boot information and transfer it to the BIOS.
1938 */
1939 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
1940 {
1941 llBootNics.sort(); /* Sort the list by boot priority. */
1942
1943 char achBootIdx[] = "0";
1944 unsigned uBootIdx = 0;
1945
1946 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
1947 {
1948 /* A NIC with priority 0 is only used if it's first in the list. */
1949 if (it->mBootPrio == 0 && uBootIdx != 0)
1950 break;
1951
1952 PCFGMNODE pNetBtDevCfg;
1953 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
1954 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
1955 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
1956 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
1957 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
1958 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
1959 }
1960 }
1961
1962 /*
1963 * Serial (UART) Ports
1964 */
1965 /* serial enabled mask to be passed to dev ACPI */
1966 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
1967 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
1968 InsertConfigNode(pDevices, "serial", &pDev);
1969 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
1970 {
1971 ComPtr<ISerialPort> serialPort;
1972 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
1973 BOOL fEnabledSerPort = FALSE;
1974 if (serialPort)
1975 {
1976 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
1977 }
1978 if (!fEnabledSerPort)
1979 {
1980 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
1981 continue;
1982 }
1983
1984 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1985 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1986 InsertConfigNode(pInst, "Config", &pCfg);
1987
1988 ULONG ulIRQ;
1989 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
1990 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1991 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
1992
1993 ULONG ulIOBase;
1994 hrc = serialPort->COMGETTER(IOAddress)(&ulIOBase); H();
1995 InsertConfigInteger(pCfg, "IOAddress", ulIOBase);
1996 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
1997
1998 BOOL fServer;
1999 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2000 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2001 UartType_T eUartType;
2002 const char *pszUartType;
2003 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2004 switch (eUartType)
2005 {
2006 case UartType_U16450: pszUartType = "16450"; break;
2007 case UartType_U16750: pszUartType = "16750"; break;
2008 default: AssertFailed(); RT_FALL_THRU();
2009 case UartType_U16550A: pszUartType = "16550A"; break;
2010 }
2011 InsertConfigString(pCfg, "UartType", pszUartType);
2012
2013 PortMode_T eHostMode;
2014 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2015
2016 m_aeSerialPortMode[ulInstance] = eHostMode;
2017 if (eHostMode != PortMode_Disconnected)
2018 {
2019 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2020 if (RT_FAILURE(vrc))
2021 return vrc;
2022 }
2023 }
2024
2025 /*
2026 * Parallel (LPT) Ports
2027 */
2028 /* parallel enabled mask to be passed to dev ACPI */
2029 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2030 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2031 InsertConfigNode(pDevices, "parallel", &pDev);
2032 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2033 {
2034 ComPtr<IParallelPort> parallelPort;
2035 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2036 BOOL fEnabledParPort = FALSE;
2037 if (parallelPort)
2038 {
2039 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2040 }
2041 if (!fEnabledParPort)
2042 continue;
2043
2044 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2045 InsertConfigNode(pInst, "Config", &pCfg);
2046
2047 ULONG ulIRQ;
2048 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2049 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2050 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2051 ULONG ulIOBase;
2052 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2053 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2054 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2055
2056 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2057 if (!bstr.isEmpty())
2058 {
2059 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2060 InsertConfigString(pLunL0, "Driver", "HostParallel");
2061 InsertConfigNode(pLunL0, "Config", &pLunL1);
2062 InsertConfigString(pLunL1, "DevicePath", bstr);
2063 }
2064 }
2065
2066 vrc = i_configVmmDev(pMachine, pBusMgr, pDevices); VRC();
2067
2068 /*
2069 * Audio configuration.
2070 */
2071 bool fAudioEnabled = false;
2072 vrc = i_configAudioCtrl(virtualBox, pMachine, pBusMgr, pDevices,
2073 fOsXGuest, &fAudioEnabled); VRC();
2074
2075#if defined(VBOX_WITH_TPM)
2076 /*
2077 * Configure the Trusted Platform Module.
2078 */
2079 ComObjPtr<ITrustedPlatformModule> ptrTpm;
2080 TpmType_T enmTpmType = TpmType_None;
2081
2082 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();
2083 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();
2084 if (enmTpmType != TpmType_None)
2085 {
2086 InsertConfigNode(pDevices, "tpm", &pDev);
2087 InsertConfigNode(pDev, "0", &pInst);
2088 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2089 InsertConfigNode(pInst, "Config", &pCfg);
2090 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2091
2092 switch (enmTpmType)
2093 {
2094 case TpmType_v1_2:
2095 case TpmType_v2_0:
2096 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");
2097 InsertConfigNode(pLunL0, "Config", &pCfg);
2098 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);
2099 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2100 InsertConfigString(pLunL1, "Driver", "NvramStore");
2101 break;
2102 case TpmType_Host:
2103#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
2104 InsertConfigString(pLunL0, "Driver", "TpmHost");
2105 InsertConfigNode(pLunL0, "Config", &pCfg);
2106#endif
2107 break;
2108 case TpmType_Swtpm:
2109 hrc = ptrTpm->COMGETTER(Location)(bstr.asOutParam()); H();
2110 InsertConfigString(pLunL0, "Driver", "TpmEmu");
2111 InsertConfigNode(pLunL0, "Config", &pCfg);
2112 InsertConfigString(pCfg, "Location", bstr);
2113 break;
2114 default:
2115 AssertFailedBreak();
2116 }
2117 }
2118#endif
2119
2120 /*
2121 * ACPI
2122 */
2123 BOOL fACPI;
2124 hrc = firmwareSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
2125 if (fACPI)
2126 {
2127 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
2128 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
2129 * intelppm driver refuses to register an idle state handler.
2130 * Always show CPU leafs for OS X guests. */
2131 BOOL fShowCpu = fOsXGuest;
2132 if (cCpus > 1 || fIOAPIC)
2133 fShowCpu = true;
2134
2135 BOOL fCpuHotPlug;
2136 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
2137
2138 InsertConfigNode(pDevices, "acpi", &pDev);
2139 InsertConfigNode(pDev, "0", &pInst);
2140 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2141 InsertConfigNode(pInst, "Config", &pCfg);
2142 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
2143
2144 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
2145
2146 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
2147 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
2148 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
2149 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
2150 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
2151 if (fOsXGuest && !llBootNics.empty())
2152 {
2153 BootNic aNic = llBootNics.front();
2154 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
2155 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
2156 }
2157 if (fOsXGuest && fAudioEnabled)
2158 {
2159 PCIBusAddress Address;
2160 if (pBusMgr->findPCIAddress("hda", 0, Address))
2161 {
2162 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
2163 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
2164 }
2165 }
2166 if (fOsXGuest)
2167 {
2168 PCIBusAddress Address;
2169 if (pBusMgr->findPCIAddress("nvme", 0, Address))
2170 {
2171 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;
2172 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);
2173 }
2174 }
2175 if (enmIommuType == IommuType_AMD)
2176 {
2177 PCIBusAddress Address;
2178 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))
2179 {
2180 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
2181 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);
2182 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
2183 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
2184 {
2185 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
2186 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
2187 }
2188 else
2189 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2190 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
2191 }
2192 }
2193 else if (enmIommuType == IommuType_Intel)
2194 {
2195 PCIBusAddress Address;
2196 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))
2197 {
2198 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;
2199 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);
2200 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);
2201 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))
2202 {
2203 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;
2204 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);
2205 }
2206 else
2207 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2208 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));
2209 }
2210 }
2211
2212 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
2213 if (chipsetType == ChipsetType_ICH9)
2214 {
2215 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
2216 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
2217 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */
2218 if (fIsGuest64Bit || fEnablePAE)
2219 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
2220 }
2221 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
2222 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
2223 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
2224
2225 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
2226 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
2227
2228 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
2229 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
2230
2231 if (auSerialIoPortBase[2])
2232 {
2233 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
2234 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
2235 }
2236
2237 if (auSerialIoPortBase[3])
2238 {
2239 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
2240 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
2241 }
2242
2243 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
2244 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
2245
2246 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
2247 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
2248
2249#if defined(VBOX_WITH_TPM)
2250 switch (enmTpmType)
2251 {
2252 case TpmType_v1_2:
2253 InsertConfigString(pCfg, "TpmMode", "tis1.2");
2254 break;
2255 case TpmType_v2_0:
2256 InsertConfigString(pCfg, "TpmMode", "fifo2.0");
2257 break;
2258 /** @todo Host and swtpm. */
2259 default:
2260 break;
2261 }
2262#endif
2263
2264 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2265 InsertConfigString(pLunL0, "Driver", "ACPIHost");
2266 InsertConfigNode(pLunL0, "Config", &pCfg);
2267
2268 /* Attach the dummy CPU drivers */
2269 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
2270 {
2271 BOOL fCpuAttached = true;
2272
2273 if (fCpuHotPlug)
2274 {
2275 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
2276 }
2277
2278 if (fCpuAttached)
2279 {
2280 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
2281 InsertConfigString(pLunL0, "Driver", "ACPICpu");
2282 InsertConfigNode(pLunL0, "Config", &pCfg);
2283 }
2284 }
2285 }
2286
2287 /*
2288 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
2289 */
2290 vrc = i_configGuestDbg(virtualBox, pMachine, pRoot); VRC();
2291 }
2292 catch (ConfigError &x)
2293 {
2294 // InsertConfig threw something:
2295 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());
2296 return x.m_vrc;
2297 }
2298 catch (HRESULT hrcXcpt)
2299 {
2300 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2301 }
2302
2303#ifdef VBOX_WITH_EXTPACK
2304 /*
2305 * Call the extension pack hooks if everything went well thus far.
2306 */
2307 if (RT_SUCCESS(vrc))
2308 {
2309 pAlock->release();
2310 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);
2311 pAlock->acquire();
2312 }
2313#endif
2314
2315 /*
2316 * Apply the CFGM overlay.
2317 */
2318 if (RT_SUCCESS(vrc))
2319 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
2320
2321 /*
2322 * Dump all extradata API settings tweaks, both global and per VM.
2323 */
2324 if (RT_SUCCESS(vrc))
2325 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
2326
2327#undef H
2328
2329 pAlock->release(); /* Avoid triggering the lock order inversion check. */
2330
2331 /*
2332 * Register VM state change handler.
2333 */
2334 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
2335 AssertRC(vrc2);
2336 if (RT_SUCCESS(vrc))
2337 vrc = vrc2;
2338
2339 /*
2340 * Register VM runtime error handler.
2341 */
2342 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
2343 AssertRC(vrc2);
2344 if (RT_SUCCESS(vrc))
2345 vrc = vrc2;
2346
2347 pAlock->acquire();
2348
2349 LogFlowFunc(("vrc = %Rrc\n", vrc));
2350 LogFlowFuncLeave();
2351
2352 return vrc;
2353}
2354
2355
2356int Console::i_configGraphicsController(PCFGMNODE pDevices,
2357 const GraphicsControllerType_T enmGraphicsController,
2358 BusAssignmentManager *pBusMgr,
2359 const ComPtr<IMachine> &ptrMachine,
2360 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
2361 const ComPtr<IFirmwareSettings> &ptrFirmwareSettings,
2362 bool fHMEnabled)
2363{
2364 // InsertConfig* throws
2365 try
2366 {
2367 PCFGMNODE pDev, pInst, pCfg, pLunL0;
2368 HRESULT hrc;
2369 Bstr bstr;
2370 const char *pcszDevice = "vga";
2371
2372#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
2373 InsertConfigNode(pDevices, pcszDevice, &pDev);
2374 InsertConfigNode(pDev, "0", &pInst);
2375 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2376
2377 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
2378 InsertConfigNode(pInst, "Config", &pCfg);
2379 ULONG cVRamMBs;
2380 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
2381 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
2382 ULONG cMonitorCount;
2383 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
2384 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
2385#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
2386 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
2387#else
2388 NOREF(fHMEnabled);
2389#endif
2390 BOOL f3DEnabled;
2391 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
2392 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
2393
2394 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
2395
2396#ifdef VBOX_WITH_VMSVGA
2397 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
2398 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
2399 {
2400 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
2401 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
2402 {
2403 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
2404 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
2405 }
2406# ifdef VBOX_WITH_VMSVGA3D
2407 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
2408# else
2409 LogRel(("VMSVGA3d not available in this build!\n"));
2410# endif /* VBOX_WITH_VMSVGA3D */
2411 }
2412#else
2413 RT_NOREF(enmGraphicsController);
2414#endif /* VBOX_WITH_VMSVGA */
2415
2416 /* Custom VESA mode list */
2417 unsigned cModes = 0;
2418 for (unsigned iMode = 1; iMode <= 16; ++iMode)
2419 {
2420 char szExtraDataKey[sizeof("CustomVideoModeXX")];
2421 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
2422 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
2423 if (bstr.isEmpty())
2424 break;
2425 InsertConfigString(pCfg, szExtraDataKey, bstr);
2426 ++cModes;
2427 }
2428 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
2429
2430 /* VESA height reduction */
2431 ULONG ulHeightReduction;
2432 IFramebuffer *pFramebuffer = NULL;
2433 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
2434 if (SUCCEEDED(hrc) && pFramebuffer)
2435 {
2436 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
2437 pFramebuffer->Release();
2438 pFramebuffer = NULL;
2439 }
2440 else
2441 {
2442 /* If framebuffer is not available, there is no height reduction. */
2443 ulHeightReduction = 0;
2444 }
2445 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
2446
2447 /*
2448 * BIOS logo
2449 */
2450 BOOL fFadeIn;
2451 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
2452 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
2453 BOOL fFadeOut;
2454 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
2455 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
2456 ULONG logoDisplayTime;
2457 hrc = ptrFirmwareSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
2458 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
2459 Bstr bstrLogoImagePath;
2460 hrc = ptrFirmwareSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
2461 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
2462
2463 /*
2464 * Boot menu
2465 */
2466 FirmwareBootMenuMode_T enmBootMenuMode;
2467 int iShowBootMenu;
2468 hrc = ptrFirmwareSettings->COMGETTER(BootMenuMode)(&enmBootMenuMode); H();
2469 switch (enmBootMenuMode)
2470 {
2471 case FirmwareBootMenuMode_Disabled: iShowBootMenu = 0; break;
2472 case FirmwareBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
2473 default: iShowBootMenu = 2; break;
2474 }
2475 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
2476
2477 /* Attach the display. */
2478 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2479 InsertConfigString(pLunL0, "Driver", "MainDisplay");
2480 InsertConfigNode(pLunL0, "Config", &pCfg);
2481 }
2482 catch (ConfigError &x)
2483 {
2484 // InsertConfig threw something:
2485 return x.m_vrc;
2486 }
2487
2488#undef H
2489
2490 return VINF_SUCCESS;
2491}
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