VirtualBox

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

Last change on this file since 70644 was 70644, checked in by vboxsync, 7 years ago

Audio/Main: More code needed for attaching / detaching host backends at runtime.

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