VirtualBox

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

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

Audio/Main: Also insert the debugging enabled / path values into the AC'97 device config. See @todo.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use