VirtualBox

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

Last change on this file since 68870 was 68870, checked in by vboxsync, 8 years ago

Main/ConsoleImpl2.cpp: Also tweak the logging groups if audio debugging is enabled.

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

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