VirtualBox

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

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

See #9440 Comment #36

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

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