VirtualBox

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

Last change on this file since 79551 was 79551, checked in by vboxsync, 5 years ago

Main/src-client/ConsoleImpl2.cpp: Make sure that VirtIO SCSI also gets the generic SCSI driver attached inbetween itself and the VD driver

  • 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 79551 2019-07-05 09:16:02Z 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
2416 /* Attach the status driver */
2417 AssertRelease(cPorts <= cLedSata);
2418 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedVirtio], 0, cPorts - 1,
2419 &mapMediumAttachments, pszCtrlDev, ulInstance);
2420 paLedDevType = &maStorageDevType[iLedVirtio];
2421 break;
2422 }
2423
2424 default:
2425 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2426 }
2427
2428 /* Attach the media to the storage controllers. */
2429 com::SafeIfaceArray<IMediumAttachment> atts;
2430 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2431 ComSafeArrayAsOutParam(atts)); H();
2432
2433 /* Builtin I/O cache - per device setting. */
2434 BOOL fBuiltinIOCache = true;
2435 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2436
2437 bool fInsertDiskIntegrityDrv = false;
2438 Bstr strDiskIntegrityFlag;
2439 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2440 strDiskIntegrityFlag.asOutParam());
2441 if ( hrc == S_OK
2442 && strDiskIntegrityFlag == "1")
2443 fInsertDiskIntegrityDrv = true;
2444
2445 for (size_t j = 0; j < atts.size(); ++j)
2446 {
2447 IMediumAttachment *pMediumAtt = atts[j];
2448 rc = i_configMediumAttachment(pszCtrlDev,
2449 ulInstance,
2450 enmBus,
2451 !!fUseHostIOCache,
2452 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2453 fInsertDiskIntegrityDrv,
2454 false /* fSetupMerge */,
2455 0 /* uMergeSource */,
2456 0 /* uMergeTarget */,
2457 pMediumAtt,
2458 mMachineState,
2459 NULL /* phrc */,
2460 false /* fAttachDetach */,
2461 false /* fForceUnmount */,
2462 false /* fHotplug */,
2463 pUVM,
2464 paLedDevType,
2465 NULL /* ppLunL0 */);
2466 if (RT_FAILURE(rc))
2467 return rc;
2468 }
2469 H();
2470 }
2471 H();
2472
2473 /*
2474 * Network adapters
2475 */
2476#ifdef VMWARE_NET_IN_SLOT_11
2477 bool fSwapSlots3and11 = false;
2478#endif
2479 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2480 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2481#ifdef VBOX_WITH_E1000
2482 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2483 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2484#endif
2485#ifdef VBOX_WITH_VIRTIO
2486 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2487 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2488#endif /* VBOX_WITH_VIRTIO */
2489 std::list<BootNic> llBootNics;
2490 for (ULONG ulInstance = 0; ulInstance < maxNetworkAdapters; ++ulInstance)
2491 {
2492 ComPtr<INetworkAdapter> networkAdapter;
2493 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
2494 BOOL fEnabledNetAdapter = FALSE;
2495 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2496 if (!fEnabledNetAdapter)
2497 continue;
2498
2499 /*
2500 * The virtual hardware type. Create appropriate device first.
2501 */
2502 const char *pszAdapterName = "pcnet";
2503 NetworkAdapterType_T adapterType;
2504 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2505 switch (adapterType)
2506 {
2507 case NetworkAdapterType_Am79C970A:
2508 case NetworkAdapterType_Am79C973:
2509 pDev = pDevPCNet;
2510 break;
2511#ifdef VBOX_WITH_E1000
2512 case NetworkAdapterType_I82540EM:
2513 case NetworkAdapterType_I82543GC:
2514 case NetworkAdapterType_I82545EM:
2515 pDev = pDevE1000;
2516 pszAdapterName = "e1000";
2517 break;
2518#endif
2519#ifdef VBOX_WITH_VIRTIO
2520 case NetworkAdapterType_Virtio:
2521 pDev = pDevVirtioNet;
2522 pszAdapterName = "virtio-net";
2523 break;
2524#endif /* VBOX_WITH_VIRTIO */
2525 default:
2526 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
2527 adapterType, ulInstance));
2528 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2529 N_("Invalid network adapter type '%d' for slot '%d'"),
2530 adapterType, ulInstance);
2531 }
2532
2533 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2534 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2535 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2536 * next 4 get 16..19. */
2537 int iPCIDeviceNo;
2538 switch (ulInstance)
2539 {
2540 case 0:
2541 iPCIDeviceNo = 3;
2542 break;
2543 case 1: case 2: case 3:
2544 iPCIDeviceNo = ulInstance - 1 + 8;
2545 break;
2546 case 4: case 5: case 6: case 7:
2547 iPCIDeviceNo = ulInstance - 4 + 16;
2548 break;
2549 default:
2550 /* auto assignment */
2551 iPCIDeviceNo = -1;
2552 break;
2553 }
2554#ifdef VMWARE_NET_IN_SLOT_11
2555 /*
2556 * Dirty hack for PCI slot compatibility with VMWare,
2557 * it assigns slot 0x11 to the first network controller.
2558 */
2559 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2560 {
2561 iPCIDeviceNo = 0x11;
2562 fSwapSlots3and11 = true;
2563 }
2564 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2565 iPCIDeviceNo = 3;
2566#endif
2567 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2568 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2569
2570 InsertConfigNode(pInst, "Config", &pCfg);
2571#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2572 if (pDev == pDevPCNet)
2573 {
2574 InsertConfigInteger(pCfg, "R0Enabled", false);
2575 }
2576#endif
2577 /*
2578 * Collect information needed for network booting and add it to the list.
2579 */
2580 BootNic nic;
2581
2582 nic.mInstance = ulInstance;
2583 /* Could be updated by reference, if auto assigned */
2584 nic.mPCIAddress = PCIAddr;
2585
2586 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2587
2588 llBootNics.push_back(nic);
2589
2590 /*
2591 * The virtual hardware type. PCNet supports two types, E1000 three,
2592 * but VirtIO only one.
2593 */
2594 switch (adapterType)
2595 {
2596 case NetworkAdapterType_Am79C970A:
2597 InsertConfigString(pCfg, "ChipType", "Am79C970A");
2598 break;
2599 case NetworkAdapterType_Am79C973:
2600 InsertConfigString(pCfg, "ChipType", "Am79C973");
2601 break;
2602 case NetworkAdapterType_I82540EM:
2603 InsertConfigInteger(pCfg, "AdapterType", 0);
2604 break;
2605 case NetworkAdapterType_I82543GC:
2606 InsertConfigInteger(pCfg, "AdapterType", 1);
2607 break;
2608 case NetworkAdapterType_I82545EM:
2609 InsertConfigInteger(pCfg, "AdapterType", 2);
2610 break;
2611 case NetworkAdapterType_Virtio:
2612 break;
2613 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
2614#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
2615 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
2616#endif
2617 }
2618
2619 /*
2620 * Get the MAC address and convert it to binary representation
2621 */
2622 Bstr macAddr;
2623 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2624 Assert(!macAddr.isEmpty());
2625 Utf8Str macAddrUtf8 = macAddr;
2626 char *macStr = (char*)macAddrUtf8.c_str();
2627 Assert(strlen(macStr) == 12);
2628 RTMAC Mac;
2629 RT_ZERO(Mac);
2630 char *pMac = (char*)&Mac;
2631 for (uint32_t i = 0; i < 6; ++i)
2632 {
2633 int c1 = *macStr++ - '0';
2634 if (c1 > 9)
2635 c1 -= 7;
2636 int c2 = *macStr++ - '0';
2637 if (c2 > 9)
2638 c2 -= 7;
2639 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2640 }
2641 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2642
2643 /*
2644 * Check if the cable is supposed to be unplugged
2645 */
2646 BOOL fCableConnected;
2647 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2648 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2649
2650 /*
2651 * Line speed to report from custom drivers
2652 */
2653 ULONG ulLineSpeed;
2654 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2655 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2656
2657 /*
2658 * Attach the status driver.
2659 */
2660 i_attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
2661
2662 /*
2663 * Configure the network card now
2664 */
2665 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2666 rc = i_configNetwork(pszAdapterName,
2667 ulInstance,
2668 0,
2669 networkAdapter,
2670 pCfg,
2671 pLunL0,
2672 pInst,
2673 false /*fAttachDetach*/,
2674 fIgnoreConnectFailure);
2675 if (RT_FAILURE(rc))
2676 return rc;
2677 }
2678
2679 /*
2680 * Build network boot information and transfer it to the BIOS.
2681 */
2682 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2683 {
2684 llBootNics.sort(); /* Sort the list by boot priority. */
2685
2686 char achBootIdx[] = "0";
2687 unsigned uBootIdx = 0;
2688
2689 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2690 {
2691 /* A NIC with priority 0 is only used if it's first in the list. */
2692 if (it->mBootPrio == 0 && uBootIdx != 0)
2693 break;
2694
2695 PCFGMNODE pNetBtDevCfg;
2696 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2697 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2698 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2699 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2700 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2701 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2702 }
2703 }
2704
2705 /*
2706 * Serial (UART) Ports
2707 */
2708 /* serial enabled mask to be passed to dev ACPI */
2709 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2710 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2711 InsertConfigNode(pDevices, "serial", &pDev);
2712 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2713 {
2714 ComPtr<ISerialPort> serialPort;
2715 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2716 BOOL fEnabledSerPort = FALSE;
2717 if (serialPort)
2718 {
2719 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2720 }
2721 if (!fEnabledSerPort)
2722 {
2723 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
2724 continue;
2725 }
2726
2727 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2728 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2729 InsertConfigNode(pInst, "Config", &pCfg);
2730
2731 ULONG ulIRQ;
2732 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2733 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2734 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2735
2736 ULONG ulIOBase;
2737 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2738 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2739 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2740
2741 BOOL fServer;
2742 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2743 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2744 UartType_T eUartType;
2745 const char *pszUartType;
2746 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2747 switch (eUartType)
2748 {
2749 case UartType_U16450: pszUartType = "16450"; break;
2750 case UartType_U16750: pszUartType = "16750"; break;
2751 default: AssertFailed(); RT_FALL_THRU();
2752 case UartType_U16550A: pszUartType = "16550A"; break;
2753 }
2754 InsertConfigString(pCfg, "UartType", pszUartType);
2755
2756 PortMode_T eHostMode;
2757 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2758
2759 m_aeSerialPortMode[ulInstance] = eHostMode;
2760 if (eHostMode != PortMode_Disconnected)
2761 {
2762 rc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2763 if (RT_FAILURE(rc))
2764 return rc;
2765 }
2766 }
2767
2768 /*
2769 * Parallel (LPT) Ports
2770 */
2771 /* parallel enabled mask to be passed to dev ACPI */
2772 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2773 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2774 InsertConfigNode(pDevices, "parallel", &pDev);
2775 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2776 {
2777 ComPtr<IParallelPort> parallelPort;
2778 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2779 BOOL fEnabledParPort = FALSE;
2780 if (parallelPort)
2781 {
2782 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2783 }
2784 if (!fEnabledParPort)
2785 continue;
2786
2787 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2788 InsertConfigNode(pInst, "Config", &pCfg);
2789
2790 ULONG ulIRQ;
2791 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2792 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2793 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2794 ULONG ulIOBase;
2795 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2796 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2797 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2798
2799 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2800 if (!bstr.isEmpty())
2801 {
2802 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2803 InsertConfigString(pLunL0, "Driver", "HostParallel");
2804 InsertConfigNode(pLunL0, "Config", &pLunL1);
2805 InsertConfigString(pLunL1, "DevicePath", bstr);
2806 }
2807 }
2808
2809 /*
2810 * VMM Device
2811 */
2812 InsertConfigNode(pDevices, "VMMDev", &pDev);
2813 InsertConfigNode(pDev, "0", &pInst);
2814 InsertConfigNode(pInst, "Config", &pCfg);
2815 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2816 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
2817
2818 Bstr hwVersion;
2819 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
2820 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2821 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2822 Bstr snapshotFolder;
2823 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2824 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2825
2826 /* the VMM device's Main driver */
2827 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2828 InsertConfigString(pLunL0, "Driver", "HGCM");
2829 InsertConfigNode(pLunL0, "Config", &pCfg);
2830 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2831
2832 /*
2833 * Attach the status driver.
2834 */
2835 i_attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
2836
2837 /*
2838 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2839 */
2840 BOOL fAudioEnabled = FALSE;
2841 ComPtr<IAudioAdapter> audioAdapter;
2842 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2843 if (audioAdapter)
2844 {
2845 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2846 }
2847
2848 if (fAudioEnabled)
2849 {
2850 Utf8Str strAudioDevice;
2851
2852 AudioControllerType_T audioController;
2853 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2854 AudioCodecType_T audioCodec;
2855 hrc = audioAdapter->COMGETTER(AudioCodec)(&audioCodec); H();
2856
2857 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
2858 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
2859
2860 Utf8Str strDebugPathOut;
2861 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
2862
2863 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
2864 * without duplicating (more) code. */
2865
2866 switch (audioController)
2867 {
2868 case AudioControllerType_AC97:
2869 {
2870 /* ICH AC'97. */
2871 strAudioDevice = "ichac97";
2872
2873 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2874 InsertConfigNode (pDev, "0", &pInst);
2875 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2876 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2877 InsertConfigNode (pInst, "Config", &pCfg);
2878 switch (audioCodec)
2879 {
2880 case AudioCodecType_STAC9700:
2881 InsertConfigString(pCfg, "Codec", "STAC9700");
2882 break;
2883 case AudioCodecType_AD1980:
2884 InsertConfigString(pCfg, "Codec", "AD1980");
2885 break;
2886 default: AssertFailedBreak();
2887 }
2888 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2889 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2890 break;
2891 }
2892 case AudioControllerType_SB16:
2893 {
2894 /* Legacy SoundBlaster16. */
2895 strAudioDevice = "sb16";
2896
2897 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2898 InsertConfigNode (pDev, "0", &pInst);
2899 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2900 InsertConfigNode (pInst, "Config", &pCfg);
2901 InsertConfigInteger(pCfg, "IRQ", 5);
2902 InsertConfigInteger(pCfg, "DMA", 1);
2903 InsertConfigInteger(pCfg, "DMA16", 5);
2904 InsertConfigInteger(pCfg, "Port", 0x220);
2905 InsertConfigInteger(pCfg, "Version", 0x0405);
2906 break;
2907 }
2908 case AudioControllerType_HDA:
2909 {
2910 /* Intel HD Audio. */
2911 strAudioDevice = "hda";
2912
2913 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2914 InsertConfigNode (pDev, "0", &pInst);
2915 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2916 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2917 InsertConfigNode (pInst, "Config", &pCfg);
2918 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2919 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2920 break;
2921 }
2922 default: AssertFailedBreak();
2923 }
2924
2925 PCFGMNODE pCfgAudioAdapter = NULL;
2926 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
2927 SafeArray<BSTR> audioProps;
2928 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2929
2930 std::list<Utf8Str> audioPropertyNamesList;
2931 for (size_t i = 0; i < audioProps.size(); ++i)
2932 {
2933 Bstr bstrValue;
2934 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2935 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2936 Utf8Str strKey(audioProps[i]);
2937 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
2938 }
2939
2940 /*
2941 * The audio driver.
2942 */
2943 Utf8Str strAudioDriver;
2944
2945 AudioDriverType_T audioDriver;
2946 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2947 switch (audioDriver)
2948 {
2949 case AudioDriverType_Null:
2950 {
2951 strAudioDriver = "NullAudio";
2952 break;
2953 }
2954#ifdef RT_OS_WINDOWS
2955# ifdef VBOX_WITH_WINMM
2956 case AudioDriverType_WinMM:
2957 {
2958 #error "Port WinMM audio backend!" /** @todo Still needed? */
2959 break;
2960 }
2961# endif
2962 case AudioDriverType_DirectSound:
2963 {
2964 strAudioDriver = "DSoundAudio";
2965 break;
2966 }
2967#endif /* RT_OS_WINDOWS */
2968#ifdef RT_OS_SOLARIS
2969 case AudioDriverType_SolAudio:
2970 {
2971 /* Should not happen, as the Solaris Audio backend is not around anymore.
2972 * Remove this sometime later. */
2973 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2974 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2975
2976 /* Manually set backend to OSS for now. */
2977 strAudioDriver = "OSSAudio";
2978 break;
2979 }
2980#endif
2981#ifdef VBOX_WITH_AUDIO_OSS
2982 case AudioDriverType_OSS:
2983 {
2984 strAudioDriver = "OSSAudio";
2985 break;
2986 }
2987#endif
2988#ifdef VBOX_WITH_AUDIO_ALSA
2989 case AudioDriverType_ALSA:
2990 {
2991 strAudioDriver = "ALSAAudio";
2992 break;
2993 }
2994#endif
2995#ifdef VBOX_WITH_AUDIO_PULSE
2996 case AudioDriverType_Pulse:
2997 {
2998 strAudioDriver = "PulseAudio";
2999 break;
3000 }
3001#endif
3002#ifdef RT_OS_DARWIN
3003 case AudioDriverType_CoreAudio:
3004 {
3005 strAudioDriver = "CoreAudio";
3006 break;
3007 }
3008#endif
3009 default: AssertFailedBreak();
3010 }
3011
3012 unsigned uAudioLUN = 0;
3013
3014 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3015 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3016 strAudioDriver.c_str());
3017 if (RT_SUCCESS(rc))
3018 uAudioLUN++;
3019
3020#ifdef VBOX_WITH_AUDIO_VRDE
3021 /* Insert dummy audio driver to have the LUN configured. */
3022 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3023 InsertConfigString(pLunL0, "Driver", "AUDIO");
3024 AudioDriverCfg DrvCfgVRDE(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVRDE");
3025 rc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3026 if (RT_SUCCESS(rc))
3027 uAudioLUN++;
3028#endif /* VBOX_WITH_AUDIO_VRDE */
3029
3030#ifdef VBOX_WITH_AUDIO_RECORDING
3031 /* Insert dummy audio driver to have the LUN configured. */
3032 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3033 InsertConfigString(pLunL0, "Driver", "AUDIO");
3034 AudioDriverCfg DrvCfgVideoRec(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVideoRec");
3035 rc = Recording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3036 if (RT_SUCCESS(rc))
3037 uAudioLUN++;
3038#endif /* VBOX_WITH_AUDIO_RECORDING */
3039
3040 if (fDebugEnabled)
3041 {
3042#ifdef VBOX_WITH_AUDIO_DEBUG
3043 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3044 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3045 "DebugAudio");
3046 if (RT_SUCCESS(rc))
3047 uAudioLUN++;
3048#endif /* VBOX_WITH_AUDIO_DEBUG */
3049
3050 /*
3051 * Tweak the logging groups.
3052 */
3053 Utf8Str strLogGroups = "drv_host_audio.e.l.l2.l3.f+" \
3054 "drv_audio.e.l.l2.l3.f+" \
3055 "audio_mixer.e.l.l2.l3.f+" \
3056 "dev_hda_codec.e.l.l2.l3.f+" \
3057 "dev_hda.e.l.l2.l3.f+" \
3058 "dev_ac97.e.l.l2.l3.f+" \
3059 "dev_sb16.e.l.l2.l3.f";
3060
3061 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strLogGroups.c_str());
3062 if (RT_FAILURE(rc))
3063 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3064 }
3065
3066#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3067 /** @todo Make this a runtime-configurable entry! */
3068
3069 /*
3070 * The ValidationKit backend.
3071 */
3072 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3073 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3074 "ValidationKitAudio");
3075 if (RT_SUCCESS(rc))
3076 uAudioLUN++;
3077#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3078 }
3079
3080#ifdef VBOX_WITH_SHARED_CLIPBOARD
3081 /*
3082 * Shared Clipboard.
3083 */
3084 {
3085 if (SharedClipboard::createInstance(this /* pConsole */) == NULL)
3086 {
3087 rc = VERR_NO_MEMORY;
3088 }
3089 else
3090 {
3091 /* Load the service */
3092 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3093 if (RT_SUCCESS(rc))
3094 {
3095 LogRel(("Shared Clipboard: Service loaded\n"));
3096 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtShrdClipboard, "VBoxSharedClipboard",
3097 &Console::i_sharedClipboardServiceCallback,
3098 this /* pvExtension */);
3099 if (RT_FAILURE(rc))
3100 {
3101 LogRel(("Shared Clipboard: Cannot register service extension, rc=%Rrc\n", rc));
3102 }
3103 else
3104 {
3105 /* Set initial clipboard mode. */
3106 ClipboardMode_T mode = ClipboardMode_Disabled;
3107 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3108
3109 rc = i_changeClipboardMode(mode);
3110 if (RT_SUCCESS(rc))
3111 {
3112 /* Setup the service. */
3113 VBOXHGCMSVCPARM parm;
3114 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3115 rc = SHAREDCLIPBOARDINST()->hostCall(VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3116 if (RT_FAILURE(rc))
3117 LogRel(("Shared Clipboard: Unable to set initial headless mode, rc=%Rrc\n", rc));
3118 }
3119 }
3120 }
3121 }
3122
3123 if (RT_FAILURE(rc))
3124 {
3125 LogRel(("Shared Clipboard: Not available, rc=%Rrc\n", rc));
3126 /* That is not a fatal failure. */
3127 rc = VINF_SUCCESS;
3128 }
3129 }
3130#endif /* VBOX_WITH_SHARED_CLIPBOARD */
3131
3132 /*
3133 * HGCM HostChannel.
3134 */
3135 {
3136 Bstr value;
3137 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3138 value.asOutParam());
3139
3140 if ( hrc == S_OK
3141 && value == "1")
3142 {
3143 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3144 if (RT_FAILURE(rc))
3145 {
3146 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3147 /* That is not a fatal failure. */
3148 rc = VINF_SUCCESS;
3149 }
3150 }
3151 }
3152
3153#ifdef VBOX_WITH_DRAG_AND_DROP
3154 /*
3155 * Drag and Drop.
3156 */
3157 {
3158 DnDMode_T enmMode = DnDMode_Disabled;
3159 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3160
3161 /* Load the service */
3162 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3163 if (RT_FAILURE(rc))
3164 {
3165 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3166 /* That is not a fatal failure. */
3167 rc = VINF_SUCCESS;
3168 }
3169 else
3170 {
3171 rc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
3172 &GuestDnD::notifyDnDDispatcher,
3173 GUESTDNDINST());
3174 if (RT_FAILURE(rc))
3175 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3176 else
3177 {
3178 LogRel(("Drag and drop service loaded\n"));
3179 rc = i_changeDnDMode(enmMode);
3180 }
3181 }
3182 }
3183#endif /* VBOX_WITH_DRAG_AND_DROP */
3184
3185#ifdef VBOX_WITH_CROGL
3186 /*
3187 * crOpenGL.
3188 */
3189 {
3190 BOOL fEnabled3D = false;
3191 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3192
3193 if ( fEnabled3D
3194# ifdef VBOX_WITH_VMSVGA3D
3195 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3196# endif
3197 )
3198 {
3199 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3200 if (!fSupports3D)
3201 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3202 N_("This VM was configured to use 3D acceleration. However, the "
3203 "3D support of the host is not working properly and the "
3204 "VM cannot be started. To fix this problem, either "
3205 "fix the host 3D support (update the host graphics driver?) "
3206 "or disable 3D acceleration in the VM settings"));
3207
3208 /* Load the service. */
3209 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3210 if (RT_FAILURE(rc))
3211 {
3212 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3213 /* That is not a fatal failure. */
3214 rc = VINF_SUCCESS;
3215 }
3216 else
3217 {
3218 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3219
3220 /* Setup the service. */
3221 VBOXHGCMSVCPARM parm;
3222 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3223
3224 parm.u.pointer.addr = (IConsole *)(Console *)this;
3225 parm.u.pointer.size = sizeof(IConsole *);
3226
3227 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3228 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3229 if (!RT_SUCCESS(rc))
3230 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3231
3232 parm.u.pointer.addr = pVM;
3233 parm.u.pointer.size = sizeof(pVM);
3234 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3235 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3236 if (!RT_SUCCESS(rc))
3237 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3238 }
3239 }
3240 }
3241#endif
3242
3243 /*
3244 * ACPI
3245 */
3246 BOOL fACPI;
3247 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3248 if (fACPI)
3249 {
3250 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3251 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3252 * intelppm driver refuses to register an idle state handler.
3253 * Always show CPU leafs for OS X guests. */
3254 BOOL fShowCpu = fOsXGuest;
3255 if (cCpus > 1 || fIOAPIC)
3256 fShowCpu = true;
3257
3258 BOOL fCpuHotPlug;
3259 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3260
3261 InsertConfigNode(pDevices, "acpi", &pDev);
3262 InsertConfigNode(pDev, "0", &pInst);
3263 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3264 InsertConfigNode(pInst, "Config", &pCfg);
3265 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3266
3267 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3268
3269 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3270 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3271 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3272 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3273 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3274 if (fOsXGuest && !llBootNics.empty())
3275 {
3276 BootNic aNic = llBootNics.front();
3277 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3278 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3279 }
3280 if (fOsXGuest && fAudioEnabled)
3281 {
3282 PCIBusAddress Address;
3283 if (pBusMgr->findPCIAddress("hda", 0, Address))
3284 {
3285 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3286 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3287 }
3288 }
3289 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3290 if (chipsetType == ChipsetType_ICH9)
3291 {
3292 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3293 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3294 /* 64-bit prefetch window root resource:
3295 * Only for ICH9 and if PAE or Long Mode is enabled.
3296 * And only with hardware virtualization (@bugref{5454}). */
3297 if ( (fEnablePAE || fIsGuest64Bit)
3298 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3299 otherwise VMM falls back to raw mode */
3300 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3301 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3302 }
3303 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3304 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3305 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3306
3307 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3308 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3309
3310 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3311 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3312
3313 if (auSerialIoPortBase[2])
3314 {
3315 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3316 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3317 }
3318
3319 if (auSerialIoPortBase[3])
3320 {
3321 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3322 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3323 }
3324
3325 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3326 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3327
3328 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3329 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3330
3331 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3332 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3333 InsertConfigNode(pLunL0, "Config", &pCfg);
3334
3335 /* Attach the dummy CPU drivers */
3336 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3337 {
3338 BOOL fCpuAttached = true;
3339
3340 if (fCpuHotPlug)
3341 {
3342 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3343 }
3344
3345 if (fCpuAttached)
3346 {
3347 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3348 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3349 InsertConfigNode(pLunL0, "Config", &pCfg);
3350 }
3351 }
3352 }
3353
3354 /*
3355 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3356 */
3357 {
3358 PCFGMNODE pDbgf;
3359 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3360
3361 /* Paths to search for debug info and such things. */
3362 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3363 Utf8Str strSettingsPath(bstr);
3364 bstr.setNull();
3365 strSettingsPath.stripFilename();
3366 strSettingsPath.append("/");
3367
3368 char szHomeDir[RTPATH_MAX + 1];
3369 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3370 if (RT_FAILURE(rc2))
3371 szHomeDir[0] = '\0';
3372 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3373
3374
3375 Utf8Str strPath;
3376 strPath.append(strSettingsPath).append("debug/;");
3377 strPath.append(strSettingsPath).append(";");
3378 strPath.append(szHomeDir);
3379
3380 InsertConfigString(pDbgf, "Path", strPath.c_str());
3381
3382 /* Tracing configuration. */
3383 BOOL fTracingEnabled;
3384 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3385 if (fTracingEnabled)
3386 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3387
3388 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3389 if (fTracingEnabled)
3390 InsertConfigString(pDbgf, "TracingConfig", bstr);
3391
3392 BOOL fAllowTracingToAccessVM;
3393 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3394 if (fAllowTracingToAccessVM)
3395 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3396
3397 /* Debugger console config. */
3398 PCFGMNODE pDbgc;
3399 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3400
3401 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3402 Utf8Str strVBoxHome = bstr;
3403 bstr.setNull();
3404 if (strVBoxHome.isNotEmpty())
3405 strVBoxHome.append("/");
3406 else
3407 {
3408 strVBoxHome = szHomeDir;
3409 strVBoxHome.append("/.vbox");
3410 }
3411
3412 Utf8Str strFile(strVBoxHome);
3413 strFile.append("dbgc-history");
3414 InsertConfigString(pDbgc, "HistoryFile", strFile);
3415
3416 strFile = strSettingsPath;
3417 strFile.append("dbgc-init");
3418 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3419
3420 strFile = strVBoxHome;
3421 strFile.append("dbgc-init");
3422 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3423 }
3424 }
3425 catch (ConfigError &x)
3426 {
3427 // InsertConfig threw something:
3428 return x.m_vrc;
3429 }
3430 catch (HRESULT hrcXcpt)
3431 {
3432 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3433 }
3434
3435#ifdef VBOX_WITH_EXTPACK
3436 /*
3437 * Call the extension pack hooks if everything went well thus far.
3438 */
3439 if (RT_SUCCESS(rc))
3440 {
3441 pAlock->release();
3442 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3443 pAlock->acquire();
3444 }
3445#endif
3446
3447 /*
3448 * Apply the CFGM overlay.
3449 */
3450 if (RT_SUCCESS(rc))
3451 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3452
3453 /*
3454 * Dump all extradata API settings tweaks, both global and per VM.
3455 */
3456 if (RT_SUCCESS(rc))
3457 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3458
3459#undef H
3460
3461 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3462
3463 /*
3464 * Register VM state change handler.
3465 */
3466 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3467 AssertRC(rc2);
3468 if (RT_SUCCESS(rc))
3469 rc = rc2;
3470
3471 /*
3472 * Register VM runtime error handler.
3473 */
3474 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3475 AssertRC(rc2);
3476 if (RT_SUCCESS(rc))
3477 rc = rc2;
3478
3479 pAlock->acquire();
3480
3481 LogFlowFunc(("vrc = %Rrc\n", rc));
3482 LogFlowFuncLeave();
3483
3484 return rc;
3485}
3486
3487/**
3488 * Retrieves an uint32_t value from the audio driver's extra data branch
3489 * (VBoxInternal2/Audio/DriverName/Value), or, if not found, use global branch
3490 * (VBoxInternal2/Audio/Value).
3491 *
3492 * The driver branch always supersedes the global branch.
3493 * If both branches are not found (empty), return the given default value.
3494 *
3495 * @return VBox status code.
3496 * @param pVirtualBox Pointer to IVirtualBox instance.
3497 * @param pMachine Pointer to IMachine instance.
3498 * @param pszDriverName Audio driver name to retrieve value for.
3499 * @param pszValue Value name to retrieve.
3500 * @param uDefault Default value to return if value not found / invalid.
3501 */
3502uint32_t Console::i_getAudioDriverValU32(IVirtualBox *pVirtualBox, IMachine *pMachine,
3503 const char *pszDriverName, const char *pszValue, uint32_t uDefault)
3504{
3505 Utf8Str strTmp;
3506
3507 Utf8StrFmt strPathDrv("VBoxInternal2/Audio/%s/%s", pszDriverName, pszValue);
3508 GetExtraDataBoth(pVirtualBox, pMachine, strPathDrv.c_str(), &strTmp);
3509 if (strTmp.isEmpty())
3510 {
3511 Utf8StrFmt strPathGlobal("VBoxInternal2/Audio/%s", pszValue);
3512 GetExtraDataBoth(pVirtualBox, pMachine, strPathGlobal.c_str(), &strTmp);
3513 if (strTmp.isNotEmpty())
3514 return strTmp.toUInt32();
3515 }
3516 else /* Return driver-specific value. */
3517 return strTmp.toUInt32();
3518
3519 return uDefault;
3520}
3521
3522/**
3523 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3524 *
3525 * @return VBox status code.
3526 * @param pAudioAdapter Pointer to audio adapter instance. Needed for the driver's input / output configuration.
3527 * @param pVirtualBox Pointer to IVirtualBox instance.
3528 * @param pMachine Pointer to IMachine instance.
3529 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3530 * @param pszDrvName Name of the driver to configure.
3531 */
3532int Console::i_configAudioDriver(IAudioAdapter *pAudioAdapter, IVirtualBox *pVirtualBox, IMachine *pMachine,
3533 PCFGMNODE pLUN, const char *pszDrvName)
3534{
3535#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3536
3537 HRESULT hrc;
3538
3539 Utf8Str strTmp;
3540 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3541 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
3542
3543 BOOL fAudioEnabledIn = FALSE;
3544 hrc = pAudioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3545 BOOL fAudioEnabledOut = FALSE;
3546 hrc = pAudioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut);
3547
3548 InsertConfigString(pLUN, "Driver", "AUDIO");
3549
3550 PCFGMNODE pCfg;
3551 InsertConfigNode(pLUN, "Config", &pCfg);
3552 InsertConfigString (pCfg, "DriverName", pszDrvName);
3553 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3554 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3555
3556 if (fDebugEnabled)
3557 {
3558 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3559
3560 Utf8Str strDebugPathOut;
3561 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3562 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3563 }
3564
3565 InsertConfigInteger(pCfg, "PeriodSizeMs",
3566 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PeriodSizeMs", 0 /* Default */));
3567 InsertConfigInteger(pCfg, "BufferSizeMs",
3568 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "BufferSizeMs", 0 /* Default */));
3569 InsertConfigInteger(pCfg, "PreBufferSizeMs",
3570 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PreBufferSizeMs", UINT32_MAX /* Default */));
3571
3572 PCFGMNODE pLunL1;
3573 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3574
3575 InsertConfigNode(pLunL1, "Config", &pCfg);
3576
3577 Bstr bstrTmp;
3578 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3579 InsertConfigString(pCfg, "StreamName", bstrTmp);
3580
3581 InsertConfigString(pLunL1, "Driver", pszDrvName);
3582
3583 LogFlowFunc(("szDrivName=%s, hrc=%Rhrc\n", pszDrvName, hrc));
3584 return hrc;
3585
3586#undef H
3587}
3588
3589/**
3590 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3591 * values.
3592 *
3593 * @returns VBox status code.
3594 * @param pRoot The root of the configuration tree.
3595 * @param pVirtualBox Pointer to the IVirtualBox interface.
3596 * @param pMachine Pointer to the IMachine interface.
3597 */
3598/* static */
3599int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3600{
3601 /*
3602 * CFGM overlay handling.
3603 *
3604 * Here we check the extra data entries for CFGM values
3605 * and create the nodes and insert the values on the fly. Existing
3606 * values will be removed and reinserted. CFGM is typed, so by default
3607 * we will guess whether it's a string or an integer (byte arrays are
3608 * not currently supported). It's possible to override this autodetection
3609 * by adding "string:", "integer:" or "bytes:" (future).
3610 *
3611 * We first perform a run on global extra data, then on the machine
3612 * extra data to support global settings with local overrides.
3613 */
3614 int rc = VINF_SUCCESS;
3615 try
3616 {
3617 /** @todo add support for removing nodes and byte blobs. */
3618 /*
3619 * Get the next key
3620 */
3621 SafeArray<BSTR> aGlobalExtraDataKeys;
3622 SafeArray<BSTR> aMachineExtraDataKeys;
3623 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3624 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3625
3626 // remember the no. of global values so we can call the correct method below
3627 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3628
3629 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3630 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3631
3632 // build a combined list from global keys...
3633 std::list<Utf8Str> llExtraDataKeys;
3634
3635 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3636 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3637 // ... and machine keys
3638 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3639 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3640
3641 size_t i2 = 0;
3642 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3643 it != llExtraDataKeys.end();
3644 ++it, ++i2)
3645 {
3646 const Utf8Str &strKey = *it;
3647
3648 /*
3649 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3650 */
3651 if (!strKey.startsWith("VBoxInternal/"))
3652 continue;
3653
3654 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3655
3656 // get the value
3657 Bstr bstrExtraDataValue;
3658 if (i2 < cGlobalValues)
3659 // this is still one of the global values:
3660 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3661 bstrExtraDataValue.asOutParam());
3662 else
3663 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3664 bstrExtraDataValue.asOutParam());
3665 if (FAILED(hrc))
3666 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3667
3668 /*
3669 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3670 * Split the two and get the node, delete the value and create the node
3671 * if necessary.
3672 */
3673 PCFGMNODE pNode;
3674 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3675 if (pszCFGMValueName)
3676 {
3677 /* terminate the node and advance to the value (Utf8Str might not
3678 offically like this but wtf) */
3679 *(char*)pszCFGMValueName = '\0';
3680 ++pszCFGMValueName;
3681
3682 /* does the node already exist? */
3683 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3684 if (pNode)
3685 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3686 else
3687 {
3688 /* create the node */
3689 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3690 if (RT_FAILURE(rc))
3691 {
3692 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3693 continue;
3694 }
3695 Assert(pNode);
3696 }
3697 }
3698 else
3699 {
3700 /* root value (no node path). */
3701 pNode = pRoot;
3702 pszCFGMValueName = pszExtraDataKey;
3703 pszExtraDataKey--;
3704 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3705 }
3706
3707 /*
3708 * Now let's have a look at the value.
3709 * Empty strings means that we should remove the value, which we've
3710 * already done above.
3711 */
3712 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3713 if (!strCFGMValueUtf8.isEmpty())
3714 {
3715 uint64_t u64Value;
3716
3717 /* check for type prefix first. */
3718 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3719 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3720 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3721 {
3722 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3723 if (RT_SUCCESS(rc))
3724 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3725 }
3726 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3727 {
3728 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3729 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3730 if (cbValue > 0)
3731 {
3732 void *pvBytes = RTMemTmpAlloc(cbValue);
3733 if (pvBytes)
3734 {
3735 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3736 if (RT_SUCCESS(rc))
3737 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3738 RTMemTmpFree(pvBytes);
3739 }
3740 else
3741 rc = VERR_NO_TMP_MEMORY;
3742 }
3743 else if (cbValue == 0)
3744 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3745 else
3746 rc = VERR_INVALID_BASE64_ENCODING;
3747 }
3748 /* auto detect type. */
3749 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3750 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3751 else
3752 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3753 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3754 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3755 }
3756 }
3757 }
3758 catch (ConfigError &x)
3759 {
3760 // InsertConfig threw something:
3761 return x.m_vrc;
3762 }
3763 return rc;
3764}
3765
3766/**
3767 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3768 * values.
3769 *
3770 * @returns VBox status code.
3771 * @param pVirtualBox Pointer to the IVirtualBox interface.
3772 * @param pMachine Pointer to the IMachine interface.
3773 */
3774/* static */
3775int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3776{
3777 {
3778 SafeArray<BSTR> aGlobalExtraDataKeys;
3779 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3780 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3781 bool hasKey = false;
3782 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3783 {
3784 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3785 if (!strKey.startsWith("VBoxInternal2/"))
3786 continue;
3787
3788 Bstr bstrValue;
3789 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3790 bstrValue.asOutParam());
3791 if (FAILED(hrc))
3792 continue;
3793 if (!hasKey)
3794 LogRel(("Global extradata API settings:\n"));
3795 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3796 hasKey = true;
3797 }
3798 }
3799
3800 {
3801 SafeArray<BSTR> aMachineExtraDataKeys;
3802 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3803 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3804 bool hasKey = false;
3805 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3806 {
3807 Utf8Str strKey(aMachineExtraDataKeys[i]);
3808 if (!strKey.startsWith("VBoxInternal2/"))
3809 continue;
3810
3811 Bstr bstrValue;
3812 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3813 bstrValue.asOutParam());
3814 if (FAILED(hrc))
3815 continue;
3816 if (!hasKey)
3817 LogRel(("Per-VM extradata API settings:\n"));
3818 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3819 hasKey = true;
3820 }
3821 }
3822
3823 return VINF_SUCCESS;
3824}
3825
3826int Console::i_configGraphicsController(PCFGMNODE pDevices,
3827 const GraphicsControllerType_T enmGraphicsController,
3828 BusAssignmentManager *pBusMgr,
3829 const ComPtr<IMachine> &ptrMachine,
3830 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3831 bool fHMEnabled)
3832{
3833 // InsertConfig* throws
3834 try
3835 {
3836 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3837 HRESULT hrc;
3838 Bstr bstr;
3839 const char *pcszDevice = "vga";
3840
3841#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3842 InsertConfigNode(pDevices, pcszDevice, &pDev);
3843 InsertConfigNode(pDev, "0", &pInst);
3844 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3845
3846 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3847 InsertConfigNode(pInst, "Config", &pCfg);
3848 ULONG cVRamMBs;
3849 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3850 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3851 ULONG cMonitorCount;
3852 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3853 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3854#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3855 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3856#else
3857 NOREF(fHMEnabled);
3858#endif
3859 BOOL f3DEnabled;
3860 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3861 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3862
3863 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3864
3865#ifdef VBOX_WITH_VMSVGA
3866 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
3867 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
3868 {
3869 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3870 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3871 {
3872 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
3873 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
3874 }
3875# ifdef VBOX_WITH_VMSVGA3D
3876 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3877# else
3878 LogRel(("VMSVGA3d not available in this build!\n"));
3879# endif
3880 }
3881#endif
3882
3883 /* Custom VESA mode list */
3884 unsigned cModes = 0;
3885 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3886 {
3887 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3888 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3889 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3890 if (bstr.isEmpty())
3891 break;
3892 InsertConfigString(pCfg, szExtraDataKey, bstr);
3893 ++cModes;
3894 }
3895 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3896
3897 /* VESA height reduction */
3898 ULONG ulHeightReduction;
3899 IFramebuffer *pFramebuffer = NULL;
3900 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3901 if (SUCCEEDED(hrc) && pFramebuffer)
3902 {
3903 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3904 pFramebuffer->Release();
3905 pFramebuffer = NULL;
3906 }
3907 else
3908 {
3909 /* If framebuffer is not available, there is no height reduction. */
3910 ulHeightReduction = 0;
3911 }
3912 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3913
3914 /*
3915 * BIOS logo
3916 */
3917 BOOL fFadeIn;
3918 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3919 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3920 BOOL fFadeOut;
3921 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3922 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3923 ULONG logoDisplayTime;
3924 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3925 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3926 Bstr logoImagePath;
3927 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3928 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3929
3930 /*
3931 * Boot menu
3932 */
3933 BIOSBootMenuMode_T eBootMenuMode;
3934 int iShowBootMenu;
3935 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3936 switch (eBootMenuMode)
3937 {
3938 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3939 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3940 default: iShowBootMenu = 2; break;
3941 }
3942 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3943
3944 /* Attach the display. */
3945 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3946 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3947 InsertConfigNode(pLunL0, "Config", &pCfg);
3948 Display *pDisplay = mDisplay;
3949 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3950 }
3951 catch (ConfigError &x)
3952 {
3953 // InsertConfig threw something:
3954 return x.m_vrc;
3955 }
3956
3957#undef H
3958
3959 return VINF_SUCCESS;
3960}
3961
3962
3963/**
3964 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3965 */
3966void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3967{
3968 va_list va;
3969 va_start(va, pszFormat);
3970 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3971 va_end(va);
3972}
3973
3974/* XXX introduce RT format specifier */
3975static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3976{
3977 if (u64Size > INT64_C(5000)*_1G)
3978 {
3979 *pszUnit = "TB";
3980 return u64Size / _1T;
3981 }
3982 else if (u64Size > INT64_C(5000)*_1M)
3983 {
3984 *pszUnit = "GB";
3985 return u64Size / _1G;
3986 }
3987 else
3988 {
3989 *pszUnit = "MB";
3990 return u64Size / _1M;
3991 }
3992}
3993
3994/**
3995 * Checks the location of the given medium for known bugs affecting the usage
3996 * of the host I/O cache setting.
3997 *
3998 * @returns VBox status code.
3999 * @param pMedium The medium to check.
4000 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
4001 */
4002int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
4003{
4004#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4005 /*
4006 * Some sanity checks.
4007 */
4008 RT_NOREF(pfUseHostIOCache);
4009 ComPtr<IMediumFormat> pMediumFormat;
4010 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
4011 ULONG uCaps = 0;
4012 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
4013 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
4014
4015 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
4016 uCaps |= mediumFormatCap[j];
4017
4018 if (uCaps & MediumFormatCapabilities_File)
4019 {
4020 Bstr strFile;
4021 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4022 Utf8Str utfFile = Utf8Str(strFile);
4023 Bstr strSnap;
4024 ComPtr<IMachine> pMachine = i_machine();
4025 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
4026 Utf8Str utfSnap = Utf8Str(strSnap);
4027 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4028 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
4029 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4030 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
4031 /* Ignore the error code. On error, the file system type is still 'unknown' so
4032 * none of the following paths are taken. This can happen for new VMs which
4033 * still don't have a snapshot folder. */
4034 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
4035 if (!mfSnapshotFolderDiskTypeShown)
4036 {
4037 LogRel(("File system of '%s' (snapshots) is %s\n",
4038 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4039 mfSnapshotFolderDiskTypeShown = true;
4040 }
4041 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4042 LONG64 i64Size;
4043 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4044#ifdef RT_OS_WINDOWS
4045 if ( enmFsTypeFile == RTFSTYPE_FAT
4046 && i64Size >= _4G)
4047 {
4048 const char *pszUnit;
4049 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4050 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4051 N_("The medium '%ls' has a logical size of %RU64%s "
4052 "but the file system the medium is located on seems "
4053 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4054 "We strongly recommend to put all your virtual disk images and "
4055 "the snapshot folder onto an NTFS partition"),
4056 strFile.raw(), u64Print, pszUnit);
4057 }
4058#else /* !RT_OS_WINDOWS */
4059 if ( enmFsTypeFile == RTFSTYPE_FAT
4060 || enmFsTypeFile == RTFSTYPE_EXT
4061 || enmFsTypeFile == RTFSTYPE_EXT2
4062 || enmFsTypeFile == RTFSTYPE_EXT3
4063 || enmFsTypeFile == RTFSTYPE_EXT4)
4064 {
4065 RTFILE file;
4066 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4067 if (RT_SUCCESS(rc))
4068 {
4069 RTFOFF maxSize;
4070 /* Careful: This function will work only on selected local file systems! */
4071 rc = RTFileGetMaxSizeEx(file, &maxSize);
4072 RTFileClose(file);
4073 if ( RT_SUCCESS(rc)
4074 && maxSize > 0
4075 && i64Size > (LONG64)maxSize)
4076 {
4077 const char *pszUnitSiz;
4078 const char *pszUnitMax;
4079 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4080 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4081 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4082 N_("The medium '%ls' has a logical size of %RU64%s "
4083 "but the file system the medium is located on can "
4084 "only handle files up to %RU64%s in theory.\n"
4085 "We strongly recommend to put all your virtual disk "
4086 "images and the snapshot folder onto a proper "
4087 "file system (e.g. ext3) with a sufficient size"),
4088 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4089 }
4090 }
4091 }
4092#endif /* !RT_OS_WINDOWS */
4093
4094 /*
4095 * Snapshot folder:
4096 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4097 */
4098 if ( enmFsTypeSnap == RTFSTYPE_FAT
4099 && i64Size >= _4G
4100 && !mfSnapshotFolderSizeWarningShown)
4101 {
4102 const char *pszUnit;
4103 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4104 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4105#ifdef RT_OS_WINDOWS
4106 N_("The snapshot folder of this VM '%ls' seems to be located on "
4107 "a FAT(32) file system. The logical size of the medium '%ls' "
4108 "(%RU64%s) is bigger than the maximum file size this file "
4109 "system can handle (4GB).\n"
4110 "We strongly recommend to put all your virtual disk images and "
4111 "the snapshot folder onto an NTFS partition"),
4112#else
4113 N_("The snapshot folder of this VM '%ls' seems to be located on "
4114 "a FAT(32) file system. The logical size of the medium '%ls' "
4115 "(%RU64%s) is bigger than the maximum file size this file "
4116 "system can handle (4GB).\n"
4117 "We strongly recommend to put all your virtual disk images and "
4118 "the snapshot folder onto a proper file system (e.g. ext3)"),
4119#endif
4120 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4121 /* Show this particular warning only once */
4122 mfSnapshotFolderSizeWarningShown = true;
4123 }
4124
4125#ifdef RT_OS_LINUX
4126 /*
4127 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4128 * on an ext4 partition.
4129 * This bug apparently applies to the XFS file system as well.
4130 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4131 */
4132
4133 char szOsRelease[128];
4134 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4135 bool fKernelHasODirectBug = RT_FAILURE(rc)
4136 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4137
4138 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4139 && !*pfUseHostIOCache
4140 && fKernelHasODirectBug)
4141 {
4142 if ( enmFsTypeFile == RTFSTYPE_EXT4
4143 || enmFsTypeFile == RTFSTYPE_XFS)
4144 {
4145 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4146 N_("The host I/O cache for at least one controller is disabled "
4147 "and the medium '%ls' for this VM "
4148 "is located on an %s partition. There is a known Linux "
4149 "kernel bug which can lead to the corruption of the virtual "
4150 "disk image under these conditions.\n"
4151 "Either enable the host I/O cache permanently in the VM "
4152 "settings or put the disk image and the snapshot folder "
4153 "onto a different file system.\n"
4154 "The host I/O cache will now be enabled for this medium"),
4155 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4156 *pfUseHostIOCache = true;
4157 }
4158 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4159 || enmFsTypeSnap == RTFSTYPE_XFS)
4160 && !mfSnapshotFolderExt4WarningShown)
4161 {
4162 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4163 N_("The host I/O cache for at least one controller is disabled "
4164 "and the snapshot folder for this VM "
4165 "is located on an %s partition. There is a known Linux "
4166 "kernel bug which can lead to the corruption of the virtual "
4167 "disk image under these conditions.\n"
4168 "Either enable the host I/O cache permanently in the VM "
4169 "settings or put the disk image and the snapshot folder "
4170 "onto a different file system.\n"
4171 "The host I/O cache will now be enabled for this medium"),
4172 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4173 *pfUseHostIOCache = true;
4174 mfSnapshotFolderExt4WarningShown = true;
4175 }
4176 }
4177
4178 /*
4179 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4180 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4181 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4182 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4183 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4184 */
4185 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4186 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4187 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4188 && !*pfUseHostIOCache
4189 && fKernelAsyncUnreliable)
4190 {
4191 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4192 N_("The host I/O cache for at least one controller is disabled. "
4193 "There is a known Linux kernel bug which can lead to kernel "
4194 "oopses under heavy load. To our knowledge this bug affects "
4195 "all 2.6.18 kernels.\n"
4196 "Either enable the host I/O cache permanently in the VM "
4197 "settings or switch to a newer host kernel.\n"
4198 "The host I/O cache will now be enabled for this medium"));
4199 *pfUseHostIOCache = true;
4200 }
4201#endif
4202 }
4203#undef H
4204
4205 return VINF_SUCCESS;
4206}
4207
4208/**
4209 * Unmounts the specified medium from the specified device.
4210 *
4211 * @returns VBox status code.
4212 * @param pUVM The usermode VM handle.
4213 * @param enmBus The storage bus.
4214 * @param enmDevType The device type.
4215 * @param pcszDevice The device emulation.
4216 * @param uInstance Instance of the device.
4217 * @param uLUN The LUN on the device.
4218 * @param fForceUnmount Whether to force unmounting.
4219 */
4220int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4221 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4222 bool fForceUnmount)
4223{
4224 /* Unmount existing media only for floppy and DVD drives. */
4225 int rc = VINF_SUCCESS;
4226 PPDMIBASE pBase;
4227 if (enmBus == StorageBus_USB)
4228 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4229 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4230 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4231 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4232 else /* IDE or Floppy */
4233 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4234
4235 if (RT_FAILURE(rc))
4236 {
4237 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4238 rc = VINF_SUCCESS;
4239 AssertRC(rc);
4240 }
4241 else
4242 {
4243 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4244 AssertReturn(pIMount, VERR_INVALID_POINTER);
4245
4246 /* Unmount the media (but do not eject the medium!) */
4247 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4248 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4249 rc = VINF_SUCCESS;
4250 /* for example if the medium is locked */
4251 else if (RT_FAILURE(rc))
4252 return rc;
4253 }
4254
4255 return rc;
4256}
4257
4258/**
4259 * Removes the currently attached medium driver form the specified device
4260 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4261 *
4262 * @returns VBox status code.
4263 * @param pCtlInst The controler instance node in the CFGM tree.
4264 * @param pcszDevice The device name.
4265 * @param uInstance The device instance.
4266 * @param uLUN The device LUN.
4267 * @param enmBus The storage bus.
4268 * @param fAttachDetach Flag whether this is a change while the VM is running
4269 * @param fHotplug Flag whether the guest should be notified about the device change.
4270 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4271 * @param pUVM The usermode VM handle.
4272 * @param enmDevType The device type.
4273 * @param ppLunL0 Where to store the node to attach the new config to on success.
4274 */
4275int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4276 const char *pcszDevice,
4277 unsigned uInstance,
4278 unsigned uLUN,
4279 StorageBus_T enmBus,
4280 bool fAttachDetach,
4281 bool fHotplug,
4282 bool fForceUnmount,
4283 PUVM pUVM,
4284 DeviceType_T enmDevType,
4285 PCFGMNODE *ppLunL0)
4286{
4287 int rc = VINF_SUCCESS;
4288 bool fAddLun = false;
4289
4290 /* First check if the LUN already exists. */
4291 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4292 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4293
4294 if (pLunL0)
4295 {
4296 /*
4297 * Unmount the currently mounted medium if we don't just hot remove the
4298 * complete device (SATA) and it supports unmounting (DVD).
4299 */
4300 if ( (enmDevType != DeviceType_HardDisk)
4301 && !fHotplug)
4302 {
4303 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4304 uInstance, uLUN, fForceUnmount);
4305 if (RT_FAILURE(rc))
4306 return rc;
4307 }
4308
4309 /*
4310 * Don't detach the SCSI driver when unmounting the current medium
4311 * (we are not ripping out the device but only eject the medium).
4312 */
4313 char *pszDriverDetach = NULL;
4314 if ( !fHotplug
4315 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4316 || enmBus == StorageBus_SAS
4317 || enmBus == StorageBus_SCSI
4318 || enmBus == StorageBus_VirtioSCSI
4319 || enmBus == StorageBus_USB))
4320 {
4321 /* Get the current attached driver we have to detach. */
4322 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4323 if (pDrvLun)
4324 {
4325 char szDriver[128];
4326 RT_ZERO(szDriver);
4327 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4328 if (RT_SUCCESS(rc))
4329 pszDriverDetach = RTStrDup(&szDriver[0]);
4330
4331 pLunL0 = pDrvLun;
4332 }
4333 }
4334
4335 if (enmBus == StorageBus_USB)
4336 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4337 pszDriverDetach, 0 /* iOccurence */,
4338 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4339 else
4340 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4341 pszDriverDetach, 0 /* iOccurence */,
4342 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4343
4344 if (pszDriverDetach)
4345 {
4346 RTStrFree(pszDriverDetach);
4347 /* Remove the complete node and create new for the new config. */
4348 CFGMR3RemoveNode(pLunL0);
4349 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4350 if (pLunL0)
4351 {
4352 try
4353 {
4354 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4355 }
4356 catch (ConfigError &x)
4357 {
4358 // InsertConfig threw something:
4359 return x.m_vrc;
4360 }
4361 }
4362 }
4363 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4364 rc = VINF_SUCCESS;
4365 AssertRCReturn(rc, rc);
4366
4367 /*
4368 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4369 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4370 */
4371 if ( fHotplug
4372 || enmBus == StorageBus_IDE
4373 || enmBus == StorageBus_Floppy
4374 || enmBus == StorageBus_PCIe
4375 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4376 {
4377 fAddLun = true;
4378 CFGMR3RemoveNode(pLunL0);
4379 }
4380 }
4381 else
4382 fAddLun = true;
4383
4384 try
4385 {
4386 if (fAddLun)
4387 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4388 }
4389 catch (ConfigError &x)
4390 {
4391 // InsertConfig threw something:
4392 return x.m_vrc;
4393 }
4394
4395 if (ppLunL0)
4396 *ppLunL0 = pLunL0;
4397
4398 return rc;
4399}
4400
4401int Console::i_configMediumAttachment(const char *pcszDevice,
4402 unsigned uInstance,
4403 StorageBus_T enmBus,
4404 bool fUseHostIOCache,
4405 bool fBuiltinIOCache,
4406 bool fInsertDiskIntegrityDrv,
4407 bool fSetupMerge,
4408 unsigned uMergeSource,
4409 unsigned uMergeTarget,
4410 IMediumAttachment *pMediumAtt,
4411 MachineState_T aMachineState,
4412 HRESULT *phrc,
4413 bool fAttachDetach,
4414 bool fForceUnmount,
4415 bool fHotplug,
4416 PUVM pUVM,
4417 DeviceType_T *paLedDevType,
4418 PCFGMNODE *ppLunL0)
4419{
4420 // InsertConfig* throws
4421 try
4422 {
4423 int rc = VINF_SUCCESS;
4424 HRESULT hrc;
4425 Bstr bstr;
4426 PCFGMNODE pCtlInst = NULL;
4427
4428// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4429#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4430
4431 LONG lDev;
4432 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4433 LONG lPort;
4434 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4435 DeviceType_T lType;
4436 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4437 BOOL fNonRotational;
4438 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4439 BOOL fDiscard;
4440 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4441
4442 if (lType == DeviceType_DVD)
4443 fInsertDiskIntegrityDrv = false;
4444
4445 unsigned uLUN;
4446 PCFGMNODE pLunL0 = NULL;
4447 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4448
4449 /* Determine the base path for the device instance. */
4450 if (enmBus != StorageBus_USB)
4451 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4452 else
4453 {
4454 /* If we hotplug a USB device create a new CFGM tree. */
4455 if (!fHotplug)
4456 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4457 else
4458 pCtlInst = CFGMR3CreateTree(pUVM);
4459 }
4460 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4461
4462 if (enmBus == StorageBus_USB)
4463 {
4464 PCFGMNODE pCfg = NULL;
4465
4466 /* Create correct instance. */
4467 if (!fHotplug)
4468 {
4469 if (!fAttachDetach)
4470 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4471 else
4472 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4473 }
4474
4475 if (!fAttachDetach)
4476 InsertConfigNode(pCtlInst, "Config", &pCfg);
4477
4478 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4479
4480 if (!fHotplug && !fAttachDetach)
4481 {
4482 char aszUuid[RTUUID_STR_LENGTH + 1];
4483 USBStorageDevice UsbMsd = USBStorageDevice();
4484
4485 memset(aszUuid, 0, sizeof(aszUuid));
4486 rc = RTUuidCreate(&UsbMsd.mUuid);
4487 AssertRCReturn(rc, rc);
4488 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4489 AssertRCReturn(rc, rc);
4490
4491 UsbMsd.iPort = uInstance;
4492
4493 InsertConfigString(pCtlInst, "UUID", aszUuid);
4494 mUSBStorageDevices.push_back(UsbMsd);
4495
4496 /** @todo No LED after hotplugging. */
4497 /* Attach the status driver */
4498 Assert(cLedUsb >= 8);
4499 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4500 &mapMediumAttachments, pcszDevice, 0);
4501 paLedDevType = &maStorageDevType[iLedUsb];
4502 }
4503 }
4504
4505 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4506 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4507 if (RT_FAILURE(rc))
4508 return rc;
4509 if (ppLunL0)
4510 *ppLunL0 = pLunL0;
4511
4512 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4513 mapMediumAttachments[devicePath] = pMediumAtt;
4514
4515 ComPtr<IMedium> pMedium;
4516 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4517
4518 /*
4519 * 1. Only check this for hard disk images.
4520 * 2. Only check during VM creation and not later, especially not during
4521 * taking an online snapshot!
4522 */
4523 if ( lType == DeviceType_HardDisk
4524 && ( aMachineState == MachineState_Starting
4525 || aMachineState == MachineState_Restoring))
4526 {
4527 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4528 if (RT_FAILURE(rc))
4529 return rc;
4530 }
4531
4532 BOOL fPassthrough = FALSE;
4533 if (pMedium)
4534 {
4535 BOOL fHostDrive;
4536 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4537 if ( ( lType == DeviceType_DVD
4538 || lType == DeviceType_Floppy)
4539 && !fHostDrive)
4540 {
4541 /*
4542 * Informative logging.
4543 */
4544 Bstr strFile;
4545 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4546 Utf8Str utfFile = Utf8Str(strFile);
4547 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4548 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4549 LogRel(("File system of '%s' (%s) is %s\n",
4550 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4551 RTFsTypeName(enmFsTypeFile)));
4552 }
4553
4554 if (fHostDrive)
4555 {
4556 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4557 }
4558 }
4559
4560 ComObjPtr<IBandwidthGroup> pBwGroup;
4561 Bstr strBwGroup;
4562 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4563
4564 if (!pBwGroup.isNull())
4565 {
4566 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4567 }
4568
4569 /*
4570 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4571 * or for SATA if the new device is a CD/DVD drive.
4572 */
4573 if ( (fHotplug || !fAttachDetach)
4574 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB || enmBus == StorageBus_VirtioSCSI)
4575 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4576 {
4577 InsertConfigString(pLunL0, "Driver", "SCSI");
4578 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4579 }
4580
4581 rc = i_configMedium(pLunL0,
4582 !!fPassthrough,
4583 lType,
4584 fUseHostIOCache,
4585 fBuiltinIOCache,
4586 fInsertDiskIntegrityDrv,
4587 fSetupMerge,
4588 uMergeSource,
4589 uMergeTarget,
4590 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4591 !!fDiscard,
4592 !!fNonRotational,
4593 pMedium,
4594 aMachineState,
4595 phrc);
4596 if (RT_FAILURE(rc))
4597 return rc;
4598
4599 if (fAttachDetach)
4600 {
4601 /* Attach the new driver. */
4602 if (enmBus == StorageBus_USB)
4603 {
4604 if (fHotplug)
4605 {
4606 USBStorageDevice UsbMsd = USBStorageDevice();
4607 RTUuidCreate(&UsbMsd.mUuid);
4608 UsbMsd.iPort = uInstance;
4609 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4610 if (RT_SUCCESS(rc))
4611 mUSBStorageDevices.push_back(UsbMsd);
4612 }
4613 else
4614 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4615 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4616 }
4617 else if ( !fHotplug
4618 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
4619 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4620 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4621 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4622 else
4623 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4624 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4625 AssertRCReturn(rc, rc);
4626
4627 /*
4628 * Make the secret key helper interface known to the VD driver if it is attached,
4629 * so we can get notified about missing keys.
4630 */
4631 PPDMIBASE pIBase = NULL;
4632 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4633 if (RT_SUCCESS(rc) && pIBase)
4634 {
4635 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4636 if (pIMedium)
4637 {
4638 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4639 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4640 }
4641 }
4642
4643 /* There is no need to handle removable medium mounting, as we
4644 * unconditionally replace everthing including the block driver level.
4645 * This means the new medium will be picked up automatically. */
4646 }
4647
4648 if (paLedDevType)
4649 paLedDevType[uLUN] = lType;
4650
4651 /* Dump the changed LUN if possible, dump the complete device otherwise */
4652 if ( aMachineState != MachineState_Starting
4653 && aMachineState != MachineState_Restoring)
4654 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4655 }
4656 catch (ConfigError &x)
4657 {
4658 // InsertConfig threw something:
4659 return x.m_vrc;
4660 }
4661
4662#undef H
4663
4664 return VINF_SUCCESS;
4665}
4666
4667int Console::i_configMedium(PCFGMNODE pLunL0,
4668 bool fPassthrough,
4669 DeviceType_T enmType,
4670 bool fUseHostIOCache,
4671 bool fBuiltinIOCache,
4672 bool fInsertDiskIntegrityDrv,
4673 bool fSetupMerge,
4674 unsigned uMergeSource,
4675 unsigned uMergeTarget,
4676 const char *pcszBwGroup,
4677 bool fDiscard,
4678 bool fNonRotational,
4679 IMedium *pMedium,
4680 MachineState_T aMachineState,
4681 HRESULT *phrc)
4682{
4683 // InsertConfig* throws
4684 try
4685 {
4686 HRESULT hrc;
4687 Bstr bstr;
4688 PCFGMNODE pCfg = NULL;
4689
4690#define H() \
4691 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4692
4693
4694 BOOL fHostDrive = FALSE;
4695 MediumType_T mediumType = MediumType_Normal;
4696 if (pMedium)
4697 {
4698 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4699 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4700 }
4701
4702 if (fHostDrive)
4703 {
4704 Assert(pMedium);
4705 if (enmType == DeviceType_DVD)
4706 {
4707 InsertConfigString(pLunL0, "Driver", "HostDVD");
4708 InsertConfigNode(pLunL0, "Config", &pCfg);
4709
4710 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4711 InsertConfigString(pCfg, "Path", bstr);
4712
4713 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4714 }
4715 else if (enmType == DeviceType_Floppy)
4716 {
4717 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4718 InsertConfigNode(pLunL0, "Config", &pCfg);
4719
4720 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4721 InsertConfigString(pCfg, "Path", bstr);
4722 }
4723 }
4724 else
4725 {
4726 if (fInsertDiskIntegrityDrv)
4727 {
4728 /*
4729 * The actual configuration is done through CFGM extra data
4730 * for each inserted driver separately.
4731 */
4732 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4733 InsertConfigNode(pLunL0, "Config", &pCfg);
4734 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4735 }
4736
4737 InsertConfigString(pLunL0, "Driver", "VD");
4738 InsertConfigNode(pLunL0, "Config", &pCfg);
4739 switch (enmType)
4740 {
4741 case DeviceType_DVD:
4742 InsertConfigString(pCfg, "Type", "DVD");
4743 InsertConfigInteger(pCfg, "Mountable", 1);
4744 break;
4745 case DeviceType_Floppy:
4746 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4747 InsertConfigInteger(pCfg, "Mountable", 1);
4748 break;
4749 case DeviceType_HardDisk:
4750 default:
4751 InsertConfigString(pCfg, "Type", "HardDisk");
4752 InsertConfigInteger(pCfg, "Mountable", 0);
4753 }
4754
4755 if ( pMedium
4756 && ( enmType == DeviceType_DVD
4757 || enmType == DeviceType_Floppy)
4758 )
4759 {
4760 // if this medium represents an ISO image and this image is inaccessible,
4761 // the ignore it instead of causing a failure; this can happen when we
4762 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4763 // Additions were mounted and the user upgraded VirtualBox. Previously
4764 // we failed on startup, but that's not good because the only way out then
4765 // would be to discard the VM state...
4766 MediumState_T mediumState;
4767 hrc = pMedium->RefreshState(&mediumState); H();
4768 if (mediumState == MediumState_Inaccessible)
4769 {
4770 Bstr loc;
4771 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4772 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4773 "The image file '%ls' is inaccessible and is being ignored. "
4774 "Please select a different image file for the virtual %s drive.",
4775 loc.raw(),
4776 enmType == DeviceType_DVD ? "DVD" : "floppy");
4777 pMedium = NULL;
4778 }
4779 }
4780
4781 if (pMedium)
4782 {
4783 /* Start with length of parent chain, as the list is reversed */
4784 unsigned uImage = 0;
4785 IMedium *pTmp = pMedium;
4786 while (pTmp)
4787 {
4788 uImage++;
4789 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4790 }
4791 /* Index of last image */
4792 uImage--;
4793
4794# ifdef VBOX_WITH_EXTPACK
4795 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4796 {
4797 /* Configure loading the VDPlugin. */
4798 static const char s_szVDPlugin[] = "VDPluginCrypt";
4799 PCFGMNODE pCfgPlugins = NULL;
4800 PCFGMNODE pCfgPlugin = NULL;
4801 Utf8Str strPlugin;
4802 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4803 // Don't fail, this is optional!
4804 if (SUCCEEDED(hrc))
4805 {
4806 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4807 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4808 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4809 }
4810 }
4811# endif
4812
4813 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4814 InsertConfigString(pCfg, "Path", bstr);
4815
4816 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4817 InsertConfigString(pCfg, "Format", bstr);
4818
4819 if (mediumType == MediumType_Readonly)
4820 InsertConfigInteger(pCfg, "ReadOnly", 1);
4821 else if (enmType == DeviceType_Floppy)
4822 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4823
4824 /* Start without exclusive write access to the images. */
4825 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4826 * we're resuming the VM if some 3rd dude have any of the VDIs open
4827 * with write sharing denied. However, if the two VMs are sharing a
4828 * image it really is necessary....
4829 *
4830 * So, on the "lock-media" command, the target teleporter should also
4831 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4832 * that. Grumble. */
4833 if ( enmType == DeviceType_HardDisk
4834 && ( aMachineState == MachineState_TeleportingIn
4835 || aMachineState == MachineState_FaultTolerantSyncing))
4836 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4837
4838 /* Flag for opening the medium for sharing between VMs. This
4839 * is done at the moment only for the first (and only) medium
4840 * in the chain, as shared media can have no diffs. */
4841 if (mediumType == MediumType_Shareable)
4842 InsertConfigInteger(pCfg, "Shareable", 1);
4843
4844 if (!fUseHostIOCache)
4845 {
4846 InsertConfigInteger(pCfg, "UseNewIo", 1);
4847 /*
4848 * Activate the builtin I/O cache for harddisks only.
4849 * It caches writes only which doesn't make sense for DVD drives
4850 * and just increases the overhead.
4851 */
4852 if ( fBuiltinIOCache
4853 && (enmType == DeviceType_HardDisk))
4854 InsertConfigInteger(pCfg, "BlockCache", 1);
4855 }
4856
4857 if (fSetupMerge)
4858 {
4859 InsertConfigInteger(pCfg, "SetupMerge", 1);
4860 if (uImage == uMergeSource)
4861 InsertConfigInteger(pCfg, "MergeSource", 1);
4862 else if (uImage == uMergeTarget)
4863 InsertConfigInteger(pCfg, "MergeTarget", 1);
4864 }
4865
4866 if (pcszBwGroup)
4867 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4868
4869 if (fDiscard)
4870 InsertConfigInteger(pCfg, "Discard", 1);
4871
4872 if (fNonRotational)
4873 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4874
4875 /* Pass all custom parameters. */
4876 bool fHostIP = true;
4877 bool fEncrypted = false;
4878 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4879
4880 /* Create an inverted list of parents. */
4881 uImage--;
4882 IMedium *pParentMedium = pMedium;
4883 for (PCFGMNODE pParent = pCfg;; uImage--)
4884 {
4885 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4886 if (!pMedium)
4887 break;
4888
4889 PCFGMNODE pCur;
4890 InsertConfigNode(pParent, "Parent", &pCur);
4891 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4892 InsertConfigString(pCur, "Path", bstr);
4893
4894 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4895 InsertConfigString(pCur, "Format", bstr);
4896
4897 if (fSetupMerge)
4898 {
4899 if (uImage == uMergeSource)
4900 InsertConfigInteger(pCur, "MergeSource", 1);
4901 else if (uImage == uMergeTarget)
4902 InsertConfigInteger(pCur, "MergeTarget", 1);
4903 }
4904
4905 /* Configure medium properties. */
4906 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4907
4908 /* next */
4909 pParent = pCur;
4910 pParentMedium = pMedium;
4911 }
4912
4913 /* Custom code: put marker to not use host IP stack to driver
4914 * configuration node. Simplifies life of DrvVD a bit. */
4915 if (!fHostIP)
4916 InsertConfigInteger(pCfg, "HostIPStack", 0);
4917
4918 if (fEncrypted)
4919 m_cDisksEncrypted++;
4920 }
4921 else
4922 {
4923 /* Set empty drive flag for DVD or floppy without media. */
4924 if ( enmType == DeviceType_DVD
4925 || enmType == DeviceType_Floppy)
4926 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4927 }
4928 }
4929#undef H
4930 }
4931 catch (ConfigError &x)
4932 {
4933 // InsertConfig threw something:
4934 return x.m_vrc;
4935 }
4936
4937 return VINF_SUCCESS;
4938}
4939
4940/**
4941 * Adds the medium properties to the CFGM tree.
4942 *
4943 * @returns VBox status code.
4944 * @param pCur The current CFGM node.
4945 * @param pMedium The medium object to configure.
4946 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4947 * @param pfEncrypted Where to return whether the medium is encrypted.
4948 */
4949int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4950{
4951 /* Pass all custom parameters. */
4952 SafeArray<BSTR> aNames;
4953 SafeArray<BSTR> aValues;
4954 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4955 ComSafeArrayAsOutParam(aValues));
4956
4957 if ( SUCCEEDED(hrc)
4958 && aNames.size() != 0)
4959 {
4960 PCFGMNODE pVDC;
4961 InsertConfigNode(pCur, "VDConfig", &pVDC);
4962 for (size_t ii = 0; ii < aNames.size(); ++ii)
4963 {
4964 if (aValues[ii] && *aValues[ii])
4965 {
4966 Utf8Str name = aNames[ii];
4967 Utf8Str value = aValues[ii];
4968 size_t offSlash = name.find("/", 0);
4969 if ( offSlash != name.npos
4970 && !name.startsWith("Special/"))
4971 {
4972 com::Utf8Str strFilter;
4973 com::Utf8Str strKey;
4974
4975 hrc = strFilter.assignEx(name, 0, offSlash);
4976 if (FAILED(hrc))
4977 break;
4978
4979 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4980 if (FAILED(hrc))
4981 break;
4982
4983 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4984 if (!pCfgFilterConfig)
4985 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4986
4987 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4988 }
4989 else
4990 {
4991 InsertConfigString(pVDC, name.c_str(), value);
4992 if ( name.compare("HostIPStack") == 0
4993 && value.compare("0") == 0)
4994 *pfHostIP = false;
4995 }
4996
4997 if ( name.compare("CRYPT/KeyId") == 0
4998 && pfEncrypted)
4999 *pfEncrypted = true;
5000 }
5001 }
5002 }
5003
5004 return hrc;
5005}
5006
5007
5008/**
5009 * Construct the Network configuration tree
5010 *
5011 * @returns VBox status code.
5012 *
5013 * @param pszDevice The PDM device name.
5014 * @param uInstance The PDM device instance.
5015 * @param uLun The PDM LUN number of the drive.
5016 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5017 * @param pCfg Configuration node for the device
5018 * @param pLunL0 To store the pointer to the LUN#0.
5019 * @param pInst The instance CFGM node
5020 * @param fAttachDetach To determine if the network attachment should
5021 * be attached/detached after/before
5022 * configuration.
5023 * @param fIgnoreConnectFailure
5024 * True if connection failures should be ignored
5025 * (makes only sense for bridged/host-only networks).
5026 *
5027 * @note Locks this object for writing.
5028 * @thread EMT
5029 */
5030int Console::i_configNetwork(const char *pszDevice,
5031 unsigned uInstance,
5032 unsigned uLun,
5033 INetworkAdapter *aNetworkAdapter,
5034 PCFGMNODE pCfg,
5035 PCFGMNODE pLunL0,
5036 PCFGMNODE pInst,
5037 bool fAttachDetach,
5038 bool fIgnoreConnectFailure)
5039{
5040 RT_NOREF(fIgnoreConnectFailure);
5041 AutoCaller autoCaller(this);
5042 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
5043
5044 // InsertConfig* throws
5045 try
5046 {
5047 int rc = VINF_SUCCESS;
5048 HRESULT hrc;
5049 Bstr bstr;
5050
5051#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
5052
5053 /*
5054 * Locking the object before doing VMR3* calls is quite safe here, since
5055 * we're on EMT. Write lock is necessary because we indirectly modify the
5056 * meAttachmentType member.
5057 */
5058 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5059
5060 ComPtr<IMachine> pMachine = i_machine();
5061
5062 ComPtr<IVirtualBox> virtualBox;
5063 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5064
5065 ComPtr<IHost> host;
5066 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5067
5068 BOOL fSniffer;
5069 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5070
5071 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5072 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5073 const char *pszPromiscuousGuestPolicy;
5074 switch (enmPromiscModePolicy)
5075 {
5076 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5077 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5078 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5079 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5080 }
5081
5082 if (fAttachDetach)
5083 {
5084 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5085 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5086 rc = VINF_SUCCESS;
5087 AssertLogRelRCReturn(rc, rc);
5088
5089 /* Nuke anything which might have been left behind. */
5090 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5091 }
5092
5093#ifdef VBOX_WITH_NETSHAPER
5094 ComObjPtr<IBandwidthGroup> pBwGroup;
5095 Bstr strBwGroup;
5096 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5097
5098 if (!pBwGroup.isNull())
5099 {
5100 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5101 }
5102#endif /* VBOX_WITH_NETSHAPER */
5103
5104 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5105 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5106
5107#ifdef VBOX_WITH_NETSHAPER
5108 if (!strBwGroup.isEmpty())
5109 {
5110 InsertConfigString(pLunL0, "Driver", "NetShaper");
5111 InsertConfigNode(pLunL0, "Config", &pCfg);
5112 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5113 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5114 }
5115#endif /* VBOX_WITH_NETSHAPER */
5116
5117 if (fSniffer)
5118 {
5119 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5120 InsertConfigNode(pLunL0, "Config", &pCfg);
5121 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5122 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5123 InsertConfigString(pCfg, "File", bstr);
5124 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5125 }
5126
5127
5128 Bstr networkName, trunkName, trunkType;
5129 NetworkAttachmentType_T eAttachmentType;
5130 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5131 switch (eAttachmentType)
5132 {
5133 case NetworkAttachmentType_Null:
5134 break;
5135
5136 case NetworkAttachmentType_NAT:
5137 {
5138 ComPtr<INATEngine> natEngine;
5139 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5140 InsertConfigString(pLunL0, "Driver", "NAT");
5141 InsertConfigNode(pLunL0, "Config", &pCfg);
5142
5143 /* Configure TFTP prefix and boot filename. */
5144 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5145 if (!bstr.isEmpty())
5146 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5147 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5148 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5149
5150 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5151 if (!bstr.isEmpty())
5152 InsertConfigString(pCfg, "Network", bstr);
5153 else
5154 {
5155 ULONG uSlot;
5156 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5157 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5158 }
5159 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5160 if (!bstr.isEmpty())
5161 InsertConfigString(pCfg, "BindIP", bstr);
5162 ULONG mtu = 0;
5163 ULONG sockSnd = 0;
5164 ULONG sockRcv = 0;
5165 ULONG tcpSnd = 0;
5166 ULONG tcpRcv = 0;
5167 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5168 if (mtu)
5169 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5170 if (sockRcv)
5171 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5172 if (sockSnd)
5173 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5174 if (tcpRcv)
5175 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5176 if (tcpSnd)
5177 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5178 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5179 if (!bstr.isEmpty())
5180 {
5181 RemoveConfigValue(pCfg, "TFTPPrefix");
5182 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5183 }
5184 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5185 if (!bstr.isEmpty())
5186 {
5187 RemoveConfigValue(pCfg, "BootFile");
5188 InsertConfigString(pCfg, "BootFile", bstr);
5189 }
5190 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5191 if (!bstr.isEmpty())
5192 InsertConfigString(pCfg, "NextServer", bstr);
5193 BOOL fDNSFlag;
5194 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5195 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5196 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5197 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5198 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5199 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5200
5201 ULONG aliasMode;
5202 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5203 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5204
5205 /* port-forwarding */
5206 SafeArray<BSTR> pfs;
5207 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5208
5209 PCFGMNODE pPFTree = NULL;
5210 if (pfs.size() > 0)
5211 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5212
5213 for (unsigned int i = 0; i < pfs.size(); ++i)
5214 {
5215 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5216
5217 uint16_t port = 0;
5218 Utf8Str utf = pfs[i];
5219 Utf8Str strName;
5220 Utf8Str strProto;
5221 Utf8Str strHostPort;
5222 Utf8Str strHostIP;
5223 Utf8Str strGuestPort;
5224 Utf8Str strGuestIP;
5225 size_t pos, ppos;
5226 pos = ppos = 0;
5227#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5228 { \
5229 pos = str.find(",", ppos); \
5230 if (pos == Utf8Str::npos) \
5231 { \
5232 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5233 continue; \
5234 } \
5235 res = str.substr(ppos, pos - ppos); \
5236 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5237 ppos = pos + 1; \
5238 } /* no do { ... } while because of 'continue' */
5239 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5240 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5241 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5242 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5243 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5244 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5245#undef ITERATE_TO_NEXT_TERM
5246
5247 uint32_t proto = strProto.toUInt32();
5248 bool fValid = true;
5249 switch (proto)
5250 {
5251 case NATProtocol_UDP:
5252 strProto = "UDP";
5253 break;
5254 case NATProtocol_TCP:
5255 strProto = "TCP";
5256 break;
5257 default:
5258 fValid = false;
5259 }
5260 /* continue with next rule if no valid proto was passed */
5261 if (!fValid)
5262 continue;
5263
5264 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5265
5266 if (!strName.isEmpty())
5267 InsertConfigString(pPF, "Name", strName);
5268
5269 InsertConfigString(pPF, "Protocol", strProto);
5270
5271 if (!strHostIP.isEmpty())
5272 InsertConfigString(pPF, "BindIP", strHostIP);
5273
5274 if (!strGuestIP.isEmpty())
5275 InsertConfigString(pPF, "GuestIP", strGuestIP);
5276
5277 port = RTStrToUInt16(strHostPort.c_str());
5278 if (port)
5279 InsertConfigInteger(pPF, "HostPort", port);
5280
5281 port = RTStrToUInt16(strGuestPort.c_str());
5282 if (port)
5283 InsertConfigInteger(pPF, "GuestPort", port);
5284 }
5285 break;
5286 }
5287
5288 case NetworkAttachmentType_Bridged:
5289 {
5290#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5291 hrc = i_attachToTapInterface(aNetworkAdapter);
5292 if (FAILED(hrc))
5293 {
5294 switch (hrc)
5295 {
5296 case VERR_ACCESS_DENIED:
5297 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5298 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5299 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5300 "change the group of that node and make yourself a member of that group. Make "
5301 "sure that these changes are permanent, especially if you are "
5302 "using udev"));
5303 default:
5304 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5305 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5306 "Failed to initialize Host Interface Networking"));
5307 }
5308 }
5309
5310 Assert((intptr_t)maTapFD[uInstance] >= 0);
5311 if ((intptr_t)maTapFD[uInstance] >= 0)
5312 {
5313 InsertConfigString(pLunL0, "Driver", "HostInterface");
5314 InsertConfigNode(pLunL0, "Config", &pCfg);
5315 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5316 }
5317
5318#elif defined(VBOX_WITH_NETFLT)
5319 /*
5320 * This is the new VBoxNetFlt+IntNet stuff.
5321 */
5322 Bstr BridgedIfName;
5323 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5324 if (FAILED(hrc))
5325 {
5326 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5327 H();
5328 }
5329
5330 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5331 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5332
5333 ComPtr<IHostNetworkInterface> hostInterface;
5334 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5335 hostInterface.asOutParam());
5336 if (!SUCCEEDED(hrc))
5337 {
5338 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5339 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5340 N_("Nonexistent host networking interface, name '%ls'"),
5341 BridgedIfName.raw());
5342 }
5343
5344# if defined(RT_OS_DARWIN)
5345 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5346 char szTrunk[INTNET_MAX_TRUNK_NAME];
5347 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5348 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5349// Quick fix for @bugref{5633}
5350// if (!pszColon)
5351// {
5352// /*
5353// * Dynamic changing of attachment causes an attempt to configure
5354// * network with invalid host adapter (as it is must be changed before
5355// * the attachment), calling Detach here will cause a deadlock.
5356// * See @bugref{4750}.
5357// * hrc = aNetworkAdapter->Detach(); H();
5358// */
5359// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5360// N_("Malformed host interface networking name '%ls'"),
5361// BridgedIfName.raw());
5362// }
5363 if (pszColon)
5364 *pszColon = '\0';
5365 const char *pszTrunk = szTrunk;
5366
5367# elif defined(RT_OS_SOLARIS)
5368 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5369 char szTrunk[256];
5370 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5371 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5372
5373 /*
5374 * Currently don't bother about malformed names here for the sake of people using
5375 * VBoxManage and setting only the NIC name from there. If there is a space we
5376 * chop it off and proceed, otherwise just use whatever we've got.
5377 */
5378 if (pszSpace)
5379 *pszSpace = '\0';
5380
5381 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5382 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5383 if (pszColon)
5384 *pszColon = '\0';
5385
5386 const char *pszTrunk = szTrunk;
5387
5388# elif defined(RT_OS_WINDOWS)
5389 HostNetworkInterfaceType_T eIfType;
5390 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5391 if (FAILED(hrc))
5392 {
5393 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5394 H();
5395 }
5396
5397 if (eIfType != HostNetworkInterfaceType_Bridged)
5398 {
5399 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5400 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5401 BridgedIfName.raw());
5402 }
5403
5404 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5405 if (FAILED(hrc))
5406 {
5407 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5408 H();
5409 }
5410 Guid hostIFGuid(bstr);
5411
5412 INetCfg *pNc;
5413 ComPtr<INetCfgComponent> pAdaptorComponent;
5414 LPWSTR pszApp;
5415
5416 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5417 Assert(hrc == S_OK);
5418 if (hrc != S_OK)
5419 {
5420 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5421 H();
5422 }
5423
5424 /* get the adapter's INetCfgComponent*/
5425 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5426 pAdaptorComponent.asOutParam());
5427 if (hrc != S_OK)
5428 {
5429 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5430 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5431 H();
5432 }
5433# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5434 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5435 char *pszTrunkName = szTrunkName;
5436 wchar_t * pswzBindName;
5437 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5438 Assert(hrc == S_OK);
5439 if (hrc == S_OK)
5440 {
5441 int cwBindName = (int)wcslen(pswzBindName) + 1;
5442 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5443 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5444 {
5445 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5446 pszTrunkName += cbFullBindNamePrefix-1;
5447 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5448 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5449 {
5450 DWORD err = GetLastError();
5451 hrc = HRESULT_FROM_WIN32(err);
5452 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5453 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5454 hrc, hrc, err));
5455 }
5456 }
5457 else
5458 {
5459 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5460 /** @todo set appropriate error code */
5461 hrc = E_FAIL;
5462 }
5463
5464 if (hrc != S_OK)
5465 {
5466 AssertFailed();
5467 CoTaskMemFree(pswzBindName);
5468 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5469 H();
5470 }
5471
5472 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5473 }
5474 else
5475 {
5476 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5477 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5478 hrc));
5479 H();
5480 }
5481
5482 const char *pszTrunk = szTrunkName;
5483 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5484
5485# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5486# if defined(RT_OS_FREEBSD)
5487 /*
5488 * If we bridge to a tap interface open it the `old' direct way.
5489 * This works and performs better than bridging a physical
5490 * interface via the current FreeBSD vboxnetflt implementation.
5491 */
5492 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5493 hrc = i_attachToTapInterface(aNetworkAdapter);
5494 if (FAILED(hrc))
5495 {
5496 switch (hrc)
5497 {
5498 case E_ACCESSDENIED:
5499 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5500 "Failed to open '/dev/%s' for read/write access. Please check the "
5501 "permissions of that node, and that the net.link.tap.user_open "
5502 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5503 "change the group of that node to vboxusers and make yourself "
5504 "a member of that group. Make sure that these changes are permanent."),
5505 pszBridgedIfName, pszBridgedIfName);
5506 default:
5507 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5508 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5509 "Failed to initialize Host Interface Networking"));
5510 }
5511 }
5512
5513 Assert((intptr_t)maTapFD[uInstance] >= 0);
5514 if ((intptr_t)maTapFD[uInstance] >= 0)
5515 {
5516 InsertConfigString(pLunL0, "Driver", "HostInterface");
5517 InsertConfigNode(pLunL0, "Config", &pCfg);
5518 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5519 }
5520 break;
5521 }
5522# endif
5523 /** @todo Check for malformed names. */
5524 const char *pszTrunk = pszBridgedIfName;
5525
5526 /* Issue a warning if the interface is down */
5527 {
5528 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5529 if (iSock >= 0)
5530 {
5531 struct ifreq Req;
5532 RT_ZERO(Req);
5533 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5534 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5535 if ((Req.ifr_flags & IFF_UP) == 0)
5536 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5537 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5538 pszBridgedIfName);
5539
5540 close(iSock);
5541 }
5542 }
5543
5544# else
5545# error "PORTME (VBOX_WITH_NETFLT)"
5546# endif
5547
5548 InsertConfigString(pLunL0, "Driver", "IntNet");
5549 InsertConfigNode(pLunL0, "Config", &pCfg);
5550 InsertConfigString(pCfg, "Trunk", pszTrunk);
5551 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5552 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5553 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5554 char szNetwork[INTNET_MAX_NETWORK_NAME];
5555
5556# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5557 /*
5558 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5559 * interface name + optional description. We must not pass any description to the VM as it can differ
5560 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5561 */
5562 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5563# else
5564 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5565# endif
5566 InsertConfigString(pCfg, "Network", szNetwork);
5567 networkName = Bstr(szNetwork);
5568 trunkName = Bstr(pszTrunk);
5569 trunkType = Bstr(TRUNKTYPE_NETFLT);
5570
5571 BOOL fSharedMacOnWire = false;
5572 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5573 if (FAILED(hrc))
5574 {
5575 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5576 H();
5577 }
5578 else if (fSharedMacOnWire)
5579 {
5580 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5581 Log(("Set SharedMacOnWire\n"));
5582 }
5583
5584# if defined(RT_OS_SOLARIS)
5585# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5586 /* Zone access restriction, don't allow snooping the global zone. */
5587 zoneid_t ZoneId = getzoneid();
5588 if (ZoneId != GLOBAL_ZONEID)
5589 {
5590 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5591 }
5592# endif
5593# endif
5594
5595#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5596 /* NOTHING TO DO HERE */
5597#elif defined(RT_OS_LINUX)
5598/// @todo aleksey: is there anything to be done here?
5599#elif defined(RT_OS_FREEBSD)
5600/** @todo FreeBSD: Check out this later (HIF networking). */
5601#else
5602# error "Port me"
5603#endif
5604 break;
5605 }
5606
5607 case NetworkAttachmentType_Internal:
5608 {
5609 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5610 if (!bstr.isEmpty())
5611 {
5612 InsertConfigString(pLunL0, "Driver", "IntNet");
5613 InsertConfigNode(pLunL0, "Config", &pCfg);
5614 InsertConfigString(pCfg, "Network", bstr);
5615 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5616 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5617 networkName = bstr;
5618 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5619 }
5620 break;
5621 }
5622
5623 case NetworkAttachmentType_HostOnly:
5624 {
5625 InsertConfigString(pLunL0, "Driver", "IntNet");
5626 InsertConfigNode(pLunL0, "Config", &pCfg);
5627
5628 Bstr HostOnlyName;
5629 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5630 if (FAILED(hrc))
5631 {
5632 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5633 H();
5634 }
5635
5636 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5637 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5638 ComPtr<IHostNetworkInterface> hostInterface;
5639 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5640 hostInterface.asOutParam());
5641 if (!SUCCEEDED(rc))
5642 {
5643 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5644 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5645 N_("Nonexistent host networking interface, name '%ls'"),
5646 HostOnlyName.raw());
5647 }
5648
5649 char szNetwork[INTNET_MAX_NETWORK_NAME];
5650 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5651
5652#if defined(RT_OS_WINDOWS)
5653# ifndef VBOX_WITH_NETFLT
5654 hrc = E_NOTIMPL;
5655 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5656 H();
5657# else /* defined VBOX_WITH_NETFLT*/
5658 /** @todo r=bird: Put this in a function. */
5659
5660 HostNetworkInterfaceType_T eIfType;
5661 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5662 if (FAILED(hrc))
5663 {
5664 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5665 H();
5666 }
5667
5668 if (eIfType != HostNetworkInterfaceType_HostOnly)
5669 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5670 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5671 HostOnlyName.raw());
5672
5673 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5674 if (FAILED(hrc))
5675 {
5676 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5677 H();
5678 }
5679 Guid hostIFGuid(bstr);
5680
5681 INetCfg *pNc;
5682 ComPtr<INetCfgComponent> pAdaptorComponent;
5683 LPWSTR pszApp;
5684 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5685 Assert(hrc == S_OK);
5686 if (hrc != S_OK)
5687 {
5688 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5689 H();
5690 }
5691
5692 /* get the adapter's INetCfgComponent*/
5693 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5694 pAdaptorComponent.asOutParam());
5695 if (hrc != S_OK)
5696 {
5697 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5698 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5699 H();
5700 }
5701# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5702 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5703 bool fNdis6 = false;
5704 wchar_t * pwszHelpText;
5705 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5706 Assert(hrc == S_OK);
5707 if (hrc == S_OK)
5708 {
5709 Log(("help-text=%ls\n", pwszHelpText));
5710 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5711 fNdis6 = true;
5712 CoTaskMemFree(pwszHelpText);
5713 }
5714 if (fNdis6)
5715 {
5716 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5717 Log(("trunk=%s\n", szTrunkName));
5718 }
5719 else
5720 {
5721 char *pszTrunkName = szTrunkName;
5722 wchar_t * pswzBindName;
5723 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5724 Assert(hrc == S_OK);
5725 if (hrc == S_OK)
5726 {
5727 int cwBindName = (int)wcslen(pswzBindName) + 1;
5728 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5729 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5730 {
5731 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5732 pszTrunkName += cbFullBindNamePrefix-1;
5733 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5734 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5735 {
5736 DWORD err = GetLastError();
5737 hrc = HRESULT_FROM_WIN32(err);
5738 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5739 hrc, hrc, err));
5740 }
5741 }
5742 else
5743 {
5744 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5745 /** @todo set appropriate error code */
5746 hrc = E_FAIL;
5747 }
5748
5749 if (hrc != S_OK)
5750 {
5751 AssertFailed();
5752 CoTaskMemFree(pswzBindName);
5753 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5754 H();
5755 }
5756 }
5757 else
5758 {
5759 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5760 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5761 hrc, hrc));
5762 H();
5763 }
5764
5765
5766 CoTaskMemFree(pswzBindName);
5767 }
5768
5769 trunkType = TRUNKTYPE_NETADP;
5770 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5771
5772 pAdaptorComponent.setNull();
5773 /* release the pNc finally */
5774 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5775
5776 const char *pszTrunk = szTrunkName;
5777
5778 InsertConfigString(pCfg, "Trunk", pszTrunk);
5779 InsertConfigString(pCfg, "Network", szNetwork);
5780 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5781 windows only?? */
5782 networkName = Bstr(szNetwork);
5783 trunkName = Bstr(pszTrunk);
5784# endif /* defined VBOX_WITH_NETFLT*/
5785#elif defined(RT_OS_DARWIN)
5786 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5787 InsertConfigString(pCfg, "Network", szNetwork);
5788 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5789 networkName = Bstr(szNetwork);
5790 trunkName = Bstr(pszHostOnlyName);
5791 trunkType = TRUNKTYPE_NETADP;
5792#else
5793 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5794 InsertConfigString(pCfg, "Network", szNetwork);
5795 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5796 networkName = Bstr(szNetwork);
5797 trunkName = Bstr(pszHostOnlyName);
5798 trunkType = TRUNKTYPE_NETFLT;
5799#endif
5800 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5801
5802#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5803
5804 Bstr tmpAddr, tmpMask;
5805
5806 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5807 pszHostOnlyName).raw(),
5808 tmpAddr.asOutParam());
5809 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5810 {
5811 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5812 pszHostOnlyName).raw(),
5813 tmpMask.asOutParam());
5814 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5815 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5816 tmpMask.raw());
5817 else
5818 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5819 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5820 }
5821 else
5822 {
5823 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5824 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5825 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5826 }
5827
5828 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5829
5830 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5831 pszHostOnlyName).raw(),
5832 tmpAddr.asOutParam());
5833 if (SUCCEEDED(hrc))
5834 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5835 tmpMask.asOutParam());
5836 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5837 {
5838 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5839 Utf8Str(tmpMask).toUInt32());
5840 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5841 }
5842#endif
5843 break;
5844 }
5845
5846 case NetworkAttachmentType_Generic:
5847 {
5848 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5849 SafeArray<BSTR> names;
5850 SafeArray<BSTR> values;
5851 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5852 ComSafeArrayAsOutParam(names),
5853 ComSafeArrayAsOutParam(values)); H();
5854
5855 InsertConfigString(pLunL0, "Driver", bstr);
5856 InsertConfigNode(pLunL0, "Config", &pCfg);
5857 for (size_t ii = 0; ii < names.size(); ++ii)
5858 {
5859 if (values[ii] && *values[ii])
5860 {
5861 Utf8Str name = names[ii];
5862 Utf8Str value = values[ii];
5863 InsertConfigString(pCfg, name.c_str(), value);
5864 }
5865 }
5866 break;
5867 }
5868
5869 case NetworkAttachmentType_NATNetwork:
5870 {
5871 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5872 if (!bstr.isEmpty())
5873 {
5874 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5875 InsertConfigString(pLunL0, "Driver", "IntNet");
5876 InsertConfigNode(pLunL0, "Config", &pCfg);
5877 InsertConfigString(pCfg, "Network", bstr);
5878 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5879 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5880 networkName = bstr;
5881 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5882 }
5883 break;
5884 }
5885
5886 default:
5887 AssertMsgFailed(("should not get here!\n"));
5888 break;
5889 }
5890
5891 /*
5892 * Attempt to attach the driver.
5893 */
5894 switch (eAttachmentType)
5895 {
5896 case NetworkAttachmentType_Null:
5897 break;
5898
5899 case NetworkAttachmentType_Bridged:
5900 case NetworkAttachmentType_Internal:
5901 case NetworkAttachmentType_HostOnly:
5902 case NetworkAttachmentType_NAT:
5903 case NetworkAttachmentType_Generic:
5904 case NetworkAttachmentType_NATNetwork:
5905 {
5906 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5907 {
5908 if (fAttachDetach)
5909 {
5910 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5911 //AssertRC(rc);
5912 }
5913
5914 {
5915 /** @todo pritesh: get the dhcp server name from the
5916 * previous network configuration and then stop the server
5917 * else it may conflict with the dhcp server running with
5918 * the current attachment type
5919 */
5920 /* Stop the hostonly DHCP Server */
5921 }
5922
5923 /*
5924 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5925 */
5926 if ( !networkName.isEmpty()
5927 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5928 {
5929 /*
5930 * Until we implement service reference counters DHCP Server will be stopped
5931 * by DHCPServerRunner destructor.
5932 */
5933 ComPtr<IDHCPServer> dhcpServer;
5934 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5935 dhcpServer.asOutParam());
5936 if (SUCCEEDED(hrc))
5937 {
5938 /* there is a DHCP server available for this network */
5939 BOOL fEnabledDhcp;
5940 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5941 if (FAILED(hrc))
5942 {
5943 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5944 H();
5945 }
5946
5947 if (fEnabledDhcp)
5948 hrc = dhcpServer->Start(networkName.raw(),
5949 trunkName.raw(),
5950 trunkType.raw());
5951 }
5952 else
5953 hrc = S_OK;
5954 }
5955 }
5956
5957 break;
5958 }
5959
5960 default:
5961 AssertMsgFailed(("should not get here!\n"));
5962 break;
5963 }
5964
5965 meAttachmentType[uInstance] = eAttachmentType;
5966 }
5967 catch (ConfigError &x)
5968 {
5969 // InsertConfig threw something:
5970 return x.m_vrc;
5971 }
5972
5973#undef H
5974
5975 return VINF_SUCCESS;
5976}
5977
5978
5979/**
5980 * Configures the serial port at the given CFGM node with the supplied parameters.
5981 *
5982 * @returns VBox status code.
5983 * @param pInst The instance CFGM node.
5984 * @param ePortMode The port mode to sue.
5985 * @param pszPath The serial port path.
5986 * @param fServer Flag whether the port should act as a server
5987 * for the pipe and TCP mode or connect as a client.
5988 */
5989int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
5990{
5991 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5992 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
5993 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
5994
5995 try
5996 {
5997 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5998 if (ePortMode == PortMode_HostPipe)
5999 {
6000 InsertConfigString(pLunL0, "Driver", "Char");
6001 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6002 InsertConfigString(pLunL1, "Driver", "NamedPipe");
6003 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6004 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6005 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6006 }
6007 else if (ePortMode == PortMode_HostDevice)
6008 {
6009 InsertConfigString(pLunL0, "Driver", "Host Serial");
6010 InsertConfigNode(pLunL0, "Config", &pLunL1);
6011 InsertConfigString(pLunL1, "DevicePath", pszPath);
6012 }
6013 else if (ePortMode == PortMode_TCP)
6014 {
6015 InsertConfigString(pLunL0, "Driver", "Char");
6016 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6017 InsertConfigString(pLunL1, "Driver", "TCP");
6018 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6019 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6020 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
6021 }
6022 else if (ePortMode == PortMode_RawFile)
6023 {
6024 InsertConfigString(pLunL0, "Driver", "Char");
6025 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
6026 InsertConfigString(pLunL1, "Driver", "RawFile");
6027 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
6028 InsertConfigString(pLunL1Cfg, "Location", pszPath);
6029 }
6030 }
6031 catch (ConfigError &x)
6032 {
6033 /* InsertConfig threw something */
6034 return x.m_vrc;
6035 }
6036
6037 return VINF_SUCCESS;
6038}
6039
Note: See TracBrowser for help on using the repository browser.

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