VirtualBox

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

Last change on this file since 85803 was 85803, checked in by vboxsync, 5 years ago

Main: bugref:9618 Populate CFGM for virtualized VMSAVE/VMLOAD (only matters if user wants to manually disable it, as it's enabled by default anyway).

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

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