VirtualBox

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

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

Main: Doxygen build fix.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use