VirtualBox

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

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

Main/*: From now on any valid UTF8 string is considered a valid guest OS type. Of course not all of them are known, so the API clients must be prepared to deal with not having a matching IGuestOSType object.
Frontends/VBoxManage+VBoxShell: adjust to deal with the change

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

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