VirtualBox

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

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

ConsoleImpl2: Use new style CFGM config for PCnet emulation.

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