VirtualBox

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

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

VMM,Main,++: Retired the unfinished FTM component.

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