VirtualBox

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

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

DevVGA, Additions: added VBE_DISPI_ID_CFG for querying the virtual graphics card features.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use