VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp@ 67918

Last change on this file since 67918 was 67918, checked in by vboxsync, 8 years ago

Main/Console: EFI graphics resolution cleanup, prepare for resolution based mode selection by default
Devices/EFI: use new CFGM keys (fall back to old ones if necessary), clean up variable and info field naming
Devices/EFI/Firmware: for both GOP and UGA (which is very deprecated) try to find the mode by resolution if possible

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 256.1 KB
Line 
1/* $Id: ConsoleImpl2.cpp 67918 2017-07-12 09:30:24Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - VM Configuration Bits.
4 *
5 * @remark We've split out the code that the 64-bit VC++ v8 compiler finds
6 * problematic to optimize so we can disable optimizations and later,
7 * perhaps, find a real solution for it (like rewriting the code and
8 * to stop resemble a tonne of spaghetti).
9 */
10
11/*
12 * Copyright (C) 2006-2017 Oracle Corporation
13 *
14 * This file is part of VirtualBox Open Source Edition (OSE), as
15 * available from http://www.215389.xyz. This file is free software;
16 * you can redistribute it and/or modify it under the terms of the GNU
17 * General Public License (GPL) as published by the Free Software
18 * Foundation, in version 2 as it comes in the "COPYING" file of the
19 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
20 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21 */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
28#include "LoggingNew.h"
29
30// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
31// header file includes Windows.h.
32#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
33# include <VBox/VBoxNetCfg-win.h>
34#endif
35
36#include "ConsoleImpl.h"
37#include "DisplayImpl.h"
38#ifdef VBOX_WITH_GUEST_CONTROL
39# include "GuestImpl.h"
40#endif
41#ifdef VBOX_WITH_DRAG_AND_DROP
42# include "GuestDnDPrivate.h"
43#endif
44#include "VMMDev.h"
45#include "Global.h"
46#ifdef VBOX_WITH_PCI_PASSTHROUGH
47# include "PCIRawDevImpl.h"
48#endif
49
50// generated header
51#include "SchemaDefs.h"
52
53#include "AutoCaller.h"
54
55#include <iprt/base64.h>
56#include <iprt/buildconfig.h>
57#include <iprt/ctype.h>
58#include <iprt/dir.h>
59#include <iprt/file.h>
60#include <iprt/param.h>
61#include <iprt/path.h>
62#include <iprt/string.h>
63#include <iprt/system.h>
64#include <iprt/cpp/exception.h>
65#if 0 /* enable to play with lots of memory. */
66# include <iprt/env.h>
67#endif
68#include <iprt/stream.h>
69
70#include <VBox/vmm/vmapi.h>
71#include <VBox/err.h>
72#include <VBox/param.h>
73#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
74#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
75#include <VBox/vmm/apic.h> /* For APICMODE enum. */
76#include <VBox/vmm/pdmstorageifs.h>
77#include <VBox/version.h>
78#include <VBox/HostServices/VBoxClipboardSvc.h>
79#ifdef VBOX_WITH_CROGL
80# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
81#include <VBox/VBoxOGL.h>
82#endif
83#ifdef VBOX_WITH_GUEST_PROPS
84# include <VBox/HostServices/GuestPropertySvc.h>
85# include <VBox/com/defs.h>
86# include <VBox/com/array.h>
87# include "HGCM.h" /** @todo It should be possible to register a service
88 * extension using a VMMDev callback. */
89# include <vector>
90#endif /* VBOX_WITH_GUEST_PROPS */
91#include <VBox/intnet.h>
92
93#include <VBox/com/com.h>
94#include <VBox/com/string.h>
95#include <VBox/com/array.h>
96
97#ifdef VBOX_WITH_NETFLT
98# if defined(RT_OS_SOLARIS)
99# include <zone.h>
100# elif defined(RT_OS_LINUX)
101# include <unistd.h>
102# include <sys/ioctl.h>
103# include <sys/socket.h>
104# include <linux/types.h>
105# include <linux/if.h>
106# include <linux/wireless.h>
107# elif defined(RT_OS_FREEBSD)
108# include <unistd.h>
109# include <sys/types.h>
110# include <sys/ioctl.h>
111# include <sys/socket.h>
112# include <net/if.h>
113# include <net80211/ieee80211_ioctl.h>
114# endif
115# if defined(RT_OS_WINDOWS)
116# include <iprt/win/ntddndis.h>
117# include <devguid.h>
118# else
119# include <HostNetworkInterfaceImpl.h>
120# include <netif.h>
121# include <stdlib.h>
122# endif
123#endif /* VBOX_WITH_NETFLT */
124
125#include "NetworkServiceRunner.h"
126#include "BusAssignmentManager.h"
127#ifdef VBOX_WITH_EXTPACK
128# include "ExtPackManagerImpl.h"
129#endif
130
131
132/*********************************************************************************************************************************
133* Internal Functions *
134*********************************************************************************************************************************/
135static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);
136
137
138/* Darwin compile kludge */
139#undef PVM
140
141/* Comment out the following line to remove VMWare compatibility hack. */
142#define VMWARE_NET_IN_SLOT_11
143
144/**
145 * Translate IDE StorageControllerType_T to string representation.
146 */
147const char* controllerString(StorageControllerType_T enmType)
148{
149 switch (enmType)
150 {
151 case StorageControllerType_PIIX3:
152 return "PIIX3";
153 case StorageControllerType_PIIX4:
154 return "PIIX4";
155 case StorageControllerType_ICH6:
156 return "ICH6";
157 default:
158 return "Unknown";
159 }
160}
161
162/**
163 * Simple class for storing network boot information.
164 */
165struct BootNic
166{
167 ULONG mInstance;
168 PCIBusAddress mPCIAddress;
169
170 ULONG mBootPrio;
171 bool operator < (const BootNic &rhs) const
172 {
173 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
174 ULONG rval = rhs.mBootPrio - 1;
175 return lval < rval; /* Zero compares as highest number (lowest prio). */
176 }
177};
178
179static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
180{
181 Bstr aFilePath, empty;
182 BOOL fPresent = FALSE;
183 HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),
184 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
185 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
186
187 if (!fPresent)
188 {
189 LogRel(("Failed to find an EFI ROM file.\n"));
190 return VERR_FILE_NOT_FOUND;
191 }
192
193 *pEfiRomFile = Utf8Str(aFilePath);
194
195 return VINF_SUCCESS;
196}
197
198/**
199 * @throws HRESULT on extra data retrival error.
200 */
201static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
202{
203 *pfGetKeyFromRealSMC = false;
204
205 /*
206 * The extra data takes precedence (if non-zero).
207 */
208 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
209 if (pStrKey->isNotEmpty())
210 return VINF_SUCCESS;
211
212#ifdef RT_OS_DARWIN
213
214 /*
215 * Work done in EFI/DevSmc
216 */
217 *pfGetKeyFromRealSMC = true;
218 int rc = VINF_SUCCESS;
219
220#else
221 /*
222 * Is it apple hardware in bootcamp?
223 */
224 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
225 * Currently falling back on the product name. */
226 char szManufacturer[256];
227 szManufacturer[0] = '\0';
228 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
229 if (szManufacturer[0] != '\0')
230 {
231 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
232 || !strcmp(szManufacturer, "Apple Inc.")
233 )
234 *pfGetKeyFromRealSMC = true;
235 }
236 else
237 {
238 char szProdName[256];
239 szProdName[0] = '\0';
240 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
241 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
242 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
243 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
244 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
245 )
246 && !strchr(szProdName, ' ') /* no spaces */
247 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
248 )
249 *pfGetKeyFromRealSMC = true;
250 }
251
252 int rc = VINF_SUCCESS;
253#endif
254
255 return rc;
256}
257
258
259/*
260 * VC++ 8 / amd64 has some serious trouble with the next functions.
261 * As a temporary measure, we'll drop global optimizations.
262 */
263#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
264# if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100
265# pragma optimize("g", off)
266# endif
267#endif
268
269class ConfigError : public RTCError
270{
271public:
272
273 ConfigError(const char *pcszFunction,
274 int vrc,
275 const char *pcszName)
276 : RTCError(Utf8StrFmt("%s failed: rc=%Rrc, pcszName=%s", pcszFunction, vrc, pcszName)),
277 m_vrc(vrc)
278 {
279 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here
280 }
281
282 int m_vrc;
283};
284
285
286/**
287 * Helper that calls CFGMR3InsertString and throws an RTCError if that
288 * fails (C-string variant).
289 * @param pNode See CFGMR3InsertStringN.
290 * @param pcszName See CFGMR3InsertStringN.
291 * @param pcszValue The string value.
292 */
293static void InsertConfigString(PCFGMNODE pNode,
294 const char *pcszName,
295 const char *pcszValue)
296{
297 int vrc = CFGMR3InsertString(pNode,
298 pcszName,
299 pcszValue);
300 if (RT_FAILURE(vrc))
301 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
302}
303
304/**
305 * Helper that calls CFGMR3InsertString and throws an RTCError if that
306 * fails (Utf8Str variant).
307 * @param pNode See CFGMR3InsertStringN.
308 * @param pcszName See CFGMR3InsertStringN.
309 * @param rStrValue The string value.
310 */
311static void InsertConfigString(PCFGMNODE pNode,
312 const char *pcszName,
313 const Utf8Str &rStrValue)
314{
315 int vrc = CFGMR3InsertStringN(pNode,
316 pcszName,
317 rStrValue.c_str(),
318 rStrValue.length());
319 if (RT_FAILURE(vrc))
320 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
321}
322
323/**
324 * Helper that calls CFGMR3InsertString and throws an RTCError if that
325 * fails (Bstr variant).
326 *
327 * @param pNode See CFGMR3InsertStringN.
328 * @param pcszName See CFGMR3InsertStringN.
329 * @param rBstrValue The string value.
330 */
331static void InsertConfigString(PCFGMNODE pNode,
332 const char *pcszName,
333 const Bstr &rBstrValue)
334{
335 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
336}
337
338/**
339 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
340 *
341 * @param pNode See CFGMR3InsertBytes.
342 * @param pcszName See CFGMR3InsertBytes.
343 * @param pvBytes See CFGMR3InsertBytes.
344 * @param cbBytes See CFGMR3InsertBytes.
345 */
346static void InsertConfigBytes(PCFGMNODE pNode,
347 const char *pcszName,
348 const void *pvBytes,
349 size_t cbBytes)
350{
351 int vrc = CFGMR3InsertBytes(pNode,
352 pcszName,
353 pvBytes,
354 cbBytes);
355 if (RT_FAILURE(vrc))
356 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
357}
358
359/**
360 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
361 * fails.
362 *
363 * @param pNode See CFGMR3InsertInteger.
364 * @param pcszName See CFGMR3InsertInteger.
365 * @param u64Integer See CFGMR3InsertInteger.
366 */
367static void InsertConfigInteger(PCFGMNODE pNode,
368 const char *pcszName,
369 uint64_t u64Integer)
370{
371 int vrc = CFGMR3InsertInteger(pNode,
372 pcszName,
373 u64Integer);
374 if (RT_FAILURE(vrc))
375 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
376}
377
378/**
379 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
380 *
381 * @param pNode See CFGMR3InsertNode.
382 * @param pcszName See CFGMR3InsertNode.
383 * @param ppChild See CFGMR3InsertNode.
384 */
385static void InsertConfigNode(PCFGMNODE pNode,
386 const char *pcszName,
387 PCFGMNODE *ppChild)
388{
389 int vrc = CFGMR3InsertNode(pNode, pcszName, ppChild);
390 if (RT_FAILURE(vrc))
391 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
392}
393
394/**
395 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
396 *
397 * @param pNode See CFGMR3RemoveValue.
398 * @param pcszName See CFGMR3RemoveValue.
399 */
400static void RemoveConfigValue(PCFGMNODE pNode,
401 const char *pcszName)
402{
403 int vrc = CFGMR3RemoveValue(pNode, pcszName);
404 if (RT_FAILURE(vrc))
405 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
406}
407
408/**
409 * Gets an extra data value, consulting both machine and global extra data.
410 *
411 * @throws HRESULT on failure
412 * @returns pStrValue for the callers convenience.
413 * @param pVirtualBox Pointer to the IVirtualBox interface.
414 * @param pMachine Pointer to the IMachine interface.
415 * @param pszName The value to get.
416 * @param pStrValue Where to return it's value (empty string if not
417 * found).
418 */
419static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
420{
421 pStrValue->setNull();
422
423 Bstr bstrName(pszName);
424 Bstr bstrValue;
425 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
426 if (FAILED(hrc))
427 throw hrc;
428 if (bstrValue.isEmpty())
429 {
430 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
431 if (FAILED(hrc))
432 throw hrc;
433 }
434
435 if (bstrValue.isNotEmpty())
436 *pStrValue = bstrValue;
437 return pStrValue;
438}
439
440
441/** Helper that finds out the next HBA port used
442 */
443static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
444{
445 LONG lNextPortUsed = 30;
446 for (size_t j = 0; j < u32Size; ++j)
447 {
448 if ( aPortUsed[j] > lBaseVal
449 && aPortUsed[j] <= lNextPortUsed)
450 lNextPortUsed = aPortUsed[j];
451 }
452 return lNextPortUsed;
453}
454
455#define MAX_BIOS_LUN_COUNT 4
456
457static int SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
458 Bstr controllerName, const char * const s_apszBiosConfig[4])
459{
460 RT_NOREF(pCfg);
461 HRESULT hrc;
462#define MAX_DEVICES 30
463#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
464
465 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
466 LONG lPortUsed[MAX_DEVICES];
467 uint32_t u32HDCount = 0;
468
469 /* init to max value */
470 lPortLUN[0] = MAX_DEVICES;
471
472 com::SafeIfaceArray<IMediumAttachment> atts;
473 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
474 ComSafeArrayAsOutParam(atts)); H();
475 size_t uNumAttachments = atts.size();
476 if (uNumAttachments > MAX_DEVICES)
477 {
478 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
479 uNumAttachments = MAX_DEVICES;
480 }
481
482 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
483 for (size_t j = 0; j < uNumAttachments; ++j)
484 {
485 IMediumAttachment *pMediumAtt = atts[j];
486 LONG lPortNum = 0;
487 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
488 if (SUCCEEDED(hrc))
489 {
490 DeviceType_T lType;
491 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
492 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
493 {
494 /* find min port number used for HD */
495 if (lPortNum < lPortLUN[0])
496 lPortLUN[0] = lPortNum;
497 lPortUsed[u32HDCount++] = lPortNum;
498 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
499 }
500 }
501 }
502
503
504 /* Pick only the top 4 used HD Ports as CMOS doesn't have space
505 * to save details for all 30 ports
506 */
507 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
508 if (u32HDCount < MAX_BIOS_LUN_COUNT)
509 u32MaxPortCount = u32HDCount;
510 for (size_t j = 1; j < u32MaxPortCount; j++)
511 lPortLUN[j] = GetNextUsedPort(lPortUsed,
512 lPortLUN[j-1],
513 u32HDCount);
514 if (pBiosCfg)
515 {
516 for (size_t j = 0; j < u32MaxPortCount; j++)
517 {
518 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
519 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
520 }
521 }
522 return VINF_SUCCESS;
523}
524
525#ifdef VBOX_WITH_PCI_PASSTHROUGH
526HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
527{
528# ifndef VBOX_WITH_EXTPACK
529 RT_NOREF(pUVM);
530# endif
531 HRESULT hrc = S_OK;
532 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
533
534 SafeIfaceArray<IPCIDeviceAttachment> assignments;
535 ComPtr<IMachine> aMachine = i_machine();
536
537 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
538 if ( hrc != S_OK
539 || assignments.size() < 1)
540 return hrc;
541
542 /*
543 * PCI passthrough is only available if the proper ExtPack is installed.
544 *
545 * Note. Configuring PCI passthrough here and providing messages about
546 * the missing extpack isn't exactly clean, but it is a necessary evil
547 * to patch over legacy compatability issues introduced by the new
548 * distribution model.
549 */
550# ifdef VBOX_WITH_EXTPACK
551 static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";
552 if (!mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName))
553 /* Always fatal! */
554 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
555 N_("Implementation of the PCI passthrough framework not found!\n"
556 "The VM cannot be started. To fix this problem, either "
557 "install the '%s' or disable PCI passthrough via VBoxManage"),
558 s_pszPCIRawExtPackName);
559# endif
560
561 PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
562 Assert(pBridges);
563
564 /* Find required bridges, and add missing ones */
565 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
566 {
567 ComPtr<IPCIDeviceAttachment> assignment = assignments[iDev];
568 LONG guest = 0;
569 PCIBusAddress GuestPCIAddress;
570
571 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
572 GuestPCIAddress.fromLong(guest);
573 Assert(GuestPCIAddress.valid());
574
575 if (GuestPCIAddress.miBus > 0)
576 {
577 int iBridgesMissed = 0;
578 int iBase = GuestPCIAddress.miBus - 1;
579
580 while (!pBusMgr->hasPCIDevice("ich9pcibridge", iBase) && iBase > 0)
581 {
582 iBridgesMissed++; iBase--;
583 }
584 iBase++;
585
586 for (int iBridge = 0; iBridge < iBridgesMissed; iBridge++)
587 {
588 InsertConfigNode(pBridges, Utf8StrFmt("%d", iBase + iBridge).c_str(), &pInst);
589 InsertConfigInteger(pInst, "Trusted", 1);
590 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);
591 }
592 }
593 }
594
595 /* Now actually add devices */
596 PCFGMNODE pPCIDevs = NULL;
597
598 if (assignments.size() > 0)
599 {
600 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);
601
602 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
603
604 /* Tell PGM to tell GPCIRaw about guest mappings. */
605 CFGMR3InsertNode(pRoot, "PGM", NULL);
606 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
607
608 /*
609 * Currently, using IOMMU needed for PCI passthrough
610 * requires RAM preallocation.
611 */
612 /** @todo check if we can lift this requirement */
613 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
614 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
615 }
616
617 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
618 {
619 PCIBusAddress HostPCIAddress, GuestPCIAddress;
620 ComPtr<IPCIDeviceAttachment> assignment = assignments[iDev];
621 LONG host, guest;
622 Bstr aDevName;
623
624 hrc = assignment->COMGETTER(HostAddress)(&host); H();
625 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
626 hrc = assignment->COMGETTER(Name)(aDevName.asOutParam()); H();
627
628 InsertConfigNode(pPCIDevs, Utf8StrFmt("%d", iDev).c_str(), &pInst);
629 InsertConfigInteger(pInst, "Trusted", 1);
630
631 HostPCIAddress.fromLong(host);
632 Assert(HostPCIAddress.valid());
633 InsertConfigNode(pInst, "Config", &pCfg);
634 InsertConfigString(pCfg, "DeviceName", aDevName);
635
636 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
637 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);
638 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);
639 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);
640
641 GuestPCIAddress.fromLong(guest);
642 Assert(GuestPCIAddress.valid());
643 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
644 if (hrc != S_OK)
645 return hrc;
646
647 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);
648 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);
649 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);
650
651 /* the driver */
652 InsertConfigNode(pInst, "LUN#0", &pLunL0);
653 InsertConfigString(pLunL0, "Driver", "pciraw");
654 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
655
656 /* the Main driver */
657 InsertConfigString(pLunL1, "Driver", "MainPciRaw");
658 InsertConfigNode(pLunL1, "Config", &pCfg);
659 PCIRawDev* pMainDev = new PCIRawDev(this);
660 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
661 }
662
663 return hrc;
664}
665#endif
666
667
668void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, PPDMLED *papLeds,
669 uint64_t uFirst, uint64_t uLast,
670 Console::MediumAttachmentMap *pmapMediumAttachments,
671 const char *pcszDevice, unsigned uInstance)
672{
673 PCFGMNODE pLunL0, pCfg;
674 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
675 InsertConfigString(pLunL0, "Driver", "MainStatus");
676 InsertConfigNode(pLunL0, "Config", &pCfg);
677 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)papLeds);
678 if (pmapMediumAttachments)
679 {
680 InsertConfigInteger(pCfg, "pmapMediumAttachments", (uintptr_t)pmapMediumAttachments);
681 InsertConfigInteger(pCfg, "pConsole", (uintptr_t)this);
682 AssertPtr(pcszDevice);
683 Utf8Str deviceInstance = Utf8StrFmt("%s/%u", pcszDevice, uInstance);
684 InsertConfigString(pCfg, "DeviceInstance", deviceInstance.c_str());
685 }
686 InsertConfigInteger(pCfg, "First", uFirst);
687 InsertConfigInteger(pCfg, "Last", uLast);
688}
689
690
691/**
692 * Construct the VM configuration tree (CFGM).
693 *
694 * This is a callback for VMR3Create() call. It is called from CFGMR3Init()
695 * in the emulation thread (EMT). Any per thread COM/XPCOM initialization
696 * is done here.
697 *
698 * @param pUVM The user mode VM handle.
699 * @param pVM The cross context VM handle.
700 * @param pvConsole Pointer to the VMPowerUpTask object.
701 * @return VBox status code.
702 *
703 * @note Locks the Console object for writing.
704 */
705DECLCALLBACK(int) Console::i_configConstructor(PUVM pUVM, PVM pVM, void *pvConsole)
706{
707 LogFlowFuncEnter();
708
709 AssertReturn(pvConsole, VERR_INVALID_POINTER);
710 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
711
712 AutoCaller autoCaller(pConsole);
713 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
714
715 /* lock the console because we widely use internal fields and methods */
716 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
717
718 /*
719 * Set the VM handle and do the rest of the job in an worker method so we
720 * can easily reset the VM handle on failure.
721 */
722 pConsole->mpUVM = pUVM;
723 VMR3RetainUVM(pUVM);
724 int vrc;
725 try
726 {
727 vrc = pConsole->i_configConstructorInner(pUVM, pVM, &alock);
728 }
729 catch (...)
730 {
731 vrc = VERR_UNEXPECTED_EXCEPTION;
732 }
733 if (RT_FAILURE(vrc))
734 {
735 pConsole->mpUVM = NULL;
736 VMR3ReleaseUVM(pUVM);
737 }
738
739 return vrc;
740}
741
742
743/**
744 * Worker for configConstructor.
745 *
746 * @return VBox status code.
747 * @param pUVM The user mode VM handle.
748 * @param pVM The cross context VM handle.
749 * @param pAlock The automatic lock instance. This is for when we have
750 * to leave it in order to avoid deadlocks (ext packs and
751 * more).
752 */
753int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
754{
755 RT_NOREF(pVM /* when everything is disabled */);
756 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
757 ComPtr<IMachine> pMachine = i_machine();
758
759 int rc;
760 HRESULT hrc;
761 Utf8Str strTmp;
762 Bstr bstr;
763
764#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
765
766 /*
767 * Get necessary objects and frequently used parameters.
768 */
769 ComPtr<IVirtualBox> virtualBox;
770 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
771
772 ComPtr<IHost> host;
773 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
774
775 ComPtr<ISystemProperties> systemProperties;
776 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
777
778 ComPtr<IBIOSSettings> biosSettings;
779 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();
780
781 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
782 RTUUID HardwareUuid;
783 rc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
784 AssertRCReturn(rc, rc);
785
786 ULONG cRamMBs;
787 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
788#if 0 /* enable to play with lots of memory. */
789 if (RTEnvExist("VBOX_RAM_SIZE"))
790 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
791#endif
792 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
793 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
794 uint64_t uMcfgBase = 0;
795 uint32_t cbMcfgLength = 0;
796
797 ParavirtProvider_T paravirtProvider;
798 hrc = pMachine->GetEffectiveParavirtProvider(&paravirtProvider); H();
799
800 Bstr strParavirtDebug;
801 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
802
803 ChipsetType_T chipsetType;
804 hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType); H();
805 if (chipsetType == ChipsetType_ICH9)
806 {
807 /* We'd better have 0x10000000 region, to cover 256 buses but this put
808 * too much load on hypervisor heap. Linux 4.8 currently complains with
809 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]
810 * only partially covers this bridge'' */
811 cbMcfgLength = 0x4000000; //0x10000000;
812 cbRamHole += cbMcfgLength;
813 uMcfgBase = _4G - cbRamHole;
814 }
815
816 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(chipsetType);
817
818 ULONG cCpus = 1;
819 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
820
821 ULONG ulCpuExecutionCap = 100;
822 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
823
824 Bstr osTypeId;
825 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
826 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
827
828 BOOL fIOAPIC;
829 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
830
831 APICMode_T apicMode;
832 hrc = biosSettings->COMGETTER(APICMode)(&apicMode); H();
833 uint32_t uFwAPIC;
834 switch (apicMode)
835 {
836 case APICMode_Disabled:
837 uFwAPIC = 0;
838 break;
839 case APICMode_APIC:
840 uFwAPIC = 1;
841 break;
842 case APICMode_X2APIC:
843 uFwAPIC = 2;
844 break;
845 default:
846 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
847 uFwAPIC = 1;
848 break;
849 }
850
851 ComPtr<IGuestOSType> guestOSType;
852 hrc = virtualBox->GetGuestOSType(osTypeId.raw(), guestOSType.asOutParam()); H();
853
854 Bstr guestTypeFamilyId;
855 hrc = guestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
856 BOOL fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
857
858 ULONG maxNetworkAdapters;
859 hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
860
861 /*
862 * Get root node first.
863 * This is the only node in the tree.
864 */
865 PCFGMNODE pRoot = CFGMR3GetRootU(pUVM);
866 Assert(pRoot);
867
868 // InsertConfigString throws
869 try
870 {
871
872 /*
873 * Set the root (and VMM) level values.
874 */
875 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
876 InsertConfigString(pRoot, "Name", bstr);
877 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
878 InsertConfigInteger(pRoot, "RamSize", cbRam);
879 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
880 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
881 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
882 InsertConfigInteger(pRoot, "TimerMillies", 10);
883#ifdef VBOX_WITH_RAW_MODE
884 InsertConfigInteger(pRoot, "RawR3Enabled", 1); /* boolean */
885 InsertConfigInteger(pRoot, "RawR0Enabled", 1); /* boolean */
886 /** @todo Config: RawR0, PATMEnabled and CSAMEnabled needs attention later. */
887 InsertConfigInteger(pRoot, "PATMEnabled", 1); /* boolean */
888 InsertConfigInteger(pRoot, "CSAMEnabled", 1); /* boolean */
889#endif
890
891#ifdef VBOX_WITH_RAW_RING1
892 if (osTypeId == "QNX")
893 {
894 /* QNX needs special treatment in raw mode due to its use of ring-1. */
895 InsertConfigInteger(pRoot, "RawR1Enabled", 1); /* boolean */
896 }
897#endif
898
899 BOOL fPageFusion = FALSE;
900 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
901 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
902
903 /* Not necessary, but makes sure this setting ends up in the release log. */
904 ULONG ulBalloonSize = 0;
905 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
906 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
907
908 /*
909 * EM values (before CPUM as it may need to set IemExecutesAll).
910 */
911 PCFGMNODE pEM;
912 InsertConfigNode(pRoot, "EM", &pEM);
913
914 /* Triple fault behavior. */
915 BOOL fTripleFaultReset = false;
916 hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();
917 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
918
919 /*
920 * CPUM values.
921 */
922 PCFGMNODE pCPUM;
923 InsertConfigNode(pRoot, "CPUM", &pCPUM);
924
925 /* cpuid leaf overrides. */
926 static uint32_t const s_auCpuIdRanges[] =
927 {
928 UINT32_C(0x00000000), UINT32_C(0x0000000a),
929 UINT32_C(0x80000000), UINT32_C(0x8000000a)
930 };
931 for (unsigned i = 0; i < RT_ELEMENTS(s_auCpuIdRanges); i += 2)
932 for (uint32_t uLeaf = s_auCpuIdRanges[i]; uLeaf < s_auCpuIdRanges[i + 1]; uLeaf++)
933 {
934 ULONG ulEax, ulEbx, ulEcx, ulEdx;
935 hrc = pMachine->GetCPUIDLeaf(uLeaf, &ulEax, &ulEbx, &ulEcx, &ulEdx);
936 if (SUCCEEDED(hrc))
937 {
938 PCFGMNODE pLeaf;
939 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
940
941 InsertConfigInteger(pLeaf, "eax", ulEax);
942 InsertConfigInteger(pLeaf, "ebx", ulEbx);
943 InsertConfigInteger(pLeaf, "ecx", ulEcx);
944 InsertConfigInteger(pLeaf, "edx", ulEdx);
945 }
946 else if (hrc != E_INVALIDARG) H();
947 }
948
949 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
950 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
951 if (osTypeId == "WindowsNT4")
952 {
953 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
954 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
955 }
956
957 /* Expose CMPXCHG16B. Currently a hack. */
958 if ( osTypeId == "Windows81_64"
959 || osTypeId == "Windows2012_64"
960 || osTypeId == "Windows10_64"
961 || osTypeId == "Windows2016_64")
962 {
963 LogRel(("Enabling CMPXCHG16B for Windows 8.1 / 2k12 or newer guests\n"));
964 InsertConfigInteger(pCPUM, "CMPXCHG16B", true);
965 }
966
967 if (fOsXGuest)
968 {
969 /* Expose extended MWAIT features to Mac OS X guests. */
970 LogRel(("Using MWAIT extensions\n"));
971 InsertConfigInteger(pCPUM, "MWaitExtensions", true);
972
973 /* Fake the CPU family/model so the guest works. This is partly
974 because older mac releases really doesn't work on newer cpus,
975 and partly because mac os x expects more from systems with newer
976 cpus (MSRs, power features, whatever). */
977 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
978 if ( osTypeId == "MacOS"
979 || osTypeId == "MacOS_64")
980 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
981 else if ( osTypeId == "MacOS106"
982 || osTypeId == "MacOS106_64")
983 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
984 else if ( osTypeId == "MacOS107"
985 || osTypeId == "MacOS107_64")
986 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
987 what is required here. */
988 else if ( osTypeId == "MacOS108"
989 || osTypeId == "MacOS108_64")
990 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
991 what is required here. */
992 else if ( osTypeId == "MacOS109"
993 || osTypeId == "MacOS109_64")
994 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
995 out what is required here. */
996 if (uMaxIntelFamilyModelStep != UINT32_MAX)
997 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
998 }
999
1000 /* CPU Portability level, */
1001 ULONG uCpuIdPortabilityLevel = 0;
1002 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
1003 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
1004
1005 /* Physical Address Extension (PAE) */
1006 BOOL fEnablePAE = false;
1007 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();
1008 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
1009
1010 /* APIC/X2APIC configuration */
1011 BOOL fEnableAPIC = true;
1012 BOOL fEnableX2APIC = true;
1013 hrc = pMachine->GetCPUProperty(CPUPropertyType_APIC, &fEnableAPIC); H();
1014 hrc = pMachine->GetCPUProperty(CPUPropertyType_X2APIC, &fEnableX2APIC); H();
1015 if (fEnableX2APIC)
1016 Assert(fEnableAPIC);
1017
1018 /* CPUM profile name. */
1019 hrc = pMachine->COMGETTER(CPUProfile)(bstr.asOutParam()); H();
1020 InsertConfigString(pCPUM, "GuestCpuName", bstr);
1021
1022 /*
1023 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
1024 * correctly. There are way too many #UDs we'll miss using VT-x,
1025 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
1026 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
1027 */
1028 if ( bstr.equals("Intel 80386") /* just for now */
1029 || bstr.equals("Intel 80286")
1030 || bstr.equals("Intel 80186")
1031 || bstr.equals("Nec V20")
1032 || bstr.equals("Intel 8086") )
1033 {
1034 InsertConfigInteger(pEM, "IemExecutesAll", true);
1035 if (!bstr.equals("Intel 80386"))
1036 {
1037 fEnableAPIC = false;
1038 fIOAPIC = false;
1039 }
1040 fEnableX2APIC = false;
1041 }
1042
1043 /* Adjust firmware APIC handling to stay within the VCPU limits. */
1044 if (uFwAPIC == 2 && !fEnableX2APIC)
1045 {
1046 if (fEnableAPIC)
1047 uFwAPIC = 1;
1048 else
1049 uFwAPIC = 0;
1050 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
1051 }
1052 else if (uFwAPIC == 1 && !fEnableAPIC)
1053 {
1054 uFwAPIC = 0;
1055 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
1056 }
1057
1058 /*
1059 * Hardware virtualization extensions.
1060 */
1061 BOOL fSupportsHwVirtEx;
1062 hrc = host->GetProcessorFeature(ProcessorFeature_HWVirtEx, &fSupportsHwVirtEx); H();
1063
1064 BOOL fIsGuest64Bit;
1065 hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H();
1066 if (fIsGuest64Bit)
1067 {
1068 BOOL fSupportsLongMode;
1069 hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, &fSupportsLongMode); H();
1070 if (!fSupportsLongMode)
1071 {
1072 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support 64-bit.\n"));
1073 fIsGuest64Bit = FALSE;
1074 }
1075 if (!fSupportsHwVirtEx)
1076 {
1077 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support HW virtualization.\n"));
1078 fIsGuest64Bit = FALSE;
1079 }
1080 }
1081
1082 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
1083 if (!fEnableAPIC)
1084 {
1085 if (fIsGuest64Bit)
1086 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Cannot disable the APIC for a 64-bit guest."));
1087 if (cCpus > 1)
1088 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Cannot disable the APIC for an SMP guest."));
1089 if (fIOAPIC)
1090 {
1091 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1092 N_("Cannot disable the APIC when the I/O APIC is present."));
1093 }
1094 }
1095
1096 BOOL fHMEnabled;
1097 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
1098 if (cCpus > 1 && !fHMEnabled)
1099 {
1100 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
1101 fHMEnabled = TRUE;
1102 }
1103
1104 BOOL fHMForced;
1105#ifdef VBOX_WITH_RAW_MODE
1106 /* - With more than 4GB PGM will use different RAMRANGE sizes for raw
1107 mode and hv mode to optimize lookup times.
1108 - With more than one virtual CPU, raw-mode isn't a fallback option.
1109 - With a 64-bit guest, raw-mode isn't a fallback option either. */
1110 fHMForced = fHMEnabled
1111 && ( cbRam + cbRamHole > _4G
1112 || cCpus > 1
1113 || fIsGuest64Bit);
1114# ifdef RT_OS_DARWIN
1115 fHMForced = fHMEnabled;
1116# endif
1117 if (fHMForced)
1118 {
1119 if (cbRam + cbRamHole > _4G)
1120 LogRel(("fHMForced=true - Lots of RAM\n"));
1121 if (cCpus > 1)
1122 LogRel(("fHMForced=true - SMP\n"));
1123 if (fIsGuest64Bit)
1124 LogRel(("fHMForced=true - 64-bit guest\n"));
1125# ifdef RT_OS_DARWIN
1126 LogRel(("fHMForced=true - Darwin host\n"));
1127# endif
1128 }
1129#else /* !VBOX_WITH_RAW_MODE */
1130 fHMEnabled = fHMForced = TRUE;
1131 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
1132#endif /* !VBOX_WITH_RAW_MODE */
1133 if (!fHMForced) /* No need to query if already forced above. */
1134 {
1135 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
1136 if (fHMForced)
1137 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
1138 }
1139 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
1140
1141 /* /HM/xzy */
1142 PCFGMNODE pHM;
1143 InsertConfigNode(pRoot, "HM", &pHM);
1144 InsertConfigInteger(pHM, "HMForced", fHMForced);
1145 if (fHMEnabled)
1146 {
1147 /* Indicate whether 64-bit guests are supported or not. */
1148 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
1149#if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */
1150 PCFGMNODE pREM;
1151 InsertConfigNode(pRoot, "REM", &pREM);
1152 InsertConfigInteger(pREM, "64bitEnabled", 1);
1153#endif
1154
1155 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
1156 but that requires quite a bit of API change in Main. */
1157 if ( fIOAPIC
1158 && ( osTypeId == "WindowsNT4"
1159 || osTypeId == "Windows2000"
1160 || osTypeId == "WindowsXP"
1161 || osTypeId == "Windows2003"))
1162 {
1163 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
1164 * We may want to consider adding more guest OSes (Solaris) later on.
1165 */
1166 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
1167 }
1168 }
1169
1170 /* HWVirtEx exclusive mode */
1171 BOOL fHMExclusive = true;
1172 hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
1173 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
1174
1175 /* Nested paging (VT-x/AMD-V) */
1176 BOOL fEnableNestedPaging = false;
1177 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
1178 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
1179
1180 /* Large pages; requires nested paging */
1181 BOOL fEnableLargePages = false;
1182 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
1183 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
1184
1185 /* VPID (VT-x) */
1186 BOOL fEnableVPID = false;
1187 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
1188 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
1189
1190 /* Unrestricted execution aka UX (VT-x) */
1191 BOOL fEnableUX = false;
1192 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
1193 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
1194
1195 /* Reset overwrite. */
1196 if (i_isResetTurnedIntoPowerOff())
1197 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
1198
1199 /*
1200 * Paravirt. provider.
1201 */
1202 PCFGMNODE pParavirtNode;
1203 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1204 const char *pcszParavirtProvider;
1205 bool fGimDeviceNeeded = true;
1206 switch (paravirtProvider)
1207 {
1208 case ParavirtProvider_None:
1209 pcszParavirtProvider = "None";
1210 fGimDeviceNeeded = false;
1211 break;
1212
1213 case ParavirtProvider_Minimal:
1214 pcszParavirtProvider = "Minimal";
1215 break;
1216
1217 case ParavirtProvider_HyperV:
1218 pcszParavirtProvider = "HyperV";
1219 break;
1220
1221 case ParavirtProvider_KVM:
1222 pcszParavirtProvider = "KVM";
1223 break;
1224
1225 default:
1226 AssertMsgFailed(("Invalid paravirtProvider=%d\n", paravirtProvider));
1227 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1228 paravirtProvider);
1229 }
1230 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1231
1232 /*
1233 * Parse paravirt. debug options.
1234 */
1235 bool fGimDebug = false;
1236 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1237 uint32_t uGimDebugPort = 50000;
1238 if (strParavirtDebug.isNotEmpty())
1239 {
1240 /* Hyper-V debug options. */
1241 if (paravirtProvider == ParavirtProvider_HyperV)
1242 {
1243 bool fGimHvDebug = false;
1244 com::Utf8Str strGimHvVendor;
1245 bool fGimHvVsIf = false;
1246 bool fGimHvHypercallIf = false;
1247
1248 size_t uPos = 0;
1249 com::Utf8Str strDebugOptions = strParavirtDebug;
1250 com::Utf8Str strKey;
1251 com::Utf8Str strVal;
1252 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1253 {
1254 if (strKey == "enabled")
1255 {
1256 if (strVal.toUInt32() == 1)
1257 {
1258 /* Apply defaults.
1259 The defaults are documented in the user manual,
1260 changes need to be reflected accordingly. */
1261 fGimHvDebug = true;
1262 strGimHvVendor = "Microsoft Hv";
1263 fGimHvVsIf = true;
1264 fGimHvHypercallIf = false;
1265 }
1266 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1267 }
1268 else if (strKey == "address")
1269 strGimDebugAddress = strVal;
1270 else if (strKey == "port")
1271 uGimDebugPort = strVal.toUInt32();
1272 else if (strKey == "vendor")
1273 strGimHvVendor = strVal;
1274 else if (strKey == "vsinterface")
1275 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1276 else if (strKey == "hypercallinterface")
1277 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1278 else
1279 {
1280 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1281 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1282 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1283 strDebugOptions.c_str());
1284 }
1285 }
1286
1287 /* Update HyperV CFGM node with active debug options. */
1288 if (fGimHvDebug)
1289 {
1290 PCFGMNODE pHvNode;
1291 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1292 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1293 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1294 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1295 fGimDebug = true;
1296 }
1297 }
1298 }
1299
1300 /*
1301 * MM values.
1302 */
1303 PCFGMNODE pMM;
1304 InsertConfigNode(pRoot, "MM", &pMM);
1305 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1306
1307 /*
1308 * PDM config.
1309 * Load drivers in VBoxC.[so|dll]
1310 */
1311 PCFGMNODE pPDM;
1312 PCFGMNODE pNode;
1313 PCFGMNODE pMod;
1314 InsertConfigNode(pRoot, "PDM", &pPDM);
1315 InsertConfigNode(pPDM, "Devices", &pNode);
1316 InsertConfigNode(pPDM, "Drivers", &pNode);
1317 InsertConfigNode(pNode, "VBoxC", &pMod);
1318#ifdef VBOX_WITH_XPCOM
1319 // VBoxC is located in the components subdirectory
1320 char szPathVBoxC[RTPATH_MAX];
1321 rc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(rc);
1322 strcat(szPathVBoxC, "/components/VBoxC");
1323 InsertConfigString(pMod, "Path", szPathVBoxC);
1324#else
1325 InsertConfigString(pMod, "Path", "VBoxC");
1326#endif
1327
1328
1329 /*
1330 * Block cache settings.
1331 */
1332 PCFGMNODE pPDMBlkCache;
1333 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
1334
1335 /* I/O cache size */
1336 ULONG ioCacheSize = 5;
1337 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
1338 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
1339
1340 /*
1341 * Bandwidth groups.
1342 */
1343 PCFGMNODE pAc;
1344 PCFGMNODE pAcFile;
1345 PCFGMNODE pAcFileBwGroups;
1346 ComPtr<IBandwidthControl> bwCtrl;
1347 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
1348
1349 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
1350
1351 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
1352
1353 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
1354 InsertConfigNode(pAc, "File", &pAcFile);
1355 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
1356#ifdef VBOX_WITH_NETSHAPER
1357 PCFGMNODE pNetworkShaper;
1358 PCFGMNODE pNetworkBwGroups;
1359
1360 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
1361 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
1362#endif /* VBOX_WITH_NETSHAPER */
1363
1364 for (size_t i = 0; i < bwGroups.size(); i++)
1365 {
1366 Bstr strName;
1367 LONG64 cMaxBytesPerSec;
1368 BandwidthGroupType_T enmType;
1369
1370 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
1371 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
1372 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
1373
1374 if (strName.isEmpty())
1375 return VMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS,
1376 N_("No bandwidth group name specified"));
1377
1378 if (enmType == BandwidthGroupType_Disk)
1379 {
1380 PCFGMNODE pBwGroup;
1381 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1382 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1383 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
1384 InsertConfigInteger(pBwGroup, "Step", 0);
1385 }
1386#ifdef VBOX_WITH_NETSHAPER
1387 else if (enmType == BandwidthGroupType_Network)
1388 {
1389 /* Network bandwidth groups. */
1390 PCFGMNODE pBwGroup;
1391 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1392 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1393 }
1394#endif /* VBOX_WITH_NETSHAPER */
1395 }
1396
1397 /*
1398 * Devices
1399 */
1400 PCFGMNODE pDevices = NULL; /* /Devices */
1401 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1402 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1403 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1404 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1405 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1406 PCFGMNODE pLunL2 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config/ */
1407 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1408 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1409
1410 InsertConfigNode(pRoot, "Devices", &pDevices);
1411
1412 /*
1413 * GIM Device
1414 */
1415 if (fGimDeviceNeeded)
1416 {
1417 InsertConfigNode(pDevices, "GIMDev", &pDev);
1418 InsertConfigNode(pDev, "0", &pInst);
1419 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1420 //InsertConfigNode(pInst, "Config", &pCfg);
1421
1422 if (fGimDebug)
1423 {
1424 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1425 InsertConfigString(pLunL0, "Driver", "UDP");
1426 InsertConfigNode(pLunL0, "Config", &pLunL1);
1427 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1428 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1429 }
1430 }
1431
1432 /*
1433 * PC Arch.
1434 */
1435 InsertConfigNode(pDevices, "pcarch", &pDev);
1436 InsertConfigNode(pDev, "0", &pInst);
1437 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1438 InsertConfigNode(pInst, "Config", &pCfg);
1439
1440 /*
1441 * The time offset
1442 */
1443 LONG64 timeOffset;
1444 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1445 PCFGMNODE pTMNode;
1446 InsertConfigNode(pRoot, "TM", &pTMNode);
1447 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1448
1449 /*
1450 * DMA
1451 */
1452 InsertConfigNode(pDevices, "8237A", &pDev);
1453 InsertConfigNode(pDev, "0", &pInst);
1454 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1455
1456 /*
1457 * PCI buses.
1458 */
1459 uint32_t uIocPCIAddress, uHbcPCIAddress;
1460 switch (chipsetType)
1461 {
1462 default:
1463 Assert(false);
1464 /* fall thru */
1465 case ChipsetType_PIIX3:
1466 InsertConfigNode(pDevices, "pci", &pDev);
1467 uHbcPCIAddress = (0x0 << 16) | 0;
1468 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1469 break;
1470 case ChipsetType_ICH9:
1471 InsertConfigNode(pDevices, "ich9pci", &pDev);
1472 uHbcPCIAddress = (0x1e << 16) | 0;
1473 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1474 break;
1475 }
1476 InsertConfigNode(pDev, "0", &pInst);
1477 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1478 InsertConfigNode(pInst, "Config", &pCfg);
1479 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1480 if (chipsetType == ChipsetType_ICH9)
1481 {
1482 /* Provide MCFG info */
1483 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1484 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1485
1486
1487 /* And register 2 bridges */
1488 InsertConfigNode(pDevices, "ich9pcibridge", &pDev);
1489 InsertConfigNode(pDev, "0", &pInst);
1490 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1491 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H();
1492
1493 InsertConfigNode(pDev, "1", &pInst);
1494 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1495 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H();
1496
1497#ifdef VBOX_WITH_PCI_PASSTHROUGH
1498 /* Add PCI passthrough devices */
1499 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1500#endif
1501 }
1502
1503 /*
1504 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1505 */
1506
1507 /*
1508 * High Precision Event Timer (HPET)
1509 */
1510 BOOL fHPETEnabled;
1511 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1512 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1513 /* so always enable HPET in extended profile */
1514 fHPETEnabled |= fOsXGuest;
1515 /* HPET is always present on ICH9 */
1516 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1517 if (fHPETEnabled)
1518 {
1519 InsertConfigNode(pDevices, "hpet", &pDev);
1520 InsertConfigNode(pDev, "0", &pInst);
1521 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1522 InsertConfigNode(pInst, "Config", &pCfg);
1523 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1524 }
1525
1526 /*
1527 * System Management Controller (SMC)
1528 */
1529 BOOL fSmcEnabled;
1530 fSmcEnabled = fOsXGuest;
1531 if (fSmcEnabled)
1532 {
1533 InsertConfigNode(pDevices, "smc", &pDev);
1534 InsertConfigNode(pDev, "0", &pInst);
1535 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1536 InsertConfigNode(pInst, "Config", &pCfg);
1537
1538 bool fGetKeyFromRealSMC;
1539 Utf8Str strKey;
1540 rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1541 AssertRCReturn(rc, rc);
1542
1543 if (!fGetKeyFromRealSMC)
1544 InsertConfigString(pCfg, "DeviceKey", strKey);
1545 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1546 }
1547
1548 /*
1549 * Low Pin Count (LPC) bus
1550 */
1551 BOOL fLpcEnabled;
1552 /** @todo implement appropriate getter */
1553 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1554 if (fLpcEnabled)
1555 {
1556 InsertConfigNode(pDevices, "lpc", &pDev);
1557 InsertConfigNode(pDev, "0", &pInst);
1558 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1559 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1560 }
1561
1562 BOOL fShowRtc;
1563 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1564
1565 /*
1566 * PS/2 keyboard & mouse.
1567 */
1568 InsertConfigNode(pDevices, "pckbd", &pDev);
1569 InsertConfigNode(pDev, "0", &pInst);
1570 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1571 InsertConfigNode(pInst, "Config", &pCfg);
1572
1573 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1574 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1575 InsertConfigNode(pLunL0, "Config", &pCfg);
1576 InsertConfigInteger(pCfg, "QueueSize", 64);
1577
1578 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1579 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1580 InsertConfigNode(pLunL1, "Config", &pCfg);
1581 Keyboard *pKeyboard = mKeyboard;
1582 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
1583
1584 Mouse *pMouse = mMouse;
1585 PointingHIDType_T aPointingHID;
1586 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1587 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1588 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1589 InsertConfigNode(pLunL0, "Config", &pCfg);
1590 InsertConfigInteger(pCfg, "QueueSize", 128);
1591
1592 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1593 InsertConfigString(pLunL1, "Driver", "MainMouse");
1594 InsertConfigNode(pLunL1, "Config", &pCfg);
1595 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
1596
1597 /*
1598 * i8254 Programmable Interval Timer And Dummy Speaker
1599 */
1600 InsertConfigNode(pDevices, "i8254", &pDev);
1601 InsertConfigNode(pDev, "0", &pInst);
1602 InsertConfigNode(pInst, "Config", &pCfg);
1603#ifdef DEBUG
1604 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1605#endif
1606
1607 /*
1608 * i8259 Programmable Interrupt Controller.
1609 */
1610 InsertConfigNode(pDevices, "i8259", &pDev);
1611 InsertConfigNode(pDev, "0", &pInst);
1612 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1613 InsertConfigNode(pInst, "Config", &pCfg);
1614
1615 /*
1616 * Advanced Programmable Interrupt Controller.
1617 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1618 * thus only single insert
1619 */
1620 if (fEnableAPIC)
1621 {
1622 InsertConfigNode(pDevices, "apic", &pDev);
1623 InsertConfigNode(pDev, "0", &pInst);
1624 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1625 InsertConfigNode(pInst, "Config", &pCfg);
1626 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1627 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1628 if (fEnableX2APIC)
1629 enmAPICMode = PDMAPICMODE_X2APIC;
1630 else if (!fEnableAPIC)
1631 enmAPICMode = PDMAPICMODE_NONE;
1632 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1633 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1634
1635 if (fIOAPIC)
1636 {
1637 /*
1638 * I/O Advanced Programmable Interrupt Controller.
1639 */
1640 InsertConfigNode(pDevices, "ioapic", &pDev);
1641 InsertConfigNode(pDev, "0", &pInst);
1642 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1643 InsertConfigNode(pInst, "Config", &pCfg);
1644 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1645 }
1646 }
1647
1648 /*
1649 * RTC MC146818.
1650 */
1651 InsertConfigNode(pDevices, "mc146818", &pDev);
1652 InsertConfigNode(pDev, "0", &pInst);
1653 InsertConfigNode(pInst, "Config", &pCfg);
1654 BOOL fRTCUseUTC;
1655 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1656 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1657
1658 /*
1659 * VGA.
1660 */
1661 GraphicsControllerType_T enmGraphicsController;
1662 hrc = pMachine->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1663 switch (enmGraphicsController)
1664 {
1665 case GraphicsControllerType_Null:
1666 break;
1667 case GraphicsControllerType_VBoxVGA:
1668#ifdef VBOX_WITH_VMSVGA
1669 case GraphicsControllerType_VMSVGA:
1670#endif
1671 rc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, biosSettings,
1672 RT_BOOL(fHMEnabled));
1673 if (FAILED(rc))
1674 return rc;
1675 break;
1676 default:
1677 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1678 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1679 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1680 }
1681
1682 /*
1683 * Firmware.
1684 */
1685 FirmwareType_T eFwType = FirmwareType_BIOS;
1686 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1687
1688#ifdef VBOX_WITH_EFI
1689 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1690#else
1691 BOOL fEfiEnabled = false;
1692#endif
1693 if (!fEfiEnabled)
1694 {
1695 /*
1696 * PC Bios.
1697 */
1698 InsertConfigNode(pDevices, "pcbios", &pDev);
1699 InsertConfigNode(pDev, "0", &pInst);
1700 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1701 InsertConfigNode(pInst, "Config", &pBiosCfg);
1702 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1703 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1704 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1705 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1706 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1707 BOOL fPXEDebug;
1708 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1709 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1710 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1711 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1712 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1713 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1714
1715 DeviceType_T bootDevice;
1716 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1717 VERR_INVALID_PARAMETER);
1718
1719 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1720 {
1721 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
1722
1723 char szParamName[] = "BootDeviceX";
1724 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1725
1726 const char *pszBootDevice;
1727 switch (bootDevice)
1728 {
1729 case DeviceType_Null:
1730 pszBootDevice = "NONE";
1731 break;
1732 case DeviceType_HardDisk:
1733 pszBootDevice = "IDE";
1734 break;
1735 case DeviceType_DVD:
1736 pszBootDevice = "DVD";
1737 break;
1738 case DeviceType_Floppy:
1739 pszBootDevice = "FLOPPY";
1740 break;
1741 case DeviceType_Network:
1742 pszBootDevice = "LAN";
1743 break;
1744 default:
1745 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
1746 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1747 N_("Invalid boot device '%d'"), bootDevice);
1748 }
1749 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1750 }
1751
1752 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1753 * this is required for Windows 2012 guests. */
1754 if (osTypeId == "Windows2012_64")
1755 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1756 }
1757 else
1758 {
1759 /* Autodetect firmware type, basing on guest type */
1760 if (eFwType == FirmwareType_EFI)
1761 {
1762 eFwType = fIsGuest64Bit
1763 ? (FirmwareType_T)FirmwareType_EFI64
1764 : (FirmwareType_T)FirmwareType_EFI32;
1765 }
1766 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1767
1768 Utf8Str efiRomFile;
1769 rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
1770 AssertRCReturn(rc, rc);
1771
1772 /* Get boot args */
1773 Utf8Str bootArgs;
1774 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1775
1776 /* Get device props */
1777 Utf8Str deviceProps;
1778 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1779
1780 /* Get graphics mode settings */
1781 uint32_t u32GraphicsMode = UINT32_MAX;
1782 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);
1783 if (strTmp.isEmpty())
1784 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1785 if (!strTmp.isEmpty())
1786 u32GraphicsMode = strTmp.toUInt32();
1787
1788 /* Get graphics resolution settings */
1789 uint32_t u32HorizontalResolution = 0;
1790 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);
1791 if (strTmp.isEmpty())
1792 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1793 if (!strTmp.isEmpty())
1794 u32HorizontalResolution = strTmp.toUInt32();
1795
1796 uint32_t u32VerticalResolution = 0;
1797 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);
1798 if (strTmp.isEmpty())
1799 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1800 if (!strTmp.isEmpty())
1801 u32VerticalResolution = strTmp.toUInt32();
1802
1803 /*
1804 * EFI subtree.
1805 */
1806 InsertConfigNode(pDevices, "efi", &pDev);
1807 InsertConfigNode(pDev, "0", &pInst);
1808 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1809 InsertConfigNode(pInst, "Config", &pCfg);
1810 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1811 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1812 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1813 InsertConfigString(pCfg, "EfiRom", efiRomFile);
1814 InsertConfigString(pCfg, "BootArgs", bootArgs);
1815 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1816 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1817 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1818 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1819 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1820 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);
1821 InsertConfigInteger(pCfg, "HorizontalResolution", u32HorizontalResolution);
1822 InsertConfigInteger(pCfg, "VerticalResolution", u32VerticalResolution);
1823
1824 /* For OS X guests we'll force passing host's DMI info to the guest */
1825 if (fOsXGuest)
1826 {
1827 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1828 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1829 }
1830 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1831 InsertConfigString(pLunL0, "Driver", "NvramStorage");
1832 InsertConfigNode(pLunL0, "Config", &pCfg);
1833 InsertConfigInteger(pCfg, "Object", (uintptr_t)mNvram);
1834#ifdef DEBUG_vvl
1835 InsertConfigInteger(pCfg, "PermanentSave", 1);
1836#endif
1837 }
1838
1839 /*
1840 * The USB Controllers.
1841 */
1842 com::SafeIfaceArray<IUSBController> usbCtrls;
1843 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
1844 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
1845 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
1846
1847 if (SUCCEEDED(hrc))
1848 {
1849 for (size_t i = 0; i < usbCtrls.size(); ++i)
1850 {
1851 USBControllerType_T enmCtrlType;
1852 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1853 if (enmCtrlType == USBControllerType_OHCI)
1854 {
1855 fOhciPresent = true;
1856 break;
1857 }
1858 else if (enmCtrlType == USBControllerType_XHCI)
1859 {
1860 fXhciPresent = true;
1861 break;
1862 }
1863 }
1864 }
1865 else if (hrc != E_NOTIMPL)
1866 {
1867 H();
1868 }
1869
1870 /*
1871 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
1872 */
1873 if (fOhciPresent || fXhciPresent)
1874 mfVMHasUsbController = true;
1875
1876 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
1877 if (mfVMHasUsbController)
1878 {
1879 for (size_t i = 0; i < usbCtrls.size(); ++i)
1880 {
1881 USBControllerType_T enmCtrlType;
1882 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1883
1884 if (enmCtrlType == USBControllerType_OHCI)
1885 {
1886 InsertConfigNode(pDevices, "usb-ohci", &pDev);
1887 InsertConfigNode(pDev, "0", &pInst);
1888 InsertConfigNode(pInst, "Config", &pCfg);
1889 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1890 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
1891 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1892 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1893 InsertConfigNode(pLunL0, "Config", &pCfg);
1894
1895 /*
1896 * Attach the status driver.
1897 */
1898 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0);
1899 }
1900#ifdef VBOX_WITH_EHCI
1901 else if (enmCtrlType == USBControllerType_EHCI)
1902 {
1903 /*
1904 * USB 2.0 is only available if the proper ExtPack is installed.
1905 *
1906 * Note. Configuring EHCI here and providing messages about
1907 * the missing extpack isn't exactly clean, but it is a
1908 * necessary evil to patch over legacy compatability issues
1909 * introduced by the new distribution model.
1910 */
1911# ifdef VBOX_WITH_EXTPACK
1912 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1913 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1914# endif
1915 {
1916 InsertConfigNode(pDevices, "usb-ehci", &pDev);
1917 InsertConfigNode(pDev, "0", &pInst);
1918 InsertConfigNode(pInst, "Config", &pCfg);
1919 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1920 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
1921
1922 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1923 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1924 InsertConfigNode(pLunL0, "Config", &pCfg);
1925
1926 /*
1927 * Attach the status driver.
1928 */
1929 i_attachStatusDriver(pInst, &mapUSBLed[1], 0, 0, NULL, NULL, 0);
1930 }
1931# ifdef VBOX_WITH_EXTPACK
1932 else
1933 {
1934 /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
1935 * but this induced problems when the user saved + restored the VM! */
1936 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1937 N_("Implementation of the USB 2.0 controller not found!\n"
1938 "Because the USB 2.0 controller state is part of the saved "
1939 "VM state, the VM cannot be started. To fix "
1940 "this problem, either install the '%s' or disable USB 2.0 "
1941 "support in the VM settings.\n"
1942 "Note! This error could also mean that an incompatible version of "
1943 "the '%s' is installed"),
1944 s_pszUsbExtPackName, s_pszUsbExtPackName);
1945 }
1946# endif
1947 }
1948#endif
1949 else if (enmCtrlType == USBControllerType_XHCI)
1950 {
1951 /*
1952 * USB 3.0 is only available if the proper ExtPack is installed.
1953 *
1954 * Note. Configuring EHCI here and providing messages about
1955 * the missing extpack isn't exactly clean, but it is a
1956 * necessary evil to patch over legacy compatability issues
1957 * introduced by the new distribution model.
1958 */
1959# ifdef VBOX_WITH_EXTPACK
1960 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1961 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1962# endif
1963 {
1964 InsertConfigNode(pDevices, "usb-xhci", &pDev);
1965 InsertConfigNode(pDev, "0", &pInst);
1966 InsertConfigNode(pInst, "Config", &pCfg);
1967 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1968 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
1969
1970 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1971 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1972 InsertConfigNode(pLunL0, "Config", &pCfg);
1973
1974 InsertConfigNode(pInst, "LUN#1", &pLunL1);
1975 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
1976 InsertConfigNode(pLunL1, "Config", &pCfg);
1977
1978 /*
1979 * Attach the status driver.
1980 */
1981 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 1, NULL, NULL, 0);
1982 }
1983# ifdef VBOX_WITH_EXTPACK
1984 else
1985 {
1986 /* Always fatal. */
1987 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1988 N_("Implementation of the USB 3.0 controller not found!\n"
1989 "Because the USB 3.0 controller state is part of the saved "
1990 "VM state, the VM cannot be started. To fix "
1991 "this problem, either install the '%s' or disable USB 3.0 "
1992 "support in the VM settings"),
1993 s_pszUsbExtPackName);
1994 }
1995# endif
1996 }
1997 } /* for every USB controller. */
1998
1999
2000 /*
2001 * Virtual USB Devices.
2002 */
2003 InsertConfigNode(pRoot, "USB", &pUsbDevices);
2004
2005#ifdef VBOX_WITH_USB
2006 {
2007 /*
2008 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
2009 * on a per device level now.
2010 */
2011 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
2012 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
2013 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
2014 //InsertConfigInteger(pCfg, "Force11Device", true);
2015 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
2016 // that it's documented somewhere.) Users needing it can use:
2017 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
2018 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
2019 }
2020#endif
2021
2022#ifdef VBOX_WITH_USB_CARDREADER
2023 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
2024 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
2025 if (aEmulatedUSBCardReaderEnabled)
2026 {
2027 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
2028 InsertConfigNode(pDev, "0", &pInst);
2029 InsertConfigNode(pInst, "Config", &pCfg);
2030
2031 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2032# ifdef VBOX_WITH_USB_CARDREADER_TEST
2033 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
2034 InsertConfigNode(pLunL0, "Config", &pCfg);
2035# else
2036 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
2037 InsertConfigNode(pLunL0, "Config", &pCfg);
2038 InsertConfigInteger(pCfg, "Object", (uintptr_t)mUsbCardReader);
2039# endif
2040 }
2041#endif
2042
2043 /* Virtual USB Mouse/Tablet */
2044 if ( aPointingHID == PointingHIDType_USBMouse
2045 || aPointingHID == PointingHIDType_USBTablet
2046 || aPointingHID == PointingHIDType_USBMultiTouch)
2047 {
2048 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
2049 InsertConfigNode(pDev, "0", &pInst);
2050 InsertConfigNode(pInst, "Config", &pCfg);
2051
2052 if (aPointingHID == PointingHIDType_USBMouse)
2053 InsertConfigString(pCfg, "Mode", "relative");
2054 else
2055 InsertConfigString(pCfg, "Mode", "absolute");
2056 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2057 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2058 InsertConfigNode(pLunL0, "Config", &pCfg);
2059 InsertConfigInteger(pCfg, "QueueSize", 128);
2060
2061 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2062 InsertConfigString(pLunL1, "Driver", "MainMouse");
2063 InsertConfigNode(pLunL1, "Config", &pCfg);
2064 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2065 }
2066 if (aPointingHID == PointingHIDType_USBMultiTouch)
2067 {
2068 InsertConfigNode(pDev, "1", &pInst);
2069 InsertConfigNode(pInst, "Config", &pCfg);
2070
2071 InsertConfigString(pCfg, "Mode", "multitouch");
2072 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2073 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2074 InsertConfigNode(pLunL0, "Config", &pCfg);
2075 InsertConfigInteger(pCfg, "QueueSize", 128);
2076
2077 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2078 InsertConfigString(pLunL1, "Driver", "MainMouse");
2079 InsertConfigNode(pLunL1, "Config", &pCfg);
2080 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2081 }
2082
2083 /* Virtual USB Keyboard */
2084 KeyboardHIDType_T aKbdHID;
2085 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
2086 if (aKbdHID == KeyboardHIDType_USBKeyboard)
2087 {
2088 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
2089 InsertConfigNode(pDev, "0", &pInst);
2090 InsertConfigNode(pInst, "Config", &pCfg);
2091
2092 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2093 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
2094 InsertConfigNode(pLunL0, "Config", &pCfg);
2095 InsertConfigInteger(pCfg, "QueueSize", 64);
2096
2097 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2098 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
2099 InsertConfigNode(pLunL1, "Config", &pCfg);
2100 pKeyboard = mKeyboard;
2101 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
2102 }
2103 }
2104
2105 /*
2106 * Storage controllers.
2107 */
2108 com::SafeIfaceArray<IStorageController> ctrls;
2109 PCFGMNODE aCtrlNodes[StorageControllerType_NVMe + 1] = {};
2110 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
2111
2112 bool fFdcEnabled = false;
2113 for (size_t i = 0; i < ctrls.size(); ++i)
2114 {
2115 DeviceType_T *paLedDevType = NULL;
2116
2117 StorageControllerType_T enmCtrlType;
2118 rc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
2119 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
2120 || enmCtrlType == StorageControllerType_USB);
2121
2122 StorageBus_T enmBus;
2123 rc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
2124
2125 Bstr controllerName;
2126 rc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
2127
2128 ULONG ulInstance = 999;
2129 rc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
2130
2131 BOOL fUseHostIOCache;
2132 rc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
2133
2134 BOOL fBootable;
2135 rc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
2136
2137 PCFGMNODE pCtlInst = NULL;
2138 const char *pszCtrlDev = i_convertControllerTypeToDev(enmCtrlType);
2139 if (enmCtrlType != StorageControllerType_USB)
2140 {
2141 /* /Devices/<ctrldev>/ */
2142 pDev = aCtrlNodes[enmCtrlType];
2143 if (!pDev)
2144 {
2145 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
2146 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
2147 }
2148
2149 /* /Devices/<ctrldev>/<instance>/ */
2150 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
2151
2152 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
2153 InsertConfigInteger(pCtlInst, "Trusted", 1);
2154 InsertConfigNode(pCtlInst, "Config", &pCfg);
2155 }
2156
2157 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
2158 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
2159
2160 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
2161 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
2162
2163 switch (enmCtrlType)
2164 {
2165 case StorageControllerType_LsiLogic:
2166 {
2167 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
2168
2169 InsertConfigInteger(pCfg, "Bootable", fBootable);
2170
2171 /* BIOS configuration values, first SCSI controller only. */
2172 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
2173 && !pBusMgr->hasPCIDevice("buslogic", 0)
2174 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2175 && pBiosCfg)
2176 {
2177 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
2178 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2179 }
2180
2181 /* Attach the status driver */
2182 Assert(cLedScsi >= 16);
2183 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2184 &mapMediumAttachments, pszCtrlDev, ulInstance);
2185 paLedDevType = &maStorageDevType[iLedScsi];
2186 break;
2187 }
2188
2189 case StorageControllerType_BusLogic:
2190 {
2191 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
2192
2193 InsertConfigInteger(pCfg, "Bootable", fBootable);
2194
2195 /* BIOS configuration values, first SCSI controller only. */
2196 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2197 && !pBusMgr->hasPCIDevice("buslogic", 1)
2198 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2199 && pBiosCfg)
2200 {
2201 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
2202 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2203 }
2204
2205 /* Attach the status driver */
2206 Assert(cLedScsi >= 16);
2207 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2208 &mapMediumAttachments, pszCtrlDev, ulInstance);
2209 paLedDevType = &maStorageDevType[iLedScsi];
2210 break;
2211 }
2212
2213 case StorageControllerType_IntelAhci:
2214 {
2215 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2216
2217 ULONG cPorts = 0;
2218 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2219 InsertConfigInteger(pCfg, "PortCount", cPorts);
2220 InsertConfigInteger(pCfg, "Bootable", fBootable);
2221
2222 com::SafeIfaceArray<IMediumAttachment> atts;
2223 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2224 ComSafeArrayAsOutParam(atts)); H();
2225
2226 /* Configure the hotpluggable flag for the port. */
2227 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2228 {
2229 IMediumAttachment *pMediumAtt = atts[idxAtt];
2230
2231 LONG lPortNum = 0;
2232 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2233
2234 BOOL fHotPluggable = FALSE;
2235 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2236 if (SUCCEEDED(hrc))
2237 {
2238 PCFGMNODE pPortCfg;
2239 char szName[24];
2240 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2241
2242 InsertConfigNode(pCfg, szName, &pPortCfg);
2243 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2244 }
2245 }
2246
2247 /* BIOS configuration values, first AHCI controller only. */
2248 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2249 && pBiosCfg)
2250 {
2251 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2252 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2253 }
2254
2255 /* Attach the status driver */
2256 AssertRelease(cPorts <= cLedSata);
2257 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSata], 0, cPorts - 1,
2258 &mapMediumAttachments, pszCtrlDev, ulInstance);
2259 paLedDevType = &maStorageDevType[iLedSata];
2260 break;
2261 }
2262
2263 case StorageControllerType_PIIX3:
2264 case StorageControllerType_PIIX4:
2265 case StorageControllerType_ICH6:
2266 {
2267 /*
2268 * IDE (update this when the main interface changes)
2269 */
2270 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2271 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2272 /* Attach the status driver */
2273 Assert(cLedIde >= 4);
2274 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedIde], 0, 3,
2275 &mapMediumAttachments, pszCtrlDev, ulInstance);
2276 paLedDevType = &maStorageDevType[iLedIde];
2277
2278 /* IDE flavors */
2279 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2280 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2281 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2282 break;
2283 }
2284
2285 case StorageControllerType_I82078:
2286 {
2287 /*
2288 * i82078 Floppy drive controller
2289 */
2290 fFdcEnabled = true;
2291 InsertConfigInteger(pCfg, "IRQ", 6);
2292 InsertConfigInteger(pCfg, "DMA", 2);
2293 InsertConfigInteger(pCfg, "MemMapped", 0 );
2294 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2295
2296 /* Attach the status driver */
2297 Assert(cLedFloppy >= 2);
2298 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedFloppy], 0, 1,
2299 &mapMediumAttachments, pszCtrlDev, ulInstance);
2300 paLedDevType = &maStorageDevType[iLedFloppy];
2301 break;
2302 }
2303
2304 case StorageControllerType_LsiLogicSas:
2305 {
2306 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2307
2308 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2309 InsertConfigInteger(pCfg, "Bootable", fBootable);
2310
2311 /* BIOS configuration values, first SCSI controller only. */
2312 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2313 && !pBusMgr->hasPCIDevice("buslogic", 0)
2314 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2315 && pBiosCfg)
2316 {
2317 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2318 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2319 }
2320
2321 ULONG cPorts = 0;
2322 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2323 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2324
2325 /* Attach the status driver */
2326 Assert(cLedSas >= 8);
2327 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSas], 0, 7,
2328 &mapMediumAttachments, pszCtrlDev, ulInstance);
2329 paLedDevType = &maStorageDevType[iLedSas];
2330 break;
2331 }
2332
2333 case StorageControllerType_USB:
2334 {
2335 if (pUsbDevices)
2336 {
2337 /*
2338 * USB MSDs are handled a bit different as the device instance
2339 * doesn't match the storage controller instance but the port.
2340 */
2341 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2342 pCtlInst = pDev;
2343 }
2344 else
2345 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2346 N_("There is no USB controller enabled but there\n"
2347 "is at least one USB storage device configured for this VM.\n"
2348 "To fix this problem either enable the USB controller or remove\n"
2349 "the storage device from the VM"));
2350 break;
2351 }
2352
2353 case StorageControllerType_NVMe:
2354 {
2355 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2356
2357 ULONG cPorts = 0;
2358 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2359 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2360
2361 /* For ICH9 we need to create a new PCI bridge if there is more than one NVMe instance. */
2362 if ( ulInstance > 0
2363 && chipsetType == ChipsetType_ICH9
2364 && !pBusMgr->hasPCIDevice("ich9pcibridge", 2))
2365 {
2366 PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
2367 Assert(pBridges);
2368
2369 InsertConfigNode(pBridges, "2", &pInst);
2370 InsertConfigInteger(pInst, "Trusted", 1);
2371 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);
2372 }
2373
2374 /* Attach the status driver */
2375 AssertRelease(cPorts <= cLedSata);
2376 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedNvme], 0, cPorts - 1,
2377 &mapMediumAttachments, pszCtrlDev, ulInstance);
2378 paLedDevType = &maStorageDevType[iLedNvme];
2379 break;
2380 }
2381
2382 default:
2383 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2384 }
2385
2386 /* Attach the media to the storage controllers. */
2387 com::SafeIfaceArray<IMediumAttachment> atts;
2388 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2389 ComSafeArrayAsOutParam(atts)); H();
2390
2391 /* Builtin I/O cache - per device setting. */
2392 BOOL fBuiltinIOCache = true;
2393 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2394
2395 bool fInsertDiskIntegrityDrv = false;
2396 Bstr strDiskIntegrityFlag;
2397 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2398 strDiskIntegrityFlag.asOutParam());
2399 if ( hrc == S_OK
2400 && strDiskIntegrityFlag == "1")
2401 fInsertDiskIntegrityDrv = true;
2402
2403 for (size_t j = 0; j < atts.size(); ++j)
2404 {
2405 IMediumAttachment *pMediumAtt = atts[j];
2406 rc = i_configMediumAttachment(pszCtrlDev,
2407 ulInstance,
2408 enmBus,
2409 !!fUseHostIOCache,
2410 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2411 fInsertDiskIntegrityDrv,
2412 false /* fSetupMerge */,
2413 0 /* uMergeSource */,
2414 0 /* uMergeTarget */,
2415 pMediumAtt,
2416 mMachineState,
2417 NULL /* phrc */,
2418 false /* fAttachDetach */,
2419 false /* fForceUnmount */,
2420 false /* fHotplug */,
2421 pUVM,
2422 paLedDevType,
2423 NULL /* ppLunL0 */);
2424 if (RT_FAILURE(rc))
2425 return rc;
2426 }
2427 H();
2428 }
2429 H();
2430
2431 /*
2432 * Network adapters
2433 */
2434#ifdef VMWARE_NET_IN_SLOT_11
2435 bool fSwapSlots3and11 = false;
2436#endif
2437 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2438 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2439#ifdef VBOX_WITH_E1000
2440 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2441 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2442#endif
2443#ifdef VBOX_WITH_VIRTIO
2444 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2445 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2446#endif /* VBOX_WITH_VIRTIO */
2447 std::list<BootNic> llBootNics;
2448 for (ULONG ulInstance = 0; ulInstance < maxNetworkAdapters; ++ulInstance)
2449 {
2450 ComPtr<INetworkAdapter> networkAdapter;
2451 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
2452 BOOL fEnabledNetAdapter = FALSE;
2453 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2454 if (!fEnabledNetAdapter)
2455 continue;
2456
2457 /*
2458 * The virtual hardware type. Create appropriate device first.
2459 */
2460 const char *pszAdapterName = "pcnet";
2461 NetworkAdapterType_T adapterType;
2462 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2463 switch (adapterType)
2464 {
2465 case NetworkAdapterType_Am79C970A:
2466 case NetworkAdapterType_Am79C973:
2467 pDev = pDevPCNet;
2468 break;
2469#ifdef VBOX_WITH_E1000
2470 case NetworkAdapterType_I82540EM:
2471 case NetworkAdapterType_I82543GC:
2472 case NetworkAdapterType_I82545EM:
2473 pDev = pDevE1000;
2474 pszAdapterName = "e1000";
2475 break;
2476#endif
2477#ifdef VBOX_WITH_VIRTIO
2478 case NetworkAdapterType_Virtio:
2479 pDev = pDevVirtioNet;
2480 pszAdapterName = "virtio-net";
2481 break;
2482#endif /* VBOX_WITH_VIRTIO */
2483 default:
2484 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
2485 adapterType, ulInstance));
2486 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2487 N_("Invalid network adapter type '%d' for slot '%d'"),
2488 adapterType, ulInstance);
2489 }
2490
2491 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2492 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2493 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2494 * next 4 get 16..19. */
2495 int iPCIDeviceNo;
2496 switch (ulInstance)
2497 {
2498 case 0:
2499 iPCIDeviceNo = 3;
2500 break;
2501 case 1: case 2: case 3:
2502 iPCIDeviceNo = ulInstance - 1 + 8;
2503 break;
2504 case 4: case 5: case 6: case 7:
2505 iPCIDeviceNo = ulInstance - 4 + 16;
2506 break;
2507 default:
2508 /* auto assignment */
2509 iPCIDeviceNo = -1;
2510 break;
2511 }
2512#ifdef VMWARE_NET_IN_SLOT_11
2513 /*
2514 * Dirty hack for PCI slot compatibility with VMWare,
2515 * it assigns slot 0x11 to the first network controller.
2516 */
2517 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2518 {
2519 iPCIDeviceNo = 0x11;
2520 fSwapSlots3and11 = true;
2521 }
2522 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2523 iPCIDeviceNo = 3;
2524#endif
2525 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2526 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2527
2528 InsertConfigNode(pInst, "Config", &pCfg);
2529#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2530 if (pDev == pDevPCNet)
2531 {
2532 InsertConfigInteger(pCfg, "R0Enabled", false);
2533 }
2534#endif
2535 /*
2536 * Collect information needed for network booting and add it to the list.
2537 */
2538 BootNic nic;
2539
2540 nic.mInstance = ulInstance;
2541 /* Could be updated by reference, if auto assigned */
2542 nic.mPCIAddress = PCIAddr;
2543
2544 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2545
2546 llBootNics.push_back(nic);
2547
2548 /*
2549 * The virtual hardware type. PCNet supports two types, E1000 three,
2550 * but VirtIO only one.
2551 */
2552 switch (adapterType)
2553 {
2554 case NetworkAdapterType_Am79C970A:
2555 InsertConfigInteger(pCfg, "Am79C973", 0);
2556 break;
2557 case NetworkAdapterType_Am79C973:
2558 InsertConfigInteger(pCfg, "Am79C973", 1);
2559 break;
2560 case NetworkAdapterType_I82540EM:
2561 InsertConfigInteger(pCfg, "AdapterType", 0);
2562 break;
2563 case NetworkAdapterType_I82543GC:
2564 InsertConfigInteger(pCfg, "AdapterType", 1);
2565 break;
2566 case NetworkAdapterType_I82545EM:
2567 InsertConfigInteger(pCfg, "AdapterType", 2);
2568 break;
2569 case NetworkAdapterType_Virtio:
2570 break;
2571 case NetworkAdapterType_Null: AssertFailedBreak(); /* Shut up MSC */
2572 }
2573
2574 /*
2575 * Get the MAC address and convert it to binary representation
2576 */
2577 Bstr macAddr;
2578 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2579 Assert(!macAddr.isEmpty());
2580 Utf8Str macAddrUtf8 = macAddr;
2581 char *macStr = (char*)macAddrUtf8.c_str();
2582 Assert(strlen(macStr) == 12);
2583 RTMAC Mac;
2584 RT_ZERO(Mac);
2585 char *pMac = (char*)&Mac;
2586 for (uint32_t i = 0; i < 6; ++i)
2587 {
2588 int c1 = *macStr++ - '0';
2589 if (c1 > 9)
2590 c1 -= 7;
2591 int c2 = *macStr++ - '0';
2592 if (c2 > 9)
2593 c2 -= 7;
2594 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2595 }
2596 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2597
2598 /*
2599 * Check if the cable is supposed to be unplugged
2600 */
2601 BOOL fCableConnected;
2602 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2603 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2604
2605 /*
2606 * Line speed to report from custom drivers
2607 */
2608 ULONG ulLineSpeed;
2609 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2610 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2611
2612 /*
2613 * Attach the status driver.
2614 */
2615 i_attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
2616
2617 /*
2618 * Configure the network card now
2619 */
2620 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2621 rc = i_configNetwork(pszAdapterName,
2622 ulInstance,
2623 0,
2624 networkAdapter,
2625 pCfg,
2626 pLunL0,
2627 pInst,
2628 false /*fAttachDetach*/,
2629 fIgnoreConnectFailure);
2630 if (RT_FAILURE(rc))
2631 return rc;
2632 }
2633
2634 /*
2635 * Build network boot information and transfer it to the BIOS.
2636 */
2637 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2638 {
2639 llBootNics.sort(); /* Sort the list by boot priority. */
2640
2641 char achBootIdx[] = "0";
2642 unsigned uBootIdx = 0;
2643
2644 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2645 {
2646 /* A NIC with priority 0 is only used if it's first in the list. */
2647 if (it->mBootPrio == 0 && uBootIdx != 0)
2648 break;
2649
2650 PCFGMNODE pNetBtDevCfg;
2651 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2652 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2653 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2654 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2655 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2656 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2657 }
2658 }
2659
2660 /*
2661 * Serial (UART) Ports
2662 */
2663 /* serial enabled mask to be passed to dev ACPI */
2664 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2665 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2666 InsertConfigNode(pDevices, "serial", &pDev);
2667 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2668 {
2669 ComPtr<ISerialPort> serialPort;
2670 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2671 BOOL fEnabledSerPort = FALSE;
2672 if (serialPort)
2673 {
2674 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2675 }
2676 if (!fEnabledSerPort)
2677 continue;
2678
2679 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2680 InsertConfigNode(pInst, "Config", &pCfg);
2681
2682 ULONG ulIRQ;
2683 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2684 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2685 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2686
2687 ULONG ulIOBase;
2688 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2689 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2690 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2691
2692 BOOL fServer;
2693 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2694 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2695 PortMode_T eHostMode;
2696 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2697 if (eHostMode != PortMode_Disconnected)
2698 {
2699 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2700 if (eHostMode == PortMode_HostPipe)
2701 {
2702 InsertConfigString(pLunL0, "Driver", "Char");
2703 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2704 InsertConfigString(pLunL1, "Driver", "NamedPipe");
2705 InsertConfigNode(pLunL1, "Config", &pLunL2);
2706 InsertConfigString(pLunL2, "Location", bstr);
2707 InsertConfigInteger(pLunL2, "IsServer", fServer);
2708 }
2709 else if (eHostMode == PortMode_HostDevice)
2710 {
2711 InsertConfigString(pLunL0, "Driver", "Host Serial");
2712 InsertConfigNode(pLunL0, "Config", &pLunL1);
2713 InsertConfigString(pLunL1, "DevicePath", bstr);
2714 }
2715 else if (eHostMode == PortMode_TCP)
2716 {
2717 InsertConfigString(pLunL0, "Driver", "Char");
2718 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2719 InsertConfigString(pLunL1, "Driver", "TCP");
2720 InsertConfigNode(pLunL1, "Config", &pLunL2);
2721 InsertConfigString(pLunL2, "Location", bstr);
2722 InsertConfigInteger(pLunL2, "IsServer", fServer);
2723 }
2724 else if (eHostMode == PortMode_RawFile)
2725 {
2726 InsertConfigString(pLunL0, "Driver", "Char");
2727 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2728 InsertConfigString(pLunL1, "Driver", "RawFile");
2729 InsertConfigNode(pLunL1, "Config", &pLunL2);
2730 InsertConfigString(pLunL2, "Location", bstr);
2731 }
2732 }
2733 }
2734
2735 /*
2736 * Parallel (LPT) Ports
2737 */
2738 /* parallel enabled mask to be passed to dev ACPI */
2739 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2740 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2741 InsertConfigNode(pDevices, "parallel", &pDev);
2742 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2743 {
2744 ComPtr<IParallelPort> parallelPort;
2745 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2746 BOOL fEnabledParPort = FALSE;
2747 if (parallelPort)
2748 {
2749 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2750 }
2751 if (!fEnabledParPort)
2752 continue;
2753
2754 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2755 InsertConfigNode(pInst, "Config", &pCfg);
2756
2757 ULONG ulIRQ;
2758 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2759 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2760 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2761 ULONG ulIOBase;
2762 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2763 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2764 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2765
2766 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2767 if (!bstr.isEmpty())
2768 {
2769 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2770 InsertConfigString(pLunL0, "Driver", "HostParallel");
2771 InsertConfigNode(pLunL0, "Config", &pLunL1);
2772 InsertConfigString(pLunL1, "DevicePath", bstr);
2773 }
2774 }
2775
2776 /*
2777 * VMM Device
2778 */
2779 InsertConfigNode(pDevices, "VMMDev", &pDev);
2780 InsertConfigNode(pDev, "0", &pInst);
2781 InsertConfigNode(pInst, "Config", &pCfg);
2782 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2783 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
2784
2785 Bstr hwVersion;
2786 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
2787 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2788 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2789 Bstr snapshotFolder;
2790 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2791 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2792
2793 /* the VMM device's Main driver */
2794 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2795 InsertConfigString(pLunL0, "Driver", "HGCM");
2796 InsertConfigNode(pLunL0, "Config", &pCfg);
2797 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2798
2799 /*
2800 * Attach the status driver.
2801 */
2802 i_attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
2803
2804 /*
2805 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2806 */
2807 BOOL fAudioEnabled = FALSE;
2808 ComPtr<IAudioAdapter> audioAdapter;
2809 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2810 if (audioAdapter)
2811 {
2812 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2813 }
2814
2815 if (fAudioEnabled)
2816 {
2817 AudioControllerType_T audioController;
2818 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2819 AudioCodecType_T audioCodec;
2820 hrc = audioAdapter->COMGETTER(AudioCodec)(&audioCodec); H();
2821 switch (audioController)
2822 {
2823 case AudioControllerType_AC97:
2824 {
2825 /* Default: ICH AC97. */
2826 InsertConfigNode(pDevices, "ichac97", &pDev);
2827 InsertConfigNode(pDev, "0", &pInst);
2828 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2829 hrc = pBusMgr->assignPCIDevice("ichac97", pInst); H();
2830 InsertConfigNode(pInst, "Config", &pCfg);
2831 switch (audioCodec)
2832 {
2833 case AudioCodecType_STAC9700:
2834 InsertConfigString(pCfg, "Codec", "STAC9700");
2835 break;
2836 case AudioCodecType_AD1980:
2837 InsertConfigString(pCfg, "Codec", "AD1980");
2838 break;
2839 default: AssertFailedBreak();
2840 }
2841 break;
2842 }
2843 case AudioControllerType_SB16:
2844 {
2845 /* Legacy SoundBlaster16. */
2846 InsertConfigNode(pDevices, "sb16", &pDev);
2847 InsertConfigNode(pDev, "0", &pInst);
2848 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2849 InsertConfigNode(pInst, "Config", &pCfg);
2850 InsertConfigInteger(pCfg, "IRQ", 5);
2851 InsertConfigInteger(pCfg, "DMA", 1);
2852 InsertConfigInteger(pCfg, "DMA16", 5);
2853 InsertConfigInteger(pCfg, "Port", 0x220);
2854 InsertConfigInteger(pCfg, "Version", 0x0405);
2855 break;
2856 }
2857 case AudioControllerType_HDA:
2858 {
2859 /* Intel HD Audio. */
2860 InsertConfigNode(pDevices, "hda", &pDev);
2861 InsertConfigNode(pDev, "0", &pInst);
2862 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2863 hrc = pBusMgr->assignPCIDevice("hda", pInst); H();
2864 InsertConfigNode(pInst, "Config", &pCfg);
2865 }
2866 }
2867
2868 PCFGMNODE pCfgAudioSettings = NULL;
2869 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioSettings);
2870 SafeArray<BSTR> audioProps;
2871 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2872
2873 std::list<Utf8Str> audioPropertyNamesList;
2874 for (size_t i = 0; i < audioProps.size(); ++i)
2875 {
2876 Bstr bstrValue;
2877 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2878 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2879 Utf8Str strKey(audioProps[i]);
2880 InsertConfigString(pCfgAudioSettings, strKey.c_str(), bstrValue);
2881 }
2882
2883 /*
2884 * The audio driver.
2885 */
2886 uint8_t u8AudioLUN = 0;
2887
2888 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", u8AudioLUN++);
2889 InsertConfigString(pLunL0, "Driver", "AUDIO");
2890 InsertConfigNode(pLunL0, "Config", &pCfg);
2891
2892 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2893 InsertConfigNode(pLunL1, "Config", &pCfg);
2894
2895 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2896 InsertConfigString(pCfg, "StreamName", bstr);
2897
2898 AudioDriverType_T audioDriver;
2899 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2900 switch (audioDriver)
2901 {
2902 case AudioDriverType_Null:
2903 {
2904 InsertConfigString(pLunL1, "Driver", "NullAudio");
2905 break;
2906 }
2907#ifdef RT_OS_WINDOWS
2908# ifdef VBOX_WITH_WINMM
2909 case AudioDriverType_WinMM:
2910 {
2911 #error "Port WinMM audio backend!" /** @todo Still needed? */
2912 break;
2913 }
2914# endif
2915 case AudioDriverType_DirectSound:
2916 {
2917 InsertConfigString(pLunL1, "Driver", "DSoundAudio");
2918 break;
2919 }
2920#endif /* RT_OS_WINDOWS */
2921#ifdef RT_OS_SOLARIS
2922 case AudioDriverType_SolAudio:
2923 {
2924 /* Should not happen, as the Solaris Audio backend is not around anymore.
2925 * Remove this sometime later. */
2926 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2927 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2928
2929 /* Manually set backend to OSS for now. */
2930 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2931 break;
2932 }
2933#endif
2934#ifdef VBOX_WITH_AUDIO_OSS
2935 case AudioDriverType_OSS:
2936 {
2937 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2938 break;
2939 }
2940#endif
2941#ifdef VBOX_WITH_AUDIO_ALSA
2942 case AudioDriverType_ALSA:
2943 {
2944 InsertConfigString(pLunL1, "Driver", "ALSAAudio");
2945 break;
2946 }
2947#endif
2948#ifdef VBOX_WITH_AUDIO_PULSE
2949 case AudioDriverType_Pulse:
2950 {
2951 InsertConfigString(pLunL1, "Driver", "PulseAudio");
2952 break;
2953 }
2954#endif
2955#ifdef RT_OS_DARWIN
2956 case AudioDriverType_CoreAudio:
2957 {
2958 InsertConfigString(pLunL1, "Driver", "CoreAudio");
2959 break;
2960 }
2961#endif
2962 default: AssertFailedBreak();
2963 }
2964
2965 /** @todo Implement a prioritizing feature here, e.g. which driver to insert in which order? */
2966
2967#ifdef VBOX_WITH_VRDE_AUDIO
2968 /*
2969 * The VRDE audio backend driver.
2970 */
2971 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2972 InsertConfigString(pLunL1, "Driver", "AUDIO");
2973
2974 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2975 InsertConfigString(pLunL1, "Driver", "AudioVRDE");
2976
2977 InsertConfigNode(pLunL1, "Config", &pCfg);
2978 InsertConfigString(pCfg, "AudioDriver", "AudioVRDE");
2979 InsertConfigString(pCfg, "StreamName", bstr);
2980 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVRDE);
2981 InsertConfigInteger(pCfg, "ObjectVRDPServer", (uintptr_t)mConsoleVRDPServer);
2982#endif /* VBOX_WITH_VRDE_AUDIO */
2983
2984#ifdef VBOX_WITH_AUDIO_VIDEOREC
2985 /*
2986 * The video recording audio backend driver.
2987 * Currently being used with VPX video recording only.
2988 */
2989 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2990 InsertConfigString(pLunL1, "Driver", "AUDIO");
2991
2992 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2993 InsertConfigString(pLunL1, "Driver", "AudioVideoRec");
2994
2995 InsertConfigNode(pLunL1, "Config", &pCfg);
2996 InsertConfigString(pCfg, "AudioDriver", "AudioVideoRec");
2997 InsertConfigString(pCfg, "StreamName", bstr);
2998 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVideoRec);
2999 InsertConfigInteger(pCfg, "ObjectConsole", (uintptr_t)this /* Console */);
3000#endif /* VBOX_WITH_AUDIO_VIDEOREC */
3001
3002#ifdef VBOX_WITH_AUDIO_DEBUG
3003 /*
3004 * The audio debug backend. Only can be used in debug builds.
3005 */
3006 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
3007 InsertConfigString(pLunL1, "Driver", "AUDIO");
3008
3009 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
3010 InsertConfigString(pLunL1, "Driver", "DebugAudio");
3011
3012 InsertConfigNode(pLunL1, "Config", &pCfg);
3013 InsertConfigString(pCfg, "AudioDriver", "DebugAudio");
3014 InsertConfigString(pCfg, "StreamName", bstr);
3015#endif /* VBOX_WITH_AUDIO_DEBUG */
3016
3017#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3018 /** @todo Make this a runtime-configurable entry! */
3019
3020 /*
3021 * The ValidationKit backend.
3022 */
3023 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
3024 InsertConfigString(pLunL1, "Driver", "AUDIO");
3025
3026 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
3027 InsertConfigString(pLunL1, "Driver", "ValidationKitAudio");
3028
3029 InsertConfigNode(pLunL1, "Config", &pCfg);
3030 InsertConfigString(pCfg, "AudioDriver", "ValidationKitAudio");
3031 InsertConfigString(pCfg, "StreamName", bstr);
3032#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3033
3034 /** @todo Add audio video recording driver here. */
3035 }
3036
3037 /*
3038 * Shared Clipboard.
3039 */
3040 {
3041 ClipboardMode_T mode = ClipboardMode_Disabled;
3042 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3043
3044 if (/* mode != ClipboardMode_Disabled */ true)
3045 {
3046 /* Load the service */
3047 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3048 if (RT_FAILURE(rc))
3049 {
3050 LogRel(("Shared clipboard is not available, rc=%Rrc\n", rc));
3051 /* That is not a fatal failure. */
3052 rc = VINF_SUCCESS;
3053 }
3054 else
3055 {
3056 LogRel(("Shared clipboard service loaded\n"));
3057
3058 i_changeClipboardMode(mode);
3059
3060 /* Setup the service. */
3061 VBOXHGCMSVCPARM parm;
3062 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
3063 parm.setUInt32(!i_useHostClipboard());
3064 pVMMDev->hgcmHostCall("VBoxSharedClipboard",
3065 VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3066 }
3067 }
3068 }
3069
3070 /*
3071 * HGCM HostChannel.
3072 */
3073 {
3074 Bstr value;
3075 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3076 value.asOutParam());
3077
3078 if ( hrc == S_OK
3079 && value == "1")
3080 {
3081 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3082 if (RT_FAILURE(rc))
3083 {
3084 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3085 /* That is not a fatal failure. */
3086 rc = VINF_SUCCESS;
3087 }
3088 }
3089 }
3090
3091#ifdef VBOX_WITH_DRAG_AND_DROP
3092 /*
3093 * Drag and Drop.
3094 */
3095 {
3096 DnDMode_T enmMode = DnDMode_Disabled;
3097 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3098
3099 /* Load the service */
3100 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3101 if (RT_FAILURE(rc))
3102 {
3103 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3104 /* That is not a fatal failure. */
3105 rc = VINF_SUCCESS;
3106 }
3107 else
3108 {
3109 HGCMSVCEXTHANDLE hDummy;
3110 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
3111 &GuestDnD::notifyDnDDispatcher,
3112 GuestDnDInst());
3113 if (RT_FAILURE(rc))
3114 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3115 else
3116 {
3117 LogRel(("Drag and drop service loaded\n"));
3118 rc = i_changeDnDMode(enmMode);
3119 }
3120 }
3121 }
3122#endif /* VBOX_WITH_DRAG_AND_DROP */
3123
3124#ifdef VBOX_WITH_CROGL
3125 /*
3126 * crOpenGL.
3127 */
3128 {
3129 BOOL fEnabled3D = false;
3130 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3131
3132 if ( fEnabled3D
3133# ifdef VBOX_WITH_VMSVGA3D
3134 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3135# endif
3136 )
3137 {
3138 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3139 if (!fSupports3D)
3140 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3141 N_("This VM was configured to use 3D acceleration. However, the "
3142 "3D support of the host is not working properly and the "
3143 "VM cannot be started. To fix this problem, either "
3144 "fix the host 3D support (update the host graphics driver?) "
3145 "or disable 3D acceleration in the VM settings"));
3146
3147 /* Load the service. */
3148 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3149 if (RT_FAILURE(rc))
3150 {
3151 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3152 /* That is not a fatal failure. */
3153 rc = VINF_SUCCESS;
3154 }
3155 else
3156 {
3157 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3158
3159 /* Setup the service. */
3160 VBOXHGCMSVCPARM parm;
3161 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3162
3163 parm.u.pointer.addr = (IConsole *)(Console *)this;
3164 parm.u.pointer.size = sizeof(IConsole *);
3165
3166 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3167 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3168 if (!RT_SUCCESS(rc))
3169 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3170
3171 parm.u.pointer.addr = pVM;
3172 parm.u.pointer.size = sizeof(pVM);
3173 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3174 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3175 if (!RT_SUCCESS(rc))
3176 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3177 }
3178 }
3179 }
3180#endif
3181
3182#ifdef VBOX_WITH_GUEST_PROPS
3183 /*
3184 * Guest property service.
3185 */
3186 rc = i_configGuestProperties(this, pUVM);
3187#endif /* VBOX_WITH_GUEST_PROPS defined */
3188
3189#ifdef VBOX_WITH_GUEST_CONTROL
3190 /*
3191 * Guest control service.
3192 */
3193 rc = i_configGuestControl(this);
3194#endif /* VBOX_WITH_GUEST_CONTROL defined */
3195
3196 /*
3197 * ACPI
3198 */
3199 BOOL fACPI;
3200 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3201 if (fACPI)
3202 {
3203 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3204 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3205 * intelppm driver refuses to register an idle state handler.
3206 * Always show CPU leafs for OS X guests. */
3207 BOOL fShowCpu = fOsXGuest;
3208 if (cCpus > 1 || fIOAPIC)
3209 fShowCpu = true;
3210
3211 BOOL fCpuHotPlug;
3212 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3213
3214 InsertConfigNode(pDevices, "acpi", &pDev);
3215 InsertConfigNode(pDev, "0", &pInst);
3216 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3217 InsertConfigNode(pInst, "Config", &pCfg);
3218 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3219
3220 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3221
3222 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3223 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3224 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3225 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3226 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3227 if (fOsXGuest && !llBootNics.empty())
3228 {
3229 BootNic aNic = llBootNics.front();
3230 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3231 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3232 }
3233 if (fOsXGuest && fAudioEnabled)
3234 {
3235 PCIBusAddress Address;
3236 if (pBusMgr->findPCIAddress("hda", 0, Address))
3237 {
3238 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3239 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3240 }
3241 }
3242 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3243 if (chipsetType == ChipsetType_ICH9)
3244 {
3245 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3246 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3247 /* 64-bit prefetch window root resource:
3248 * Only for ICH9 and if PAE or Long Mode is enabled.
3249 * And only with hardware virtualization (@bugref{5454}). */
3250 if ( (fEnablePAE || fIsGuest64Bit)
3251 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3252 otherwise VMM falls back to raw mode */
3253 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3254 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3255 }
3256 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3257 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3258 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3259
3260 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3261 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3262
3263 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3264 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3265
3266 if (auSerialIoPortBase[2])
3267 {
3268 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3269 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3270 }
3271
3272 if (auSerialIoPortBase[3])
3273 {
3274 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3275 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3276 }
3277
3278 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3279 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3280
3281 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3282 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3283
3284 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3285 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3286 InsertConfigNode(pLunL0, "Config", &pCfg);
3287
3288 /* Attach the dummy CPU drivers */
3289 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3290 {
3291 BOOL fCpuAttached = true;
3292
3293 if (fCpuHotPlug)
3294 {
3295 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3296 }
3297
3298 if (fCpuAttached)
3299 {
3300 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3301 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3302 InsertConfigNode(pLunL0, "Config", &pCfg);
3303 }
3304 }
3305 }
3306
3307 /*
3308 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3309 */
3310 {
3311 PCFGMNODE pDbgf;
3312 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3313
3314 /* Paths to search for debug info and such things. */
3315 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3316 Utf8Str strSettingsPath(bstr);
3317 bstr.setNull();
3318 strSettingsPath.stripFilename();
3319 strSettingsPath.append("/");
3320
3321 char szHomeDir[RTPATH_MAX + 1];
3322 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3323 if (RT_FAILURE(rc2))
3324 szHomeDir[0] = '\0';
3325 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3326
3327
3328 Utf8Str strPath;
3329 strPath.append(strSettingsPath).append("debug/;");
3330 strPath.append(strSettingsPath).append(";");
3331 strPath.append(szHomeDir);
3332
3333 InsertConfigString(pDbgf, "Path", strPath.c_str());
3334
3335 /* Tracing configuration. */
3336 BOOL fTracingEnabled;
3337 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3338 if (fTracingEnabled)
3339 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3340
3341 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3342 if (fTracingEnabled)
3343 InsertConfigString(pDbgf, "TracingConfig", bstr);
3344
3345 BOOL fAllowTracingToAccessVM;
3346 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3347 if (fAllowTracingToAccessVM)
3348 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3349
3350 /* Debugger console config. */
3351 PCFGMNODE pDbgc;
3352 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3353
3354 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3355 Utf8Str strVBoxHome = bstr;
3356 bstr.setNull();
3357 if (strVBoxHome.isNotEmpty())
3358 strVBoxHome.append("/");
3359 else
3360 {
3361 strVBoxHome = szHomeDir;
3362 strVBoxHome.append("/.vbox");
3363 }
3364
3365 Utf8Str strFile(strVBoxHome);
3366 strFile.append("dbgc-history");
3367 InsertConfigString(pDbgc, "HistoryFile", strFile);
3368
3369 strFile = strSettingsPath;
3370 strFile.append("dbgc-init");
3371 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3372
3373 strFile = strVBoxHome;
3374 strFile.append("dbgc-init");
3375 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3376 }
3377 }
3378 catch (ConfigError &x)
3379 {
3380 // InsertConfig threw something:
3381 return x.m_vrc;
3382 }
3383 catch (HRESULT hrcXcpt)
3384 {
3385 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3386 }
3387
3388#ifdef VBOX_WITH_EXTPACK
3389 /*
3390 * Call the extension pack hooks if everything went well thus far.
3391 */
3392 if (RT_SUCCESS(rc))
3393 {
3394 pAlock->release();
3395 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3396 pAlock->acquire();
3397 }
3398#endif
3399
3400 /*
3401 * Apply the CFGM overlay.
3402 */
3403 if (RT_SUCCESS(rc))
3404 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3405
3406 /*
3407 * Dump all extradata API settings tweaks, both global and per VM.
3408 */
3409 if (RT_SUCCESS(rc))
3410 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3411
3412#undef H
3413
3414 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3415
3416 /*
3417 * Register VM state change handler.
3418 */
3419 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3420 AssertRC(rc2);
3421 if (RT_SUCCESS(rc))
3422 rc = rc2;
3423
3424 /*
3425 * Register VM runtime error handler.
3426 */
3427 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3428 AssertRC(rc2);
3429 if (RT_SUCCESS(rc))
3430 rc = rc2;
3431
3432 pAlock->acquire();
3433
3434 LogFlowFunc(("vrc = %Rrc\n", rc));
3435 LogFlowFuncLeave();
3436
3437 return rc;
3438}
3439
3440/**
3441 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3442 * values.
3443 *
3444 * @returns VBox status code.
3445 * @param pRoot The root of the configuration tree.
3446 * @param pVirtualBox Pointer to the IVirtualBox interface.
3447 * @param pMachine Pointer to the IMachine interface.
3448 */
3449/* static */
3450int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3451{
3452 /*
3453 * CFGM overlay handling.
3454 *
3455 * Here we check the extra data entries for CFGM values
3456 * and create the nodes and insert the values on the fly. Existing
3457 * values will be removed and reinserted. CFGM is typed, so by default
3458 * we will guess whether it's a string or an integer (byte arrays are
3459 * not currently supported). It's possible to override this autodetection
3460 * by adding "string:", "integer:" or "bytes:" (future).
3461 *
3462 * We first perform a run on global extra data, then on the machine
3463 * extra data to support global settings with local overrides.
3464 */
3465 int rc = VINF_SUCCESS;
3466 try
3467 {
3468 /** @todo add support for removing nodes and byte blobs. */
3469 /*
3470 * Get the next key
3471 */
3472 SafeArray<BSTR> aGlobalExtraDataKeys;
3473 SafeArray<BSTR> aMachineExtraDataKeys;
3474 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3475 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3476
3477 // remember the no. of global values so we can call the correct method below
3478 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3479
3480 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3481 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3482
3483 // build a combined list from global keys...
3484 std::list<Utf8Str> llExtraDataKeys;
3485
3486 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3487 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3488 // ... and machine keys
3489 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3490 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3491
3492 size_t i2 = 0;
3493 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3494 it != llExtraDataKeys.end();
3495 ++it, ++i2)
3496 {
3497 const Utf8Str &strKey = *it;
3498
3499 /*
3500 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3501 */
3502 if (!strKey.startsWith("VBoxInternal/"))
3503 continue;
3504
3505 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3506
3507 // get the value
3508 Bstr bstrExtraDataValue;
3509 if (i2 < cGlobalValues)
3510 // this is still one of the global values:
3511 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3512 bstrExtraDataValue.asOutParam());
3513 else
3514 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3515 bstrExtraDataValue.asOutParam());
3516 if (FAILED(hrc))
3517 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3518
3519 /*
3520 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3521 * Split the two and get the node, delete the value and create the node
3522 * if necessary.
3523 */
3524 PCFGMNODE pNode;
3525 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3526 if (pszCFGMValueName)
3527 {
3528 /* terminate the node and advance to the value (Utf8Str might not
3529 offically like this but wtf) */
3530 *(char*)pszCFGMValueName = '\0';
3531 ++pszCFGMValueName;
3532
3533 /* does the node already exist? */
3534 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3535 if (pNode)
3536 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3537 else
3538 {
3539 /* create the node */
3540 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3541 if (RT_FAILURE(rc))
3542 {
3543 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3544 continue;
3545 }
3546 Assert(pNode);
3547 }
3548 }
3549 else
3550 {
3551 /* root value (no node path). */
3552 pNode = pRoot;
3553 pszCFGMValueName = pszExtraDataKey;
3554 pszExtraDataKey--;
3555 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3556 }
3557
3558 /*
3559 * Now let's have a look at the value.
3560 * Empty strings means that we should remove the value, which we've
3561 * already done above.
3562 */
3563 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3564 if (!strCFGMValueUtf8.isEmpty())
3565 {
3566 uint64_t u64Value;
3567
3568 /* check for type prefix first. */
3569 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3570 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3571 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3572 {
3573 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3574 if (RT_SUCCESS(rc))
3575 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3576 }
3577 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3578 {
3579 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3580 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3581 if (cbValue > 0)
3582 {
3583 void *pvBytes = RTMemTmpAlloc(cbValue);
3584 if (pvBytes)
3585 {
3586 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3587 if (RT_SUCCESS(rc))
3588 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3589 RTMemTmpFree(pvBytes);
3590 }
3591 else
3592 rc = VERR_NO_TMP_MEMORY;
3593 }
3594 else if (cbValue == 0)
3595 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3596 else
3597 rc = VERR_INVALID_BASE64_ENCODING;
3598 }
3599 /* auto detect type. */
3600 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3601 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3602 else
3603 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3604 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3605 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3606 }
3607 }
3608 }
3609 catch (ConfigError &x)
3610 {
3611 // InsertConfig threw something:
3612 return x.m_vrc;
3613 }
3614 return rc;
3615}
3616
3617/**
3618 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3619 * values.
3620 *
3621 * @returns VBox status code.
3622 * @param pVirtualBox Pointer to the IVirtualBox interface.
3623 * @param pMachine Pointer to the IMachine interface.
3624 */
3625/* static */
3626int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3627{
3628 {
3629 SafeArray<BSTR> aGlobalExtraDataKeys;
3630 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3631 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3632 bool hasKey = false;
3633 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3634 {
3635 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3636 if (!strKey.startsWith("VBoxInternal2/"))
3637 continue;
3638
3639 Bstr bstrValue;
3640 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3641 bstrValue.asOutParam());
3642 if (FAILED(hrc))
3643 continue;
3644 if (!hasKey)
3645 LogRel(("Global extradata API settings:\n"));
3646 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3647 hasKey = true;
3648 }
3649 }
3650
3651 {
3652 SafeArray<BSTR> aMachineExtraDataKeys;
3653 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3654 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3655 bool hasKey = false;
3656 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3657 {
3658 Utf8Str strKey(aMachineExtraDataKeys[i]);
3659 if (!strKey.startsWith("VBoxInternal2/"))
3660 continue;
3661
3662 Bstr bstrValue;
3663 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3664 bstrValue.asOutParam());
3665 if (FAILED(hrc))
3666 continue;
3667 if (!hasKey)
3668 LogRel(("Per-VM extradata API settings:\n"));
3669 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3670 hasKey = true;
3671 }
3672 }
3673
3674 return VINF_SUCCESS;
3675}
3676
3677int Console::i_configGraphicsController(PCFGMNODE pDevices,
3678 const GraphicsControllerType_T enmGraphicsController,
3679 BusAssignmentManager *pBusMgr,
3680 const ComPtr<IMachine> &ptrMachine,
3681 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3682 bool fHMEnabled)
3683{
3684 // InsertConfig* throws
3685 try
3686 {
3687 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3688 HRESULT hrc;
3689 Bstr bstr;
3690 const char *pcszDevice = "vga";
3691
3692#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3693 InsertConfigNode(pDevices, pcszDevice, &pDev);
3694 InsertConfigNode(pDev, "0", &pInst);
3695 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3696
3697 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3698 InsertConfigNode(pInst, "Config", &pCfg);
3699 ULONG cVRamMBs;
3700 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3701 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3702 ULONG cMonitorCount;
3703 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3704 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3705#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3706 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3707#else
3708 NOREF(fHMEnabled);
3709#endif
3710
3711 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3712
3713#ifdef VBOX_WITH_VMSVGA
3714 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3715 {
3716 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3717#ifdef VBOX_WITH_VMSVGA3D
3718 IFramebuffer *pFramebuffer = NULL;
3719 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3720 if (SUCCEEDED(hrc) && pFramebuffer)
3721 {
3722 LONG64 winId = 0;
3723 /** @todo deal with multimonitor setup */
3724 Assert(cMonitorCount == 1);
3725 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3726 InsertConfigInteger(pCfg, "HostWindowId", winId);
3727 pFramebuffer->Release();
3728 }
3729 BOOL f3DEnabled;
3730 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3731 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3732#else
3733 LogRel(("VMSVGA3d not available in this build!\n"));
3734#endif
3735 }
3736#endif
3737
3738 /* Custom VESA mode list */
3739 unsigned cModes = 0;
3740 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3741 {
3742 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3743 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3744 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3745 if (bstr.isEmpty())
3746 break;
3747 InsertConfigString(pCfg, szExtraDataKey, bstr);
3748 ++cModes;
3749 }
3750 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3751
3752 /* VESA height reduction */
3753 ULONG ulHeightReduction;
3754 IFramebuffer *pFramebuffer = NULL;
3755 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3756 if (SUCCEEDED(hrc) && pFramebuffer)
3757 {
3758 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3759 pFramebuffer->Release();
3760 pFramebuffer = NULL;
3761 }
3762 else
3763 {
3764 /* If framebuffer is not available, there is no height reduction. */
3765 ulHeightReduction = 0;
3766 }
3767 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3768
3769 /*
3770 * BIOS logo
3771 */
3772 BOOL fFadeIn;
3773 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3774 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3775 BOOL fFadeOut;
3776 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3777 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3778 ULONG logoDisplayTime;
3779 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3780 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3781 Bstr logoImagePath;
3782 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3783 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3784
3785 /*
3786 * Boot menu
3787 */
3788 BIOSBootMenuMode_T eBootMenuMode;
3789 int iShowBootMenu;
3790 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3791 switch (eBootMenuMode)
3792 {
3793 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3794 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3795 default: iShowBootMenu = 2; break;
3796 }
3797 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3798
3799 /* Attach the display. */
3800 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3801 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3802 InsertConfigNode(pLunL0, "Config", &pCfg);
3803 Display *pDisplay = mDisplay;
3804 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3805 }
3806 catch (ConfigError &x)
3807 {
3808 // InsertConfig threw something:
3809 return x.m_vrc;
3810 }
3811
3812#undef H
3813
3814 return VINF_SUCCESS;
3815}
3816
3817
3818/**
3819 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3820 */
3821void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3822{
3823 va_list va;
3824 va_start(va, pszFormat);
3825 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3826 va_end(va);
3827}
3828
3829/* XXX introduce RT format specifier */
3830static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3831{
3832 if (u64Size > INT64_C(5000)*_1G)
3833 {
3834 *pszUnit = "TB";
3835 return u64Size / _1T;
3836 }
3837 else if (u64Size > INT64_C(5000)*_1M)
3838 {
3839 *pszUnit = "GB";
3840 return u64Size / _1G;
3841 }
3842 else
3843 {
3844 *pszUnit = "MB";
3845 return u64Size / _1M;
3846 }
3847}
3848
3849/**
3850 * Checks the location of the given medium for known bugs affecting the usage
3851 * of the host I/O cache setting.
3852 *
3853 * @returns VBox status code.
3854 * @param pMedium The medium to check.
3855 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3856 */
3857int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3858{
3859#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3860 /*
3861 * Some sanity checks.
3862 */
3863 RT_NOREF(pfUseHostIOCache);
3864 ComPtr<IMediumFormat> pMediumFormat;
3865 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3866 ULONG uCaps = 0;
3867 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3868 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3869
3870 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3871 uCaps |= mediumFormatCap[j];
3872
3873 if (uCaps & MediumFormatCapabilities_File)
3874 {
3875 Bstr strFile;
3876 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3877 Utf8Str utfFile = Utf8Str(strFile);
3878 Bstr strSnap;
3879 ComPtr<IMachine> pMachine = i_machine();
3880 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3881 Utf8Str utfSnap = Utf8Str(strSnap);
3882 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3883 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3884 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3885 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3886 /* Ignore the error code. On error, the file system type is still 'unknown' so
3887 * none of the following paths are taken. This can happen for new VMs which
3888 * still don't have a snapshot folder. */
3889 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3890 if (!mfSnapshotFolderDiskTypeShown)
3891 {
3892 LogRel(("File system of '%s' (snapshots) is %s\n",
3893 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3894 mfSnapshotFolderDiskTypeShown = true;
3895 }
3896 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3897 LONG64 i64Size;
3898 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3899#ifdef RT_OS_WINDOWS
3900 if ( enmFsTypeFile == RTFSTYPE_FAT
3901 && i64Size >= _4G)
3902 {
3903 const char *pszUnit;
3904 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3905 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3906 N_("The medium '%ls' has a logical size of %RU64%s "
3907 "but the file system the medium is located on seems "
3908 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3909 "We strongly recommend to put all your virtual disk images and "
3910 "the snapshot folder onto an NTFS partition"),
3911 strFile.raw(), u64Print, pszUnit);
3912 }
3913#else /* !RT_OS_WINDOWS */
3914 if ( enmFsTypeFile == RTFSTYPE_FAT
3915 || enmFsTypeFile == RTFSTYPE_EXT
3916 || enmFsTypeFile == RTFSTYPE_EXT2
3917 || enmFsTypeFile == RTFSTYPE_EXT3
3918 || enmFsTypeFile == RTFSTYPE_EXT4)
3919 {
3920 RTFILE file;
3921 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3922 if (RT_SUCCESS(rc))
3923 {
3924 RTFOFF maxSize;
3925 /* Careful: This function will work only on selected local file systems! */
3926 rc = RTFileGetMaxSizeEx(file, &maxSize);
3927 RTFileClose(file);
3928 if ( RT_SUCCESS(rc)
3929 && maxSize > 0
3930 && i64Size > (LONG64)maxSize)
3931 {
3932 const char *pszUnitSiz;
3933 const char *pszUnitMax;
3934 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3935 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3936 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3937 N_("The medium '%ls' has a logical size of %RU64%s "
3938 "but the file system the medium is located on can "
3939 "only handle files up to %RU64%s in theory.\n"
3940 "We strongly recommend to put all your virtual disk "
3941 "images and the snapshot folder onto a proper "
3942 "file system (e.g. ext3) with a sufficient size"),
3943 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3944 }
3945 }
3946 }
3947#endif /* !RT_OS_WINDOWS */
3948
3949 /*
3950 * Snapshot folder:
3951 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3952 */
3953 if ( enmFsTypeSnap == RTFSTYPE_FAT
3954 && i64Size >= _4G
3955 && !mfSnapshotFolderSizeWarningShown)
3956 {
3957 const char *pszUnit;
3958 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3959 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3960#ifdef RT_OS_WINDOWS
3961 N_("The snapshot folder of this VM '%ls' seems to be located on "
3962 "a FAT(32) file system. The logical size of the medium '%ls' "
3963 "(%RU64%s) is bigger than the maximum file size this file "
3964 "system can handle (4GB).\n"
3965 "We strongly recommend to put all your virtual disk images and "
3966 "the snapshot folder onto an NTFS partition"),
3967#else
3968 N_("The snapshot folder of this VM '%ls' seems to be located on "
3969 "a FAT(32) file system. The logical size of the medium '%ls' "
3970 "(%RU64%s) is bigger than the maximum file size this file "
3971 "system can handle (4GB).\n"
3972 "We strongly recommend to put all your virtual disk images and "
3973 "the snapshot folder onto a proper file system (e.g. ext3)"),
3974#endif
3975 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3976 /* Show this particular warning only once */
3977 mfSnapshotFolderSizeWarningShown = true;
3978 }
3979
3980#ifdef RT_OS_LINUX
3981 /*
3982 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3983 * on an ext4 partition.
3984 * This bug apparently applies to the XFS file system as well.
3985 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3986 */
3987
3988 char szOsRelease[128];
3989 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3990 bool fKernelHasODirectBug = RT_FAILURE(rc)
3991 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3992
3993 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3994 && !*pfUseHostIOCache
3995 && fKernelHasODirectBug)
3996 {
3997 if ( enmFsTypeFile == RTFSTYPE_EXT4
3998 || enmFsTypeFile == RTFSTYPE_XFS)
3999 {
4000 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4001 N_("The host I/O cache for at least one controller is disabled "
4002 "and the medium '%ls' for this VM "
4003 "is located on an %s partition. There is a known Linux "
4004 "kernel bug which can lead to the corruption of the virtual "
4005 "disk image under these conditions.\n"
4006 "Either enable the host I/O cache permanently in the VM "
4007 "settings or put the disk image and the snapshot folder "
4008 "onto a different file system.\n"
4009 "The host I/O cache will now be enabled for this medium"),
4010 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4011 *pfUseHostIOCache = true;
4012 }
4013 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4014 || enmFsTypeSnap == RTFSTYPE_XFS)
4015 && !mfSnapshotFolderExt4WarningShown)
4016 {
4017 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4018 N_("The host I/O cache for at least one controller is disabled "
4019 "and the snapshot folder for this VM "
4020 "is located on an %s partition. There is a known Linux "
4021 "kernel bug which can lead to the corruption of the virtual "
4022 "disk image under these conditions.\n"
4023 "Either enable the host I/O cache permanently in the VM "
4024 "settings or put the disk image and the snapshot folder "
4025 "onto a different file system.\n"
4026 "The host I/O cache will now be enabled for this medium"),
4027 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4028 *pfUseHostIOCache = true;
4029 mfSnapshotFolderExt4WarningShown = true;
4030 }
4031 }
4032
4033 /*
4034 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4035 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4036 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4037 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4038 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4039 */
4040 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4041 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4042 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4043 && !*pfUseHostIOCache
4044 && fKernelAsyncUnreliable)
4045 {
4046 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4047 N_("The host I/O cache for at least one controller is disabled. "
4048 "There is a known Linux kernel bug which can lead to kernel "
4049 "oopses under heavy load. To our knowledge this bug affects "
4050 "all 2.6.18 kernels.\n"
4051 "Either enable the host I/O cache permanently in the VM "
4052 "settings or switch to a newer host kernel.\n"
4053 "The host I/O cache will now be enabled for this medium"));
4054 *pfUseHostIOCache = true;
4055 }
4056#endif
4057 }
4058#undef H
4059
4060 return VINF_SUCCESS;
4061}
4062
4063/**
4064 * Unmounts the specified medium from the specified device.
4065 *
4066 * @returns VBox status code.
4067 * @param pUVM The usermode VM handle.
4068 * @param enmBus The storage bus.
4069 * @param enmDevType The device type.
4070 * @param pcszDevice The device emulation.
4071 * @param uInstance Instance of the device.
4072 * @param uLUN The LUN on the device.
4073 * @param fForceUnmount Whether to force unmounting.
4074 */
4075int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4076 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4077 bool fForceUnmount)
4078{
4079 /* Unmount existing media only for floppy and DVD drives. */
4080 int rc = VINF_SUCCESS;
4081 PPDMIBASE pBase;
4082 if (enmBus == StorageBus_USB)
4083 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4084 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4085 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4086 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4087 else /* IDE or Floppy */
4088 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4089
4090 if (RT_FAILURE(rc))
4091 {
4092 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4093 rc = VINF_SUCCESS;
4094 AssertRC(rc);
4095 }
4096 else
4097 {
4098 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4099 AssertReturn(pIMount, VERR_INVALID_POINTER);
4100
4101 /* Unmount the media (but do not eject the medium!) */
4102 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4103 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4104 rc = VINF_SUCCESS;
4105 /* for example if the medium is locked */
4106 else if (RT_FAILURE(rc))
4107 return rc;
4108 }
4109
4110 return rc;
4111}
4112
4113/**
4114 * Removes the currently attached medium driver form the specified device
4115 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4116 *
4117 * @returns VBox status code.
4118 * @param pCtlInst The controler instance node in the CFGM tree.
4119 * @param pcszDevice The device name.
4120 * @param uInstance The device instance.
4121 * @param uLUN The device LUN.
4122 * @param enmBus The storage bus.
4123 * @param fAttachDetach Flag whether this is a change while the VM is running
4124 * @param fHotplug Flag whether the guest should be notified about the device change.
4125 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4126 * @param pUVM The usermode VM handle.
4127 * @param enmDevType The device type.
4128 * @param ppLunL0 Where to store the node to attach the new config to on success.
4129 */
4130int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4131 const char *pcszDevice,
4132 unsigned uInstance,
4133 unsigned uLUN,
4134 StorageBus_T enmBus,
4135 bool fAttachDetach,
4136 bool fHotplug,
4137 bool fForceUnmount,
4138 PUVM pUVM,
4139 DeviceType_T enmDevType,
4140 PCFGMNODE *ppLunL0)
4141{
4142 int rc = VINF_SUCCESS;
4143 bool fAddLun = false;
4144
4145 /* First check if the LUN already exists. */
4146 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4147 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4148
4149 if (pLunL0)
4150 {
4151 /*
4152 * Unmount the currently mounted medium if we don't just hot remove the
4153 * complete device (SATA) and it supports unmounting (DVD).
4154 */
4155 if ( (enmDevType != DeviceType_HardDisk)
4156 && !fHotplug)
4157 {
4158 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4159 uInstance, uLUN, fForceUnmount);
4160 if (RT_FAILURE(rc))
4161 return rc;
4162 }
4163
4164 /*
4165 * Don't detach the SCSI driver when unmounting the current medium
4166 * (we are not ripping out the device but only eject the medium).
4167 */
4168 char *pszDriverDetach = NULL;
4169 if ( !fHotplug
4170 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4171 || enmBus == StorageBus_SAS
4172 || enmBus == StorageBus_SCSI
4173 || enmBus == StorageBus_USB))
4174 {
4175 /* Get the current attached driver we have to detach. */
4176 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4177 if (pDrvLun)
4178 {
4179 char szDriver[128];
4180 RT_ZERO(szDriver);
4181 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4182 if (RT_SUCCESS(rc))
4183 pszDriverDetach = RTStrDup(&szDriver[0]);
4184
4185 pLunL0 = pDrvLun;
4186 }
4187 }
4188
4189 if (enmBus == StorageBus_USB)
4190 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4191 pszDriverDetach, 0 /* iOccurence */,
4192 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4193 else
4194 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4195 pszDriverDetach, 0 /* iOccurence */,
4196 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4197
4198 if (pszDriverDetach)
4199 {
4200 RTStrFree(pszDriverDetach);
4201 /* Remove the complete node and create new for the new config. */
4202 CFGMR3RemoveNode(pLunL0);
4203 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4204 if (pLunL0)
4205 {
4206 try
4207 {
4208 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4209 }
4210 catch (ConfigError &x)
4211 {
4212 // InsertConfig threw something:
4213 return x.m_vrc;
4214 }
4215 }
4216 }
4217 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4218 rc = VINF_SUCCESS;
4219 AssertRCReturn(rc, rc);
4220
4221 /*
4222 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4223 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4224 */
4225 if ( fHotplug
4226 || enmBus == StorageBus_IDE
4227 || enmBus == StorageBus_Floppy
4228 || enmBus == StorageBus_PCIe
4229 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4230 {
4231 fAddLun = true;
4232 CFGMR3RemoveNode(pLunL0);
4233 }
4234 }
4235 else
4236 fAddLun = true;
4237
4238 try
4239 {
4240 if (fAddLun)
4241 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4242 }
4243 catch (ConfigError &x)
4244 {
4245 // InsertConfig threw something:
4246 return x.m_vrc;
4247 }
4248
4249 if (ppLunL0)
4250 *ppLunL0 = pLunL0;
4251
4252 return rc;
4253}
4254
4255int Console::i_configMediumAttachment(const char *pcszDevice,
4256 unsigned uInstance,
4257 StorageBus_T enmBus,
4258 bool fUseHostIOCache,
4259 bool fBuiltinIOCache,
4260 bool fInsertDiskIntegrityDrv,
4261 bool fSetupMerge,
4262 unsigned uMergeSource,
4263 unsigned uMergeTarget,
4264 IMediumAttachment *pMediumAtt,
4265 MachineState_T aMachineState,
4266 HRESULT *phrc,
4267 bool fAttachDetach,
4268 bool fForceUnmount,
4269 bool fHotplug,
4270 PUVM pUVM,
4271 DeviceType_T *paLedDevType,
4272 PCFGMNODE *ppLunL0)
4273{
4274 // InsertConfig* throws
4275 try
4276 {
4277 int rc = VINF_SUCCESS;
4278 HRESULT hrc;
4279 Bstr bstr;
4280 PCFGMNODE pCtlInst = NULL;
4281
4282// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4283#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4284
4285 LONG lDev;
4286 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4287 LONG lPort;
4288 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4289 DeviceType_T lType;
4290 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4291 BOOL fNonRotational;
4292 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4293 BOOL fDiscard;
4294 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4295
4296 unsigned uLUN;
4297 PCFGMNODE pLunL0 = NULL;
4298 hrc = Console::i_convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4299
4300 /* Determine the base path for the device instance. */
4301 if (enmBus != StorageBus_USB)
4302 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4303 else
4304 {
4305 /* If we hotplug a USB device create a new CFGM tree. */
4306 if (!fHotplug)
4307 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4308 else
4309 pCtlInst = CFGMR3CreateTree(pUVM);
4310 }
4311 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4312
4313 if (enmBus == StorageBus_USB)
4314 {
4315 PCFGMNODE pCfg = NULL;
4316
4317 /* Create correct instance. */
4318 if (!fHotplug)
4319 {
4320 if (!fAttachDetach)
4321 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4322 else
4323 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4324 }
4325
4326 if (!fAttachDetach)
4327 InsertConfigNode(pCtlInst, "Config", &pCfg);
4328
4329 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4330
4331 if (!fHotplug && !fAttachDetach)
4332 {
4333 char aszUuid[RTUUID_STR_LENGTH + 1];
4334 USBStorageDevice UsbMsd = USBStorageDevice();
4335
4336 memset(aszUuid, 0, sizeof(aszUuid));
4337 rc = RTUuidCreate(&UsbMsd.mUuid);
4338 AssertRCReturn(rc, rc);
4339 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4340 AssertRCReturn(rc, rc);
4341
4342 UsbMsd.iPort = uInstance;
4343
4344 InsertConfigString(pCtlInst, "UUID", aszUuid);
4345 mUSBStorageDevices.push_back(UsbMsd);
4346
4347 /** @todo No LED after hotplugging. */
4348 /* Attach the status driver */
4349 Assert(cLedUsb >= 8);
4350 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4351 &mapMediumAttachments, pcszDevice, 0);
4352 paLedDevType = &maStorageDevType[iLedUsb];
4353 }
4354 }
4355
4356 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4357 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4358 if (RT_FAILURE(rc))
4359 return rc;
4360 if (ppLunL0)
4361 *ppLunL0 = pLunL0;
4362
4363 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4364 mapMediumAttachments[devicePath] = pMediumAtt;
4365
4366 ComPtr<IMedium> pMedium;
4367 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4368
4369 /*
4370 * 1. Only check this for hard disk images.
4371 * 2. Only check during VM creation and not later, especially not during
4372 * taking an online snapshot!
4373 */
4374 if ( lType == DeviceType_HardDisk
4375 && ( aMachineState == MachineState_Starting
4376 || aMachineState == MachineState_Restoring))
4377 {
4378 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4379 if (RT_FAILURE(rc))
4380 return rc;
4381 }
4382
4383 BOOL fPassthrough = FALSE;
4384 if (pMedium)
4385 {
4386 BOOL fHostDrive;
4387 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4388 if ( ( lType == DeviceType_DVD
4389 || lType == DeviceType_Floppy)
4390 && !fHostDrive)
4391 {
4392 /*
4393 * Informative logging.
4394 */
4395 Bstr strFile;
4396 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4397 Utf8Str utfFile = Utf8Str(strFile);
4398 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4399 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4400 LogRel(("File system of '%s' (%s) is %s\n",
4401 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4402 RTFsTypeName(enmFsTypeFile)));
4403 }
4404
4405 if (fHostDrive)
4406 {
4407 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4408 }
4409 }
4410
4411 ComObjPtr<IBandwidthGroup> pBwGroup;
4412 Bstr strBwGroup;
4413 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4414
4415 if (!pBwGroup.isNull())
4416 {
4417 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4418 }
4419
4420 /*
4421 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4422 * or for SATA if the new device is a CD/DVD drive.
4423 */
4424 if ( (fHotplug || !fAttachDetach)
4425 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4426 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4427 {
4428 InsertConfigString(pLunL0, "Driver", "SCSI");
4429 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4430 }
4431
4432 rc = i_configMedium(pLunL0,
4433 !!fPassthrough,
4434 lType,
4435 fUseHostIOCache,
4436 fBuiltinIOCache,
4437 fInsertDiskIntegrityDrv,
4438 fSetupMerge,
4439 uMergeSource,
4440 uMergeTarget,
4441 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4442 !!fDiscard,
4443 !!fNonRotational,
4444 pMedium,
4445 aMachineState,
4446 phrc);
4447 if (RT_FAILURE(rc))
4448 return rc;
4449
4450 if (fAttachDetach)
4451 {
4452 /* Attach the new driver. */
4453 if (enmBus == StorageBus_USB)
4454 {
4455 if (fHotplug)
4456 {
4457 USBStorageDevice UsbMsd = USBStorageDevice();
4458 RTUuidCreate(&UsbMsd.mUuid);
4459 UsbMsd.iPort = uInstance;
4460 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4461 if (RT_SUCCESS(rc))
4462 mUSBStorageDevices.push_back(UsbMsd);
4463 }
4464 else
4465 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4466 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4467 }
4468 else if ( !fHotplug
4469 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4470 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4471 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4472 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4473 else
4474 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4475 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4476 AssertRCReturn(rc, rc);
4477
4478 /*
4479 * Make the secret key helper interface known to the VD driver if it is attached,
4480 * so we can get notified about missing keys.
4481 */
4482 PPDMIBASE pIBase = NULL;
4483 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4484 if (RT_SUCCESS(rc) && pIBase)
4485 {
4486 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4487 if (pIMedium)
4488 {
4489 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4490 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4491 }
4492 }
4493
4494 /* There is no need to handle removable medium mounting, as we
4495 * unconditionally replace everthing including the block driver level.
4496 * This means the new medium will be picked up automatically. */
4497 }
4498
4499 if (paLedDevType)
4500 paLedDevType[uLUN] = lType;
4501
4502 /* Dump the changed LUN if possible, dump the complete device otherwise */
4503 if ( aMachineState != MachineState_Starting
4504 && aMachineState != MachineState_Restoring)
4505 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4506 }
4507 catch (ConfigError &x)
4508 {
4509 // InsertConfig threw something:
4510 return x.m_vrc;
4511 }
4512
4513#undef H
4514
4515 return VINF_SUCCESS;
4516}
4517
4518int Console::i_configMedium(PCFGMNODE pLunL0,
4519 bool fPassthrough,
4520 DeviceType_T enmType,
4521 bool fUseHostIOCache,
4522 bool fBuiltinIOCache,
4523 bool fInsertDiskIntegrityDrv,
4524 bool fSetupMerge,
4525 unsigned uMergeSource,
4526 unsigned uMergeTarget,
4527 const char *pcszBwGroup,
4528 bool fDiscard,
4529 bool fNonRotational,
4530 IMedium *pMedium,
4531 MachineState_T aMachineState,
4532 HRESULT *phrc)
4533{
4534 // InsertConfig* throws
4535 try
4536 {
4537 HRESULT hrc;
4538 Bstr bstr;
4539 PCFGMNODE pCfg = NULL;
4540
4541#define H() \
4542 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4543
4544
4545 BOOL fHostDrive = FALSE;
4546 MediumType_T mediumType = MediumType_Normal;
4547 if (pMedium)
4548 {
4549 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4550 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4551 }
4552
4553 if (fHostDrive)
4554 {
4555 Assert(pMedium);
4556 if (enmType == DeviceType_DVD)
4557 {
4558 InsertConfigString(pLunL0, "Driver", "HostDVD");
4559 InsertConfigNode(pLunL0, "Config", &pCfg);
4560
4561 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4562 InsertConfigString(pCfg, "Path", bstr);
4563
4564 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4565 }
4566 else if (enmType == DeviceType_Floppy)
4567 {
4568 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4569 InsertConfigNode(pLunL0, "Config", &pCfg);
4570
4571 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4572 InsertConfigString(pCfg, "Path", bstr);
4573 }
4574 }
4575 else
4576 {
4577 if (fInsertDiskIntegrityDrv)
4578 {
4579 /*
4580 * The actual configuration is done through CFGM extra data
4581 * for each inserted driver separately.
4582 */
4583 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4584 InsertConfigNode(pLunL0, "Config", &pCfg);
4585 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4586 }
4587
4588 InsertConfigString(pLunL0, "Driver", "VD");
4589 InsertConfigNode(pLunL0, "Config", &pCfg);
4590 switch (enmType)
4591 {
4592 case DeviceType_DVD:
4593 InsertConfigString(pCfg, "Type", "DVD");
4594 InsertConfigInteger(pCfg, "Mountable", 1);
4595 break;
4596 case DeviceType_Floppy:
4597 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4598 InsertConfigInteger(pCfg, "Mountable", 1);
4599 break;
4600 case DeviceType_HardDisk:
4601 default:
4602 InsertConfigString(pCfg, "Type", "HardDisk");
4603 InsertConfigInteger(pCfg, "Mountable", 0);
4604 }
4605
4606 if ( pMedium
4607 && ( enmType == DeviceType_DVD
4608 || enmType == DeviceType_Floppy)
4609 )
4610 {
4611 // if this medium represents an ISO image and this image is inaccessible,
4612 // the ignore it instead of causing a failure; this can happen when we
4613 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4614 // Additions were mounted and the user upgraded VirtualBox. Previously
4615 // we failed on startup, but that's not good because the only way out then
4616 // would be to discard the VM state...
4617 MediumState_T mediumState;
4618 hrc = pMedium->RefreshState(&mediumState); H();
4619 if (mediumState == MediumState_Inaccessible)
4620 {
4621 Bstr loc;
4622 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4623 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4624 "The image file '%ls' is inaccessible and is being ignored. "
4625 "Please select a different image file for the virtual %s drive.",
4626 loc.raw(),
4627 enmType == DeviceType_DVD ? "DVD" : "floppy");
4628 pMedium = NULL;
4629 }
4630 }
4631
4632 if (pMedium)
4633 {
4634 /* Start with length of parent chain, as the list is reversed */
4635 unsigned uImage = 0;
4636 IMedium *pTmp = pMedium;
4637 while (pTmp)
4638 {
4639 uImage++;
4640 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4641 }
4642 /* Index of last image */
4643 uImage--;
4644
4645# ifdef VBOX_WITH_EXTPACK
4646 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4647 {
4648 /* Configure loading the VDPlugin. */
4649 static const char s_szVDPlugin[] = "VDPluginCrypt";
4650 PCFGMNODE pCfgPlugins = NULL;
4651 PCFGMNODE pCfgPlugin = NULL;
4652 Utf8Str strPlugin;
4653 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4654 // Don't fail, this is optional!
4655 if (SUCCEEDED(hrc))
4656 {
4657 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4658 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4659 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4660 }
4661 }
4662# endif
4663
4664 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4665 InsertConfigString(pCfg, "Path", bstr);
4666
4667 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4668 InsertConfigString(pCfg, "Format", bstr);
4669
4670 if (mediumType == MediumType_Readonly)
4671 InsertConfigInteger(pCfg, "ReadOnly", 1);
4672 else if (enmType == DeviceType_Floppy)
4673 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4674
4675 /* Start without exclusive write access to the images. */
4676 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4677 * we're resuming the VM if some 3rd dude have any of the VDIs open
4678 * with write sharing denied. However, if the two VMs are sharing a
4679 * image it really is necessary....
4680 *
4681 * So, on the "lock-media" command, the target teleporter should also
4682 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4683 * that. Grumble. */
4684 if ( enmType == DeviceType_HardDisk
4685 && ( aMachineState == MachineState_TeleportingIn
4686 || aMachineState == MachineState_FaultTolerantSyncing))
4687 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4688
4689 /* Flag for opening the medium for sharing between VMs. This
4690 * is done at the moment only for the first (and only) medium
4691 * in the chain, as shared media can have no diffs. */
4692 if (mediumType == MediumType_Shareable)
4693 InsertConfigInteger(pCfg, "Shareable", 1);
4694
4695 if (!fUseHostIOCache)
4696 {
4697 InsertConfigInteger(pCfg, "UseNewIo", 1);
4698 /*
4699 * Activate the builtin I/O cache for harddisks only.
4700 * It caches writes only which doesn't make sense for DVD drives
4701 * and just increases the overhead.
4702 */
4703 if ( fBuiltinIOCache
4704 && (enmType == DeviceType_HardDisk))
4705 InsertConfigInteger(pCfg, "BlockCache", 1);
4706 }
4707
4708 if (fSetupMerge)
4709 {
4710 InsertConfigInteger(pCfg, "SetupMerge", 1);
4711 if (uImage == uMergeSource)
4712 InsertConfigInteger(pCfg, "MergeSource", 1);
4713 else if (uImage == uMergeTarget)
4714 InsertConfigInteger(pCfg, "MergeTarget", 1);
4715 }
4716
4717 if (pcszBwGroup)
4718 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4719
4720 if (fDiscard)
4721 InsertConfigInteger(pCfg, "Discard", 1);
4722
4723 if (fNonRotational)
4724 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4725
4726 /* Pass all custom parameters. */
4727 bool fHostIP = true;
4728 bool fEncrypted = false;
4729 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4730
4731 /* Create an inverted list of parents. */
4732 uImage--;
4733 IMedium *pParentMedium = pMedium;
4734 for (PCFGMNODE pParent = pCfg;; uImage--)
4735 {
4736 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4737 if (!pMedium)
4738 break;
4739
4740 PCFGMNODE pCur;
4741 InsertConfigNode(pParent, "Parent", &pCur);
4742 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4743 InsertConfigString(pCur, "Path", bstr);
4744
4745 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4746 InsertConfigString(pCur, "Format", bstr);
4747
4748 if (fSetupMerge)
4749 {
4750 if (uImage == uMergeSource)
4751 InsertConfigInteger(pCur, "MergeSource", 1);
4752 else if (uImage == uMergeTarget)
4753 InsertConfigInteger(pCur, "MergeTarget", 1);
4754 }
4755
4756 /* Configure medium properties. */
4757 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4758
4759 /* next */
4760 pParent = pCur;
4761 pParentMedium = pMedium;
4762 }
4763
4764 /* Custom code: put marker to not use host IP stack to driver
4765 * configuration node. Simplifies life of DrvVD a bit. */
4766 if (!fHostIP)
4767 InsertConfigInteger(pCfg, "HostIPStack", 0);
4768
4769 if (fEncrypted)
4770 m_cDisksEncrypted++;
4771 }
4772 else
4773 {
4774 /* Set empty drive flag for DVD or floppy without media. */
4775 if ( enmType == DeviceType_DVD
4776 || enmType == DeviceType_Floppy)
4777 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4778 }
4779 }
4780#undef H
4781 }
4782 catch (ConfigError &x)
4783 {
4784 // InsertConfig threw something:
4785 return x.m_vrc;
4786 }
4787
4788 return VINF_SUCCESS;
4789}
4790
4791/**
4792 * Adds the medium properties to the CFGM tree.
4793 *
4794 * @returns VBox status code.
4795 * @param pCur The current CFGM node.
4796 * @param pMedium The medium object to configure.
4797 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4798 * @param pfEncrypted Where to return whether the medium is encrypted.
4799 */
4800int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4801{
4802 /* Pass all custom parameters. */
4803 SafeArray<BSTR> aNames;
4804 SafeArray<BSTR> aValues;
4805 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4806 ComSafeArrayAsOutParam(aValues));
4807
4808 if ( SUCCEEDED(hrc)
4809 && aNames.size() != 0)
4810 {
4811 PCFGMNODE pVDC;
4812 InsertConfigNode(pCur, "VDConfig", &pVDC);
4813 for (size_t ii = 0; ii < aNames.size(); ++ii)
4814 {
4815 if (aValues[ii] && *aValues[ii])
4816 {
4817 Utf8Str name = aNames[ii];
4818 Utf8Str value = aValues[ii];
4819 size_t offSlash = name.find("/", 0);
4820 if ( offSlash != name.npos
4821 && !name.startsWith("Special/"))
4822 {
4823 com::Utf8Str strFilter;
4824 com::Utf8Str strKey;
4825
4826 hrc = strFilter.assignEx(name, 0, offSlash);
4827 if (FAILED(hrc))
4828 break;
4829
4830 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4831 if (FAILED(hrc))
4832 break;
4833
4834 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4835 if (!pCfgFilterConfig)
4836 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4837
4838 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4839 }
4840 else
4841 {
4842 InsertConfigString(pVDC, name.c_str(), value);
4843 if ( name.compare("HostIPStack") == 0
4844 && value.compare("0") == 0)
4845 *pfHostIP = false;
4846 }
4847
4848 if ( name.compare("CRYPT/KeyId") == 0
4849 && pfEncrypted)
4850 *pfEncrypted = true;
4851 }
4852 }
4853 }
4854
4855 return hrc;
4856}
4857
4858
4859/**
4860 * Construct the Network configuration tree
4861 *
4862 * @returns VBox status code.
4863 *
4864 * @param pszDevice The PDM device name.
4865 * @param uInstance The PDM device instance.
4866 * @param uLun The PDM LUN number of the drive.
4867 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4868 * @param pCfg Configuration node for the device
4869 * @param pLunL0 To store the pointer to the LUN#0.
4870 * @param pInst The instance CFGM node
4871 * @param fAttachDetach To determine if the network attachment should
4872 * be attached/detached after/before
4873 * configuration.
4874 * @param fIgnoreConnectFailure
4875 * True if connection failures should be ignored
4876 * (makes only sense for bridged/host-only networks).
4877 *
4878 * @note Locks this object for writing.
4879 * @thread EMT
4880 */
4881int Console::i_configNetwork(const char *pszDevice,
4882 unsigned uInstance,
4883 unsigned uLun,
4884 INetworkAdapter *aNetworkAdapter,
4885 PCFGMNODE pCfg,
4886 PCFGMNODE pLunL0,
4887 PCFGMNODE pInst,
4888 bool fAttachDetach,
4889 bool fIgnoreConnectFailure)
4890{
4891 RT_NOREF(fIgnoreConnectFailure);
4892 AutoCaller autoCaller(this);
4893 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4894
4895 // InsertConfig* throws
4896 try
4897 {
4898 int rc = VINF_SUCCESS;
4899 HRESULT hrc;
4900 Bstr bstr;
4901
4902#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4903
4904 /*
4905 * Locking the object before doing VMR3* calls is quite safe here, since
4906 * we're on EMT. Write lock is necessary because we indirectly modify the
4907 * meAttachmentType member.
4908 */
4909 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4910
4911 ComPtr<IMachine> pMachine = i_machine();
4912
4913 ComPtr<IVirtualBox> virtualBox;
4914 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4915
4916 ComPtr<IHost> host;
4917 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4918
4919 BOOL fSniffer;
4920 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4921
4922 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4923 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4924 const char *pszPromiscuousGuestPolicy;
4925 switch (enmPromiscModePolicy)
4926 {
4927 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4928 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4929 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4930 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4931 }
4932
4933 if (fAttachDetach)
4934 {
4935 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4936 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4937 rc = VINF_SUCCESS;
4938 AssertLogRelRCReturn(rc, rc);
4939
4940 /* nuke anything which might have been left behind. */
4941 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4942 }
4943
4944#ifdef VBOX_WITH_NETSHAPER
4945 ComObjPtr<IBandwidthGroup> pBwGroup;
4946 Bstr strBwGroup;
4947 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4948
4949 if (!pBwGroup.isNull())
4950 {
4951 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4952 }
4953#endif /* VBOX_WITH_NETSHAPER */
4954
4955 Utf8Str strNetDriver;
4956
4957
4958 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4959
4960#ifdef VBOX_WITH_NETSHAPER
4961 if (!strBwGroup.isEmpty())
4962 {
4963 InsertConfigString(pLunL0, "Driver", "NetShaper");
4964 InsertConfigNode(pLunL0, "Config", &pCfg);
4965 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4966 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4967 }
4968#endif /* VBOX_WITH_NETSHAPER */
4969
4970 if (fSniffer)
4971 {
4972 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4973 InsertConfigNode(pLunL0, "Config", &pCfg);
4974 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4975 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4976 InsertConfigString(pCfg, "File", bstr);
4977 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4978 }
4979
4980
4981 Bstr networkName, trunkName, trunkType;
4982 NetworkAttachmentType_T eAttachmentType;
4983 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4984 switch (eAttachmentType)
4985 {
4986 case NetworkAttachmentType_Null:
4987 break;
4988
4989 case NetworkAttachmentType_NAT:
4990 {
4991 ComPtr<INATEngine> natEngine;
4992 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4993 InsertConfigString(pLunL0, "Driver", "NAT");
4994 InsertConfigNode(pLunL0, "Config", &pCfg);
4995
4996 /* Configure TFTP prefix and boot filename. */
4997 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4998 if (!bstr.isEmpty())
4999 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5000 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5001 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5002
5003 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5004 if (!bstr.isEmpty())
5005 InsertConfigString(pCfg, "Network", bstr);
5006 else
5007 {
5008 ULONG uSlot;
5009 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5010 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5011 }
5012 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5013 if (!bstr.isEmpty())
5014 InsertConfigString(pCfg, "BindIP", bstr);
5015 ULONG mtu = 0;
5016 ULONG sockSnd = 0;
5017 ULONG sockRcv = 0;
5018 ULONG tcpSnd = 0;
5019 ULONG tcpRcv = 0;
5020 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5021 if (mtu)
5022 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5023 if (sockRcv)
5024 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5025 if (sockSnd)
5026 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5027 if (tcpRcv)
5028 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5029 if (tcpSnd)
5030 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5031 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5032 if (!bstr.isEmpty())
5033 {
5034 RemoveConfigValue(pCfg, "TFTPPrefix");
5035 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5036 }
5037 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5038 if (!bstr.isEmpty())
5039 {
5040 RemoveConfigValue(pCfg, "BootFile");
5041 InsertConfigString(pCfg, "BootFile", bstr);
5042 }
5043 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5044 if (!bstr.isEmpty())
5045 InsertConfigString(pCfg, "NextServer", bstr);
5046 BOOL fDNSFlag;
5047 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5048 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5049 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5050 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5051 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5052 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5053
5054 ULONG aliasMode;
5055 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5056 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5057
5058 /* port-forwarding */
5059 SafeArray<BSTR> pfs;
5060 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5061
5062 PCFGMNODE pPFTree = NULL;
5063 if (pfs.size() > 0)
5064 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5065
5066 for (unsigned int i = 0; i < pfs.size(); ++i)
5067 {
5068 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5069
5070 uint16_t port = 0;
5071 BSTR r = pfs[i];
5072 Utf8Str utf = Utf8Str(r);
5073 Utf8Str strName;
5074 Utf8Str strProto;
5075 Utf8Str strHostPort;
5076 Utf8Str strHostIP;
5077 Utf8Str strGuestPort;
5078 Utf8Str strGuestIP;
5079 size_t pos, ppos;
5080 pos = ppos = 0;
5081#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5082 { \
5083 pos = str.find(",", ppos); \
5084 if (pos == Utf8Str::npos) \
5085 { \
5086 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5087 continue; \
5088 } \
5089 res = str.substr(ppos, pos - ppos); \
5090 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5091 ppos = pos + 1; \
5092 } /* no do { ... } while because of 'continue' */
5093 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5094 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5095 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5096 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5097 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5098 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5099#undef ITERATE_TO_NEXT_TERM
5100
5101 uint32_t proto = strProto.toUInt32();
5102 bool fValid = true;
5103 switch (proto)
5104 {
5105 case NATProtocol_UDP:
5106 strProto = "UDP";
5107 break;
5108 case NATProtocol_TCP:
5109 strProto = "TCP";
5110 break;
5111 default:
5112 fValid = false;
5113 }
5114 /* continue with next rule if no valid proto was passed */
5115 if (!fValid)
5116 continue;
5117
5118 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5119
5120 if (!strName.isEmpty())
5121 InsertConfigString(pPF, "Name", strName);
5122
5123 InsertConfigString(pPF, "Protocol", strProto);
5124
5125 if (!strHostIP.isEmpty())
5126 InsertConfigString(pPF, "BindIP", strHostIP);
5127
5128 if (!strGuestIP.isEmpty())
5129 InsertConfigString(pPF, "GuestIP", strGuestIP);
5130
5131 port = RTStrToUInt16(strHostPort.c_str());
5132 if (port)
5133 InsertConfigInteger(pPF, "HostPort", port);
5134
5135 port = RTStrToUInt16(strGuestPort.c_str());
5136 if (port)
5137 InsertConfigInteger(pPF, "GuestPort", port);
5138 }
5139 break;
5140 }
5141
5142 case NetworkAttachmentType_Bridged:
5143 {
5144#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5145 hrc = i_attachToTapInterface(aNetworkAdapter);
5146 if (FAILED(hrc))
5147 {
5148 switch (hrc)
5149 {
5150 case VERR_ACCESS_DENIED:
5151 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5152 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5153 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5154 "change the group of that node and make yourself a member of that group. Make "
5155 "sure that these changes are permanent, especially if you are "
5156 "using udev"));
5157 default:
5158 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5159 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5160 "Failed to initialize Host Interface Networking"));
5161 }
5162 }
5163
5164 Assert((intptr_t)maTapFD[uInstance] >= 0);
5165 if ((intptr_t)maTapFD[uInstance] >= 0)
5166 {
5167 InsertConfigString(pLunL0, "Driver", "HostInterface");
5168 InsertConfigNode(pLunL0, "Config", &pCfg);
5169 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5170 }
5171
5172#elif defined(VBOX_WITH_NETFLT)
5173 /*
5174 * This is the new VBoxNetFlt+IntNet stuff.
5175 */
5176 Bstr BridgedIfName;
5177 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5178 if (FAILED(hrc))
5179 {
5180 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5181 H();
5182 }
5183
5184 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5185 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5186
5187# if defined(RT_OS_DARWIN)
5188 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5189 char szTrunk[8];
5190 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5191 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5192// Quick fix for @bugref{5633}
5193// if (!pszColon)
5194// {
5195// /*
5196// * Dynamic changing of attachment causes an attempt to configure
5197// * network with invalid host adapter (as it is must be changed before
5198// * the attachment), calling Detach here will cause a deadlock.
5199// * See @bugref{4750}.
5200// * hrc = aNetworkAdapter->Detach(); H();
5201// */
5202// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5203// N_("Malformed host interface networking name '%ls'"),
5204// BridgedIfName.raw());
5205// }
5206 if (pszColon)
5207 *pszColon = '\0';
5208 const char *pszTrunk = szTrunk;
5209
5210# elif defined(RT_OS_SOLARIS)
5211 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5212 char szTrunk[256];
5213 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5214 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5215
5216 /*
5217 * Currently don't bother about malformed names here for the sake of people using
5218 * VBoxManage and setting only the NIC name from there. If there is a space we
5219 * chop it off and proceed, otherwise just use whatever we've got.
5220 */
5221 if (pszSpace)
5222 *pszSpace = '\0';
5223
5224 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5225 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5226 if (pszColon)
5227 *pszColon = '\0';
5228
5229 const char *pszTrunk = szTrunk;
5230
5231# elif defined(RT_OS_WINDOWS)
5232 ComPtr<IHostNetworkInterface> hostInterface;
5233 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5234 hostInterface.asOutParam());
5235 if (!SUCCEEDED(hrc))
5236 {
5237 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5238 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5239 N_("Nonexistent host networking interface, name '%ls'"),
5240 BridgedIfName.raw());
5241 }
5242
5243 HostNetworkInterfaceType_T eIfType;
5244 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5245 if (FAILED(hrc))
5246 {
5247 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5248 H();
5249 }
5250
5251 if (eIfType != HostNetworkInterfaceType_Bridged)
5252 {
5253 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5254 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5255 BridgedIfName.raw());
5256 }
5257
5258 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5259 if (FAILED(hrc))
5260 {
5261 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5262 H();
5263 }
5264 Guid hostIFGuid(bstr);
5265
5266 INetCfg *pNc;
5267 ComPtr<INetCfgComponent> pAdaptorComponent;
5268 LPWSTR pszApp;
5269
5270 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5271 Assert(hrc == S_OK);
5272 if (hrc != S_OK)
5273 {
5274 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5275 H();
5276 }
5277
5278 /* get the adapter's INetCfgComponent*/
5279 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5280 pAdaptorComponent.asOutParam());
5281 if (hrc != S_OK)
5282 {
5283 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5284 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5285 H();
5286 }
5287# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5288 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5289 char *pszTrunkName = szTrunkName;
5290 wchar_t * pswzBindName;
5291 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5292 Assert(hrc == S_OK);
5293 if (hrc == S_OK)
5294 {
5295 int cwBindName = (int)wcslen(pswzBindName) + 1;
5296 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5297 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5298 {
5299 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5300 pszTrunkName += cbFullBindNamePrefix-1;
5301 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5302 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5303 {
5304 DWORD err = GetLastError();
5305 hrc = HRESULT_FROM_WIN32(err);
5306 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5307 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5308 hrc, hrc, err));
5309 }
5310 }
5311 else
5312 {
5313 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5314 /** @todo set appropriate error code */
5315 hrc = E_FAIL;
5316 }
5317
5318 if (hrc != S_OK)
5319 {
5320 AssertFailed();
5321 CoTaskMemFree(pswzBindName);
5322 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5323 H();
5324 }
5325
5326 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5327 }
5328 else
5329 {
5330 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5331 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5332 hrc));
5333 H();
5334 }
5335
5336 const char *pszTrunk = szTrunkName;
5337 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5338
5339# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5340# if defined(RT_OS_FREEBSD)
5341 /*
5342 * If we bridge to a tap interface open it the `old' direct way.
5343 * This works and performs better than bridging a physical
5344 * interface via the current FreeBSD vboxnetflt implementation.
5345 */
5346 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5347 hrc = i_attachToTapInterface(aNetworkAdapter);
5348 if (FAILED(hrc))
5349 {
5350 switch (hrc)
5351 {
5352 case VERR_ACCESS_DENIED:
5353 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5354 "Failed to open '/dev/%s' for read/write access. Please check the "
5355 "permissions of that node, and that the net.link.tap.user_open "
5356 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5357 "change the group of that node to vboxusers and make yourself "
5358 "a member of that group. Make sure that these changes are permanent."),
5359 pszBridgedIfName, pszBridgedIfName);
5360 default:
5361 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5362 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5363 "Failed to initialize Host Interface Networking"));
5364 }
5365 }
5366
5367 Assert((intptr_t)maTapFD[uInstance] >= 0);
5368 if ((intptr_t)maTapFD[uInstance] >= 0)
5369 {
5370 InsertConfigString(pLunL0, "Driver", "HostInterface");
5371 InsertConfigNode(pLunL0, "Config", &pCfg);
5372 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5373 }
5374 break;
5375 }
5376# endif
5377 /** @todo Check for malformed names. */
5378 const char *pszTrunk = pszBridgedIfName;
5379
5380 /* Issue a warning if the interface is down */
5381 {
5382 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5383 if (iSock >= 0)
5384 {
5385 struct ifreq Req;
5386 RT_ZERO(Req);
5387 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5388 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5389 if ((Req.ifr_flags & IFF_UP) == 0)
5390 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5391 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5392 pszBridgedIfName);
5393
5394 close(iSock);
5395 }
5396 }
5397
5398# else
5399# error "PORTME (VBOX_WITH_NETFLT)"
5400# endif
5401
5402 InsertConfigString(pLunL0, "Driver", "IntNet");
5403 InsertConfigNode(pLunL0, "Config", &pCfg);
5404 InsertConfigString(pCfg, "Trunk", pszTrunk);
5405 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5406 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5407 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5408 char szNetwork[INTNET_MAX_NETWORK_NAME];
5409
5410# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5411 /*
5412 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5413 * interface name + optional description. We must not pass any description to the VM as it can differ
5414 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5415 */
5416 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5417# else
5418 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5419# endif
5420 InsertConfigString(pCfg, "Network", szNetwork);
5421 networkName = Bstr(szNetwork);
5422 trunkName = Bstr(pszTrunk);
5423 trunkType = Bstr(TRUNKTYPE_NETFLT);
5424
5425# if defined(RT_OS_DARWIN)
5426 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
5427 if ( strstr(pszBridgedIfName, "Wireless")
5428 || strstr(pszBridgedIfName, "AirPort" ))
5429 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5430# elif defined(RT_OS_LINUX)
5431 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5432 if (iSock >= 0)
5433 {
5434 struct iwreq WRq;
5435
5436 RT_ZERO(WRq);
5437 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
5438 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
5439 close(iSock);
5440 if (fSharedMacOnWire)
5441 {
5442 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5443 Log(("Set SharedMacOnWire\n"));
5444 }
5445 else
5446 Log(("Failed to get wireless name\n"));
5447 }
5448 else
5449 Log(("Failed to open wireless socket\n"));
5450# elif defined(RT_OS_FREEBSD)
5451 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5452 if (iSock >= 0)
5453 {
5454 struct ieee80211req WReq;
5455 uint8_t abData[32];
5456
5457 RT_ZERO(WReq);
5458 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
5459 WReq.i_type = IEEE80211_IOC_SSID;
5460 WReq.i_val = -1;
5461 WReq.i_data = abData;
5462 WReq.i_len = sizeof(abData);
5463
5464 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
5465 close(iSock);
5466 if (fSharedMacOnWire)
5467 {
5468 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5469 Log(("Set SharedMacOnWire\n"));
5470 }
5471 else
5472 Log(("Failed to get wireless name\n"));
5473 }
5474 else
5475 Log(("Failed to open wireless socket\n"));
5476# elif defined(RT_OS_WINDOWS)
5477# define DEVNAME_PREFIX L"\\\\.\\"
5478 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
5479 * there is a pretty long way till there though since we need to obtain the symbolic link name
5480 * for the adapter device we are going to query given the device Guid */
5481
5482
5483 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
5484
5485 wchar_t FileName[MAX_PATH];
5486 wcscpy(FileName, DEVNAME_PREFIX);
5487 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
5488
5489 /* open the device */
5490 HANDLE hDevice = CreateFile(FileName,
5491 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5492 NULL,
5493 OPEN_EXISTING,
5494 FILE_ATTRIBUTE_NORMAL,
5495 NULL);
5496
5497 if (hDevice != INVALID_HANDLE_VALUE)
5498 {
5499 bool fSharedMacOnWire = false;
5500
5501 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
5502 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
5503 NDIS_PHYSICAL_MEDIUM PhMedium;
5504 DWORD cbResult;
5505 if (DeviceIoControl(hDevice,
5506 IOCTL_NDIS_QUERY_GLOBAL_STATS,
5507 &Oid,
5508 sizeof(Oid),
5509 &PhMedium,
5510 sizeof(PhMedium),
5511 &cbResult,
5512 NULL))
5513 {
5514 /* that was simple, now examine PhMedium */
5515 if ( PhMedium == NdisPhysicalMediumWirelessWan
5516 || PhMedium == NdisPhysicalMediumWirelessLan
5517 || PhMedium == NdisPhysicalMediumNative802_11
5518 || PhMedium == NdisPhysicalMediumBluetooth)
5519 fSharedMacOnWire = true;
5520 }
5521 else
5522 {
5523 int winEr = GetLastError();
5524 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
5525 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
5526 }
5527 CloseHandle(hDevice);
5528
5529 if (fSharedMacOnWire)
5530 {
5531 Log(("this is a wireless adapter"));
5532 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5533 Log(("Set SharedMacOnWire\n"));
5534 }
5535 else
5536 Log(("this is NOT a wireless adapter"));
5537 }
5538 else
5539 {
5540 int winEr = GetLastError();
5541 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
5542 }
5543
5544 CoTaskMemFree(pswzBindName);
5545
5546 pAdaptorComponent.setNull();
5547 /* release the pNc finally */
5548 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5549# else
5550 /** @todo PORTME: wireless detection */
5551# endif
5552
5553# if defined(RT_OS_SOLARIS)
5554# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5555 /* Zone access restriction, don't allow snooping the global zone. */
5556 zoneid_t ZoneId = getzoneid();
5557 if (ZoneId != GLOBAL_ZONEID)
5558 {
5559 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5560 }
5561# endif
5562# endif
5563
5564#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5565 /* NOTHING TO DO HERE */
5566#elif defined(RT_OS_LINUX)
5567/// @todo aleksey: is there anything to be done here?
5568#elif defined(RT_OS_FREEBSD)
5569/** @todo FreeBSD: Check out this later (HIF networking). */
5570#else
5571# error "Port me"
5572#endif
5573 break;
5574 }
5575
5576 case NetworkAttachmentType_Internal:
5577 {
5578 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5579 if (!bstr.isEmpty())
5580 {
5581 InsertConfigString(pLunL0, "Driver", "IntNet");
5582 InsertConfigNode(pLunL0, "Config", &pCfg);
5583 InsertConfigString(pCfg, "Network", bstr);
5584 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5585 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5586 networkName = bstr;
5587 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5588 }
5589 break;
5590 }
5591
5592 case NetworkAttachmentType_HostOnly:
5593 {
5594 InsertConfigString(pLunL0, "Driver", "IntNet");
5595 InsertConfigNode(pLunL0, "Config", &pCfg);
5596
5597 Bstr HostOnlyName;
5598 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5599 if (FAILED(hrc))
5600 {
5601 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5602 H();
5603 }
5604
5605 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5606 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5607 ComPtr<IHostNetworkInterface> hostInterface;
5608 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5609 hostInterface.asOutParam());
5610 if (!SUCCEEDED(rc))
5611 {
5612 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5613 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5614 N_("Nonexistent host networking interface, name '%ls'"),
5615 HostOnlyName.raw());
5616 }
5617
5618 char szNetwork[INTNET_MAX_NETWORK_NAME];
5619 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5620
5621#if defined(RT_OS_WINDOWS)
5622# ifndef VBOX_WITH_NETFLT
5623 hrc = E_NOTIMPL;
5624 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5625 H();
5626# else /* defined VBOX_WITH_NETFLT*/
5627 /** @todo r=bird: Put this in a function. */
5628
5629 HostNetworkInterfaceType_T eIfType;
5630 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5631 if (FAILED(hrc))
5632 {
5633 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5634 H();
5635 }
5636
5637 if (eIfType != HostNetworkInterfaceType_HostOnly)
5638 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5639 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5640 HostOnlyName.raw());
5641
5642 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5643 if (FAILED(hrc))
5644 {
5645 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5646 H();
5647 }
5648 Guid hostIFGuid(bstr);
5649
5650 INetCfg *pNc;
5651 ComPtr<INetCfgComponent> pAdaptorComponent;
5652 LPWSTR pszApp;
5653 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5654 Assert(hrc == S_OK);
5655 if (hrc != S_OK)
5656 {
5657 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5658 H();
5659 }
5660
5661 /* get the adapter's INetCfgComponent*/
5662 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5663 pAdaptorComponent.asOutParam());
5664 if (hrc != S_OK)
5665 {
5666 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5667 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5668 H();
5669 }
5670# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5671 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5672 bool fNdis6 = false;
5673 wchar_t * pwszHelpText;
5674 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5675 Assert(hrc == S_OK);
5676 if (hrc == S_OK)
5677 {
5678 Log(("help-text=%ls\n", pwszHelpText));
5679 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5680 fNdis6 = true;
5681 CoTaskMemFree(pwszHelpText);
5682 }
5683 if (fNdis6)
5684 {
5685 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5686 Log(("trunk=%s\n", szTrunkName));
5687 }
5688 else
5689 {
5690 char *pszTrunkName = szTrunkName;
5691 wchar_t * pswzBindName;
5692 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5693 Assert(hrc == S_OK);
5694 if (hrc == S_OK)
5695 {
5696 int cwBindName = (int)wcslen(pswzBindName) + 1;
5697 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5698 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5699 {
5700 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5701 pszTrunkName += cbFullBindNamePrefix-1;
5702 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5703 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5704 {
5705 DWORD err = GetLastError();
5706 hrc = HRESULT_FROM_WIN32(err);
5707 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5708 hrc, hrc, err));
5709 }
5710 }
5711 else
5712 {
5713 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5714 /** @todo set appropriate error code */
5715 hrc = E_FAIL;
5716 }
5717
5718 if (hrc != S_OK)
5719 {
5720 AssertFailed();
5721 CoTaskMemFree(pswzBindName);
5722 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5723 H();
5724 }
5725 }
5726 else
5727 {
5728 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5729 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5730 hrc, hrc));
5731 H();
5732 }
5733
5734
5735 CoTaskMemFree(pswzBindName);
5736 }
5737
5738 trunkType = TRUNKTYPE_NETADP;
5739 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5740
5741 pAdaptorComponent.setNull();
5742 /* release the pNc finally */
5743 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5744
5745 const char *pszTrunk = szTrunkName;
5746
5747 InsertConfigString(pCfg, "Trunk", pszTrunk);
5748 InsertConfigString(pCfg, "Network", szNetwork);
5749 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5750 windows only?? */
5751 networkName = Bstr(szNetwork);
5752 trunkName = Bstr(pszTrunk);
5753# endif /* defined VBOX_WITH_NETFLT*/
5754#elif defined(RT_OS_DARWIN)
5755 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5756 InsertConfigString(pCfg, "Network", szNetwork);
5757 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5758 networkName = Bstr(szNetwork);
5759 trunkName = Bstr(pszHostOnlyName);
5760 trunkType = TRUNKTYPE_NETADP;
5761#else
5762 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5763 InsertConfigString(pCfg, "Network", szNetwork);
5764 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5765 networkName = Bstr(szNetwork);
5766 trunkName = Bstr(pszHostOnlyName);
5767 trunkType = TRUNKTYPE_NETFLT;
5768#endif
5769 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5770
5771#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5772
5773 Bstr tmpAddr, tmpMask;
5774
5775 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5776 pszHostOnlyName).raw(),
5777 tmpAddr.asOutParam());
5778 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5779 {
5780 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5781 pszHostOnlyName).raw(),
5782 tmpMask.asOutParam());
5783 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5784 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5785 tmpMask.raw());
5786 else
5787 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5788 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5789 }
5790 else
5791 {
5792 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5793 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5794 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5795 }
5796
5797 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5798
5799 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5800 pszHostOnlyName).raw(),
5801 tmpAddr.asOutParam());
5802 if (SUCCEEDED(hrc))
5803 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5804 tmpMask.asOutParam());
5805 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5806 {
5807 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5808 Utf8Str(tmpMask).toUInt32());
5809 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5810 }
5811#endif
5812 break;
5813 }
5814
5815 case NetworkAttachmentType_Generic:
5816 {
5817 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5818 SafeArray<BSTR> names;
5819 SafeArray<BSTR> values;
5820 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5821 ComSafeArrayAsOutParam(names),
5822 ComSafeArrayAsOutParam(values)); H();
5823
5824 InsertConfigString(pLunL0, "Driver", bstr);
5825 InsertConfigNode(pLunL0, "Config", &pCfg);
5826 for (size_t ii = 0; ii < names.size(); ++ii)
5827 {
5828 if (values[ii] && *values[ii])
5829 {
5830 Utf8Str name = names[ii];
5831 Utf8Str value = values[ii];
5832 InsertConfigString(pCfg, name.c_str(), value);
5833 }
5834 }
5835 break;
5836 }
5837
5838 case NetworkAttachmentType_NATNetwork:
5839 {
5840 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5841 if (!bstr.isEmpty())
5842 {
5843 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5844 InsertConfigString(pLunL0, "Driver", "IntNet");
5845 InsertConfigNode(pLunL0, "Config", &pCfg);
5846 InsertConfigString(pCfg, "Network", bstr);
5847 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5848 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5849 networkName = bstr;
5850 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5851 }
5852 break;
5853 }
5854
5855 default:
5856 AssertMsgFailed(("should not get here!\n"));
5857 break;
5858 }
5859
5860 /*
5861 * Attempt to attach the driver.
5862 */
5863 switch (eAttachmentType)
5864 {
5865 case NetworkAttachmentType_Null:
5866 break;
5867
5868 case NetworkAttachmentType_Bridged:
5869 case NetworkAttachmentType_Internal:
5870 case NetworkAttachmentType_HostOnly:
5871 case NetworkAttachmentType_NAT:
5872 case NetworkAttachmentType_Generic:
5873 case NetworkAttachmentType_NATNetwork:
5874 {
5875 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5876 {
5877 if (fAttachDetach)
5878 {
5879 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5880 //AssertRC(rc);
5881 }
5882
5883 {
5884 /** @todo pritesh: get the dhcp server name from the
5885 * previous network configuration and then stop the server
5886 * else it may conflict with the dhcp server running with
5887 * the current attachment type
5888 */
5889 /* Stop the hostonly DHCP Server */
5890 }
5891
5892 /*
5893 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5894 */
5895 if ( !networkName.isEmpty()
5896 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5897 {
5898 /*
5899 * Until we implement service reference counters DHCP Server will be stopped
5900 * by DHCPServerRunner destructor.
5901 */
5902 ComPtr<IDHCPServer> dhcpServer;
5903 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5904 dhcpServer.asOutParam());
5905 if (SUCCEEDED(hrc))
5906 {
5907 /* there is a DHCP server available for this network */
5908 BOOL fEnabledDhcp;
5909 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5910 if (FAILED(hrc))
5911 {
5912 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5913 H();
5914 }
5915
5916 if (fEnabledDhcp)
5917 hrc = dhcpServer->Start(networkName.raw(),
5918 trunkName.raw(),
5919 trunkType.raw());
5920 }
5921 else
5922 hrc = S_OK;
5923 }
5924 }
5925
5926 break;
5927 }
5928
5929 default:
5930 AssertMsgFailed(("should not get here!\n"));
5931 break;
5932 }
5933
5934 meAttachmentType[uInstance] = eAttachmentType;
5935 }
5936 catch (ConfigError &x)
5937 {
5938 // InsertConfig threw something:
5939 return x.m_vrc;
5940 }
5941
5942#undef H
5943
5944 return VINF_SUCCESS;
5945}
5946
5947#ifdef VBOX_WITH_GUEST_PROPS
5948/**
5949 * Set an array of guest properties
5950 */
5951static void configSetProperties(VMMDev * const pVMMDev,
5952 void *names,
5953 void *values,
5954 void *timestamps,
5955 void *flags)
5956{
5957 VBOXHGCMSVCPARM parms[4];
5958
5959 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5960 parms[0].u.pointer.addr = names;
5961 parms[0].u.pointer.size = 0; /* We don't actually care. */
5962 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5963 parms[1].u.pointer.addr = values;
5964 parms[1].u.pointer.size = 0; /* We don't actually care. */
5965 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5966 parms[2].u.pointer.addr = timestamps;
5967 parms[2].u.pointer.size = 0; /* We don't actually care. */
5968 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5969 parms[3].u.pointer.addr = flags;
5970 parms[3].u.pointer.size = 0; /* We don't actually care. */
5971
5972 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5973 guestProp::SET_PROPS_HOST,
5974 4,
5975 &parms[0]);
5976}
5977
5978/**
5979 * Set a single guest property
5980 */
5981static void configSetProperty(VMMDev * const pVMMDev,
5982 const char *pszName,
5983 const char *pszValue,
5984 const char *pszFlags)
5985{
5986 VBOXHGCMSVCPARM parms[4];
5987
5988 AssertPtrReturnVoid(pszName);
5989 AssertPtrReturnVoid(pszValue);
5990 AssertPtrReturnVoid(pszFlags);
5991 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5992 parms[0].u.pointer.addr = (void *)pszName;
5993 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5994 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5995 parms[1].u.pointer.addr = (void *)pszValue;
5996 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5997 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5998 parms[2].u.pointer.addr = (void *)pszFlags;
5999 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
6000 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
6001 &parms[0]);
6002}
6003
6004/**
6005 * Set the global flags value by calling the service
6006 * @returns the status returned by the call to the service
6007 *
6008 * @param pTable the service instance handle
6009 * @param eFlags the flags to set
6010 */
6011int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
6012 guestProp::ePropFlags eFlags)
6013{
6014 VBOXHGCMSVCPARM paParm;
6015 paParm.setUInt32(eFlags);
6016 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
6017 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
6018 &paParm);
6019 if (RT_FAILURE(rc))
6020 {
6021 char szFlags[guestProp::MAX_FLAGS_LEN];
6022 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
6023 Log(("Failed to set the global flags.\n"));
6024 else
6025 Log(("Failed to set the global flags \"%s\".\n", szFlags));
6026 }
6027 return rc;
6028}
6029#endif /* VBOX_WITH_GUEST_PROPS */
6030
6031/**
6032 * Set up the Guest Property service, populate it with properties read from
6033 * the machine XML and set a couple of initial properties.
6034 */
6035/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
6036{
6037#ifdef VBOX_WITH_GUEST_PROPS
6038 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6039 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6040 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
6041
6042 /* Load the service */
6043 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
6044
6045 if (RT_FAILURE(rc))
6046 {
6047 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
6048 /* That is not a fatal failure. */
6049 rc = VINF_SUCCESS;
6050 }
6051 else
6052 {
6053 /*
6054 * Initialize built-in properties that can be changed and saved.
6055 *
6056 * These are typically transient properties that the guest cannot
6057 * change.
6058 */
6059
6060 {
6061 VBOXHGCMSVCPARM Params[2];
6062 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
6063 if (RT_SUCCESS(rc2))
6064 {
6065 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
6066 void *pService = (void*)Params[1].u.pointer.addr;
6067 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
6068 }
6069 }
6070
6071 /* Sysprep execution by VBoxService. */
6072 configSetProperty(pConsole->m_pVMMDev,
6073 "/VirtualBox/HostGuest/SysprepExec", "",
6074 "TRANSIENT, RDONLYGUEST");
6075 configSetProperty(pConsole->m_pVMMDev,
6076 "/VirtualBox/HostGuest/SysprepArgs", "",
6077 "TRANSIENT, RDONLYGUEST");
6078
6079 /*
6080 * Pull over the properties from the server.
6081 */
6082 SafeArray<BSTR> namesOut;
6083 SafeArray<BSTR> valuesOut;
6084 SafeArray<LONG64> timestampsOut;
6085 SafeArray<BSTR> flagsOut;
6086 HRESULT hrc;
6087 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
6088 ComSafeArrayAsOutParam(valuesOut),
6089 ComSafeArrayAsOutParam(timestampsOut),
6090 ComSafeArrayAsOutParam(flagsOut));
6091 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6092 size_t cProps = namesOut.size();
6093 size_t cAlloc = cProps + 1;
6094 if ( valuesOut.size() != cProps
6095 || timestampsOut.size() != cProps
6096 || flagsOut.size() != cProps
6097 )
6098 AssertFailedReturn(VERR_INVALID_PARAMETER);
6099
6100 char **papszNames, **papszValues, **papszFlags;
6101 char szEmpty[] = "";
6102 LONG64 *pai64Timestamps;
6103 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6104 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6105 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
6106 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6107 if (papszNames && papszValues && pai64Timestamps && papszFlags)
6108 {
6109 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
6110 {
6111 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
6112 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
6113 if (RT_FAILURE(rc))
6114 break;
6115 if (valuesOut[i])
6116 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6117 else
6118 papszValues[i] = szEmpty;
6119 if (RT_FAILURE(rc))
6120 break;
6121 pai64Timestamps[i] = timestampsOut[i];
6122 if (flagsOut[i])
6123 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6124 else
6125 papszFlags[i] = szEmpty;
6126 }
6127 if (RT_SUCCESS(rc))
6128 configSetProperties(pConsole->m_pVMMDev,
6129 (void *)papszNames,
6130 (void *)papszValues,
6131 (void *)pai64Timestamps,
6132 (void *)papszFlags);
6133 for (unsigned i = 0; i < cProps; ++i)
6134 {
6135 RTStrFree(papszNames[i]);
6136 if (valuesOut[i])
6137 RTStrFree(papszValues[i]);
6138 if (flagsOut[i])
6139 RTStrFree(papszFlags[i]);
6140 }
6141 }
6142 else
6143 rc = VERR_NO_MEMORY;
6144 RTMemTmpFree(papszNames);
6145 RTMemTmpFree(papszValues);
6146 RTMemTmpFree(pai64Timestamps);
6147 RTMemTmpFree(papszFlags);
6148 AssertRCReturn(rc, rc);
6149
6150 /*
6151 * These properties have to be set before pulling over the properties
6152 * from the machine XML, to ensure that properties saved in the XML
6153 * will override them.
6154 */
6155 /* Set the raw VBox version string as a guest property. Used for host/guest
6156 * version comparison. */
6157 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6158 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6159 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6160 * information/branding and/or pre-release tags. */
6161 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6162 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6163 /* Set the VBox SVN revision as a guest property */
6164 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6165 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6166
6167 /*
6168 * Register the host notification callback
6169 */
6170 HGCMSVCEXTHANDLE hDummy;
6171 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6172 Console::i_doGuestPropNotification,
6173 pvConsole);
6174
6175#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6176 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
6177 guestProp::RDONLYGUEST);
6178 AssertRCReturn(rc, rc);
6179#endif
6180
6181 Log(("Set VBoxGuestPropSvc property store\n"));
6182 }
6183 return VINF_SUCCESS;
6184#else /* !VBOX_WITH_GUEST_PROPS */
6185 return VERR_NOT_SUPPORTED;
6186#endif /* !VBOX_WITH_GUEST_PROPS */
6187}
6188
6189/**
6190 * Set up the Guest Control service.
6191 */
6192/* static */ int Console::i_configGuestControl(void *pvConsole)
6193{
6194#ifdef VBOX_WITH_GUEST_CONTROL
6195 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6196 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6197
6198 /* Load the service */
6199 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6200
6201 if (RT_FAILURE(rc))
6202 {
6203 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6204 /* That is not a fatal failure. */
6205 rc = VINF_SUCCESS;
6206 }
6207 else
6208 {
6209 HGCMSVCEXTHANDLE hDummy;
6210 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6211 &Guest::i_notifyCtrlDispatcher,
6212 pConsole->i_getGuest());
6213 if (RT_FAILURE(rc))
6214 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6215 else
6216 LogRel(("Guest Control service loaded\n"));
6217 }
6218
6219 return rc;
6220#else /* !VBOX_WITH_GUEST_CONTROL */
6221 return VERR_NOT_SUPPORTED;
6222#endif /* !VBOX_WITH_GUEST_CONTROL */
6223}
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