VirtualBox

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

Last change on this file since 70021 was 70021, checked in by vboxsync, 7 years ago

Audio/Main: Use uint64_t for fDebugEnabled flag, as we're writing integers instead of booleans here.

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

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