VirtualBox

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

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

don't insist on the presence of the crypt lib

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

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