VirtualBox

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

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

Main/NetIf (bugref:8915) Moved wireless detection from ConsoleImpl2.cpp to NetIf and exposed wireless flag via IHostNetworkInterface.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 250.9 KB
Line 
1/* $Id: ConsoleImpl2.cpp 68026 2017-07-18 14:15:32Z 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 /* Default: ICH AC97. */
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 uint8_t u8AudioLUN = 0;
2886
2887 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", u8AudioLUN++);
2888 InsertConfigString(pLunL0, "Driver", "AUDIO");
2889 InsertConfigNode(pLunL0, "Config", &pCfg);
2890
2891 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2892 InsertConfigNode(pLunL1, "Config", &pCfg);
2893
2894 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2895 InsertConfigString(pCfg, "StreamName", bstr);
2896
2897 AudioDriverType_T audioDriver;
2898 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2899 switch (audioDriver)
2900 {
2901 case AudioDriverType_Null:
2902 {
2903 InsertConfigString(pLunL1, "Driver", "NullAudio");
2904 break;
2905 }
2906#ifdef RT_OS_WINDOWS
2907# ifdef VBOX_WITH_WINMM
2908 case AudioDriverType_WinMM:
2909 {
2910 #error "Port WinMM audio backend!" /** @todo Still needed? */
2911 break;
2912 }
2913# endif
2914 case AudioDriverType_DirectSound:
2915 {
2916 InsertConfigString(pLunL1, "Driver", "DSoundAudio");
2917 break;
2918 }
2919#endif /* RT_OS_WINDOWS */
2920#ifdef RT_OS_SOLARIS
2921 case AudioDriverType_SolAudio:
2922 {
2923 /* Should not happen, as the Solaris Audio backend is not around anymore.
2924 * Remove this sometime later. */
2925 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2926 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2927
2928 /* Manually set backend to OSS for now. */
2929 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2930 break;
2931 }
2932#endif
2933#ifdef VBOX_WITH_AUDIO_OSS
2934 case AudioDriverType_OSS:
2935 {
2936 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2937 break;
2938 }
2939#endif
2940#ifdef VBOX_WITH_AUDIO_ALSA
2941 case AudioDriverType_ALSA:
2942 {
2943 InsertConfigString(pLunL1, "Driver", "ALSAAudio");
2944 break;
2945 }
2946#endif
2947#ifdef VBOX_WITH_AUDIO_PULSE
2948 case AudioDriverType_Pulse:
2949 {
2950 InsertConfigString(pLunL1, "Driver", "PulseAudio");
2951 break;
2952 }
2953#endif
2954#ifdef RT_OS_DARWIN
2955 case AudioDriverType_CoreAudio:
2956 {
2957 InsertConfigString(pLunL1, "Driver", "CoreAudio");
2958 break;
2959 }
2960#endif
2961 default: AssertFailedBreak();
2962 }
2963
2964 /** @todo Implement a prioritizing feature here, e.g. which driver to insert in which order? */
2965
2966#ifdef VBOX_WITH_VRDE_AUDIO
2967 /*
2968 * The VRDE audio backend driver.
2969 */
2970 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2971 InsertConfigString(pLunL1, "Driver", "AUDIO");
2972
2973 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2974 InsertConfigString(pLunL1, "Driver", "AudioVRDE");
2975
2976 InsertConfigNode(pLunL1, "Config", &pCfg);
2977 InsertConfigString(pCfg, "AudioDriver", "AudioVRDE");
2978 InsertConfigString(pCfg, "StreamName", bstr);
2979 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVRDE);
2980 InsertConfigInteger(pCfg, "ObjectVRDPServer", (uintptr_t)mConsoleVRDPServer);
2981#endif /* VBOX_WITH_VRDE_AUDIO */
2982
2983#ifdef VBOX_WITH_AUDIO_VIDEOREC
2984 /*
2985 * The video recording audio backend driver.
2986 * Currently being used with VPX video recording only.
2987 */
2988 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2989 InsertConfigString(pLunL1, "Driver", "AUDIO");
2990
2991 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2992 InsertConfigString(pLunL1, "Driver", "AudioVideoRec");
2993
2994 InsertConfigNode(pLunL1, "Config", &pCfg);
2995 InsertConfigString(pCfg, "AudioDriver", "AudioVideoRec");
2996 InsertConfigString(pCfg, "StreamName", bstr);
2997 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVideoRec);
2998 InsertConfigInteger(pCfg, "ObjectConsole", (uintptr_t)this /* Console */);
2999#endif /* VBOX_WITH_AUDIO_VIDEOREC */
3000
3001#ifdef VBOX_WITH_AUDIO_DEBUG
3002 /*
3003 * The audio debug backend. Only can be used in debug builds.
3004 */
3005 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
3006 InsertConfigString(pLunL1, "Driver", "AUDIO");
3007
3008 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
3009 InsertConfigString(pLunL1, "Driver", "DebugAudio");
3010
3011 InsertConfigNode(pLunL1, "Config", &pCfg);
3012 InsertConfigString(pCfg, "AudioDriver", "DebugAudio");
3013 InsertConfigString(pCfg, "StreamName", bstr);
3014#endif /* VBOX_WITH_AUDIO_DEBUG */
3015
3016#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3017 /** @todo Make this a runtime-configurable entry! */
3018
3019 /*
3020 * The ValidationKit backend.
3021 */
3022 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
3023 InsertConfigString(pLunL1, "Driver", "AUDIO");
3024
3025 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
3026 InsertConfigString(pLunL1, "Driver", "ValidationKitAudio");
3027
3028 InsertConfigNode(pLunL1, "Config", &pCfg);
3029 InsertConfigString(pCfg, "AudioDriver", "ValidationKitAudio");
3030 InsertConfigString(pCfg, "StreamName", bstr);
3031#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3032
3033 /** @todo Add audio video recording driver here. */
3034 }
3035
3036 /*
3037 * Shared Clipboard.
3038 */
3039 {
3040 ClipboardMode_T mode = ClipboardMode_Disabled;
3041 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3042
3043 if (/* mode != ClipboardMode_Disabled */ true)
3044 {
3045 /* Load the service */
3046 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3047 if (RT_FAILURE(rc))
3048 {
3049 LogRel(("Shared clipboard is not available, rc=%Rrc\n", rc));
3050 /* That is not a fatal failure. */
3051 rc = VINF_SUCCESS;
3052 }
3053 else
3054 {
3055 LogRel(("Shared clipboard service loaded\n"));
3056
3057 i_changeClipboardMode(mode);
3058
3059 /* Setup the service. */
3060 VBOXHGCMSVCPARM parm;
3061 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
3062 parm.setUInt32(!i_useHostClipboard());
3063 pVMMDev->hgcmHostCall("VBoxSharedClipboard",
3064 VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3065 }
3066 }
3067 }
3068
3069 /*
3070 * HGCM HostChannel.
3071 */
3072 {
3073 Bstr value;
3074 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3075 value.asOutParam());
3076
3077 if ( hrc == S_OK
3078 && value == "1")
3079 {
3080 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3081 if (RT_FAILURE(rc))
3082 {
3083 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3084 /* That is not a fatal failure. */
3085 rc = VINF_SUCCESS;
3086 }
3087 }
3088 }
3089
3090#ifdef VBOX_WITH_DRAG_AND_DROP
3091 /*
3092 * Drag and Drop.
3093 */
3094 {
3095 DnDMode_T enmMode = DnDMode_Disabled;
3096 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3097
3098 /* Load the service */
3099 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3100 if (RT_FAILURE(rc))
3101 {
3102 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3103 /* That is not a fatal failure. */
3104 rc = VINF_SUCCESS;
3105 }
3106 else
3107 {
3108 HGCMSVCEXTHANDLE hDummy;
3109 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
3110 &GuestDnD::notifyDnDDispatcher,
3111 GuestDnDInst());
3112 if (RT_FAILURE(rc))
3113 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3114 else
3115 {
3116 LogRel(("Drag and drop service loaded\n"));
3117 rc = i_changeDnDMode(enmMode);
3118 }
3119 }
3120 }
3121#endif /* VBOX_WITH_DRAG_AND_DROP */
3122
3123#ifdef VBOX_WITH_CROGL
3124 /*
3125 * crOpenGL.
3126 */
3127 {
3128 BOOL fEnabled3D = false;
3129 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3130
3131 if ( fEnabled3D
3132# ifdef VBOX_WITH_VMSVGA3D
3133 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3134# endif
3135 )
3136 {
3137 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3138 if (!fSupports3D)
3139 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3140 N_("This VM was configured to use 3D acceleration. However, the "
3141 "3D support of the host is not working properly and the "
3142 "VM cannot be started. To fix this problem, either "
3143 "fix the host 3D support (update the host graphics driver?) "
3144 "or disable 3D acceleration in the VM settings"));
3145
3146 /* Load the service. */
3147 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3148 if (RT_FAILURE(rc))
3149 {
3150 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3151 /* That is not a fatal failure. */
3152 rc = VINF_SUCCESS;
3153 }
3154 else
3155 {
3156 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3157
3158 /* Setup the service. */
3159 VBOXHGCMSVCPARM parm;
3160 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3161
3162 parm.u.pointer.addr = (IConsole *)(Console *)this;
3163 parm.u.pointer.size = sizeof(IConsole *);
3164
3165 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3166 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3167 if (!RT_SUCCESS(rc))
3168 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3169
3170 parm.u.pointer.addr = pVM;
3171 parm.u.pointer.size = sizeof(pVM);
3172 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3173 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3174 if (!RT_SUCCESS(rc))
3175 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3176 }
3177 }
3178 }
3179#endif
3180
3181#ifdef VBOX_WITH_GUEST_PROPS
3182 /*
3183 * Guest property service.
3184 */
3185 rc = i_configGuestProperties(this, pUVM);
3186#endif /* VBOX_WITH_GUEST_PROPS defined */
3187
3188#ifdef VBOX_WITH_GUEST_CONTROL
3189 /*
3190 * Guest control service.
3191 */
3192 rc = i_configGuestControl(this);
3193#endif /* VBOX_WITH_GUEST_CONTROL defined */
3194
3195 /*
3196 * ACPI
3197 */
3198 BOOL fACPI;
3199 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3200 if (fACPI)
3201 {
3202 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3203 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3204 * intelppm driver refuses to register an idle state handler.
3205 * Always show CPU leafs for OS X guests. */
3206 BOOL fShowCpu = fOsXGuest;
3207 if (cCpus > 1 || fIOAPIC)
3208 fShowCpu = true;
3209
3210 BOOL fCpuHotPlug;
3211 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3212
3213 InsertConfigNode(pDevices, "acpi", &pDev);
3214 InsertConfigNode(pDev, "0", &pInst);
3215 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3216 InsertConfigNode(pInst, "Config", &pCfg);
3217 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3218
3219 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3220
3221 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3222 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3223 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3224 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3225 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3226 if (fOsXGuest && !llBootNics.empty())
3227 {
3228 BootNic aNic = llBootNics.front();
3229 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3230 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3231 }
3232 if (fOsXGuest && fAudioEnabled)
3233 {
3234 PCIBusAddress Address;
3235 if (pBusMgr->findPCIAddress("hda", 0, Address))
3236 {
3237 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3238 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3239 }
3240 }
3241 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3242 if (chipsetType == ChipsetType_ICH9)
3243 {
3244 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3245 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3246 /* 64-bit prefetch window root resource:
3247 * Only for ICH9 and if PAE or Long Mode is enabled.
3248 * And only with hardware virtualization (@bugref{5454}). */
3249 if ( (fEnablePAE || fIsGuest64Bit)
3250 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3251 otherwise VMM falls back to raw mode */
3252 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3253 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3254 }
3255 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3256 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3257 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3258
3259 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3260 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3261
3262 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3263 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3264
3265 if (auSerialIoPortBase[2])
3266 {
3267 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3268 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3269 }
3270
3271 if (auSerialIoPortBase[3])
3272 {
3273 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3274 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3275 }
3276
3277 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3278 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3279
3280 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3281 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3282
3283 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3284 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3285 InsertConfigNode(pLunL0, "Config", &pCfg);
3286
3287 /* Attach the dummy CPU drivers */
3288 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3289 {
3290 BOOL fCpuAttached = true;
3291
3292 if (fCpuHotPlug)
3293 {
3294 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3295 }
3296
3297 if (fCpuAttached)
3298 {
3299 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3300 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3301 InsertConfigNode(pLunL0, "Config", &pCfg);
3302 }
3303 }
3304 }
3305
3306 /*
3307 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3308 */
3309 {
3310 PCFGMNODE pDbgf;
3311 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3312
3313 /* Paths to search for debug info and such things. */
3314 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3315 Utf8Str strSettingsPath(bstr);
3316 bstr.setNull();
3317 strSettingsPath.stripFilename();
3318 strSettingsPath.append("/");
3319
3320 char szHomeDir[RTPATH_MAX + 1];
3321 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3322 if (RT_FAILURE(rc2))
3323 szHomeDir[0] = '\0';
3324 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3325
3326
3327 Utf8Str strPath;
3328 strPath.append(strSettingsPath).append("debug/;");
3329 strPath.append(strSettingsPath).append(";");
3330 strPath.append(szHomeDir);
3331
3332 InsertConfigString(pDbgf, "Path", strPath.c_str());
3333
3334 /* Tracing configuration. */
3335 BOOL fTracingEnabled;
3336 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3337 if (fTracingEnabled)
3338 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3339
3340 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3341 if (fTracingEnabled)
3342 InsertConfigString(pDbgf, "TracingConfig", bstr);
3343
3344 BOOL fAllowTracingToAccessVM;
3345 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3346 if (fAllowTracingToAccessVM)
3347 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3348
3349 /* Debugger console config. */
3350 PCFGMNODE pDbgc;
3351 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3352
3353 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3354 Utf8Str strVBoxHome = bstr;
3355 bstr.setNull();
3356 if (strVBoxHome.isNotEmpty())
3357 strVBoxHome.append("/");
3358 else
3359 {
3360 strVBoxHome = szHomeDir;
3361 strVBoxHome.append("/.vbox");
3362 }
3363
3364 Utf8Str strFile(strVBoxHome);
3365 strFile.append("dbgc-history");
3366 InsertConfigString(pDbgc, "HistoryFile", strFile);
3367
3368 strFile = strSettingsPath;
3369 strFile.append("dbgc-init");
3370 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3371
3372 strFile = strVBoxHome;
3373 strFile.append("dbgc-init");
3374 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3375 }
3376 }
3377 catch (ConfigError &x)
3378 {
3379 // InsertConfig threw something:
3380 return x.m_vrc;
3381 }
3382 catch (HRESULT hrcXcpt)
3383 {
3384 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3385 }
3386
3387#ifdef VBOX_WITH_EXTPACK
3388 /*
3389 * Call the extension pack hooks if everything went well thus far.
3390 */
3391 if (RT_SUCCESS(rc))
3392 {
3393 pAlock->release();
3394 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3395 pAlock->acquire();
3396 }
3397#endif
3398
3399 /*
3400 * Apply the CFGM overlay.
3401 */
3402 if (RT_SUCCESS(rc))
3403 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3404
3405 /*
3406 * Dump all extradata API settings tweaks, both global and per VM.
3407 */
3408 if (RT_SUCCESS(rc))
3409 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3410
3411#undef H
3412
3413 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3414
3415 /*
3416 * Register VM state change handler.
3417 */
3418 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3419 AssertRC(rc2);
3420 if (RT_SUCCESS(rc))
3421 rc = rc2;
3422
3423 /*
3424 * Register VM runtime error handler.
3425 */
3426 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3427 AssertRC(rc2);
3428 if (RT_SUCCESS(rc))
3429 rc = rc2;
3430
3431 pAlock->acquire();
3432
3433 LogFlowFunc(("vrc = %Rrc\n", rc));
3434 LogFlowFuncLeave();
3435
3436 return rc;
3437}
3438
3439/**
3440 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3441 * values.
3442 *
3443 * @returns VBox status code.
3444 * @param pRoot The root of the configuration tree.
3445 * @param pVirtualBox Pointer to the IVirtualBox interface.
3446 * @param pMachine Pointer to the IMachine interface.
3447 */
3448/* static */
3449int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3450{
3451 /*
3452 * CFGM overlay handling.
3453 *
3454 * Here we check the extra data entries for CFGM values
3455 * and create the nodes and insert the values on the fly. Existing
3456 * values will be removed and reinserted. CFGM is typed, so by default
3457 * we will guess whether it's a string or an integer (byte arrays are
3458 * not currently supported). It's possible to override this autodetection
3459 * by adding "string:", "integer:" or "bytes:" (future).
3460 *
3461 * We first perform a run on global extra data, then on the machine
3462 * extra data to support global settings with local overrides.
3463 */
3464 int rc = VINF_SUCCESS;
3465 try
3466 {
3467 /** @todo add support for removing nodes and byte blobs. */
3468 /*
3469 * Get the next key
3470 */
3471 SafeArray<BSTR> aGlobalExtraDataKeys;
3472 SafeArray<BSTR> aMachineExtraDataKeys;
3473 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3474 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3475
3476 // remember the no. of global values so we can call the correct method below
3477 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3478
3479 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3480 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3481
3482 // build a combined list from global keys...
3483 std::list<Utf8Str> llExtraDataKeys;
3484
3485 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3486 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3487 // ... and machine keys
3488 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3489 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3490
3491 size_t i2 = 0;
3492 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3493 it != llExtraDataKeys.end();
3494 ++it, ++i2)
3495 {
3496 const Utf8Str &strKey = *it;
3497
3498 /*
3499 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3500 */
3501 if (!strKey.startsWith("VBoxInternal/"))
3502 continue;
3503
3504 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3505
3506 // get the value
3507 Bstr bstrExtraDataValue;
3508 if (i2 < cGlobalValues)
3509 // this is still one of the global values:
3510 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3511 bstrExtraDataValue.asOutParam());
3512 else
3513 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3514 bstrExtraDataValue.asOutParam());
3515 if (FAILED(hrc))
3516 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3517
3518 /*
3519 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3520 * Split the two and get the node, delete the value and create the node
3521 * if necessary.
3522 */
3523 PCFGMNODE pNode;
3524 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3525 if (pszCFGMValueName)
3526 {
3527 /* terminate the node and advance to the value (Utf8Str might not
3528 offically like this but wtf) */
3529 *(char*)pszCFGMValueName = '\0';
3530 ++pszCFGMValueName;
3531
3532 /* does the node already exist? */
3533 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3534 if (pNode)
3535 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3536 else
3537 {
3538 /* create the node */
3539 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3540 if (RT_FAILURE(rc))
3541 {
3542 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3543 continue;
3544 }
3545 Assert(pNode);
3546 }
3547 }
3548 else
3549 {
3550 /* root value (no node path). */
3551 pNode = pRoot;
3552 pszCFGMValueName = pszExtraDataKey;
3553 pszExtraDataKey--;
3554 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3555 }
3556
3557 /*
3558 * Now let's have a look at the value.
3559 * Empty strings means that we should remove the value, which we've
3560 * already done above.
3561 */
3562 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3563 if (!strCFGMValueUtf8.isEmpty())
3564 {
3565 uint64_t u64Value;
3566
3567 /* check for type prefix first. */
3568 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3569 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3570 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3571 {
3572 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3573 if (RT_SUCCESS(rc))
3574 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3575 }
3576 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3577 {
3578 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3579 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3580 if (cbValue > 0)
3581 {
3582 void *pvBytes = RTMemTmpAlloc(cbValue);
3583 if (pvBytes)
3584 {
3585 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3586 if (RT_SUCCESS(rc))
3587 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3588 RTMemTmpFree(pvBytes);
3589 }
3590 else
3591 rc = VERR_NO_TMP_MEMORY;
3592 }
3593 else if (cbValue == 0)
3594 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3595 else
3596 rc = VERR_INVALID_BASE64_ENCODING;
3597 }
3598 /* auto detect type. */
3599 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3600 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3601 else
3602 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3603 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3604 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3605 }
3606 }
3607 }
3608 catch (ConfigError &x)
3609 {
3610 // InsertConfig threw something:
3611 return x.m_vrc;
3612 }
3613 return rc;
3614}
3615
3616/**
3617 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3618 * values.
3619 *
3620 * @returns VBox status code.
3621 * @param pVirtualBox Pointer to the IVirtualBox interface.
3622 * @param pMachine Pointer to the IMachine interface.
3623 */
3624/* static */
3625int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3626{
3627 {
3628 SafeArray<BSTR> aGlobalExtraDataKeys;
3629 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3630 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3631 bool hasKey = false;
3632 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3633 {
3634 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3635 if (!strKey.startsWith("VBoxInternal2/"))
3636 continue;
3637
3638 Bstr bstrValue;
3639 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3640 bstrValue.asOutParam());
3641 if (FAILED(hrc))
3642 continue;
3643 if (!hasKey)
3644 LogRel(("Global extradata API settings:\n"));
3645 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3646 hasKey = true;
3647 }
3648 }
3649
3650 {
3651 SafeArray<BSTR> aMachineExtraDataKeys;
3652 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3653 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3654 bool hasKey = false;
3655 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3656 {
3657 Utf8Str strKey(aMachineExtraDataKeys[i]);
3658 if (!strKey.startsWith("VBoxInternal2/"))
3659 continue;
3660
3661 Bstr bstrValue;
3662 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3663 bstrValue.asOutParam());
3664 if (FAILED(hrc))
3665 continue;
3666 if (!hasKey)
3667 LogRel(("Per-VM extradata API settings:\n"));
3668 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3669 hasKey = true;
3670 }
3671 }
3672
3673 return VINF_SUCCESS;
3674}
3675
3676int Console::i_configGraphicsController(PCFGMNODE pDevices,
3677 const GraphicsControllerType_T enmGraphicsController,
3678 BusAssignmentManager *pBusMgr,
3679 const ComPtr<IMachine> &ptrMachine,
3680 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3681 bool fHMEnabled)
3682{
3683 // InsertConfig* throws
3684 try
3685 {
3686 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3687 HRESULT hrc;
3688 Bstr bstr;
3689 const char *pcszDevice = "vga";
3690
3691#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3692 InsertConfigNode(pDevices, pcszDevice, &pDev);
3693 InsertConfigNode(pDev, "0", &pInst);
3694 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3695
3696 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3697 InsertConfigNode(pInst, "Config", &pCfg);
3698 ULONG cVRamMBs;
3699 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3700 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3701 ULONG cMonitorCount;
3702 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3703 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3704#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3705 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3706#else
3707 NOREF(fHMEnabled);
3708#endif
3709
3710 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3711
3712#ifdef VBOX_WITH_VMSVGA
3713 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3714 {
3715 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3716#ifdef VBOX_WITH_VMSVGA3D
3717 IFramebuffer *pFramebuffer = NULL;
3718 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3719 if (SUCCEEDED(hrc) && pFramebuffer)
3720 {
3721 LONG64 winId = 0;
3722 /** @todo deal with multimonitor setup */
3723 Assert(cMonitorCount == 1);
3724 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3725 InsertConfigInteger(pCfg, "HostWindowId", winId);
3726 pFramebuffer->Release();
3727 }
3728 BOOL f3DEnabled;
3729 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3730 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3731#else
3732 LogRel(("VMSVGA3d not available in this build!\n"));
3733#endif
3734 }
3735#endif
3736
3737 /* Custom VESA mode list */
3738 unsigned cModes = 0;
3739 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3740 {
3741 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3742 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3743 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3744 if (bstr.isEmpty())
3745 break;
3746 InsertConfigString(pCfg, szExtraDataKey, bstr);
3747 ++cModes;
3748 }
3749 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3750
3751 /* VESA height reduction */
3752 ULONG ulHeightReduction;
3753 IFramebuffer *pFramebuffer = NULL;
3754 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3755 if (SUCCEEDED(hrc) && pFramebuffer)
3756 {
3757 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3758 pFramebuffer->Release();
3759 pFramebuffer = NULL;
3760 }
3761 else
3762 {
3763 /* If framebuffer is not available, there is no height reduction. */
3764 ulHeightReduction = 0;
3765 }
3766 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3767
3768 /*
3769 * BIOS logo
3770 */
3771 BOOL fFadeIn;
3772 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3773 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3774 BOOL fFadeOut;
3775 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3776 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3777 ULONG logoDisplayTime;
3778 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3779 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3780 Bstr logoImagePath;
3781 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3782 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3783
3784 /*
3785 * Boot menu
3786 */
3787 BIOSBootMenuMode_T eBootMenuMode;
3788 int iShowBootMenu;
3789 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3790 switch (eBootMenuMode)
3791 {
3792 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3793 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3794 default: iShowBootMenu = 2; break;
3795 }
3796 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3797
3798 /* Attach the display. */
3799 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3800 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3801 InsertConfigNode(pLunL0, "Config", &pCfg);
3802 Display *pDisplay = mDisplay;
3803 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3804 }
3805 catch (ConfigError &x)
3806 {
3807 // InsertConfig threw something:
3808 return x.m_vrc;
3809 }
3810
3811#undef H
3812
3813 return VINF_SUCCESS;
3814}
3815
3816
3817/**
3818 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3819 */
3820void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3821{
3822 va_list va;
3823 va_start(va, pszFormat);
3824 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3825 va_end(va);
3826}
3827
3828/* XXX introduce RT format specifier */
3829static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3830{
3831 if (u64Size > INT64_C(5000)*_1G)
3832 {
3833 *pszUnit = "TB";
3834 return u64Size / _1T;
3835 }
3836 else if (u64Size > INT64_C(5000)*_1M)
3837 {
3838 *pszUnit = "GB";
3839 return u64Size / _1G;
3840 }
3841 else
3842 {
3843 *pszUnit = "MB";
3844 return u64Size / _1M;
3845 }
3846}
3847
3848/**
3849 * Checks the location of the given medium for known bugs affecting the usage
3850 * of the host I/O cache setting.
3851 *
3852 * @returns VBox status code.
3853 * @param pMedium The medium to check.
3854 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3855 */
3856int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3857{
3858#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3859 /*
3860 * Some sanity checks.
3861 */
3862 RT_NOREF(pfUseHostIOCache);
3863 ComPtr<IMediumFormat> pMediumFormat;
3864 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3865 ULONG uCaps = 0;
3866 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3867 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3868
3869 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3870 uCaps |= mediumFormatCap[j];
3871
3872 if (uCaps & MediumFormatCapabilities_File)
3873 {
3874 Bstr strFile;
3875 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3876 Utf8Str utfFile = Utf8Str(strFile);
3877 Bstr strSnap;
3878 ComPtr<IMachine> pMachine = i_machine();
3879 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3880 Utf8Str utfSnap = Utf8Str(strSnap);
3881 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3882 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3883 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3884 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3885 /* Ignore the error code. On error, the file system type is still 'unknown' so
3886 * none of the following paths are taken. This can happen for new VMs which
3887 * still don't have a snapshot folder. */
3888 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3889 if (!mfSnapshotFolderDiskTypeShown)
3890 {
3891 LogRel(("File system of '%s' (snapshots) is %s\n",
3892 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3893 mfSnapshotFolderDiskTypeShown = true;
3894 }
3895 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3896 LONG64 i64Size;
3897 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3898#ifdef RT_OS_WINDOWS
3899 if ( enmFsTypeFile == RTFSTYPE_FAT
3900 && i64Size >= _4G)
3901 {
3902 const char *pszUnit;
3903 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3904 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3905 N_("The medium '%ls' has a logical size of %RU64%s "
3906 "but the file system the medium is located on seems "
3907 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3908 "We strongly recommend to put all your virtual disk images and "
3909 "the snapshot folder onto an NTFS partition"),
3910 strFile.raw(), u64Print, pszUnit);
3911 }
3912#else /* !RT_OS_WINDOWS */
3913 if ( enmFsTypeFile == RTFSTYPE_FAT
3914 || enmFsTypeFile == RTFSTYPE_EXT
3915 || enmFsTypeFile == RTFSTYPE_EXT2
3916 || enmFsTypeFile == RTFSTYPE_EXT3
3917 || enmFsTypeFile == RTFSTYPE_EXT4)
3918 {
3919 RTFILE file;
3920 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3921 if (RT_SUCCESS(rc))
3922 {
3923 RTFOFF maxSize;
3924 /* Careful: This function will work only on selected local file systems! */
3925 rc = RTFileGetMaxSizeEx(file, &maxSize);
3926 RTFileClose(file);
3927 if ( RT_SUCCESS(rc)
3928 && maxSize > 0
3929 && i64Size > (LONG64)maxSize)
3930 {
3931 const char *pszUnitSiz;
3932 const char *pszUnitMax;
3933 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3934 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3935 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3936 N_("The medium '%ls' has a logical size of %RU64%s "
3937 "but the file system the medium is located on can "
3938 "only handle files up to %RU64%s in theory.\n"
3939 "We strongly recommend to put all your virtual disk "
3940 "images and the snapshot folder onto a proper "
3941 "file system (e.g. ext3) with a sufficient size"),
3942 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3943 }
3944 }
3945 }
3946#endif /* !RT_OS_WINDOWS */
3947
3948 /*
3949 * Snapshot folder:
3950 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3951 */
3952 if ( enmFsTypeSnap == RTFSTYPE_FAT
3953 && i64Size >= _4G
3954 && !mfSnapshotFolderSizeWarningShown)
3955 {
3956 const char *pszUnit;
3957 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3958 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3959#ifdef RT_OS_WINDOWS
3960 N_("The snapshot folder of this VM '%ls' seems to be located on "
3961 "a FAT(32) file system. The logical size of the medium '%ls' "
3962 "(%RU64%s) is bigger than the maximum file size this file "
3963 "system can handle (4GB).\n"
3964 "We strongly recommend to put all your virtual disk images and "
3965 "the snapshot folder onto an NTFS partition"),
3966#else
3967 N_("The snapshot folder of this VM '%ls' seems to be located on "
3968 "a FAT(32) file system. The logical size of the medium '%ls' "
3969 "(%RU64%s) is bigger than the maximum file size this file "
3970 "system can handle (4GB).\n"
3971 "We strongly recommend to put all your virtual disk images and "
3972 "the snapshot folder onto a proper file system (e.g. ext3)"),
3973#endif
3974 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3975 /* Show this particular warning only once */
3976 mfSnapshotFolderSizeWarningShown = true;
3977 }
3978
3979#ifdef RT_OS_LINUX
3980 /*
3981 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3982 * on an ext4 partition.
3983 * This bug apparently applies to the XFS file system as well.
3984 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3985 */
3986
3987 char szOsRelease[128];
3988 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3989 bool fKernelHasODirectBug = RT_FAILURE(rc)
3990 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3991
3992 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3993 && !*pfUseHostIOCache
3994 && fKernelHasODirectBug)
3995 {
3996 if ( enmFsTypeFile == RTFSTYPE_EXT4
3997 || enmFsTypeFile == RTFSTYPE_XFS)
3998 {
3999 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4000 N_("The host I/O cache for at least one controller is disabled "
4001 "and the medium '%ls' for this VM "
4002 "is located on an %s partition. There is a known Linux "
4003 "kernel bug which can lead to the corruption of the virtual "
4004 "disk image under these conditions.\n"
4005 "Either enable the host I/O cache permanently in the VM "
4006 "settings or put the disk image and the snapshot folder "
4007 "onto a different file system.\n"
4008 "The host I/O cache will now be enabled for this medium"),
4009 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4010 *pfUseHostIOCache = true;
4011 }
4012 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4013 || enmFsTypeSnap == RTFSTYPE_XFS)
4014 && !mfSnapshotFolderExt4WarningShown)
4015 {
4016 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4017 N_("The host I/O cache for at least one controller is disabled "
4018 "and the snapshot folder for this VM "
4019 "is located on an %s partition. There is a known Linux "
4020 "kernel bug which can lead to the corruption of the virtual "
4021 "disk image under these conditions.\n"
4022 "Either enable the host I/O cache permanently in the VM "
4023 "settings or put the disk image and the snapshot folder "
4024 "onto a different file system.\n"
4025 "The host I/O cache will now be enabled for this medium"),
4026 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4027 *pfUseHostIOCache = true;
4028 mfSnapshotFolderExt4WarningShown = true;
4029 }
4030 }
4031
4032 /*
4033 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4034 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4035 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4036 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4037 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4038 */
4039 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4040 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4041 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4042 && !*pfUseHostIOCache
4043 && fKernelAsyncUnreliable)
4044 {
4045 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4046 N_("The host I/O cache for at least one controller is disabled. "
4047 "There is a known Linux kernel bug which can lead to kernel "
4048 "oopses under heavy load. To our knowledge this bug affects "
4049 "all 2.6.18 kernels.\n"
4050 "Either enable the host I/O cache permanently in the VM "
4051 "settings or switch to a newer host kernel.\n"
4052 "The host I/O cache will now be enabled for this medium"));
4053 *pfUseHostIOCache = true;
4054 }
4055#endif
4056 }
4057#undef H
4058
4059 return VINF_SUCCESS;
4060}
4061
4062/**
4063 * Unmounts the specified medium from the specified device.
4064 *
4065 * @returns VBox status code.
4066 * @param pUVM The usermode VM handle.
4067 * @param enmBus The storage bus.
4068 * @param enmDevType The device type.
4069 * @param pcszDevice The device emulation.
4070 * @param uInstance Instance of the device.
4071 * @param uLUN The LUN on the device.
4072 * @param fForceUnmount Whether to force unmounting.
4073 */
4074int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4075 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4076 bool fForceUnmount)
4077{
4078 /* Unmount existing media only for floppy and DVD drives. */
4079 int rc = VINF_SUCCESS;
4080 PPDMIBASE pBase;
4081 if (enmBus == StorageBus_USB)
4082 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4083 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4084 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4085 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4086 else /* IDE or Floppy */
4087 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4088
4089 if (RT_FAILURE(rc))
4090 {
4091 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4092 rc = VINF_SUCCESS;
4093 AssertRC(rc);
4094 }
4095 else
4096 {
4097 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4098 AssertReturn(pIMount, VERR_INVALID_POINTER);
4099
4100 /* Unmount the media (but do not eject the medium!) */
4101 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4102 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4103 rc = VINF_SUCCESS;
4104 /* for example if the medium is locked */
4105 else if (RT_FAILURE(rc))
4106 return rc;
4107 }
4108
4109 return rc;
4110}
4111
4112/**
4113 * Removes the currently attached medium driver form the specified device
4114 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4115 *
4116 * @returns VBox status code.
4117 * @param pCtlInst The controler instance node in the CFGM tree.
4118 * @param pcszDevice The device name.
4119 * @param uInstance The device instance.
4120 * @param uLUN The device LUN.
4121 * @param enmBus The storage bus.
4122 * @param fAttachDetach Flag whether this is a change while the VM is running
4123 * @param fHotplug Flag whether the guest should be notified about the device change.
4124 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4125 * @param pUVM The usermode VM handle.
4126 * @param enmDevType The device type.
4127 * @param ppLunL0 Where to store the node to attach the new config to on success.
4128 */
4129int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4130 const char *pcszDevice,
4131 unsigned uInstance,
4132 unsigned uLUN,
4133 StorageBus_T enmBus,
4134 bool fAttachDetach,
4135 bool fHotplug,
4136 bool fForceUnmount,
4137 PUVM pUVM,
4138 DeviceType_T enmDevType,
4139 PCFGMNODE *ppLunL0)
4140{
4141 int rc = VINF_SUCCESS;
4142 bool fAddLun = false;
4143
4144 /* First check if the LUN already exists. */
4145 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4146 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4147
4148 if (pLunL0)
4149 {
4150 /*
4151 * Unmount the currently mounted medium if we don't just hot remove the
4152 * complete device (SATA) and it supports unmounting (DVD).
4153 */
4154 if ( (enmDevType != DeviceType_HardDisk)
4155 && !fHotplug)
4156 {
4157 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4158 uInstance, uLUN, fForceUnmount);
4159 if (RT_FAILURE(rc))
4160 return rc;
4161 }
4162
4163 /*
4164 * Don't detach the SCSI driver when unmounting the current medium
4165 * (we are not ripping out the device but only eject the medium).
4166 */
4167 char *pszDriverDetach = NULL;
4168 if ( !fHotplug
4169 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4170 || enmBus == StorageBus_SAS
4171 || enmBus == StorageBus_SCSI
4172 || enmBus == StorageBus_USB))
4173 {
4174 /* Get the current attached driver we have to detach. */
4175 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4176 if (pDrvLun)
4177 {
4178 char szDriver[128];
4179 RT_ZERO(szDriver);
4180 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4181 if (RT_SUCCESS(rc))
4182 pszDriverDetach = RTStrDup(&szDriver[0]);
4183
4184 pLunL0 = pDrvLun;
4185 }
4186 }
4187
4188 if (enmBus == StorageBus_USB)
4189 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4190 pszDriverDetach, 0 /* iOccurence */,
4191 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4192 else
4193 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4194 pszDriverDetach, 0 /* iOccurence */,
4195 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4196
4197 if (pszDriverDetach)
4198 {
4199 RTStrFree(pszDriverDetach);
4200 /* Remove the complete node and create new for the new config. */
4201 CFGMR3RemoveNode(pLunL0);
4202 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4203 if (pLunL0)
4204 {
4205 try
4206 {
4207 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4208 }
4209 catch (ConfigError &x)
4210 {
4211 // InsertConfig threw something:
4212 return x.m_vrc;
4213 }
4214 }
4215 }
4216 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4217 rc = VINF_SUCCESS;
4218 AssertRCReturn(rc, rc);
4219
4220 /*
4221 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4222 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4223 */
4224 if ( fHotplug
4225 || enmBus == StorageBus_IDE
4226 || enmBus == StorageBus_Floppy
4227 || enmBus == StorageBus_PCIe
4228 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4229 {
4230 fAddLun = true;
4231 CFGMR3RemoveNode(pLunL0);
4232 }
4233 }
4234 else
4235 fAddLun = true;
4236
4237 try
4238 {
4239 if (fAddLun)
4240 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4241 }
4242 catch (ConfigError &x)
4243 {
4244 // InsertConfig threw something:
4245 return x.m_vrc;
4246 }
4247
4248 if (ppLunL0)
4249 *ppLunL0 = pLunL0;
4250
4251 return rc;
4252}
4253
4254int Console::i_configMediumAttachment(const char *pcszDevice,
4255 unsigned uInstance,
4256 StorageBus_T enmBus,
4257 bool fUseHostIOCache,
4258 bool fBuiltinIOCache,
4259 bool fInsertDiskIntegrityDrv,
4260 bool fSetupMerge,
4261 unsigned uMergeSource,
4262 unsigned uMergeTarget,
4263 IMediumAttachment *pMediumAtt,
4264 MachineState_T aMachineState,
4265 HRESULT *phrc,
4266 bool fAttachDetach,
4267 bool fForceUnmount,
4268 bool fHotplug,
4269 PUVM pUVM,
4270 DeviceType_T *paLedDevType,
4271 PCFGMNODE *ppLunL0)
4272{
4273 // InsertConfig* throws
4274 try
4275 {
4276 int rc = VINF_SUCCESS;
4277 HRESULT hrc;
4278 Bstr bstr;
4279 PCFGMNODE pCtlInst = NULL;
4280
4281// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4282#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4283
4284 LONG lDev;
4285 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4286 LONG lPort;
4287 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4288 DeviceType_T lType;
4289 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4290 BOOL fNonRotational;
4291 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4292 BOOL fDiscard;
4293 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4294
4295 unsigned uLUN;
4296 PCFGMNODE pLunL0 = NULL;
4297 hrc = Console::i_convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4298
4299 /* Determine the base path for the device instance. */
4300 if (enmBus != StorageBus_USB)
4301 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4302 else
4303 {
4304 /* If we hotplug a USB device create a new CFGM tree. */
4305 if (!fHotplug)
4306 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4307 else
4308 pCtlInst = CFGMR3CreateTree(pUVM);
4309 }
4310 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4311
4312 if (enmBus == StorageBus_USB)
4313 {
4314 PCFGMNODE pCfg = NULL;
4315
4316 /* Create correct instance. */
4317 if (!fHotplug)
4318 {
4319 if (!fAttachDetach)
4320 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4321 else
4322 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4323 }
4324
4325 if (!fAttachDetach)
4326 InsertConfigNode(pCtlInst, "Config", &pCfg);
4327
4328 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4329
4330 if (!fHotplug && !fAttachDetach)
4331 {
4332 char aszUuid[RTUUID_STR_LENGTH + 1];
4333 USBStorageDevice UsbMsd = USBStorageDevice();
4334
4335 memset(aszUuid, 0, sizeof(aszUuid));
4336 rc = RTUuidCreate(&UsbMsd.mUuid);
4337 AssertRCReturn(rc, rc);
4338 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4339 AssertRCReturn(rc, rc);
4340
4341 UsbMsd.iPort = uInstance;
4342
4343 InsertConfigString(pCtlInst, "UUID", aszUuid);
4344 mUSBStorageDevices.push_back(UsbMsd);
4345
4346 /** @todo No LED after hotplugging. */
4347 /* Attach the status driver */
4348 Assert(cLedUsb >= 8);
4349 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4350 &mapMediumAttachments, pcszDevice, 0);
4351 paLedDevType = &maStorageDevType[iLedUsb];
4352 }
4353 }
4354
4355 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4356 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4357 if (RT_FAILURE(rc))
4358 return rc;
4359 if (ppLunL0)
4360 *ppLunL0 = pLunL0;
4361
4362 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4363 mapMediumAttachments[devicePath] = pMediumAtt;
4364
4365 ComPtr<IMedium> pMedium;
4366 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4367
4368 /*
4369 * 1. Only check this for hard disk images.
4370 * 2. Only check during VM creation and not later, especially not during
4371 * taking an online snapshot!
4372 */
4373 if ( lType == DeviceType_HardDisk
4374 && ( aMachineState == MachineState_Starting
4375 || aMachineState == MachineState_Restoring))
4376 {
4377 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4378 if (RT_FAILURE(rc))
4379 return rc;
4380 }
4381
4382 BOOL fPassthrough = FALSE;
4383 if (pMedium)
4384 {
4385 BOOL fHostDrive;
4386 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4387 if ( ( lType == DeviceType_DVD
4388 || lType == DeviceType_Floppy)
4389 && !fHostDrive)
4390 {
4391 /*
4392 * Informative logging.
4393 */
4394 Bstr strFile;
4395 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4396 Utf8Str utfFile = Utf8Str(strFile);
4397 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4398 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4399 LogRel(("File system of '%s' (%s) is %s\n",
4400 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4401 RTFsTypeName(enmFsTypeFile)));
4402 }
4403
4404 if (fHostDrive)
4405 {
4406 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4407 }
4408 }
4409
4410 ComObjPtr<IBandwidthGroup> pBwGroup;
4411 Bstr strBwGroup;
4412 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4413
4414 if (!pBwGroup.isNull())
4415 {
4416 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4417 }
4418
4419 /*
4420 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4421 * or for SATA if the new device is a CD/DVD drive.
4422 */
4423 if ( (fHotplug || !fAttachDetach)
4424 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4425 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4426 {
4427 InsertConfigString(pLunL0, "Driver", "SCSI");
4428 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4429 }
4430
4431 rc = i_configMedium(pLunL0,
4432 !!fPassthrough,
4433 lType,
4434 fUseHostIOCache,
4435 fBuiltinIOCache,
4436 fInsertDiskIntegrityDrv,
4437 fSetupMerge,
4438 uMergeSource,
4439 uMergeTarget,
4440 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4441 !!fDiscard,
4442 !!fNonRotational,
4443 pMedium,
4444 aMachineState,
4445 phrc);
4446 if (RT_FAILURE(rc))
4447 return rc;
4448
4449 if (fAttachDetach)
4450 {
4451 /* Attach the new driver. */
4452 if (enmBus == StorageBus_USB)
4453 {
4454 if (fHotplug)
4455 {
4456 USBStorageDevice UsbMsd = USBStorageDevice();
4457 RTUuidCreate(&UsbMsd.mUuid);
4458 UsbMsd.iPort = uInstance;
4459 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4460 if (RT_SUCCESS(rc))
4461 mUSBStorageDevices.push_back(UsbMsd);
4462 }
4463 else
4464 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4465 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4466 }
4467 else if ( !fHotplug
4468 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4469 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4470 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4471 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4472 else
4473 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4474 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4475 AssertRCReturn(rc, rc);
4476
4477 /*
4478 * Make the secret key helper interface known to the VD driver if it is attached,
4479 * so we can get notified about missing keys.
4480 */
4481 PPDMIBASE pIBase = NULL;
4482 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4483 if (RT_SUCCESS(rc) && pIBase)
4484 {
4485 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4486 if (pIMedium)
4487 {
4488 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4489 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4490 }
4491 }
4492
4493 /* There is no need to handle removable medium mounting, as we
4494 * unconditionally replace everthing including the block driver level.
4495 * This means the new medium will be picked up automatically. */
4496 }
4497
4498 if (paLedDevType)
4499 paLedDevType[uLUN] = lType;
4500
4501 /* Dump the changed LUN if possible, dump the complete device otherwise */
4502 if ( aMachineState != MachineState_Starting
4503 && aMachineState != MachineState_Restoring)
4504 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4505 }
4506 catch (ConfigError &x)
4507 {
4508 // InsertConfig threw something:
4509 return x.m_vrc;
4510 }
4511
4512#undef H
4513
4514 return VINF_SUCCESS;
4515}
4516
4517int Console::i_configMedium(PCFGMNODE pLunL0,
4518 bool fPassthrough,
4519 DeviceType_T enmType,
4520 bool fUseHostIOCache,
4521 bool fBuiltinIOCache,
4522 bool fInsertDiskIntegrityDrv,
4523 bool fSetupMerge,
4524 unsigned uMergeSource,
4525 unsigned uMergeTarget,
4526 const char *pcszBwGroup,
4527 bool fDiscard,
4528 bool fNonRotational,
4529 IMedium *pMedium,
4530 MachineState_T aMachineState,
4531 HRESULT *phrc)
4532{
4533 // InsertConfig* throws
4534 try
4535 {
4536 HRESULT hrc;
4537 Bstr bstr;
4538 PCFGMNODE pCfg = NULL;
4539
4540#define H() \
4541 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4542
4543
4544 BOOL fHostDrive = FALSE;
4545 MediumType_T mediumType = MediumType_Normal;
4546 if (pMedium)
4547 {
4548 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4549 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4550 }
4551
4552 if (fHostDrive)
4553 {
4554 Assert(pMedium);
4555 if (enmType == DeviceType_DVD)
4556 {
4557 InsertConfigString(pLunL0, "Driver", "HostDVD");
4558 InsertConfigNode(pLunL0, "Config", &pCfg);
4559
4560 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4561 InsertConfigString(pCfg, "Path", bstr);
4562
4563 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4564 }
4565 else if (enmType == DeviceType_Floppy)
4566 {
4567 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4568 InsertConfigNode(pLunL0, "Config", &pCfg);
4569
4570 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4571 InsertConfigString(pCfg, "Path", bstr);
4572 }
4573 }
4574 else
4575 {
4576 if (fInsertDiskIntegrityDrv)
4577 {
4578 /*
4579 * The actual configuration is done through CFGM extra data
4580 * for each inserted driver separately.
4581 */
4582 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4583 InsertConfigNode(pLunL0, "Config", &pCfg);
4584 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4585 }
4586
4587 InsertConfigString(pLunL0, "Driver", "VD");
4588 InsertConfigNode(pLunL0, "Config", &pCfg);
4589 switch (enmType)
4590 {
4591 case DeviceType_DVD:
4592 InsertConfigString(pCfg, "Type", "DVD");
4593 InsertConfigInteger(pCfg, "Mountable", 1);
4594 break;
4595 case DeviceType_Floppy:
4596 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4597 InsertConfigInteger(pCfg, "Mountable", 1);
4598 break;
4599 case DeviceType_HardDisk:
4600 default:
4601 InsertConfigString(pCfg, "Type", "HardDisk");
4602 InsertConfigInteger(pCfg, "Mountable", 0);
4603 }
4604
4605 if ( pMedium
4606 && ( enmType == DeviceType_DVD
4607 || enmType == DeviceType_Floppy)
4608 )
4609 {
4610 // if this medium represents an ISO image and this image is inaccessible,
4611 // the ignore it instead of causing a failure; this can happen when we
4612 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4613 // Additions were mounted and the user upgraded VirtualBox. Previously
4614 // we failed on startup, but that's not good because the only way out then
4615 // would be to discard the VM state...
4616 MediumState_T mediumState;
4617 hrc = pMedium->RefreshState(&mediumState); H();
4618 if (mediumState == MediumState_Inaccessible)
4619 {
4620 Bstr loc;
4621 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4622 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4623 "The image file '%ls' is inaccessible and is being ignored. "
4624 "Please select a different image file for the virtual %s drive.",
4625 loc.raw(),
4626 enmType == DeviceType_DVD ? "DVD" : "floppy");
4627 pMedium = NULL;
4628 }
4629 }
4630
4631 if (pMedium)
4632 {
4633 /* Start with length of parent chain, as the list is reversed */
4634 unsigned uImage = 0;
4635 IMedium *pTmp = pMedium;
4636 while (pTmp)
4637 {
4638 uImage++;
4639 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4640 }
4641 /* Index of last image */
4642 uImage--;
4643
4644# ifdef VBOX_WITH_EXTPACK
4645 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4646 {
4647 /* Configure loading the VDPlugin. */
4648 static const char s_szVDPlugin[] = "VDPluginCrypt";
4649 PCFGMNODE pCfgPlugins = NULL;
4650 PCFGMNODE pCfgPlugin = NULL;
4651 Utf8Str strPlugin;
4652 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4653 // Don't fail, this is optional!
4654 if (SUCCEEDED(hrc))
4655 {
4656 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4657 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4658 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4659 }
4660 }
4661# endif
4662
4663 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4664 InsertConfigString(pCfg, "Path", bstr);
4665
4666 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4667 InsertConfigString(pCfg, "Format", bstr);
4668
4669 if (mediumType == MediumType_Readonly)
4670 InsertConfigInteger(pCfg, "ReadOnly", 1);
4671 else if (enmType == DeviceType_Floppy)
4672 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4673
4674 /* Start without exclusive write access to the images. */
4675 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4676 * we're resuming the VM if some 3rd dude have any of the VDIs open
4677 * with write sharing denied. However, if the two VMs are sharing a
4678 * image it really is necessary....
4679 *
4680 * So, on the "lock-media" command, the target teleporter should also
4681 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4682 * that. Grumble. */
4683 if ( enmType == DeviceType_HardDisk
4684 && ( aMachineState == MachineState_TeleportingIn
4685 || aMachineState == MachineState_FaultTolerantSyncing))
4686 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4687
4688 /* Flag for opening the medium for sharing between VMs. This
4689 * is done at the moment only for the first (and only) medium
4690 * in the chain, as shared media can have no diffs. */
4691 if (mediumType == MediumType_Shareable)
4692 InsertConfigInteger(pCfg, "Shareable", 1);
4693
4694 if (!fUseHostIOCache)
4695 {
4696 InsertConfigInteger(pCfg, "UseNewIo", 1);
4697 /*
4698 * Activate the builtin I/O cache for harddisks only.
4699 * It caches writes only which doesn't make sense for DVD drives
4700 * and just increases the overhead.
4701 */
4702 if ( fBuiltinIOCache
4703 && (enmType == DeviceType_HardDisk))
4704 InsertConfigInteger(pCfg, "BlockCache", 1);
4705 }
4706
4707 if (fSetupMerge)
4708 {
4709 InsertConfigInteger(pCfg, "SetupMerge", 1);
4710 if (uImage == uMergeSource)
4711 InsertConfigInteger(pCfg, "MergeSource", 1);
4712 else if (uImage == uMergeTarget)
4713 InsertConfigInteger(pCfg, "MergeTarget", 1);
4714 }
4715
4716 if (pcszBwGroup)
4717 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4718
4719 if (fDiscard)
4720 InsertConfigInteger(pCfg, "Discard", 1);
4721
4722 if (fNonRotational)
4723 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4724
4725 /* Pass all custom parameters. */
4726 bool fHostIP = true;
4727 bool fEncrypted = false;
4728 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4729
4730 /* Create an inverted list of parents. */
4731 uImage--;
4732 IMedium *pParentMedium = pMedium;
4733 for (PCFGMNODE pParent = pCfg;; uImage--)
4734 {
4735 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4736 if (!pMedium)
4737 break;
4738
4739 PCFGMNODE pCur;
4740 InsertConfigNode(pParent, "Parent", &pCur);
4741 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4742 InsertConfigString(pCur, "Path", bstr);
4743
4744 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4745 InsertConfigString(pCur, "Format", bstr);
4746
4747 if (fSetupMerge)
4748 {
4749 if (uImage == uMergeSource)
4750 InsertConfigInteger(pCur, "MergeSource", 1);
4751 else if (uImage == uMergeTarget)
4752 InsertConfigInteger(pCur, "MergeTarget", 1);
4753 }
4754
4755 /* Configure medium properties. */
4756 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4757
4758 /* next */
4759 pParent = pCur;
4760 pParentMedium = pMedium;
4761 }
4762
4763 /* Custom code: put marker to not use host IP stack to driver
4764 * configuration node. Simplifies life of DrvVD a bit. */
4765 if (!fHostIP)
4766 InsertConfigInteger(pCfg, "HostIPStack", 0);
4767
4768 if (fEncrypted)
4769 m_cDisksEncrypted++;
4770 }
4771 else
4772 {
4773 /* Set empty drive flag for DVD or floppy without media. */
4774 if ( enmType == DeviceType_DVD
4775 || enmType == DeviceType_Floppy)
4776 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4777 }
4778 }
4779#undef H
4780 }
4781 catch (ConfigError &x)
4782 {
4783 // InsertConfig threw something:
4784 return x.m_vrc;
4785 }
4786
4787 return VINF_SUCCESS;
4788}
4789
4790/**
4791 * Adds the medium properties to the CFGM tree.
4792 *
4793 * @returns VBox status code.
4794 * @param pCur The current CFGM node.
4795 * @param pMedium The medium object to configure.
4796 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4797 * @param pfEncrypted Where to return whether the medium is encrypted.
4798 */
4799int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4800{
4801 /* Pass all custom parameters. */
4802 SafeArray<BSTR> aNames;
4803 SafeArray<BSTR> aValues;
4804 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4805 ComSafeArrayAsOutParam(aValues));
4806
4807 if ( SUCCEEDED(hrc)
4808 && aNames.size() != 0)
4809 {
4810 PCFGMNODE pVDC;
4811 InsertConfigNode(pCur, "VDConfig", &pVDC);
4812 for (size_t ii = 0; ii < aNames.size(); ++ii)
4813 {
4814 if (aValues[ii] && *aValues[ii])
4815 {
4816 Utf8Str name = aNames[ii];
4817 Utf8Str value = aValues[ii];
4818 size_t offSlash = name.find("/", 0);
4819 if ( offSlash != name.npos
4820 && !name.startsWith("Special/"))
4821 {
4822 com::Utf8Str strFilter;
4823 com::Utf8Str strKey;
4824
4825 hrc = strFilter.assignEx(name, 0, offSlash);
4826 if (FAILED(hrc))
4827 break;
4828
4829 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4830 if (FAILED(hrc))
4831 break;
4832
4833 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4834 if (!pCfgFilterConfig)
4835 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4836
4837 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4838 }
4839 else
4840 {
4841 InsertConfigString(pVDC, name.c_str(), value);
4842 if ( name.compare("HostIPStack") == 0
4843 && value.compare("0") == 0)
4844 *pfHostIP = false;
4845 }
4846
4847 if ( name.compare("CRYPT/KeyId") == 0
4848 && pfEncrypted)
4849 *pfEncrypted = true;
4850 }
4851 }
4852 }
4853
4854 return hrc;
4855}
4856
4857
4858/**
4859 * Construct the Network configuration tree
4860 *
4861 * @returns VBox status code.
4862 *
4863 * @param pszDevice The PDM device name.
4864 * @param uInstance The PDM device instance.
4865 * @param uLun The PDM LUN number of the drive.
4866 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4867 * @param pCfg Configuration node for the device
4868 * @param pLunL0 To store the pointer to the LUN#0.
4869 * @param pInst The instance CFGM node
4870 * @param fAttachDetach To determine if the network attachment should
4871 * be attached/detached after/before
4872 * configuration.
4873 * @param fIgnoreConnectFailure
4874 * True if connection failures should be ignored
4875 * (makes only sense for bridged/host-only networks).
4876 *
4877 * @note Locks this object for writing.
4878 * @thread EMT
4879 */
4880int Console::i_configNetwork(const char *pszDevice,
4881 unsigned uInstance,
4882 unsigned uLun,
4883 INetworkAdapter *aNetworkAdapter,
4884 PCFGMNODE pCfg,
4885 PCFGMNODE pLunL0,
4886 PCFGMNODE pInst,
4887 bool fAttachDetach,
4888 bool fIgnoreConnectFailure)
4889{
4890 RT_NOREF(fIgnoreConnectFailure);
4891 AutoCaller autoCaller(this);
4892 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4893
4894 // InsertConfig* throws
4895 try
4896 {
4897 int rc = VINF_SUCCESS;
4898 HRESULT hrc;
4899 Bstr bstr;
4900
4901#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4902
4903 /*
4904 * Locking the object before doing VMR3* calls is quite safe here, since
4905 * we're on EMT. Write lock is necessary because we indirectly modify the
4906 * meAttachmentType member.
4907 */
4908 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4909
4910 ComPtr<IMachine> pMachine = i_machine();
4911
4912 ComPtr<IVirtualBox> virtualBox;
4913 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4914
4915 ComPtr<IHost> host;
4916 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4917
4918 BOOL fSniffer;
4919 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4920
4921 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4922 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4923 const char *pszPromiscuousGuestPolicy;
4924 switch (enmPromiscModePolicy)
4925 {
4926 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4927 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4928 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4929 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4930 }
4931
4932 if (fAttachDetach)
4933 {
4934 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4935 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4936 rc = VINF_SUCCESS;
4937 AssertLogRelRCReturn(rc, rc);
4938
4939 /* nuke anything which might have been left behind. */
4940 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4941 }
4942
4943#ifdef VBOX_WITH_NETSHAPER
4944 ComObjPtr<IBandwidthGroup> pBwGroup;
4945 Bstr strBwGroup;
4946 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4947
4948 if (!pBwGroup.isNull())
4949 {
4950 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4951 }
4952#endif /* VBOX_WITH_NETSHAPER */
4953
4954 Utf8Str strNetDriver;
4955
4956
4957 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4958
4959#ifdef VBOX_WITH_NETSHAPER
4960 if (!strBwGroup.isEmpty())
4961 {
4962 InsertConfigString(pLunL0, "Driver", "NetShaper");
4963 InsertConfigNode(pLunL0, "Config", &pCfg);
4964 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4965 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4966 }
4967#endif /* VBOX_WITH_NETSHAPER */
4968
4969 if (fSniffer)
4970 {
4971 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4972 InsertConfigNode(pLunL0, "Config", &pCfg);
4973 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4974 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4975 InsertConfigString(pCfg, "File", bstr);
4976 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4977 }
4978
4979
4980 Bstr networkName, trunkName, trunkType;
4981 NetworkAttachmentType_T eAttachmentType;
4982 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4983 switch (eAttachmentType)
4984 {
4985 case NetworkAttachmentType_Null:
4986 break;
4987
4988 case NetworkAttachmentType_NAT:
4989 {
4990 ComPtr<INATEngine> natEngine;
4991 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4992 InsertConfigString(pLunL0, "Driver", "NAT");
4993 InsertConfigNode(pLunL0, "Config", &pCfg);
4994
4995 /* Configure TFTP prefix and boot filename. */
4996 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4997 if (!bstr.isEmpty())
4998 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
4999 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5000 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5001
5002 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5003 if (!bstr.isEmpty())
5004 InsertConfigString(pCfg, "Network", bstr);
5005 else
5006 {
5007 ULONG uSlot;
5008 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5009 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5010 }
5011 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5012 if (!bstr.isEmpty())
5013 InsertConfigString(pCfg, "BindIP", bstr);
5014 ULONG mtu = 0;
5015 ULONG sockSnd = 0;
5016 ULONG sockRcv = 0;
5017 ULONG tcpSnd = 0;
5018 ULONG tcpRcv = 0;
5019 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5020 if (mtu)
5021 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5022 if (sockRcv)
5023 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5024 if (sockSnd)
5025 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5026 if (tcpRcv)
5027 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5028 if (tcpSnd)
5029 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5030 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5031 if (!bstr.isEmpty())
5032 {
5033 RemoveConfigValue(pCfg, "TFTPPrefix");
5034 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5035 }
5036 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5037 if (!bstr.isEmpty())
5038 {
5039 RemoveConfigValue(pCfg, "BootFile");
5040 InsertConfigString(pCfg, "BootFile", bstr);
5041 }
5042 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5043 if (!bstr.isEmpty())
5044 InsertConfigString(pCfg, "NextServer", bstr);
5045 BOOL fDNSFlag;
5046 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5047 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5048 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5049 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5050 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5051 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5052
5053 ULONG aliasMode;
5054 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5055 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5056
5057 /* port-forwarding */
5058 SafeArray<BSTR> pfs;
5059 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5060
5061 PCFGMNODE pPFTree = NULL;
5062 if (pfs.size() > 0)
5063 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5064
5065 for (unsigned int i = 0; i < pfs.size(); ++i)
5066 {
5067 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5068
5069 uint16_t port = 0;
5070 BSTR r = pfs[i];
5071 Utf8Str utf = Utf8Str(r);
5072 Utf8Str strName;
5073 Utf8Str strProto;
5074 Utf8Str strHostPort;
5075 Utf8Str strHostIP;
5076 Utf8Str strGuestPort;
5077 Utf8Str strGuestIP;
5078 size_t pos, ppos;
5079 pos = ppos = 0;
5080#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5081 { \
5082 pos = str.find(",", ppos); \
5083 if (pos == Utf8Str::npos) \
5084 { \
5085 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5086 continue; \
5087 } \
5088 res = str.substr(ppos, pos - ppos); \
5089 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5090 ppos = pos + 1; \
5091 } /* no do { ... } while because of 'continue' */
5092 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5093 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5094 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5095 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5096 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5097 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5098#undef ITERATE_TO_NEXT_TERM
5099
5100 uint32_t proto = strProto.toUInt32();
5101 bool fValid = true;
5102 switch (proto)
5103 {
5104 case NATProtocol_UDP:
5105 strProto = "UDP";
5106 break;
5107 case NATProtocol_TCP:
5108 strProto = "TCP";
5109 break;
5110 default:
5111 fValid = false;
5112 }
5113 /* continue with next rule if no valid proto was passed */
5114 if (!fValid)
5115 continue;
5116
5117 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5118
5119 if (!strName.isEmpty())
5120 InsertConfigString(pPF, "Name", strName);
5121
5122 InsertConfigString(pPF, "Protocol", strProto);
5123
5124 if (!strHostIP.isEmpty())
5125 InsertConfigString(pPF, "BindIP", strHostIP);
5126
5127 if (!strGuestIP.isEmpty())
5128 InsertConfigString(pPF, "GuestIP", strGuestIP);
5129
5130 port = RTStrToUInt16(strHostPort.c_str());
5131 if (port)
5132 InsertConfigInteger(pPF, "HostPort", port);
5133
5134 port = RTStrToUInt16(strGuestPort.c_str());
5135 if (port)
5136 InsertConfigInteger(pPF, "GuestPort", port);
5137 }
5138 break;
5139 }
5140
5141 case NetworkAttachmentType_Bridged:
5142 {
5143#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5144 hrc = i_attachToTapInterface(aNetworkAdapter);
5145 if (FAILED(hrc))
5146 {
5147 switch (hrc)
5148 {
5149 case VERR_ACCESS_DENIED:
5150 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5151 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5152 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5153 "change the group of that node and make yourself a member of that group. Make "
5154 "sure that these changes are permanent, especially if you are "
5155 "using udev"));
5156 default:
5157 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5158 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5159 "Failed to initialize Host Interface Networking"));
5160 }
5161 }
5162
5163 Assert((intptr_t)maTapFD[uInstance] >= 0);
5164 if ((intptr_t)maTapFD[uInstance] >= 0)
5165 {
5166 InsertConfigString(pLunL0, "Driver", "HostInterface");
5167 InsertConfigNode(pLunL0, "Config", &pCfg);
5168 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5169 }
5170
5171#elif defined(VBOX_WITH_NETFLT)
5172 /*
5173 * This is the new VBoxNetFlt+IntNet stuff.
5174 */
5175 Bstr BridgedIfName;
5176 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5177 if (FAILED(hrc))
5178 {
5179 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5180 H();
5181 }
5182
5183 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5184 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5185
5186 ComPtr<IHostNetworkInterface> hostInterface;
5187 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5188 hostInterface.asOutParam());
5189 if (!SUCCEEDED(hrc))
5190 {
5191 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5192 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5193 N_("Nonexistent host networking interface, name '%ls'"),
5194 BridgedIfName.raw());
5195 }
5196
5197# if defined(RT_OS_DARWIN)
5198 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5199 char szTrunk[8];
5200 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5201 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5202// Quick fix for @bugref{5633}
5203// if (!pszColon)
5204// {
5205// /*
5206// * Dynamic changing of attachment causes an attempt to configure
5207// * network with invalid host adapter (as it is must be changed before
5208// * the attachment), calling Detach here will cause a deadlock.
5209// * See @bugref{4750}.
5210// * hrc = aNetworkAdapter->Detach(); H();
5211// */
5212// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5213// N_("Malformed host interface networking name '%ls'"),
5214// BridgedIfName.raw());
5215// }
5216 if (pszColon)
5217 *pszColon = '\0';
5218 const char *pszTrunk = szTrunk;
5219
5220# elif defined(RT_OS_SOLARIS)
5221 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5222 char szTrunk[256];
5223 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5224 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5225
5226 /*
5227 * Currently don't bother about malformed names here for the sake of people using
5228 * VBoxManage and setting only the NIC name from there. If there is a space we
5229 * chop it off and proceed, otherwise just use whatever we've got.
5230 */
5231 if (pszSpace)
5232 *pszSpace = '\0';
5233
5234 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5235 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5236 if (pszColon)
5237 *pszColon = '\0';
5238
5239 const char *pszTrunk = szTrunk;
5240
5241# elif defined(RT_OS_WINDOWS)
5242 HostNetworkInterfaceType_T eIfType;
5243 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5244 if (FAILED(hrc))
5245 {
5246 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5247 H();
5248 }
5249
5250 if (eIfType != HostNetworkInterfaceType_Bridged)
5251 {
5252 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5253 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5254 BridgedIfName.raw());
5255 }
5256
5257 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5258 if (FAILED(hrc))
5259 {
5260 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5261 H();
5262 }
5263 Guid hostIFGuid(bstr);
5264
5265 INetCfg *pNc;
5266 ComPtr<INetCfgComponent> pAdaptorComponent;
5267 LPWSTR pszApp;
5268
5269 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5270 Assert(hrc == S_OK);
5271 if (hrc != S_OK)
5272 {
5273 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5274 H();
5275 }
5276
5277 /* get the adapter's INetCfgComponent*/
5278 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5279 pAdaptorComponent.asOutParam());
5280 if (hrc != S_OK)
5281 {
5282 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5283 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5284 H();
5285 }
5286# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5287 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5288 char *pszTrunkName = szTrunkName;
5289 wchar_t * pswzBindName;
5290 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5291 Assert(hrc == S_OK);
5292 if (hrc == S_OK)
5293 {
5294 int cwBindName = (int)wcslen(pswzBindName) + 1;
5295 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5296 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5297 {
5298 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5299 pszTrunkName += cbFullBindNamePrefix-1;
5300 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5301 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5302 {
5303 DWORD err = GetLastError();
5304 hrc = HRESULT_FROM_WIN32(err);
5305 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5306 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5307 hrc, hrc, err));
5308 }
5309 }
5310 else
5311 {
5312 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5313 /** @todo set appropriate error code */
5314 hrc = E_FAIL;
5315 }
5316
5317 if (hrc != S_OK)
5318 {
5319 AssertFailed();
5320 CoTaskMemFree(pswzBindName);
5321 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5322 H();
5323 }
5324
5325 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5326 }
5327 else
5328 {
5329 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5330 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5331 hrc));
5332 H();
5333 }
5334
5335 const char *pszTrunk = szTrunkName;
5336 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5337
5338# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5339# if defined(RT_OS_FREEBSD)
5340 /*
5341 * If we bridge to a tap interface open it the `old' direct way.
5342 * This works and performs better than bridging a physical
5343 * interface via the current FreeBSD vboxnetflt implementation.
5344 */
5345 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5346 hrc = i_attachToTapInterface(aNetworkAdapter);
5347 if (FAILED(hrc))
5348 {
5349 switch (hrc)
5350 {
5351 case VERR_ACCESS_DENIED:
5352 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5353 "Failed to open '/dev/%s' for read/write access. Please check the "
5354 "permissions of that node, and that the net.link.tap.user_open "
5355 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5356 "change the group of that node to vboxusers and make yourself "
5357 "a member of that group. Make sure that these changes are permanent."),
5358 pszBridgedIfName, pszBridgedIfName);
5359 default:
5360 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5361 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5362 "Failed to initialize Host Interface Networking"));
5363 }
5364 }
5365
5366 Assert((intptr_t)maTapFD[uInstance] >= 0);
5367 if ((intptr_t)maTapFD[uInstance] >= 0)
5368 {
5369 InsertConfigString(pLunL0, "Driver", "HostInterface");
5370 InsertConfigNode(pLunL0, "Config", &pCfg);
5371 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5372 }
5373 break;
5374 }
5375# endif
5376 /** @todo Check for malformed names. */
5377 const char *pszTrunk = pszBridgedIfName;
5378
5379 /* Issue a warning if the interface is down */
5380 {
5381 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5382 if (iSock >= 0)
5383 {
5384 struct ifreq Req;
5385 RT_ZERO(Req);
5386 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5387 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5388 if ((Req.ifr_flags & IFF_UP) == 0)
5389 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5390 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5391 pszBridgedIfName);
5392
5393 close(iSock);
5394 }
5395 }
5396
5397# else
5398# error "PORTME (VBOX_WITH_NETFLT)"
5399# endif
5400
5401 InsertConfigString(pLunL0, "Driver", "IntNet");
5402 InsertConfigNode(pLunL0, "Config", &pCfg);
5403 InsertConfigString(pCfg, "Trunk", pszTrunk);
5404 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5405 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5406 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5407 char szNetwork[INTNET_MAX_NETWORK_NAME];
5408
5409# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5410 /*
5411 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5412 * interface name + optional description. We must not pass any description to the VM as it can differ
5413 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5414 */
5415 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5416# else
5417 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5418# endif
5419 InsertConfigString(pCfg, "Network", szNetwork);
5420 networkName = Bstr(szNetwork);
5421 trunkName = Bstr(pszTrunk);
5422 trunkType = Bstr(TRUNKTYPE_NETFLT);
5423
5424 BOOL fSharedMacOnWire = false;
5425 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5426 if (FAILED(hrc))
5427 {
5428 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5429 H();
5430 }
5431 else if (fSharedMacOnWire)
5432 {
5433 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5434 Log(("Set SharedMacOnWire\n"));
5435 }
5436
5437# if defined(RT_OS_SOLARIS)
5438# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5439 /* Zone access restriction, don't allow snooping the global zone. */
5440 zoneid_t ZoneId = getzoneid();
5441 if (ZoneId != GLOBAL_ZONEID)
5442 {
5443 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5444 }
5445# endif
5446# endif
5447
5448#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5449 /* NOTHING TO DO HERE */
5450#elif defined(RT_OS_LINUX)
5451/// @todo aleksey: is there anything to be done here?
5452#elif defined(RT_OS_FREEBSD)
5453/** @todo FreeBSD: Check out this later (HIF networking). */
5454#else
5455# error "Port me"
5456#endif
5457 break;
5458 }
5459
5460 case NetworkAttachmentType_Internal:
5461 {
5462 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5463 if (!bstr.isEmpty())
5464 {
5465 InsertConfigString(pLunL0, "Driver", "IntNet");
5466 InsertConfigNode(pLunL0, "Config", &pCfg);
5467 InsertConfigString(pCfg, "Network", bstr);
5468 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5469 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5470 networkName = bstr;
5471 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5472 }
5473 break;
5474 }
5475
5476 case NetworkAttachmentType_HostOnly:
5477 {
5478 InsertConfigString(pLunL0, "Driver", "IntNet");
5479 InsertConfigNode(pLunL0, "Config", &pCfg);
5480
5481 Bstr HostOnlyName;
5482 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5483 if (FAILED(hrc))
5484 {
5485 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5486 H();
5487 }
5488
5489 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5490 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5491 ComPtr<IHostNetworkInterface> hostInterface;
5492 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5493 hostInterface.asOutParam());
5494 if (!SUCCEEDED(rc))
5495 {
5496 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5497 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5498 N_("Nonexistent host networking interface, name '%ls'"),
5499 HostOnlyName.raw());
5500 }
5501
5502 char szNetwork[INTNET_MAX_NETWORK_NAME];
5503 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5504
5505#if defined(RT_OS_WINDOWS)
5506# ifndef VBOX_WITH_NETFLT
5507 hrc = E_NOTIMPL;
5508 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5509 H();
5510# else /* defined VBOX_WITH_NETFLT*/
5511 /** @todo r=bird: Put this in a function. */
5512
5513 HostNetworkInterfaceType_T eIfType;
5514 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5515 if (FAILED(hrc))
5516 {
5517 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5518 H();
5519 }
5520
5521 if (eIfType != HostNetworkInterfaceType_HostOnly)
5522 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5523 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5524 HostOnlyName.raw());
5525
5526 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5527 if (FAILED(hrc))
5528 {
5529 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5530 H();
5531 }
5532 Guid hostIFGuid(bstr);
5533
5534 INetCfg *pNc;
5535 ComPtr<INetCfgComponent> pAdaptorComponent;
5536 LPWSTR pszApp;
5537 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5538 Assert(hrc == S_OK);
5539 if (hrc != S_OK)
5540 {
5541 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5542 H();
5543 }
5544
5545 /* get the adapter's INetCfgComponent*/
5546 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5547 pAdaptorComponent.asOutParam());
5548 if (hrc != S_OK)
5549 {
5550 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5551 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5552 H();
5553 }
5554# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5555 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5556 bool fNdis6 = false;
5557 wchar_t * pwszHelpText;
5558 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5559 Assert(hrc == S_OK);
5560 if (hrc == S_OK)
5561 {
5562 Log(("help-text=%ls\n", pwszHelpText));
5563 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5564 fNdis6 = true;
5565 CoTaskMemFree(pwszHelpText);
5566 }
5567 if (fNdis6)
5568 {
5569 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5570 Log(("trunk=%s\n", szTrunkName));
5571 }
5572 else
5573 {
5574 char *pszTrunkName = szTrunkName;
5575 wchar_t * pswzBindName;
5576 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5577 Assert(hrc == S_OK);
5578 if (hrc == S_OK)
5579 {
5580 int cwBindName = (int)wcslen(pswzBindName) + 1;
5581 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5582 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5583 {
5584 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5585 pszTrunkName += cbFullBindNamePrefix-1;
5586 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5587 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5588 {
5589 DWORD err = GetLastError();
5590 hrc = HRESULT_FROM_WIN32(err);
5591 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5592 hrc, hrc, err));
5593 }
5594 }
5595 else
5596 {
5597 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5598 /** @todo set appropriate error code */
5599 hrc = E_FAIL;
5600 }
5601
5602 if (hrc != S_OK)
5603 {
5604 AssertFailed();
5605 CoTaskMemFree(pswzBindName);
5606 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5607 H();
5608 }
5609 }
5610 else
5611 {
5612 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5613 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5614 hrc, hrc));
5615 H();
5616 }
5617
5618
5619 CoTaskMemFree(pswzBindName);
5620 }
5621
5622 trunkType = TRUNKTYPE_NETADP;
5623 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5624
5625 pAdaptorComponent.setNull();
5626 /* release the pNc finally */
5627 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5628
5629 const char *pszTrunk = szTrunkName;
5630
5631 InsertConfigString(pCfg, "Trunk", pszTrunk);
5632 InsertConfigString(pCfg, "Network", szNetwork);
5633 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5634 windows only?? */
5635 networkName = Bstr(szNetwork);
5636 trunkName = Bstr(pszTrunk);
5637# endif /* defined VBOX_WITH_NETFLT*/
5638#elif defined(RT_OS_DARWIN)
5639 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5640 InsertConfigString(pCfg, "Network", szNetwork);
5641 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5642 networkName = Bstr(szNetwork);
5643 trunkName = Bstr(pszHostOnlyName);
5644 trunkType = TRUNKTYPE_NETADP;
5645#else
5646 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5647 InsertConfigString(pCfg, "Network", szNetwork);
5648 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5649 networkName = Bstr(szNetwork);
5650 trunkName = Bstr(pszHostOnlyName);
5651 trunkType = TRUNKTYPE_NETFLT;
5652#endif
5653 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5654
5655#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5656
5657 Bstr tmpAddr, tmpMask;
5658
5659 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5660 pszHostOnlyName).raw(),
5661 tmpAddr.asOutParam());
5662 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5663 {
5664 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5665 pszHostOnlyName).raw(),
5666 tmpMask.asOutParam());
5667 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5668 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5669 tmpMask.raw());
5670 else
5671 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5672 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5673 }
5674 else
5675 {
5676 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5677 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5678 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5679 }
5680
5681 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5682
5683 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5684 pszHostOnlyName).raw(),
5685 tmpAddr.asOutParam());
5686 if (SUCCEEDED(hrc))
5687 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5688 tmpMask.asOutParam());
5689 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5690 {
5691 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5692 Utf8Str(tmpMask).toUInt32());
5693 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5694 }
5695#endif
5696 break;
5697 }
5698
5699 case NetworkAttachmentType_Generic:
5700 {
5701 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5702 SafeArray<BSTR> names;
5703 SafeArray<BSTR> values;
5704 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5705 ComSafeArrayAsOutParam(names),
5706 ComSafeArrayAsOutParam(values)); H();
5707
5708 InsertConfigString(pLunL0, "Driver", bstr);
5709 InsertConfigNode(pLunL0, "Config", &pCfg);
5710 for (size_t ii = 0; ii < names.size(); ++ii)
5711 {
5712 if (values[ii] && *values[ii])
5713 {
5714 Utf8Str name = names[ii];
5715 Utf8Str value = values[ii];
5716 InsertConfigString(pCfg, name.c_str(), value);
5717 }
5718 }
5719 break;
5720 }
5721
5722 case NetworkAttachmentType_NATNetwork:
5723 {
5724 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5725 if (!bstr.isEmpty())
5726 {
5727 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5728 InsertConfigString(pLunL0, "Driver", "IntNet");
5729 InsertConfigNode(pLunL0, "Config", &pCfg);
5730 InsertConfigString(pCfg, "Network", bstr);
5731 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5732 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5733 networkName = bstr;
5734 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5735 }
5736 break;
5737 }
5738
5739 default:
5740 AssertMsgFailed(("should not get here!\n"));
5741 break;
5742 }
5743
5744 /*
5745 * Attempt to attach the driver.
5746 */
5747 switch (eAttachmentType)
5748 {
5749 case NetworkAttachmentType_Null:
5750 break;
5751
5752 case NetworkAttachmentType_Bridged:
5753 case NetworkAttachmentType_Internal:
5754 case NetworkAttachmentType_HostOnly:
5755 case NetworkAttachmentType_NAT:
5756 case NetworkAttachmentType_Generic:
5757 case NetworkAttachmentType_NATNetwork:
5758 {
5759 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5760 {
5761 if (fAttachDetach)
5762 {
5763 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5764 //AssertRC(rc);
5765 }
5766
5767 {
5768 /** @todo pritesh: get the dhcp server name from the
5769 * previous network configuration and then stop the server
5770 * else it may conflict with the dhcp server running with
5771 * the current attachment type
5772 */
5773 /* Stop the hostonly DHCP Server */
5774 }
5775
5776 /*
5777 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5778 */
5779 if ( !networkName.isEmpty()
5780 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5781 {
5782 /*
5783 * Until we implement service reference counters DHCP Server will be stopped
5784 * by DHCPServerRunner destructor.
5785 */
5786 ComPtr<IDHCPServer> dhcpServer;
5787 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5788 dhcpServer.asOutParam());
5789 if (SUCCEEDED(hrc))
5790 {
5791 /* there is a DHCP server available for this network */
5792 BOOL fEnabledDhcp;
5793 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5794 if (FAILED(hrc))
5795 {
5796 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5797 H();
5798 }
5799
5800 if (fEnabledDhcp)
5801 hrc = dhcpServer->Start(networkName.raw(),
5802 trunkName.raw(),
5803 trunkType.raw());
5804 }
5805 else
5806 hrc = S_OK;
5807 }
5808 }
5809
5810 break;
5811 }
5812
5813 default:
5814 AssertMsgFailed(("should not get here!\n"));
5815 break;
5816 }
5817
5818 meAttachmentType[uInstance] = eAttachmentType;
5819 }
5820 catch (ConfigError &x)
5821 {
5822 // InsertConfig threw something:
5823 return x.m_vrc;
5824 }
5825
5826#undef H
5827
5828 return VINF_SUCCESS;
5829}
5830
5831#ifdef VBOX_WITH_GUEST_PROPS
5832/**
5833 * Set an array of guest properties
5834 */
5835static void configSetProperties(VMMDev * const pVMMDev,
5836 void *names,
5837 void *values,
5838 void *timestamps,
5839 void *flags)
5840{
5841 VBOXHGCMSVCPARM parms[4];
5842
5843 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5844 parms[0].u.pointer.addr = names;
5845 parms[0].u.pointer.size = 0; /* We don't actually care. */
5846 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5847 parms[1].u.pointer.addr = values;
5848 parms[1].u.pointer.size = 0; /* We don't actually care. */
5849 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5850 parms[2].u.pointer.addr = timestamps;
5851 parms[2].u.pointer.size = 0; /* We don't actually care. */
5852 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5853 parms[3].u.pointer.addr = flags;
5854 parms[3].u.pointer.size = 0; /* We don't actually care. */
5855
5856 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5857 guestProp::SET_PROPS_HOST,
5858 4,
5859 &parms[0]);
5860}
5861
5862/**
5863 * Set a single guest property
5864 */
5865static void configSetProperty(VMMDev * const pVMMDev,
5866 const char *pszName,
5867 const char *pszValue,
5868 const char *pszFlags)
5869{
5870 VBOXHGCMSVCPARM parms[4];
5871
5872 AssertPtrReturnVoid(pszName);
5873 AssertPtrReturnVoid(pszValue);
5874 AssertPtrReturnVoid(pszFlags);
5875 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5876 parms[0].u.pointer.addr = (void *)pszName;
5877 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5878 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5879 parms[1].u.pointer.addr = (void *)pszValue;
5880 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5881 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5882 parms[2].u.pointer.addr = (void *)pszFlags;
5883 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
5884 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
5885 &parms[0]);
5886}
5887
5888/**
5889 * Set the global flags value by calling the service
5890 * @returns the status returned by the call to the service
5891 *
5892 * @param pTable the service instance handle
5893 * @param eFlags the flags to set
5894 */
5895int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
5896 guestProp::ePropFlags eFlags)
5897{
5898 VBOXHGCMSVCPARM paParm;
5899 paParm.setUInt32(eFlags);
5900 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5901 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
5902 &paParm);
5903 if (RT_FAILURE(rc))
5904 {
5905 char szFlags[guestProp::MAX_FLAGS_LEN];
5906 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
5907 Log(("Failed to set the global flags.\n"));
5908 else
5909 Log(("Failed to set the global flags \"%s\".\n", szFlags));
5910 }
5911 return rc;
5912}
5913#endif /* VBOX_WITH_GUEST_PROPS */
5914
5915/**
5916 * Set up the Guest Property service, populate it with properties read from
5917 * the machine XML and set a couple of initial properties.
5918 */
5919/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
5920{
5921#ifdef VBOX_WITH_GUEST_PROPS
5922 AssertReturn(pvConsole, VERR_INVALID_POINTER);
5923 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
5924 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
5925
5926 /* Load the service */
5927 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
5928
5929 if (RT_FAILURE(rc))
5930 {
5931 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
5932 /* That is not a fatal failure. */
5933 rc = VINF_SUCCESS;
5934 }
5935 else
5936 {
5937 /*
5938 * Initialize built-in properties that can be changed and saved.
5939 *
5940 * These are typically transient properties that the guest cannot
5941 * change.
5942 */
5943
5944 {
5945 VBOXHGCMSVCPARM Params[2];
5946 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
5947 if (RT_SUCCESS(rc2))
5948 {
5949 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
5950 void *pService = (void*)Params[1].u.pointer.addr;
5951 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
5952 }
5953 }
5954
5955 /* Sysprep execution by VBoxService. */
5956 configSetProperty(pConsole->m_pVMMDev,
5957 "/VirtualBox/HostGuest/SysprepExec", "",
5958 "TRANSIENT, RDONLYGUEST");
5959 configSetProperty(pConsole->m_pVMMDev,
5960 "/VirtualBox/HostGuest/SysprepArgs", "",
5961 "TRANSIENT, RDONLYGUEST");
5962
5963 /*
5964 * Pull over the properties from the server.
5965 */
5966 SafeArray<BSTR> namesOut;
5967 SafeArray<BSTR> valuesOut;
5968 SafeArray<LONG64> timestampsOut;
5969 SafeArray<BSTR> flagsOut;
5970 HRESULT hrc;
5971 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
5972 ComSafeArrayAsOutParam(valuesOut),
5973 ComSafeArrayAsOutParam(timestampsOut),
5974 ComSafeArrayAsOutParam(flagsOut));
5975 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
5976 size_t cProps = namesOut.size();
5977 size_t cAlloc = cProps + 1;
5978 if ( valuesOut.size() != cProps
5979 || timestampsOut.size() != cProps
5980 || flagsOut.size() != cProps
5981 )
5982 AssertFailedReturn(VERR_INVALID_PARAMETER);
5983
5984 char **papszNames, **papszValues, **papszFlags;
5985 char szEmpty[] = "";
5986 LONG64 *pai64Timestamps;
5987 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5988 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5989 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
5990 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5991 if (papszNames && papszValues && pai64Timestamps && papszFlags)
5992 {
5993 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
5994 {
5995 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
5996 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
5997 if (RT_FAILURE(rc))
5998 break;
5999 if (valuesOut[i])
6000 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6001 else
6002 papszValues[i] = szEmpty;
6003 if (RT_FAILURE(rc))
6004 break;
6005 pai64Timestamps[i] = timestampsOut[i];
6006 if (flagsOut[i])
6007 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6008 else
6009 papszFlags[i] = szEmpty;
6010 }
6011 if (RT_SUCCESS(rc))
6012 configSetProperties(pConsole->m_pVMMDev,
6013 (void *)papszNames,
6014 (void *)papszValues,
6015 (void *)pai64Timestamps,
6016 (void *)papszFlags);
6017 for (unsigned i = 0; i < cProps; ++i)
6018 {
6019 RTStrFree(papszNames[i]);
6020 if (valuesOut[i])
6021 RTStrFree(papszValues[i]);
6022 if (flagsOut[i])
6023 RTStrFree(papszFlags[i]);
6024 }
6025 }
6026 else
6027 rc = VERR_NO_MEMORY;
6028 RTMemTmpFree(papszNames);
6029 RTMemTmpFree(papszValues);
6030 RTMemTmpFree(pai64Timestamps);
6031 RTMemTmpFree(papszFlags);
6032 AssertRCReturn(rc, rc);
6033
6034 /*
6035 * These properties have to be set before pulling over the properties
6036 * from the machine XML, to ensure that properties saved in the XML
6037 * will override them.
6038 */
6039 /* Set the raw VBox version string as a guest property. Used for host/guest
6040 * version comparison. */
6041 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6042 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6043 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6044 * information/branding and/or pre-release tags. */
6045 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6046 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6047 /* Set the VBox SVN revision as a guest property */
6048 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6049 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6050
6051 /*
6052 * Register the host notification callback
6053 */
6054 HGCMSVCEXTHANDLE hDummy;
6055 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6056 Console::i_doGuestPropNotification,
6057 pvConsole);
6058
6059#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6060 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
6061 guestProp::RDONLYGUEST);
6062 AssertRCReturn(rc, rc);
6063#endif
6064
6065 Log(("Set VBoxGuestPropSvc property store\n"));
6066 }
6067 return VINF_SUCCESS;
6068#else /* !VBOX_WITH_GUEST_PROPS */
6069 return VERR_NOT_SUPPORTED;
6070#endif /* !VBOX_WITH_GUEST_PROPS */
6071}
6072
6073/**
6074 * Set up the Guest Control service.
6075 */
6076/* static */ int Console::i_configGuestControl(void *pvConsole)
6077{
6078#ifdef VBOX_WITH_GUEST_CONTROL
6079 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6080 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6081
6082 /* Load the service */
6083 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6084
6085 if (RT_FAILURE(rc))
6086 {
6087 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6088 /* That is not a fatal failure. */
6089 rc = VINF_SUCCESS;
6090 }
6091 else
6092 {
6093 HGCMSVCEXTHANDLE hDummy;
6094 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6095 &Guest::i_notifyCtrlDispatcher,
6096 pConsole->i_getGuest());
6097 if (RT_FAILURE(rc))
6098 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6099 else
6100 LogRel(("Guest Control service loaded\n"));
6101 }
6102
6103 return rc;
6104#else /* !VBOX_WITH_GUEST_CONTROL */
6105 return VERR_NOT_SUPPORTED;
6106#endif /* !VBOX_WITH_GUEST_CONTROL */
6107}
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