VirtualBox

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

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

Main/Console+Host: winsock2 include fixing

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