VirtualBox

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

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

VideoRec: Renaming (be more consistent): video capture vs. video recording.

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