VirtualBox

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

Last change on this file since 55436 was 55398, checked in by vboxsync, 10 years ago

Main: Fix hotplugging USB disks

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