VirtualBox

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

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

Audio: Implemented support for dumping raw PCM data if debug mode is enabled.

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

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