VirtualBox

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

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

Main: Only insert ScsiHardDiskDevice CFGM key once.

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

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