VirtualBox

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

Last change on this file since 73037 was 73000, checked in by vboxsync, 6 years ago

ConsoleImpl2.cpp: Missing break.

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