VirtualBox

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

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

Main/Console: when changing a medium or network attachment, suspend the VM before doing the actual VMR3Req* call. Doing this in the EM context has bad side effects, see @bugref{4744} and @bugref{7283}. Also, don't dump the complete device instance but dump only the affected LUN.

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