VirtualBox

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

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

Audio/Main: Also made the video recording driver use the new AudioDriver base class, more bugfixing and clearer abstraction for the AudioDriver API.

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

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