VirtualBox

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

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

updates (bugref:9087)

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