VirtualBox

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

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

Build fix.

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

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