VirtualBox

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

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

Audio: Added "VBoxInternal2/Audio/Debug/Enabled" to also make use of the debugging backend in regular (release) builds when needed. Disabled by default.

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