VirtualBox

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

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

Main,VBoxManage: Changed the CPUID override methods on IMachine to take sub-leaves into account. Currently we do not support non-zero sub-leaves due to VMM, but that can be fixed later.

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