VirtualBox

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

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

Main,FE/VBoxManage: Allow changing the serial port attachment type during runtime

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

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