VirtualBox

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

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

VMM,Main: Added 286, 186 and 8086 CPU profiles to play with.

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