VirtualBox

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

Last change on this file since 87242 was 87242, checked in by vboxsync, 3 years ago

AMD IOMMU: bugref:9654 Main/API: Adjusted BusAssignmentManager and ConsoleImpl2 to use the newly added API methods.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use