VirtualBox

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

Last change on this file since 55988 was 55941, checked in by vboxsync, 10 years ago

Network/HostOnly: Use driver enumeration instead of registry access for trunk type detection (#7849)

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

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