VirtualBox

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

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

Main/Serial+Devices/Serial: new TCP backend for serial port. Contributed by Alexey Eromenko. Thanks!
Frontends/VirtualBox+VBoxManage: adapted accordingly

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

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