VirtualBox

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

Last change on this file since 55384 was 55362, checked in by vboxsync, 10 years ago

DevSmc cleanup

  • 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 55362 2015-04-21 17:28:50Z 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 && !fAttachDetach)
3699 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
3700 else if (fAttachDetach)
3701 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
3702
3703 if (!fAttachDetach)
3704 InsertConfigNode(pCtlInst, "Config", &pCfg);
3705
3706 uInstance = lPort; /* Overwrite uInstance with the correct one. */
3707
3708 if (!fHotplug && !fAttachDetach)
3709 {
3710 char aszUuid[RTUUID_STR_LENGTH + 1];
3711 USBStorageDevice UsbMsd = USBStorageDevice();
3712
3713 memset(aszUuid, 0, sizeof(aszUuid));
3714 rc = RTUuidCreate(&UsbMsd.mUuid);
3715 AssertRCReturn(rc, rc);
3716 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
3717 AssertRCReturn(rc, rc);
3718
3719 UsbMsd.iPort = uInstance;
3720
3721 InsertConfigString(pCtlInst, "UUID", aszUuid);
3722 mUSBStorageDevices.push_back(UsbMsd);
3723
3724 /** @todo: No LED after hotplugging. */
3725 /* Attach the status driver */
3726 Assert(cLedUsb >= 8);
3727 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
3728 &mapMediumAttachments, pcszDevice, 0);
3729 paLedDevType = &maStorageDevType[iLedUsb];
3730 }
3731 }
3732
3733 /* First check if the LUN already exists. */
3734 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
3735 if (pLunL0)
3736 {
3737 if (fAttachDetach)
3738 {
3739 if (lType != DeviceType_HardDisk)
3740 {
3741 /* Unmount existing media only for floppy and DVD drives. */
3742 PPDMIBASE pBase;
3743 if (enmBus == StorageBus_USB)
3744 rc = PDMR3UsbQueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
3745 else
3746 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
3747 if (RT_FAILURE(rc))
3748 {
3749 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
3750 rc = VINF_SUCCESS;
3751 AssertRC(rc);
3752 }
3753 else
3754 {
3755 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
3756 AssertReturn(pIMount, VERR_INVALID_POINTER);
3757
3758 /* Unmount the media (but do not eject the medium!) */
3759 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
3760 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
3761 rc = VINF_SUCCESS;
3762 /* for example if the medium is locked */
3763 else if (RT_FAILURE(rc))
3764 return rc;
3765 }
3766 }
3767
3768 if (enmBus == StorageBus_USB)
3769 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN, NULL, 0,
3770 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
3771 else
3772 rc = PDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
3773 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
3774 rc = VINF_SUCCESS;
3775 AssertRCReturn(rc, rc);
3776
3777 CFGMR3RemoveNode(pLunL0);
3778 }
3779 else
3780 AssertFailedReturn(VERR_INTERNAL_ERROR);
3781 }
3782
3783 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
3784 if (ppLunL0)
3785 *ppLunL0 = pLunL0;
3786
3787 PCFGMNODE pCfg = CFGMR3GetChild(pCtlInst, "Config");
3788 if (pCfg)
3789 {
3790 if (!strcmp(pcszDevice, "piix3ide"))
3791 {
3792 PCFGMNODE pDrive = CFGMR3GetChild(pCfg, g_apszIDEDrives[uLUN]);
3793 if (!pDrive)
3794 InsertConfigNode(pCfg, g_apszIDEDrives[uLUN], &pDrive);
3795 /* Don't use the RemoveConfigValue wrapper above, as we don't
3796 * know if the leaf is present or not. */
3797 CFGMR3RemoveValue(pDrive, "NonRotationalMedium");
3798 InsertConfigInteger(pDrive, "NonRotationalMedium", !!fNonRotational);
3799 }
3800 else if (!strcmp(pcszDevice, "ahci"))
3801 {
3802 Utf8Str strPort = Utf8StrFmt("Port%u", uLUN);
3803 PCFGMNODE pDrive = CFGMR3GetChild(pCfg, strPort.c_str());
3804 if (!pDrive)
3805 InsertConfigNode(pCfg, strPort.c_str(), &pDrive);
3806 /* Don't use the RemoveConfigValue wrapper above, as we don't
3807 * know if the leaf is present or not. */
3808 CFGMR3RemoveValue(pDrive, "NonRotationalMedium");
3809 InsertConfigInteger(pDrive, "NonRotationalMedium", !!fNonRotational);
3810 }
3811 }
3812
3813 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
3814 mapMediumAttachments[devicePath] = pMediumAtt;
3815
3816 /* SCSI has a another driver between device and block. */
3817 if (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
3818 {
3819 InsertConfigString(pLunL0, "Driver", "SCSI");
3820 PCFGMNODE pL1Cfg = NULL;
3821 InsertConfigNode(pLunL0, "Config", &pL1Cfg);
3822 InsertConfigInteger(pL1Cfg, "NonRotationalMedium", !!fNonRotational);
3823
3824 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
3825 }
3826
3827 ComPtr<IMedium> pMedium;
3828 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
3829
3830 /*
3831 * 1. Only check this for hard disk images.
3832 * 2. Only check during VM creation and not later, especially not during
3833 * taking an online snapshot!
3834 */
3835 if ( lType == DeviceType_HardDisk
3836 && ( aMachineState == MachineState_Starting
3837 || aMachineState == MachineState_Restoring))
3838 {
3839 /*
3840 * Some sanity checks.
3841 */
3842 ComPtr<IMediumFormat> pMediumFormat;
3843 hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3844 ULONG uCaps = 0;
3845 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3846 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3847
3848 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3849 uCaps |= mediumFormatCap[j];
3850
3851 if (uCaps & MediumFormatCapabilities_File)
3852 {
3853 Bstr strFile;
3854 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3855 Utf8Str utfFile = Utf8Str(strFile);
3856 Bstr strSnap;
3857 ComPtr<IMachine> pMachine = i_machine();
3858 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3859 Utf8Str utfSnap = Utf8Str(strSnap);
3860 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3861 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3862 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3863 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3864 /* Ignore the error code. On error, the file system type is still 'unknown' so
3865 * none of the following paths are taken. This can happen for new VMs which
3866 * still don't have a snapshot folder. */
3867 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3868 if (!mfSnapshotFolderDiskTypeShown)
3869 {
3870 LogRel(("File system of '%s' (snapshots) is %s\n",
3871 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3872 mfSnapshotFolderDiskTypeShown = true;
3873 }
3874 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3875 LONG64 i64Size;
3876 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3877#ifdef RT_OS_WINDOWS
3878 if ( enmFsTypeFile == RTFSTYPE_FAT
3879 && i64Size >= _4G)
3880 {
3881 const char *pszUnit;
3882 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3883 i_setVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3884 N_("The medium '%ls' has a logical size of %RU64%s "
3885 "but the file system the medium is located on seems "
3886 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3887 "We strongly recommend to put all your virtual disk images and "
3888 "the snapshot folder onto an NTFS partition"),
3889 strFile.raw(), u64Print, pszUnit);
3890 }
3891#else /* !RT_OS_WINDOWS */
3892 if ( enmFsTypeFile == RTFSTYPE_FAT
3893 || enmFsTypeFile == RTFSTYPE_EXT
3894 || enmFsTypeFile == RTFSTYPE_EXT2
3895 || enmFsTypeFile == RTFSTYPE_EXT3
3896 || enmFsTypeFile == RTFSTYPE_EXT4)
3897 {
3898 RTFILE file;
3899 rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3900 if (RT_SUCCESS(rc))
3901 {
3902 RTFOFF maxSize;
3903 /* Careful: This function will work only on selected local file systems! */
3904 rc = RTFileGetMaxSizeEx(file, &maxSize);
3905 RTFileClose(file);
3906 if ( RT_SUCCESS(rc)
3907 && maxSize > 0
3908 && i64Size > (LONG64)maxSize)
3909 {
3910 const char *pszUnitSiz;
3911 const char *pszUnitMax;
3912 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3913 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3914 i_setVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3915 N_("The medium '%ls' has a logical size of %RU64%s "
3916 "but the file system the medium is located on can "
3917 "only handle files up to %RU64%s in theory.\n"
3918 "We strongly recommend to put all your virtual disk "
3919 "images and the snapshot folder onto a proper "
3920 "file system (e.g. ext3) with a sufficient size"),
3921 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3922 }
3923 }
3924 }
3925#endif /* !RT_OS_WINDOWS */
3926
3927 /*
3928 * Snapshot folder:
3929 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3930 */
3931 if ( enmFsTypeSnap == RTFSTYPE_FAT
3932 && i64Size >= _4G
3933 && !mfSnapshotFolderSizeWarningShown)
3934 {
3935 const char *pszUnit;
3936 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3937 i_setVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3938#ifdef RT_OS_WINDOWS
3939 N_("The snapshot folder of this VM '%ls' seems to be located on "
3940 "a FAT(32) file system. The logical size of the medium '%ls' "
3941 "(%RU64%s) is bigger than the maximum file size this file "
3942 "system can handle (4GB).\n"
3943 "We strongly recommend to put all your virtual disk images and "
3944 "the snapshot folder onto an NTFS partition"),
3945#else
3946 N_("The snapshot folder of this VM '%ls' seems to be located on "
3947 "a FAT(32) file system. The logical size of the medium '%ls' "
3948 "(%RU64%s) is bigger than the maximum file size this file "
3949 "system can handle (4GB).\n"
3950 "We strongly recommend to put all your virtual disk images and "
3951 "the snapshot folder onto a proper file system (e.g. ext3)"),
3952#endif
3953 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3954 /* Show this particular warning only once */
3955 mfSnapshotFolderSizeWarningShown = true;
3956 }
3957
3958#ifdef RT_OS_LINUX
3959 /*
3960 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3961 * on an ext4 partition. Later we have to check the Linux kernel version!
3962 * This bug apparently applies to the XFS file system as well.
3963 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3964 */
3965
3966 char szOsRelease[128];
3967 rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3968 bool fKernelHasODirectBug = RT_FAILURE(rc)
3969 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3970
3971 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3972 && !fUseHostIOCache
3973 && fKernelHasODirectBug)
3974 {
3975 if ( enmFsTypeFile == RTFSTYPE_EXT4
3976 || enmFsTypeFile == RTFSTYPE_XFS)
3977 {
3978 i_setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3979 N_("The host I/O cache for at least one controller is disabled "
3980 "and the medium '%ls' for this VM "
3981 "is located on an %s partition. There is a known Linux "
3982 "kernel bug which can lead to the corruption of the virtual "
3983 "disk image under these conditions.\n"
3984 "Either enable the host I/O cache permanently in the VM "
3985 "settings or put the disk image and the snapshot folder "
3986 "onto a different file system.\n"
3987 "The host I/O cache will now be enabled for this medium"),
3988 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3989 fUseHostIOCache = true;
3990 }
3991 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
3992 || enmFsTypeSnap == RTFSTYPE_XFS)
3993 && !mfSnapshotFolderExt4WarningShown)
3994 {
3995 i_setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3996 N_("The host I/O cache for at least one controller is disabled "
3997 "and the snapshot folder for this VM "
3998 "is located on an %s partition. There is a known Linux "
3999 "kernel bug which can lead to the corruption of the virtual "
4000 "disk image under these conditions.\n"
4001 "Either enable the host I/O cache permanently in the VM "
4002 "settings or put the disk image and the snapshot folder "
4003 "onto a different file system.\n"
4004 "The host I/O cache will now be enabled for this medium"),
4005 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4006 fUseHostIOCache = true;
4007 mfSnapshotFolderExt4WarningShown = true;
4008 }
4009 }
4010#endif
4011 }
4012 }
4013
4014 if (pMedium)
4015 {
4016 BOOL fHostDrive;
4017 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4018 if ( ( lType == DeviceType_DVD
4019 || lType == DeviceType_Floppy)
4020 && !fHostDrive)
4021 {
4022 /*
4023 * Informative logging.
4024 */
4025 Bstr strFile;
4026 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4027 Utf8Str utfFile = Utf8Str(strFile);
4028 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4029 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4030 LogRel(("File system of '%s' (%s) is %s\n",
4031 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4032 RTFsTypeName(enmFsTypeFile)));
4033 }
4034 }
4035
4036 BOOL fPassthrough;
4037 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4038
4039 ComObjPtr<IBandwidthGroup> pBwGroup;
4040 Bstr strBwGroup;
4041 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4042
4043 if (!pBwGroup.isNull())
4044 {
4045 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4046 }
4047
4048 rc = i_configMedium(pLunL0,
4049 !!fPassthrough,
4050 lType,
4051 fUseHostIOCache,
4052 fBuiltinIOCache,
4053 fSetupMerge,
4054 uMergeSource,
4055 uMergeTarget,
4056 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4057 !!fDiscard,
4058 pMedium,
4059 aMachineState,
4060 phrc);
4061 if (RT_FAILURE(rc))
4062 return rc;
4063
4064 if (fAttachDetach)
4065 {
4066 /* Attach the new driver. */
4067 if (enmBus == StorageBus_USB)
4068 {
4069 if (fHotplug)
4070 {
4071 USBStorageDevice UsbMsd = USBStorageDevice();
4072 RTUuidCreate(&UsbMsd.mUuid);
4073 UsbMsd.iPort = uInstance;
4074 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4075 if (RT_SUCCESS(rc))
4076 mUSBStorageDevices.push_back(UsbMsd);
4077 }
4078 else
4079 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4080 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4081 }
4082 else
4083 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4084 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4085 AssertRCReturn(rc, rc);
4086
4087 /*
4088 * Make the secret key helper interface known to the VD driver if it is attached,
4089 * so we can get notified about missing keys.
4090 */
4091 PPDMIBASE pIBase = NULL;
4092 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4093 if (RT_SUCCESS(rc) && pIBase)
4094 {
4095 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4096 if (pIMedium)
4097 {
4098 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4099 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4100 }
4101 }
4102
4103 /* There is no need to handle removable medium mounting, as we
4104 * unconditionally replace everthing including the block driver level.
4105 * This means the new medium will be picked up automatically. */
4106 }
4107
4108 if (paLedDevType)
4109 paLedDevType[uLUN] = lType;
4110
4111 /* Dump the changed LUN if possible, dump the complete device otherwise */
4112 if ( aMachineState != MachineState_Starting
4113 && aMachineState != MachineState_Restoring)
4114 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4115 }
4116 catch (ConfigError &x)
4117 {
4118 // InsertConfig threw something:
4119 return x.m_vrc;
4120 }
4121
4122#undef H
4123
4124 return VINF_SUCCESS;
4125}
4126
4127int Console::i_configMedium(PCFGMNODE pLunL0,
4128 bool fPassthrough,
4129 DeviceType_T enmType,
4130 bool fUseHostIOCache,
4131 bool fBuiltinIOCache,
4132 bool fSetupMerge,
4133 unsigned uMergeSource,
4134 unsigned uMergeTarget,
4135 const char *pcszBwGroup,
4136 bool fDiscard,
4137 IMedium *pMedium,
4138 MachineState_T aMachineState,
4139 HRESULT *phrc)
4140{
4141 // InsertConfig* throws
4142 try
4143 {
4144 int rc = VINF_SUCCESS;
4145 HRESULT hrc;
4146 Bstr bstr;
4147 PCFGMNODE pLunL1 = NULL;
4148 PCFGMNODE pCfg = NULL;
4149
4150#define H() \
4151 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4152
4153
4154 BOOL fHostDrive = FALSE;
4155 MediumType_T mediumType = MediumType_Normal;
4156 if (pMedium)
4157 {
4158 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4159 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4160 }
4161
4162 if (fHostDrive)
4163 {
4164 Assert(pMedium);
4165 if (enmType == DeviceType_DVD)
4166 {
4167 InsertConfigString(pLunL0, "Driver", "HostDVD");
4168 InsertConfigNode(pLunL0, "Config", &pCfg);
4169
4170 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4171 InsertConfigString(pCfg, "Path", bstr);
4172
4173 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4174 }
4175 else if (enmType == DeviceType_Floppy)
4176 {
4177 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4178 InsertConfigNode(pLunL0, "Config", &pCfg);
4179
4180 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4181 InsertConfigString(pCfg, "Path", bstr);
4182 }
4183 }
4184 else
4185 {
4186 InsertConfigString(pLunL0, "Driver", "Block");
4187 InsertConfigNode(pLunL0, "Config", &pCfg);
4188 switch (enmType)
4189 {
4190 case DeviceType_DVD:
4191 InsertConfigString(pCfg, "Type", "DVD");
4192 InsertConfigInteger(pCfg, "Mountable", 1);
4193 break;
4194 case DeviceType_Floppy:
4195 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4196 InsertConfigInteger(pCfg, "Mountable", 1);
4197 break;
4198 case DeviceType_HardDisk:
4199 default:
4200 InsertConfigString(pCfg, "Type", "HardDisk");
4201 InsertConfigInteger(pCfg, "Mountable", 0);
4202 }
4203
4204 if ( pMedium
4205 && ( enmType == DeviceType_DVD
4206 || enmType == DeviceType_Floppy)
4207 )
4208 {
4209 // if this medium represents an ISO image and this image is inaccessible,
4210 // the ignore it instead of causing a failure; this can happen when we
4211 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4212 // Additions were mounted and the user upgraded VirtualBox. Previously
4213 // we failed on startup, but that's not good because the only way out then
4214 // would be to discard the VM state...
4215 MediumState_T mediumState;
4216 hrc = pMedium->RefreshState(&mediumState); H();
4217 if (mediumState == MediumState_Inaccessible)
4218 {
4219 Bstr loc;
4220 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4221 i_setVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4222 "The image file '%ls' is inaccessible and is being ignored. "
4223 "Please select a different image file for the virtual %s drive.",
4224 loc.raw(),
4225 enmType == DeviceType_DVD ? "DVD" : "floppy");
4226 pMedium = NULL;
4227 }
4228 }
4229
4230 if (pMedium)
4231 {
4232 /* Start with length of parent chain, as the list is reversed */
4233 unsigned uImage = 0;
4234 IMedium *pTmp = pMedium;
4235 while (pTmp)
4236 {
4237 uImage++;
4238 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4239 }
4240 /* Index of last image */
4241 uImage--;
4242
4243#if 0 /* Enable for I/O debugging */
4244 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4245 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4246 InsertConfigNode(pLunL0, "Config", &pCfg);
4247 InsertConfigInteger(pCfg, "CheckConsistency", 0);
4248 InsertConfigInteger(pCfg, "CheckDoubleCompletions", 1);
4249#endif
4250
4251 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4252 InsertConfigString(pLunL1, "Driver", "VD");
4253 InsertConfigNode(pLunL1, "Config", &pCfg);
4254
4255# ifdef VBOX_WITH_EXTPACK
4256 static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack");
4257 static const char *s_pszVDPlugin = "VDPluginCrypt";
4258 if (mptrExtPackManager->i_isExtPackUsable(strExtPackPuel.c_str()))
4259 {
4260 /* Configure loading the VDPlugin. */
4261 PCFGMNODE pCfgPlugins = NULL;
4262 PCFGMNODE pCfgPlugin = NULL;
4263 Utf8Str strPlugin;
4264 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_pszVDPlugin, &strExtPackPuel, &strPlugin);
4265 // Don't fail, this is optional!
4266 if (SUCCEEDED(hrc))
4267 {
4268 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4269 InsertConfigNode(pCfgPlugins, s_pszVDPlugin, &pCfgPlugin);
4270 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4271 }
4272 }
4273# endif
4274
4275 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4276 InsertConfigString(pCfg, "Path", bstr);
4277
4278 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4279 InsertConfigString(pCfg, "Format", bstr);
4280
4281 if (mediumType == MediumType_Readonly)
4282 InsertConfigInteger(pCfg, "ReadOnly", 1);
4283 else if (enmType == DeviceType_Floppy)
4284 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4285
4286 /* Start without exclusive write access to the images. */
4287 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4288 * we're resuming the VM if some 3rd dude have any of the VDIs open
4289 * with write sharing denied. However, if the two VMs are sharing a
4290 * image it really is necessary....
4291 *
4292 * So, on the "lock-media" command, the target teleporter should also
4293 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4294 * that. Grumble. */
4295 if ( enmType == DeviceType_HardDisk
4296 && ( aMachineState == MachineState_TeleportingIn
4297 || aMachineState == MachineState_FaultTolerantSyncing))
4298 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4299
4300 /* Flag for opening the medium for sharing between VMs. This
4301 * is done at the moment only for the first (and only) medium
4302 * in the chain, as shared media can have no diffs. */
4303 if (mediumType == MediumType_Shareable)
4304 InsertConfigInteger(pCfg, "Shareable", 1);
4305
4306 if (!fUseHostIOCache)
4307 {
4308 InsertConfigInteger(pCfg, "UseNewIo", 1);
4309 /*
4310 * Activate the builtin I/O cache for harddisks only.
4311 * It caches writes only which doesn't make sense for DVD drives
4312 * and just increases the overhead.
4313 */
4314 if ( fBuiltinIOCache
4315 && (enmType == DeviceType_HardDisk))
4316 InsertConfigInteger(pCfg, "BlockCache", 1);
4317 }
4318
4319 if (fSetupMerge)
4320 {
4321 InsertConfigInteger(pCfg, "SetupMerge", 1);
4322 if (uImage == uMergeSource)
4323 InsertConfigInteger(pCfg, "MergeSource", 1);
4324 else if (uImage == uMergeTarget)
4325 InsertConfigInteger(pCfg, "MergeTarget", 1);
4326 }
4327
4328 switch (enmType)
4329 {
4330 case DeviceType_DVD:
4331 InsertConfigString(pCfg, "Type", "DVD");
4332 break;
4333 case DeviceType_Floppy:
4334 InsertConfigString(pCfg, "Type", "Floppy");
4335 break;
4336 case DeviceType_HardDisk:
4337 default:
4338 InsertConfigString(pCfg, "Type", "HardDisk");
4339 }
4340
4341 if (pcszBwGroup)
4342 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4343
4344 if (fDiscard)
4345 InsertConfigInteger(pCfg, "Discard", 1);
4346
4347 /* Pass all custom parameters. */
4348 bool fHostIP = true;
4349 bool fEncrypted = false;
4350 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4351
4352 /* Create an inverted list of parents. */
4353 uImage--;
4354 IMedium *pParentMedium = pMedium;
4355 for (PCFGMNODE pParent = pCfg;; uImage--)
4356 {
4357 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4358 if (!pMedium)
4359 break;
4360
4361 PCFGMNODE pCur;
4362 InsertConfigNode(pParent, "Parent", &pCur);
4363 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4364 InsertConfigString(pCur, "Path", bstr);
4365
4366 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4367 InsertConfigString(pCur, "Format", bstr);
4368
4369 if (fSetupMerge)
4370 {
4371 if (uImage == uMergeSource)
4372 InsertConfigInteger(pCur, "MergeSource", 1);
4373 else if (uImage == uMergeTarget)
4374 InsertConfigInteger(pCur, "MergeTarget", 1);
4375 }
4376
4377 /* Configure medium properties. */
4378 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4379
4380 /* next */
4381 pParent = pCur;
4382 pParentMedium = pMedium;
4383 }
4384
4385 /* Custom code: put marker to not use host IP stack to driver
4386 * configuration node. Simplifies life of DrvVD a bit. */
4387 if (!fHostIP)
4388 InsertConfigInteger(pCfg, "HostIPStack", 0);
4389
4390 if (fEncrypted)
4391 m_cDisksEncrypted++;
4392 }
4393 }
4394#undef H
4395 }
4396 catch (ConfigError &x)
4397 {
4398 // InsertConfig threw something:
4399 return x.m_vrc;
4400 }
4401
4402 return VINF_SUCCESS;
4403}
4404
4405/**
4406 * Adds the medium properties to the CFGM tree.
4407 *
4408 * @returns VBox status code.
4409 * @param pCur The current CFGM node.
4410 * @param pMedium The medium object to configure.
4411 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4412 * @param pfEncrypted Where to return whether the medium is encrypted.
4413 */
4414int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4415{
4416 /* Pass all custom parameters. */
4417 SafeArray<BSTR> aNames;
4418 SafeArray<BSTR> aValues;
4419 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4420 ComSafeArrayAsOutParam(aValues));
4421
4422 if ( SUCCEEDED(hrc)
4423 && aNames.size() != 0)
4424 {
4425 PCFGMNODE pVDC;
4426 InsertConfigNode(pCur, "VDConfig", &pVDC);
4427 for (size_t ii = 0; ii < aNames.size(); ++ii)
4428 {
4429 if (aValues[ii] && *aValues[ii])
4430 {
4431 Utf8Str name = aNames[ii];
4432 Utf8Str value = aValues[ii];
4433 size_t offSlash = name.find("/", 0);
4434 if ( offSlash != name.npos
4435 && !name.startsWith("Special/"))
4436 {
4437 com::Utf8Str strFilter;
4438 com::Utf8Str strKey;
4439
4440 hrc = strFilter.assignEx(name, 0, offSlash);
4441 if (FAILED(hrc))
4442 break;
4443
4444 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4445 if (FAILED(hrc))
4446 break;
4447
4448 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4449 if (!pCfgFilterConfig)
4450 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4451
4452 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4453 }
4454 else
4455 {
4456 InsertConfigString(pVDC, name.c_str(), value);
4457 if ( name.compare("HostIPStack") == 0
4458 && value.compare("0") == 0)
4459 *pfHostIP = false;
4460 }
4461
4462 if ( name.compare("CRYPT/KeyId") == 0
4463 && pfEncrypted)
4464 *pfEncrypted = true;
4465 }
4466 }
4467 }
4468
4469 return hrc;
4470}
4471
4472/**
4473 * Construct the Network configuration tree
4474 *
4475 * @returns VBox status code.
4476 *
4477 * @param pszDevice The PDM device name.
4478 * @param uInstance The PDM device instance.
4479 * @param uLun The PDM LUN number of the drive.
4480 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4481 * @param pCfg Configuration node for the device
4482 * @param pLunL0 To store the pointer to the LUN#0.
4483 * @param pInst The instance CFGM node
4484 * @param fAttachDetach To determine if the network attachment should
4485 * be attached/detached after/before
4486 * configuration.
4487 * @param fIgnoreConnectFailure
4488 * True if connection failures should be ignored
4489 * (makes only sense for bridged/host-only networks).
4490 *
4491 * @note Locks this object for writing.
4492 * @thread EMT
4493 */
4494int Console::i_configNetwork(const char *pszDevice,
4495 unsigned uInstance,
4496 unsigned uLun,
4497 INetworkAdapter *aNetworkAdapter,
4498 PCFGMNODE pCfg,
4499 PCFGMNODE pLunL0,
4500 PCFGMNODE pInst,
4501 bool fAttachDetach,
4502 bool fIgnoreConnectFailure)
4503{
4504 AutoCaller autoCaller(this);
4505 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4506
4507 // InsertConfig* throws
4508 try
4509 {
4510 int rc = VINF_SUCCESS;
4511 HRESULT hrc;
4512 Bstr bstr;
4513
4514#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4515
4516 /*
4517 * Locking the object before doing VMR3* calls is quite safe here, since
4518 * we're on EMT. Write lock is necessary because we indirectly modify the
4519 * meAttachmentType member.
4520 */
4521 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4522
4523 ComPtr<IMachine> pMachine = i_machine();
4524
4525 ComPtr<IVirtualBox> virtualBox;
4526 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4527
4528 ComPtr<IHost> host;
4529 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4530
4531 BOOL fSniffer;
4532 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4533
4534 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4535 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4536 const char *pszPromiscuousGuestPolicy;
4537 switch (enmPromiscModePolicy)
4538 {
4539 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4540 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4541 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4542 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4543 }
4544
4545 if (fAttachDetach)
4546 {
4547 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4548 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4549 rc = VINF_SUCCESS;
4550 AssertLogRelRCReturn(rc, rc);
4551
4552 /* nuke anything which might have been left behind. */
4553 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4554 }
4555
4556#ifdef VBOX_WITH_NETSHAPER
4557 ComObjPtr<IBandwidthGroup> pBwGroup;
4558 Bstr strBwGroup;
4559 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4560
4561 if (!pBwGroup.isNull())
4562 {
4563 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4564 }
4565#endif /* VBOX_WITH_NETSHAPER */
4566
4567 Utf8Str strNetDriver;
4568
4569
4570 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4571
4572#ifdef VBOX_WITH_NETSHAPER
4573 if (!strBwGroup.isEmpty())
4574 {
4575 InsertConfigString(pLunL0, "Driver", "NetShaper");
4576 InsertConfigNode(pLunL0, "Config", &pCfg);
4577 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4578 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4579 }
4580#endif /* VBOX_WITH_NETSHAPER */
4581
4582 if (fSniffer)
4583 {
4584 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4585 InsertConfigNode(pLunL0, "Config", &pCfg);
4586 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4587 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4588 InsertConfigString(pCfg, "File", bstr);
4589 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4590 }
4591
4592
4593 Bstr networkName, trunkName, trunkType;
4594 NetworkAttachmentType_T eAttachmentType;
4595 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4596 switch (eAttachmentType)
4597 {
4598 case NetworkAttachmentType_Null:
4599 break;
4600
4601 case NetworkAttachmentType_NAT:
4602 {
4603 ComPtr<INATEngine> natEngine;
4604 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4605 InsertConfigString(pLunL0, "Driver", "NAT");
4606 InsertConfigNode(pLunL0, "Config", &pCfg);
4607
4608 /* Configure TFTP prefix and boot filename. */
4609 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4610 if (!bstr.isEmpty())
4611 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
4612 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
4613 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
4614
4615 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
4616 if (!bstr.isEmpty())
4617 InsertConfigString(pCfg, "Network", bstr);
4618 else
4619 {
4620 ULONG uSlot;
4621 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
4622 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
4623 }
4624 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
4625 if (!bstr.isEmpty())
4626 InsertConfigString(pCfg, "BindIP", bstr);
4627 ULONG mtu = 0;
4628 ULONG sockSnd = 0;
4629 ULONG sockRcv = 0;
4630 ULONG tcpSnd = 0;
4631 ULONG tcpRcv = 0;
4632 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
4633 if (mtu)
4634 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
4635 if (sockRcv)
4636 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
4637 if (sockSnd)
4638 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
4639 if (tcpRcv)
4640 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
4641 if (tcpSnd)
4642 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
4643 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
4644 if (!bstr.isEmpty())
4645 {
4646 RemoveConfigValue(pCfg, "TFTPPrefix");
4647 InsertConfigString(pCfg, "TFTPPrefix", bstr);
4648 }
4649 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
4650 if (!bstr.isEmpty())
4651 {
4652 RemoveConfigValue(pCfg, "BootFile");
4653 InsertConfigString(pCfg, "BootFile", bstr);
4654 }
4655 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
4656 if (!bstr.isEmpty())
4657 InsertConfigString(pCfg, "NextServer", bstr);
4658 BOOL fDNSFlag;
4659 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
4660 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
4661 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
4662 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
4663 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
4664 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
4665
4666 ULONG aliasMode;
4667 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
4668 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
4669
4670 /* port-forwarding */
4671 SafeArray<BSTR> pfs;
4672 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
4673 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PF#0/ */
4674 for (unsigned int i = 0; i < pfs.size(); ++i)
4675 {
4676 uint16_t port = 0;
4677 BSTR r = pfs[i];
4678 Utf8Str utf = Utf8Str(r);
4679 Utf8Str strName;
4680 Utf8Str strProto;
4681 Utf8Str strHostPort;
4682 Utf8Str strHostIP;
4683 Utf8Str strGuestPort;
4684 Utf8Str strGuestIP;
4685 size_t pos, ppos;
4686 pos = ppos = 0;
4687#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
4688 do { \
4689 pos = str.find(",", ppos); \
4690 if (pos == Utf8Str::npos) \
4691 { \
4692 Log(( #res " extracting from %s is failed\n", str.c_str())); \
4693 continue; \
4694 } \
4695 res = str.substr(ppos, pos - ppos); \
4696 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
4697 ppos = pos + 1; \
4698 } while (0)
4699 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
4700 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
4701 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
4702 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
4703 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
4704 strGuestPort = utf.substr(ppos, utf.length() - ppos);
4705#undef ITERATE_TO_NEXT_TERM
4706
4707 uint32_t proto = strProto.toUInt32();
4708 bool fValid = true;
4709 switch (proto)
4710 {
4711 case NATProtocol_UDP:
4712 strProto = "UDP";
4713 break;
4714 case NATProtocol_TCP:
4715 strProto = "TCP";
4716 break;
4717 default:
4718 fValid = false;
4719 }
4720 /* continue with next rule if no valid proto was passed */
4721 if (!fValid)
4722 continue;
4723
4724 if (strName.isEmpty())
4725 VMSetError(VMR3GetVM(mpUVM), VERR_CFGM_NO_NODE, RT_SRC_POS,
4726 N_("NAT redirection rule without a name"));
4727
4728 InsertConfigNode(pCfg, strName.c_str(), &pPF);
4729 InsertConfigString(pPF, "Protocol", strProto);
4730
4731 if (!strHostIP.isEmpty())
4732 InsertConfigString(pPF, "BindIP", strHostIP);
4733
4734 if (!strGuestIP.isEmpty())
4735 InsertConfigString(pPF, "GuestIP", strGuestIP);
4736
4737 port = RTStrToUInt16(strHostPort.c_str());
4738 if (port)
4739 InsertConfigInteger(pPF, "HostPort", port);
4740
4741 port = RTStrToUInt16(strGuestPort.c_str());
4742 if (port)
4743 InsertConfigInteger(pPF, "GuestPort", port);
4744 }
4745 break;
4746 }
4747
4748 case NetworkAttachmentType_Bridged:
4749 {
4750#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
4751 hrc = i_attachToTapInterface(aNetworkAdapter);
4752 if (FAILED(hrc))
4753 {
4754 switch (hrc)
4755 {
4756 case VERR_ACCESS_DENIED:
4757 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4758 "Failed to open '/dev/net/tun' for read/write access. Please check the "
4759 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
4760 "change the group of that node and make yourself a member of that group. Make "
4761 "sure that these changes are permanent, especially if you are "
4762 "using udev"));
4763 default:
4764 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
4765 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4766 "Failed to initialize Host Interface Networking"));
4767 }
4768 }
4769
4770 Assert((intptr_t)maTapFD[uInstance] >= 0);
4771 if ((intptr_t)maTapFD[uInstance] >= 0)
4772 {
4773 InsertConfigString(pLunL0, "Driver", "HostInterface");
4774 InsertConfigNode(pLunL0, "Config", &pCfg);
4775 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
4776 }
4777
4778#elif defined(VBOX_WITH_NETFLT)
4779 /*
4780 * This is the new VBoxNetFlt+IntNet stuff.
4781 */
4782 Bstr BridgedIfName;
4783 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
4784 if (FAILED(hrc))
4785 {
4786 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
4787 H();
4788 }
4789
4790 Utf8Str BridgedIfNameUtf8(BridgedIfName);
4791 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
4792
4793# if defined(RT_OS_DARWIN)
4794 /* The name is on the form 'ifX: long name', chop it off at the colon. */
4795 char szTrunk[8];
4796 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
4797 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
4798// Quick fix for @bugref{5633}
4799// if (!pszColon)
4800// {
4801// /*
4802// * Dynamic changing of attachment causes an attempt to configure
4803// * network with invalid host adapter (as it is must be changed before
4804// * the attachment), calling Detach here will cause a deadlock.
4805// * See @bugref{4750}.
4806// * hrc = aNetworkAdapter->Detach(); H();
4807// */
4808// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
4809// N_("Malformed host interface networking name '%ls'"),
4810// BridgedIfName.raw());
4811// }
4812 if (pszColon)
4813 *pszColon = '\0';
4814 const char *pszTrunk = szTrunk;
4815
4816# elif defined(RT_OS_SOLARIS)
4817 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
4818 char szTrunk[256];
4819 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
4820 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
4821
4822 /*
4823 * Currently don't bother about malformed names here for the sake of people using
4824 * VBoxManage and setting only the NIC name from there. If there is a space we
4825 * chop it off and proceed, otherwise just use whatever we've got.
4826 */
4827 if (pszSpace)
4828 *pszSpace = '\0';
4829
4830 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
4831 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
4832 if (pszColon)
4833 *pszColon = '\0';
4834
4835 const char *pszTrunk = szTrunk;
4836
4837# elif defined(RT_OS_WINDOWS)
4838 ComPtr<IHostNetworkInterface> hostInterface;
4839 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
4840 hostInterface.asOutParam());
4841 if (!SUCCEEDED(hrc))
4842 {
4843 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
4844 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
4845 N_("Nonexistent host networking interface, name '%ls'"),
4846 BridgedIfName.raw());
4847 }
4848
4849 HostNetworkInterfaceType_T eIfType;
4850 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
4851 if (FAILED(hrc))
4852 {
4853 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
4854 H();
4855 }
4856
4857 if (eIfType != HostNetworkInterfaceType_Bridged)
4858 {
4859 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
4860 N_("Interface ('%ls') is not a Bridged Adapter interface"),
4861 BridgedIfName.raw());
4862 }
4863
4864 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
4865 if (FAILED(hrc))
4866 {
4867 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
4868 H();
4869 }
4870 Guid hostIFGuid(bstr);
4871
4872 INetCfg *pNc;
4873 ComPtr<INetCfgComponent> pAdaptorComponent;
4874 LPWSTR pszApp;
4875
4876 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
4877 Assert(hrc == S_OK);
4878 if (hrc != S_OK)
4879 {
4880 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
4881 H();
4882 }
4883
4884 /* get the adapter's INetCfgComponent*/
4885 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
4886 pAdaptorComponent.asOutParam());
4887 if (hrc != S_OK)
4888 {
4889 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4890 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
4891 H();
4892 }
4893#define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
4894 char szTrunkName[INTNET_MAX_TRUNK_NAME];
4895 char *pszTrunkName = szTrunkName;
4896 wchar_t * pswzBindName;
4897 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
4898 Assert(hrc == S_OK);
4899 if (hrc == S_OK)
4900 {
4901 int cwBindName = (int)wcslen(pswzBindName) + 1;
4902 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
4903 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
4904 {
4905 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
4906 pszTrunkName += cbFullBindNamePrefix-1;
4907 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
4908 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
4909 {
4910 DWORD err = GetLastError();
4911 hrc = HRESULT_FROM_WIN32(err);
4912 AssertMsgFailed(("%hrc=%Rhrc %#x\n", hrc, hrc));
4913 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
4914 hrc, hrc, err));
4915 }
4916 }
4917 else
4918 {
4919 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
4920 /** @todo set appropriate error code */
4921 hrc = E_FAIL;
4922 }
4923
4924 if (hrc != S_OK)
4925 {
4926 AssertFailed();
4927 CoTaskMemFree(pswzBindName);
4928 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4929 H();
4930 }
4931
4932 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
4933 }
4934 else
4935 {
4936 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4937 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
4938 hrc));
4939 H();
4940 }
4941
4942 const char *pszTrunk = szTrunkName;
4943 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
4944
4945# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
4946# if defined(RT_OS_FREEBSD)
4947 /*
4948 * If we bridge to a tap interface open it the `old' direct way.
4949 * This works and performs better than bridging a physical
4950 * interface via the current FreeBSD vboxnetflt implementation.
4951 */
4952 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
4953 hrc = i_attachToTapInterface(aNetworkAdapter);
4954 if (FAILED(hrc))
4955 {
4956 switch (hrc)
4957 {
4958 case VERR_ACCESS_DENIED:
4959 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4960 "Failed to open '/dev/%s' for read/write access. Please check the "
4961 "permissions of that node, and that the net.link.tap.user_open "
4962 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
4963 "change the group of that node to vboxusers and make yourself "
4964 "a member of that group. Make sure that these changes are permanent."),
4965 pszBridgedIfName, pszBridgedIfName);
4966 default:
4967 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
4968 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4969 "Failed to initialize Host Interface Networking"));
4970 }
4971 }
4972
4973 Assert((intptr_t)maTapFD[uInstance] >= 0);
4974 if ((intptr_t)maTapFD[uInstance] >= 0)
4975 {
4976 InsertConfigString(pLunL0, "Driver", "HostInterface");
4977 InsertConfigNode(pLunL0, "Config", &pCfg);
4978 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
4979 }
4980 break;
4981 }
4982# endif
4983 /** @todo Check for malformed names. */
4984 const char *pszTrunk = pszBridgedIfName;
4985
4986 /* Issue a warning if the interface is down */
4987 {
4988 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
4989 if (iSock >= 0)
4990 {
4991 struct ifreq Req;
4992 RT_ZERO(Req);
4993 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
4994 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
4995 if ((Req.ifr_flags & IFF_UP) == 0)
4996 i_setVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
4997 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
4998 pszBridgedIfName);
4999
5000 close(iSock);
5001 }
5002 }
5003
5004# else
5005# error "PORTME (VBOX_WITH_NETFLT)"
5006# endif
5007
5008 InsertConfigString(pLunL0, "Driver", "IntNet");
5009 InsertConfigNode(pLunL0, "Config", &pCfg);
5010 InsertConfigString(pCfg, "Trunk", pszTrunk);
5011 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5012 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5013 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5014 char szNetwork[INTNET_MAX_NETWORK_NAME];
5015
5016#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5017 /*
5018 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5019 * interface name + optional description. We must not pass any description to the VM as it can differ
5020 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5021 */
5022 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5023#else
5024 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5025#endif
5026 InsertConfigString(pCfg, "Network", szNetwork);
5027 networkName = Bstr(szNetwork);
5028 trunkName = Bstr(pszTrunk);
5029 trunkType = Bstr(TRUNKTYPE_NETFLT);
5030
5031# if defined(RT_OS_DARWIN)
5032 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
5033 if ( strstr(pszBridgedIfName, "Wireless")
5034 || strstr(pszBridgedIfName, "AirPort" ))
5035 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5036# elif defined(RT_OS_LINUX)
5037 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5038 if (iSock >= 0)
5039 {
5040 struct iwreq WRq;
5041
5042 RT_ZERO(WRq);
5043 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
5044 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
5045 close(iSock);
5046 if (fSharedMacOnWire)
5047 {
5048 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5049 Log(("Set SharedMacOnWire\n"));
5050 }
5051 else
5052 Log(("Failed to get wireless name\n"));
5053 }
5054 else
5055 Log(("Failed to open wireless socket\n"));
5056# elif defined(RT_OS_FREEBSD)
5057 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5058 if (iSock >= 0)
5059 {
5060 struct ieee80211req WReq;
5061 uint8_t abData[32];
5062
5063 RT_ZERO(WReq);
5064 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
5065 WReq.i_type = IEEE80211_IOC_SSID;
5066 WReq.i_val = -1;
5067 WReq.i_data = abData;
5068 WReq.i_len = sizeof(abData);
5069
5070 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
5071 close(iSock);
5072 if (fSharedMacOnWire)
5073 {
5074 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5075 Log(("Set SharedMacOnWire\n"));
5076 }
5077 else
5078 Log(("Failed to get wireless name\n"));
5079 }
5080 else
5081 Log(("Failed to open wireless socket\n"));
5082# elif defined(RT_OS_WINDOWS)
5083# define DEVNAME_PREFIX L"\\\\.\\"
5084 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
5085 * there is a pretty long way till there though since we need to obtain the symbolic link name
5086 * for the adapter device we are going to query given the device Guid */
5087
5088
5089 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
5090
5091 wchar_t FileName[MAX_PATH];
5092 wcscpy(FileName, DEVNAME_PREFIX);
5093 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
5094
5095 /* open the device */
5096 HANDLE hDevice = CreateFile(FileName,
5097 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5098 NULL,
5099 OPEN_EXISTING,
5100 FILE_ATTRIBUTE_NORMAL,
5101 NULL);
5102
5103 if (hDevice != INVALID_HANDLE_VALUE)
5104 {
5105 bool fSharedMacOnWire = false;
5106
5107 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
5108 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
5109 NDIS_PHYSICAL_MEDIUM PhMedium;
5110 DWORD cbResult;
5111 if (DeviceIoControl(hDevice,
5112 IOCTL_NDIS_QUERY_GLOBAL_STATS,
5113 &Oid,
5114 sizeof(Oid),
5115 &PhMedium,
5116 sizeof(PhMedium),
5117 &cbResult,
5118 NULL))
5119 {
5120 /* that was simple, now examine PhMedium */
5121 if ( PhMedium == NdisPhysicalMediumWirelessWan
5122 || PhMedium == NdisPhysicalMediumWirelessLan
5123 || PhMedium == NdisPhysicalMediumNative802_11
5124 || PhMedium == NdisPhysicalMediumBluetooth)
5125 fSharedMacOnWire = true;
5126 }
5127 else
5128 {
5129 int winEr = GetLastError();
5130 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
5131 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
5132 }
5133 CloseHandle(hDevice);
5134
5135 if (fSharedMacOnWire)
5136 {
5137 Log(("this is a wireless adapter"));
5138 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5139 Log(("Set SharedMacOnWire\n"));
5140 }
5141 else
5142 Log(("this is NOT a wireless adapter"));
5143 }
5144 else
5145 {
5146 int winEr = GetLastError();
5147 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
5148 }
5149
5150 CoTaskMemFree(pswzBindName);
5151
5152 pAdaptorComponent.setNull();
5153 /* release the pNc finally */
5154 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5155# else
5156 /** @todo PORTME: wireless detection */
5157# endif
5158
5159# if defined(RT_OS_SOLARIS)
5160# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5161 /* Zone access restriction, don't allow snooping the global zone. */
5162 zoneid_t ZoneId = getzoneid();
5163 if (ZoneId != GLOBAL_ZONEID)
5164 {
5165 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5166 }
5167# endif
5168# endif
5169
5170#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5171 /* NOTHING TO DO HERE */
5172#elif defined(RT_OS_LINUX)
5173/// @todo aleksey: is there anything to be done here?
5174#elif defined(RT_OS_FREEBSD)
5175/** @todo FreeBSD: Check out this later (HIF networking). */
5176#else
5177# error "Port me"
5178#endif
5179 break;
5180 }
5181
5182 case NetworkAttachmentType_Internal:
5183 {
5184 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5185 if (!bstr.isEmpty())
5186 {
5187 InsertConfigString(pLunL0, "Driver", "IntNet");
5188 InsertConfigNode(pLunL0, "Config", &pCfg);
5189 InsertConfigString(pCfg, "Network", bstr);
5190 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5191 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5192 networkName = bstr;
5193 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5194 }
5195 break;
5196 }
5197
5198 case NetworkAttachmentType_HostOnly:
5199 {
5200 InsertConfigString(pLunL0, "Driver", "IntNet");
5201 InsertConfigNode(pLunL0, "Config", &pCfg);
5202
5203 Bstr HostOnlyName;
5204 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5205 if (FAILED(hrc))
5206 {
5207 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5208 H();
5209 }
5210
5211 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5212 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5213 ComPtr<IHostNetworkInterface> hostInterface;
5214 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5215 hostInterface.asOutParam());
5216 if (!SUCCEEDED(rc))
5217 {
5218 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5219 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5220 N_("Nonexistent host networking interface, name '%ls'"),
5221 HostOnlyName.raw());
5222 }
5223
5224 char szNetwork[INTNET_MAX_NETWORK_NAME];
5225 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5226
5227#if defined(RT_OS_WINDOWS)
5228# ifndef VBOX_WITH_NETFLT
5229 hrc = E_NOTIMPL;
5230 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5231 H();
5232# else /* defined VBOX_WITH_NETFLT*/
5233 /** @todo r=bird: Put this in a function. */
5234
5235 HostNetworkInterfaceType_T eIfType;
5236 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5237 if (FAILED(hrc))
5238 {
5239 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5240 H();
5241 }
5242
5243 if (eIfType != HostNetworkInterfaceType_HostOnly)
5244 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5245 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5246 HostOnlyName.raw());
5247
5248 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5249 if (FAILED(hrc))
5250 {
5251 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5252 H();
5253 }
5254 Guid hostIFGuid(bstr);
5255
5256 INetCfg *pNc;
5257 ComPtr<INetCfgComponent> pAdaptorComponent;
5258 LPWSTR pszApp;
5259 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5260 Assert(hrc == S_OK);
5261 if (hrc != S_OK)
5262 {
5263 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5264 H();
5265 }
5266
5267 /* get the adapter's INetCfgComponent*/
5268 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5269 pAdaptorComponent.asOutParam());
5270 if (hrc != S_OK)
5271 {
5272 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5273 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5274 H();
5275 }
5276# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5277 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5278 char *pszTrunkName = szTrunkName;
5279 wchar_t * pswzBindName;
5280 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5281 Assert(hrc == S_OK);
5282 if (hrc == S_OK)
5283 {
5284 int cwBindName = (int)wcslen(pswzBindName) + 1;
5285 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5286 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5287 {
5288 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5289 pszTrunkName += cbFullBindNamePrefix-1;
5290 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5291 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5292 {
5293 DWORD err = GetLastError();
5294 hrc = HRESULT_FROM_WIN32(err);
5295 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5296 hrc, hrc, err));
5297 }
5298 }
5299 else
5300 {
5301 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5302 /** @todo set appropriate error code */
5303 hrc = E_FAIL;
5304 }
5305
5306 if (hrc != S_OK)
5307 {
5308 AssertFailed();
5309 CoTaskMemFree(pswzBindName);
5310 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5311 H();
5312 }
5313 }
5314 else
5315 {
5316 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5317 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5318 hrc, hrc));
5319 H();
5320 }
5321
5322
5323 CoTaskMemFree(pswzBindName);
5324
5325 /* Assume we should use the old NDIS5.1 version of driver which uses TRUNKTYPE_NETADP */
5326 trunkType = TRUNKTYPE_NETADP;
5327
5328 HKEY hkParams;
5329 hrc = pAdaptorComponent->OpenParamKey(&hkParams);
5330 Assert(hrc == S_OK);
5331 if (hrc == S_OK)
5332 {
5333 WCHAR swzInfSection[16];
5334 DWORD dwSize = sizeof(swzInfSection);
5335 hrc = RegQueryValueExW(hkParams, L"InfSection", NULL, NULL, (LPBYTE)swzInfSection, &dwSize);
5336 if (hrc == S_OK)
5337 {
5338 if (!_wcsnicmp(swzInfSection, L"VBoxNetAdp6.ndi", sizeof(L"VBoxNetAdp6.ndi")/2))
5339 {
5340 /*
5341 * This is NDIS 6.x miniport, it relies on NetLwf filter to
5342 * run actual traffic. We use netflt attachment instead of
5343 * netadp, which is used in case of NDIS 5.x.
5344 */
5345 trunkType = TRUNKTYPE_NETFLT;
5346 }
5347 }
5348 RegCloseKey(hkParams);
5349 }
5350 else
5351 {
5352 LogRel(("Console::i_configNetwork: INetCfgComponent::GetId(%s) failed, err (0x%x), "
5353 "falling back to NDIS5 attachment\n", pszTrunkName, hrc));
5354 /* Nothing to do here as the trunk type defaults to NETADP */
5355 }
5356 InsertConfigInteger(pCfg, "TrunkType", trunkType == TRUNKTYPE_NETFLT ? kIntNetTrunkType_NetFlt : kIntNetTrunkType_NetAdp);
5357
5358 pAdaptorComponent.setNull();
5359 /* release the pNc finally */
5360 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5361
5362 const char *pszTrunk = szTrunkName;
5363
5364 InsertConfigString(pCfg, "Trunk", pszTrunk);
5365 InsertConfigString(pCfg, "Network", szNetwork);
5366 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5367 windows only?? */
5368 networkName = Bstr(szNetwork);
5369 trunkName = Bstr(pszTrunk);
5370# endif /* defined VBOX_WITH_NETFLT*/
5371#elif defined(RT_OS_DARWIN)
5372 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5373 InsertConfigString(pCfg, "Network", szNetwork);
5374 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5375 networkName = Bstr(szNetwork);
5376 trunkName = Bstr(pszHostOnlyName);
5377 trunkType = TRUNKTYPE_NETADP;
5378#else
5379 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5380 InsertConfigString(pCfg, "Network", szNetwork);
5381 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5382 networkName = Bstr(szNetwork);
5383 trunkName = Bstr(pszHostOnlyName);
5384 trunkType = TRUNKTYPE_NETFLT;
5385#endif
5386 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5387
5388#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5389
5390 Bstr tmpAddr, tmpMask;
5391
5392 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5393 pszHostOnlyName).raw(),
5394 tmpAddr.asOutParam());
5395 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5396 {
5397 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5398 pszHostOnlyName).raw(),
5399 tmpMask.asOutParam());
5400 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5401 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5402 tmpMask.raw());
5403 else
5404 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5405 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5406 }
5407 else
5408 {
5409 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5410 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5411 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5412 }
5413
5414 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5415
5416 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5417 pszHostOnlyName).raw(),
5418 tmpAddr.asOutParam());
5419 if (SUCCEEDED(hrc))
5420 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5421 tmpMask.asOutParam());
5422 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5423 {
5424 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5425 Utf8Str(tmpMask).toUInt32());
5426 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5427 }
5428#endif
5429 break;
5430 }
5431
5432 case NetworkAttachmentType_Generic:
5433 {
5434 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5435 SafeArray<BSTR> names;
5436 SafeArray<BSTR> values;
5437 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5438 ComSafeArrayAsOutParam(names),
5439 ComSafeArrayAsOutParam(values)); H();
5440
5441 InsertConfigString(pLunL0, "Driver", bstr);
5442 InsertConfigNode(pLunL0, "Config", &pCfg);
5443 for (size_t ii = 0; ii < names.size(); ++ii)
5444 {
5445 if (values[ii] && *values[ii])
5446 {
5447 Utf8Str name = names[ii];
5448 Utf8Str value = values[ii];
5449 InsertConfigString(pCfg, name.c_str(), value);
5450 }
5451 }
5452 break;
5453 }
5454
5455 case NetworkAttachmentType_NATNetwork:
5456 {
5457 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5458 if (!bstr.isEmpty())
5459 {
5460 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5461 InsertConfigString(pLunL0, "Driver", "IntNet");
5462 InsertConfigNode(pLunL0, "Config", &pCfg);
5463 InsertConfigString(pCfg, "Network", bstr);
5464 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5465 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5466 networkName = bstr;
5467 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5468 }
5469 break;
5470 }
5471
5472 default:
5473 AssertMsgFailed(("should not get here!\n"));
5474 break;
5475 }
5476
5477 /*
5478 * Attempt to attach the driver.
5479 */
5480 switch (eAttachmentType)
5481 {
5482 case NetworkAttachmentType_Null:
5483 break;
5484
5485 case NetworkAttachmentType_Bridged:
5486 case NetworkAttachmentType_Internal:
5487 case NetworkAttachmentType_HostOnly:
5488 case NetworkAttachmentType_NAT:
5489 case NetworkAttachmentType_Generic:
5490 case NetworkAttachmentType_NATNetwork:
5491 {
5492 if (SUCCEEDED(hrc) && SUCCEEDED(rc))
5493 {
5494 if (fAttachDetach)
5495 {
5496 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5497 //AssertRC(rc);
5498 }
5499
5500 {
5501 /** @todo pritesh: get the dhcp server name from the
5502 * previous network configuration and then stop the server
5503 * else it may conflict with the dhcp server running with
5504 * the current attachment type
5505 */
5506 /* Stop the hostonly DHCP Server */
5507 }
5508
5509 /*
5510 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5511 */
5512 if ( !networkName.isEmpty()
5513 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5514 {
5515 /*
5516 * Until we implement service reference counters DHCP Server will be stopped
5517 * by DHCPServerRunner destructor.
5518 */
5519 ComPtr<IDHCPServer> dhcpServer;
5520 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5521 dhcpServer.asOutParam());
5522 if (SUCCEEDED(hrc))
5523 {
5524 /* there is a DHCP server available for this network */
5525 BOOL fEnabledDhcp;
5526 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5527 if (FAILED(hrc))
5528 {
5529 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5530 H();
5531 }
5532
5533 if (fEnabledDhcp)
5534 hrc = dhcpServer->Start(networkName.raw(),
5535 trunkName.raw(),
5536 trunkType.raw());
5537 }
5538 else
5539 hrc = S_OK;
5540 }
5541 }
5542
5543 break;
5544 }
5545
5546 default:
5547 AssertMsgFailed(("should not get here!\n"));
5548 break;
5549 }
5550
5551 meAttachmentType[uInstance] = eAttachmentType;
5552 }
5553 catch (ConfigError &x)
5554 {
5555 // InsertConfig threw something:
5556 return x.m_vrc;
5557 }
5558
5559#undef H
5560
5561 return VINF_SUCCESS;
5562}
5563
5564#ifdef VBOX_WITH_GUEST_PROPS
5565/**
5566 * Set an array of guest properties
5567 */
5568static void configSetProperties(VMMDev * const pVMMDev,
5569 void *names,
5570 void *values,
5571 void *timestamps,
5572 void *flags)
5573{
5574 VBOXHGCMSVCPARM parms[4];
5575
5576 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5577 parms[0].u.pointer.addr = names;
5578 parms[0].u.pointer.size = 0; /* We don't actually care. */
5579 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5580 parms[1].u.pointer.addr = values;
5581 parms[1].u.pointer.size = 0; /* We don't actually care. */
5582 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5583 parms[2].u.pointer.addr = timestamps;
5584 parms[2].u.pointer.size = 0; /* We don't actually care. */
5585 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5586 parms[3].u.pointer.addr = flags;
5587 parms[3].u.pointer.size = 0; /* We don't actually care. */
5588
5589 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5590 guestProp::SET_PROPS_HOST,
5591 4,
5592 &parms[0]);
5593}
5594
5595/**
5596 * Set a single guest property
5597 */
5598static void configSetProperty(VMMDev * const pVMMDev,
5599 const char *pszName,
5600 const char *pszValue,
5601 const char *pszFlags)
5602{
5603 VBOXHGCMSVCPARM parms[4];
5604
5605 AssertPtrReturnVoid(pszName);
5606 AssertPtrReturnVoid(pszValue);
5607 AssertPtrReturnVoid(pszFlags);
5608 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5609 parms[0].u.pointer.addr = (void *)pszName;
5610 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5611 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5612 parms[1].u.pointer.addr = (void *)pszValue;
5613 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5614 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5615 parms[2].u.pointer.addr = (void *)pszFlags;
5616 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
5617 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
5618 &parms[0]);
5619}
5620
5621/**
5622 * Set the global flags value by calling the service
5623 * @returns the status returned by the call to the service
5624 *
5625 * @param pTable the service instance handle
5626 * @param eFlags the flags to set
5627 */
5628int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
5629 guestProp::ePropFlags eFlags)
5630{
5631 VBOXHGCMSVCPARM paParm;
5632 paParm.setUInt32(eFlags);
5633 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5634 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
5635 &paParm);
5636 if (RT_FAILURE(rc))
5637 {
5638 char szFlags[guestProp::MAX_FLAGS_LEN];
5639 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
5640 Log(("Failed to set the global flags.\n"));
5641 else
5642 Log(("Failed to set the global flags \"%s\".\n", szFlags));
5643 }
5644 return rc;
5645}
5646#endif /* VBOX_WITH_GUEST_PROPS */
5647
5648/**
5649 * Set up the Guest Property service, populate it with properties read from
5650 * the machine XML and set a couple of initial properties.
5651 */
5652/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
5653{
5654#ifdef VBOX_WITH_GUEST_PROPS
5655 AssertReturn(pvConsole, VERR_INVALID_POINTER);
5656 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
5657 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
5658
5659 /* Load the service */
5660 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
5661
5662 if (RT_FAILURE(rc))
5663 {
5664 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
5665 /* That is not a fatal failure. */
5666 rc = VINF_SUCCESS;
5667 }
5668 else
5669 {
5670 /*
5671 * Initialize built-in properties that can be changed and saved.
5672 *
5673 * These are typically transient properties that the guest cannot
5674 * change.
5675 */
5676
5677 {
5678 VBOXHGCMSVCPARM Params[2];
5679 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
5680 if (RT_SUCCESS(rc2))
5681 {
5682 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
5683 void *pService = (void*)Params[1].u.pointer.addr;
5684 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
5685 }
5686 }
5687
5688 /* Sysprep execution by VBoxService. */
5689 configSetProperty(pConsole->m_pVMMDev,
5690 "/VirtualBox/HostGuest/SysprepExec", "",
5691 "TRANSIENT, RDONLYGUEST");
5692 configSetProperty(pConsole->m_pVMMDev,
5693 "/VirtualBox/HostGuest/SysprepArgs", "",
5694 "TRANSIENT, RDONLYGUEST");
5695
5696 /*
5697 * Pull over the properties from the server.
5698 */
5699 SafeArray<BSTR> namesOut;
5700 SafeArray<BSTR> valuesOut;
5701 SafeArray<LONG64> timestampsOut;
5702 SafeArray<BSTR> flagsOut;
5703 HRESULT hrc;
5704 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
5705 ComSafeArrayAsOutParam(valuesOut),
5706 ComSafeArrayAsOutParam(timestampsOut),
5707 ComSafeArrayAsOutParam(flagsOut));
5708 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
5709 size_t cProps = namesOut.size();
5710 size_t cAlloc = cProps + 1;
5711 if ( valuesOut.size() != cProps
5712 || timestampsOut.size() != cProps
5713 || flagsOut.size() != cProps
5714 )
5715 AssertFailedReturn(VERR_INVALID_PARAMETER);
5716
5717 char **papszNames, **papszValues, **papszFlags;
5718 char szEmpty[] = "";
5719 LONG64 *pai64Timestamps;
5720 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5721 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5722 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
5723 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5724 if (papszNames && papszValues && pai64Timestamps && papszFlags)
5725 {
5726 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
5727 {
5728 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
5729 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
5730 if (RT_FAILURE(rc))
5731 break;
5732 if (valuesOut[i])
5733 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
5734 else
5735 papszValues[i] = szEmpty;
5736 if (RT_FAILURE(rc))
5737 break;
5738 pai64Timestamps[i] = timestampsOut[i];
5739 if (flagsOut[i])
5740 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
5741 else
5742 papszFlags[i] = szEmpty;
5743 }
5744 if (RT_SUCCESS(rc))
5745 configSetProperties(pConsole->m_pVMMDev,
5746 (void *)papszNames,
5747 (void *)papszValues,
5748 (void *)pai64Timestamps,
5749 (void *)papszFlags);
5750 for (unsigned i = 0; i < cProps; ++i)
5751 {
5752 RTStrFree(papszNames[i]);
5753 if (valuesOut[i])
5754 RTStrFree(papszValues[i]);
5755 if (flagsOut[i])
5756 RTStrFree(papszFlags[i]);
5757 }
5758 }
5759 else
5760 rc = VERR_NO_MEMORY;
5761 RTMemTmpFree(papszNames);
5762 RTMemTmpFree(papszValues);
5763 RTMemTmpFree(pai64Timestamps);
5764 RTMemTmpFree(papszFlags);
5765 AssertRCReturn(rc, rc);
5766
5767 /*
5768 * These properties have to be set before pulling over the properties
5769 * from the machine XML, to ensure that properties saved in the XML
5770 * will override them.
5771 */
5772 /* Set the raw VBox version string as a guest property. Used for host/guest
5773 * version comparison. */
5774 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
5775 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
5776 /* Set the full VBox version string as a guest property. Can contain vendor-specific
5777 * information/branding and/or pre-release tags. */
5778 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
5779 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
5780 /* Set the VBox SVN revision as a guest property */
5781 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
5782 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
5783
5784 /*
5785 * Register the host notification callback
5786 */
5787 HGCMSVCEXTHANDLE hDummy;
5788 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
5789 Console::i_doGuestPropNotification,
5790 pvConsole);
5791
5792#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
5793 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
5794 guestProp::RDONLYGUEST);
5795 AssertRCReturn(rc, rc);
5796#endif
5797
5798 Log(("Set VBoxGuestPropSvc property store\n"));
5799 }
5800 return VINF_SUCCESS;
5801#else /* !VBOX_WITH_GUEST_PROPS */
5802 return VERR_NOT_SUPPORTED;
5803#endif /* !VBOX_WITH_GUEST_PROPS */
5804}
5805
5806/**
5807 * Set up the Guest Control service.
5808 */
5809/* static */ int Console::i_configGuestControl(void *pvConsole)
5810{
5811#ifdef VBOX_WITH_GUEST_CONTROL
5812 AssertReturn(pvConsole, VERR_INVALID_POINTER);
5813 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
5814
5815 /* Load the service */
5816 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
5817
5818 if (RT_FAILURE(rc))
5819 {
5820 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
5821 /* That is not a fatal failure. */
5822 rc = VINF_SUCCESS;
5823 }
5824 else
5825 {
5826 HGCMSVCEXTHANDLE hDummy;
5827 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
5828 &Guest::i_notifyCtrlDispatcher,
5829 pConsole->i_getGuest());
5830 if (RT_FAILURE(rc))
5831 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
5832 else
5833 LogRel(("Guest Control service loaded\n"));
5834 }
5835
5836 return rc;
5837#else /* !VBOX_WITH_GUEST_CONTROL */
5838 return VERR_NOT_SUPPORTED;
5839#endif /* !VBOX_WITH_GUEST_CONTROL */
5840}
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