VirtualBox

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

Last change on this file since 69046 was 69046, checked in by vboxsync, 7 years ago

Global: replace fall-through comments with RT_FALL_THRU().
bugref:8192: gcc warnings

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette