VirtualBox

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

Last change on this file since 56273 was 56273, checked in by vboxsync, 9 years ago

Main/Console: detect NDIS version without admin privileges (#7849)

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

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