VirtualBox

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

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

ConsoleImpl: Pass BIOS disk information along for SCSI/SAS drives, too.

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

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