VirtualBox

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

Last change on this file since 59288 was 59288, checked in by vboxsync, 9 years ago

Main: fix for VBOX_WITH_VUSB disabled

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