VirtualBox

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

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

Main/ConsoleImpl: Fix config for multiple NVMe controllers if ICH9 is used

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

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