VirtualBox

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

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

DevEFI: Easier configuration approach using a single CFGM entry, falling back to old configuration if not used. Turn EFI logging to LogRel2 (too chatty for normal use).
EFI/Firmware: Support for custom video modes (reusing existing DevVGA mechanism). Shuffle around the graphics mode initialization code to make sure the blanking is handled correctly.
Main/Console: Curresponding configuration using a single extradata entry.

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