VirtualBox

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

Last change on this file since 70772 was 70772, checked in by vboxsync, 6 years ago

Doxygen fix

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

© 2023 Oracle
ContactPrivacy policyTerms of Use