VirtualBox

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

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

Audio: Implemented ability to enable / disable audio input / output on-the-fly via API.

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