VirtualBox

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

Last change on this file since 52994 was 52994, checked in by vboxsync, 11 years ago

USB: Forgot to commit part of double LUN change.

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