VirtualBox

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

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

DBGC,Main: Global and per-VM debugger console init script support.

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

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