VirtualBox

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

Last change on this file since 70712 was 70712, checked in by vboxsync, 7 years ago

Main,VBoxManage: Added CPUPropertyType_HWVirt. Translates to --nested-hw-virt in VBoxManage/modifyvm

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette