VirtualBox

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

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

Added speculation control settings to API, refined implementation.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use