VirtualBox

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

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

Comments and nits.

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