VirtualBox

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

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

Main: disabled assert

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