VirtualBox

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

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

Main/ExtPack: also mention that the version of the ExtPack might be incompatible

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