VirtualBox

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

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

Main/ConsoleImple2: The new serial device needs the trusted helpers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 256.4 KB
Line 
1/* $Id: ConsoleImpl2.cpp 73308 2018-07-22 20:15:18Z 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 switch (audioController)
2816 {
2817 case AudioControllerType_AC97:
2818 {
2819 /* ICH AC'97. */
2820 strAudioDevice = "ichac97";
2821
2822 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2823 InsertConfigNode (pDev, "0", &pInst);
2824 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2825 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2826 InsertConfigNode (pInst, "Config", &pCfg);
2827 switch (audioCodec)
2828 {
2829 case AudioCodecType_STAC9700:
2830 InsertConfigString(pCfg, "Codec", "STAC9700");
2831 break;
2832 case AudioCodecType_AD1980:
2833 InsertConfigString(pCfg, "Codec", "AD1980");
2834 break;
2835 default: AssertFailedBreak();
2836 }
2837 break;
2838 }
2839 case AudioControllerType_SB16:
2840 {
2841 /* Legacy SoundBlaster16. */
2842 strAudioDevice = "sb16";
2843
2844 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2845 InsertConfigNode (pDev, "0", &pInst);
2846 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2847 InsertConfigNode (pInst, "Config", &pCfg);
2848 InsertConfigInteger(pCfg, "IRQ", 5);
2849 InsertConfigInteger(pCfg, "DMA", 1);
2850 InsertConfigInteger(pCfg, "DMA16", 5);
2851 InsertConfigInteger(pCfg, "Port", 0x220);
2852 InsertConfigInteger(pCfg, "Version", 0x0405);
2853 break;
2854 }
2855 case AudioControllerType_HDA:
2856 {
2857 /* Intel HD Audio. */
2858 strAudioDevice = "hda";
2859
2860 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2861 InsertConfigNode (pDev, "0", &pInst);
2862 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2863 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2864 InsertConfigNode (pInst, "Config", &pCfg);
2865
2866 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2867 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2868 break;
2869 }
2870 default: AssertFailedBreak();
2871 }
2872
2873 PCFGMNODE pCfgAudioAdapter = NULL;
2874 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
2875 SafeArray<BSTR> audioProps;
2876 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2877
2878 std::list<Utf8Str> audioPropertyNamesList;
2879 for (size_t i = 0; i < audioProps.size(); ++i)
2880 {
2881 Bstr bstrValue;
2882 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2883 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2884 Utf8Str strKey(audioProps[i]);
2885 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
2886 }
2887
2888 /*
2889 * The audio driver.
2890 */
2891 Utf8Str strAudioDriver;
2892
2893 AudioDriverType_T audioDriver;
2894 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2895 switch (audioDriver)
2896 {
2897 case AudioDriverType_Null:
2898 {
2899 strAudioDriver = "NullAudio";
2900 break;
2901 }
2902#ifdef RT_OS_WINDOWS
2903# ifdef VBOX_WITH_WINMM
2904 case AudioDriverType_WinMM:
2905 {
2906 #error "Port WinMM audio backend!" /** @todo Still needed? */
2907 break;
2908 }
2909# endif
2910 case AudioDriverType_DirectSound:
2911 {
2912 strAudioDriver = "DSoundAudio";
2913 break;
2914 }
2915#endif /* RT_OS_WINDOWS */
2916#ifdef RT_OS_SOLARIS
2917 case AudioDriverType_SolAudio:
2918 {
2919 /* Should not happen, as the Solaris Audio backend is not around anymore.
2920 * Remove this sometime later. */
2921 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2922 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2923
2924 /* Manually set backend to OSS for now. */
2925 strAudioDriver = "OSSAudio";
2926 break;
2927 }
2928#endif
2929#ifdef VBOX_WITH_AUDIO_OSS
2930 case AudioDriverType_OSS:
2931 {
2932 strAudioDriver = "OSSAudio";
2933 break;
2934 }
2935#endif
2936#ifdef VBOX_WITH_AUDIO_ALSA
2937 case AudioDriverType_ALSA:
2938 {
2939 strAudioDriver = "ALSAAudio";
2940 break;
2941 }
2942#endif
2943#ifdef VBOX_WITH_AUDIO_PULSE
2944 case AudioDriverType_Pulse:
2945 {
2946 strAudioDriver = "PulseAudio";
2947 break;
2948 }
2949#endif
2950#ifdef RT_OS_DARWIN
2951 case AudioDriverType_CoreAudio:
2952 {
2953 strAudioDriver = "CoreAudio";
2954 break;
2955 }
2956#endif
2957 default: AssertFailedBreak();
2958 }
2959
2960 unsigned uAudioLUN = 0;
2961
2962 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2963 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
2964 strAudioDriver.c_str());
2965 if (RT_SUCCESS(rc))
2966 uAudioLUN++;
2967
2968#ifdef VBOX_WITH_AUDIO_VRDE
2969 /* Insert dummy audio driver to have the LUN configured. */
2970 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2971 InsertConfigString(pLunL0, "Driver", "AUDIO");
2972 AudioDriverCfg DrvCfgVRDE(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVRDE");
2973 rc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
2974 if (RT_SUCCESS(rc))
2975 uAudioLUN++;
2976#endif /* VBOX_WITH_AUDIO_VRDE */
2977
2978#ifdef VBOX_WITH_AUDIO_VIDEOREC
2979 /* Insert dummy audio driver to have the LUN configured. */
2980 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2981 InsertConfigString(pLunL0, "Driver", "AUDIO");
2982 AudioDriverCfg DrvCfgVideoRec(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVideoRec");
2983 rc = mAudioVideoRec->InitializeConfig(&DrvCfgVideoRec);
2984 if (RT_SUCCESS(rc))
2985 uAudioLUN++;
2986#endif /* VBOX_WITH_AUDIO_VIDEOREC */
2987
2988 if (fDebugEnabled)
2989 {
2990#ifdef VBOX_WITH_AUDIO_DEBUG
2991 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2992 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
2993 "DebugAudio");
2994 if (RT_SUCCESS(rc))
2995 uAudioLUN++;
2996#endif /* VBOX_WITH_AUDIO_DEBUG */
2997
2998 /*
2999 * Tweak the logging groups.
3000 */
3001 Utf8Str strLogGroups = "drv_host_audio.e.l.l2.l3.f+" \
3002 "drv_audio.e.l.l2.l3.f+" \
3003 "audio_mixer.e.l.l2.l3.f+" \
3004 "dev_hda_codec.e.l.l2.l3.f+" \
3005 "dev_hda.e.l.l2.l3.f+" \
3006 "dev_ac97.e.l.l2.l3.f+" \
3007 "dev_sb16.e.l.l2.l3.f";
3008
3009 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strLogGroups.c_str());
3010 if (RT_FAILURE(rc))
3011 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3012 }
3013
3014#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3015 /** @todo Make this a runtime-configurable entry! */
3016
3017 /*
3018 * The ValidationKit backend.
3019 */
3020 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3021 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3022 "ValidationKitAudio");
3023 if (RT_SUCCESS(rc))
3024 uAudioLUN++;
3025#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3026 }
3027
3028 /*
3029 * Shared Clipboard.
3030 */
3031 {
3032 ClipboardMode_T mode = ClipboardMode_Disabled;
3033 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3034
3035 if (/* mode != ClipboardMode_Disabled */ true)
3036 {
3037 /* Load the service */
3038 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3039 if (RT_FAILURE(rc))
3040 {
3041 LogRel(("Shared clipboard is not available, rc=%Rrc\n", rc));
3042 /* That is not a fatal failure. */
3043 rc = VINF_SUCCESS;
3044 }
3045 else
3046 {
3047 LogRel(("Shared clipboard service loaded\n"));
3048
3049 i_changeClipboardMode(mode);
3050
3051 /* Setup the service. */
3052 VBOXHGCMSVCPARM parm;
3053 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
3054 parm.setUInt32(!i_useHostClipboard());
3055 pVMMDev->hgcmHostCall("VBoxSharedClipboard",
3056 VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3057 }
3058 }
3059 }
3060
3061 /*
3062 * HGCM HostChannel.
3063 */
3064 {
3065 Bstr value;
3066 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3067 value.asOutParam());
3068
3069 if ( hrc == S_OK
3070 && value == "1")
3071 {
3072 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3073 if (RT_FAILURE(rc))
3074 {
3075 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3076 /* That is not a fatal failure. */
3077 rc = VINF_SUCCESS;
3078 }
3079 }
3080 }
3081
3082#ifdef VBOX_WITH_DRAG_AND_DROP
3083 /*
3084 * Drag and Drop.
3085 */
3086 {
3087 DnDMode_T enmMode = DnDMode_Disabled;
3088 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3089
3090 /* Load the service */
3091 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3092 if (RT_FAILURE(rc))
3093 {
3094 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3095 /* That is not a fatal failure. */
3096 rc = VINF_SUCCESS;
3097 }
3098 else
3099 {
3100 HGCMSVCEXTHANDLE hDummy;
3101 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
3102 &GuestDnD::notifyDnDDispatcher,
3103 GuestDnDInst());
3104 if (RT_FAILURE(rc))
3105 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3106 else
3107 {
3108 LogRel(("Drag and drop service loaded\n"));
3109 rc = i_changeDnDMode(enmMode);
3110 }
3111 }
3112 }
3113#endif /* VBOX_WITH_DRAG_AND_DROP */
3114
3115#ifdef VBOX_WITH_CROGL
3116 /*
3117 * crOpenGL.
3118 */
3119 {
3120 BOOL fEnabled3D = false;
3121 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3122
3123 if ( fEnabled3D
3124# ifdef VBOX_WITH_VMSVGA3D
3125 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3126# endif
3127 )
3128 {
3129 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3130 if (!fSupports3D)
3131 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3132 N_("This VM was configured to use 3D acceleration. However, the "
3133 "3D support of the host is not working properly and the "
3134 "VM cannot be started. To fix this problem, either "
3135 "fix the host 3D support (update the host graphics driver?) "
3136 "or disable 3D acceleration in the VM settings"));
3137
3138 /* Load the service. */
3139 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3140 if (RT_FAILURE(rc))
3141 {
3142 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3143 /* That is not a fatal failure. */
3144 rc = VINF_SUCCESS;
3145 }
3146 else
3147 {
3148 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3149
3150 /* Setup the service. */
3151 VBOXHGCMSVCPARM parm;
3152 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3153
3154 parm.u.pointer.addr = (IConsole *)(Console *)this;
3155 parm.u.pointer.size = sizeof(IConsole *);
3156
3157 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3158 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3159 if (!RT_SUCCESS(rc))
3160 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3161
3162 parm.u.pointer.addr = pVM;
3163 parm.u.pointer.size = sizeof(pVM);
3164 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3165 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3166 if (!RT_SUCCESS(rc))
3167 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3168 }
3169 }
3170 }
3171#endif
3172
3173#ifdef VBOX_WITH_GUEST_PROPS
3174 /*
3175 * Guest property service.
3176 */
3177 rc = i_configGuestProperties(this, pUVM);
3178#endif /* VBOX_WITH_GUEST_PROPS defined */
3179
3180#ifdef VBOX_WITH_GUEST_CONTROL
3181 /*
3182 * Guest control service.
3183 */
3184 rc = i_configGuestControl(this);
3185#endif /* VBOX_WITH_GUEST_CONTROL defined */
3186
3187 /*
3188 * ACPI
3189 */
3190 BOOL fACPI;
3191 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3192 if (fACPI)
3193 {
3194 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3195 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3196 * intelppm driver refuses to register an idle state handler.
3197 * Always show CPU leafs for OS X guests. */
3198 BOOL fShowCpu = fOsXGuest;
3199 if (cCpus > 1 || fIOAPIC)
3200 fShowCpu = true;
3201
3202 BOOL fCpuHotPlug;
3203 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3204
3205 InsertConfigNode(pDevices, "acpi", &pDev);
3206 InsertConfigNode(pDev, "0", &pInst);
3207 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3208 InsertConfigNode(pInst, "Config", &pCfg);
3209 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3210
3211 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3212
3213 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3214 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3215 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3216 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3217 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3218 if (fOsXGuest && !llBootNics.empty())
3219 {
3220 BootNic aNic = llBootNics.front();
3221 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3222 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3223 }
3224 if (fOsXGuest && fAudioEnabled)
3225 {
3226 PCIBusAddress Address;
3227 if (pBusMgr->findPCIAddress("hda", 0, Address))
3228 {
3229 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3230 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3231 }
3232 }
3233 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3234 if (chipsetType == ChipsetType_ICH9)
3235 {
3236 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3237 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3238 /* 64-bit prefetch window root resource:
3239 * Only for ICH9 and if PAE or Long Mode is enabled.
3240 * And only with hardware virtualization (@bugref{5454}). */
3241 if ( (fEnablePAE || fIsGuest64Bit)
3242 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3243 otherwise VMM falls back to raw mode */
3244 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3245 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3246 }
3247 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3248 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3249 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3250
3251 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3252 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3253
3254 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3255 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3256
3257 if (auSerialIoPortBase[2])
3258 {
3259 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3260 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3261 }
3262
3263 if (auSerialIoPortBase[3])
3264 {
3265 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3266 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3267 }
3268
3269 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3270 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3271
3272 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3273 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3274
3275 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3276 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3277 InsertConfigNode(pLunL0, "Config", &pCfg);
3278
3279 /* Attach the dummy CPU drivers */
3280 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3281 {
3282 BOOL fCpuAttached = true;
3283
3284 if (fCpuHotPlug)
3285 {
3286 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3287 }
3288
3289 if (fCpuAttached)
3290 {
3291 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3292 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3293 InsertConfigNode(pLunL0, "Config", &pCfg);
3294 }
3295 }
3296 }
3297
3298 /*
3299 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3300 */
3301 {
3302 PCFGMNODE pDbgf;
3303 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3304
3305 /* Paths to search for debug info and such things. */
3306 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3307 Utf8Str strSettingsPath(bstr);
3308 bstr.setNull();
3309 strSettingsPath.stripFilename();
3310 strSettingsPath.append("/");
3311
3312 char szHomeDir[RTPATH_MAX + 1];
3313 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3314 if (RT_FAILURE(rc2))
3315 szHomeDir[0] = '\0';
3316 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3317
3318
3319 Utf8Str strPath;
3320 strPath.append(strSettingsPath).append("debug/;");
3321 strPath.append(strSettingsPath).append(";");
3322 strPath.append(szHomeDir);
3323
3324 InsertConfigString(pDbgf, "Path", strPath.c_str());
3325
3326 /* Tracing configuration. */
3327 BOOL fTracingEnabled;
3328 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3329 if (fTracingEnabled)
3330 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3331
3332 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3333 if (fTracingEnabled)
3334 InsertConfigString(pDbgf, "TracingConfig", bstr);
3335
3336 BOOL fAllowTracingToAccessVM;
3337 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3338 if (fAllowTracingToAccessVM)
3339 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3340
3341 /* Debugger console config. */
3342 PCFGMNODE pDbgc;
3343 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3344
3345 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3346 Utf8Str strVBoxHome = bstr;
3347 bstr.setNull();
3348 if (strVBoxHome.isNotEmpty())
3349 strVBoxHome.append("/");
3350 else
3351 {
3352 strVBoxHome = szHomeDir;
3353 strVBoxHome.append("/.vbox");
3354 }
3355
3356 Utf8Str strFile(strVBoxHome);
3357 strFile.append("dbgc-history");
3358 InsertConfigString(pDbgc, "HistoryFile", strFile);
3359
3360 strFile = strSettingsPath;
3361 strFile.append("dbgc-init");
3362 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3363
3364 strFile = strVBoxHome;
3365 strFile.append("dbgc-init");
3366 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3367 }
3368 }
3369 catch (ConfigError &x)
3370 {
3371 // InsertConfig threw something:
3372 return x.m_vrc;
3373 }
3374 catch (HRESULT hrcXcpt)
3375 {
3376 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3377 }
3378
3379#ifdef VBOX_WITH_EXTPACK
3380 /*
3381 * Call the extension pack hooks if everything went well thus far.
3382 */
3383 if (RT_SUCCESS(rc))
3384 {
3385 pAlock->release();
3386 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3387 pAlock->acquire();
3388 }
3389#endif
3390
3391 /*
3392 * Apply the CFGM overlay.
3393 */
3394 if (RT_SUCCESS(rc))
3395 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3396
3397 /*
3398 * Dump all extradata API settings tweaks, both global and per VM.
3399 */
3400 if (RT_SUCCESS(rc))
3401 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3402
3403#undef H
3404
3405 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3406
3407 /*
3408 * Register VM state change handler.
3409 */
3410 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3411 AssertRC(rc2);
3412 if (RT_SUCCESS(rc))
3413 rc = rc2;
3414
3415 /*
3416 * Register VM runtime error handler.
3417 */
3418 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3419 AssertRC(rc2);
3420 if (RT_SUCCESS(rc))
3421 rc = rc2;
3422
3423 pAlock->acquire();
3424
3425 LogFlowFunc(("vrc = %Rrc\n", rc));
3426 LogFlowFuncLeave();
3427
3428 return rc;
3429}
3430
3431/**
3432 * Retrieves an uint32_t value from audio's extra data branch and returns a default value
3433 * if not found or an invalid value is found.
3434 *
3435 * @return VBox status code.
3436 * @param pVirtualBox Pointer to IVirtualBox instance.
3437 * @param pMachine Pointer to IMachine instance.
3438 * @param pszDriverName Audio driver name to retrieve value for.
3439 * @param pszValue Value name to retrieve.
3440 * @param uDefault Default value to return if value not found / invalid.
3441 */
3442uint32_t Console::i_getAudioDriverValU32(IVirtualBox *pVirtualBox, IMachine *pMachine,
3443 const char *pszDriverName, const char *pszValue, uint32_t uDefault)
3444{
3445 Utf8StrFmt strPath("VBoxInternal2/Audio/%s/%s", pszDriverName, pszValue);
3446
3447 Utf8Str strTmp;
3448 GetExtraDataBoth(pVirtualBox, pMachine, strPath.c_str(), &strTmp);
3449
3450 if (strTmp.isNotEmpty())
3451 return strTmp.toUInt32();
3452
3453 return uDefault;
3454}
3455
3456/**
3457 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3458 *
3459 * @return VBox status code.
3460 * @param pAudioAdapter Pointer to audio adapter instance. Needed for the driver's input / output configuration.
3461 * @param pVirtualBox Pointer to IVirtualBox instance.
3462 * @param pMachine Pointer to IMachine instance.
3463 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3464 * @param pszDrvName Name of the driver to configure.
3465 */
3466int Console::i_configAudioDriver(IAudioAdapter *pAudioAdapter, IVirtualBox *pVirtualBox, IMachine *pMachine,
3467 PCFGMNODE pLUN, const char *pszDrvName)
3468{
3469#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3470
3471 HRESULT hrc;
3472
3473 Utf8Str strTmp;
3474 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3475 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
3476
3477 BOOL fAudioEnabledIn = FALSE;
3478 hrc = pAudioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3479 BOOL fAudioEnabledOut = FALSE;
3480 hrc = pAudioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut);
3481
3482 InsertConfigString(pLUN, "Driver", "AUDIO");
3483
3484 PCFGMNODE pCfg;
3485 InsertConfigNode(pLUN, "Config", &pCfg);
3486 InsertConfigString (pCfg, "DriverName", pszDrvName);
3487 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3488 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3489
3490 if (fDebugEnabled)
3491 {
3492 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3493
3494 Utf8Str strDebugPathOut;
3495 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3496 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3497 }
3498
3499 InsertConfigInteger(pCfg, "PeriodMs",
3500 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PeriodMs", 0 /* Default */));
3501 InsertConfigInteger(pCfg, "BufferSizeMs",
3502 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "BufferSizeMs", 0 /* Default */));
3503 InsertConfigInteger(pCfg, "PreBufferMs",
3504 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PreBufferMs", UINT32_MAX /* Default */));
3505
3506 PCFGMNODE pLunL1;
3507 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3508
3509 InsertConfigNode(pLunL1, "Config", &pCfg);
3510
3511 Bstr bstrTmp;
3512 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3513 InsertConfigString(pCfg, "StreamName", bstrTmp);
3514
3515 InsertConfigString(pLunL1, "Driver", pszDrvName);
3516
3517 LogFlowFunc(("szDrivName=%s, hrc=%Rhrc\n", pszDrvName, hrc));
3518 return hrc;
3519
3520#undef H
3521}
3522
3523/**
3524 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3525 * values.
3526 *
3527 * @returns VBox status code.
3528 * @param pRoot The root of the configuration tree.
3529 * @param pVirtualBox Pointer to the IVirtualBox interface.
3530 * @param pMachine Pointer to the IMachine interface.
3531 */
3532/* static */
3533int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3534{
3535 /*
3536 * CFGM overlay handling.
3537 *
3538 * Here we check the extra data entries for CFGM values
3539 * and create the nodes and insert the values on the fly. Existing
3540 * values will be removed and reinserted. CFGM is typed, so by default
3541 * we will guess whether it's a string or an integer (byte arrays are
3542 * not currently supported). It's possible to override this autodetection
3543 * by adding "string:", "integer:" or "bytes:" (future).
3544 *
3545 * We first perform a run on global extra data, then on the machine
3546 * extra data to support global settings with local overrides.
3547 */
3548 int rc = VINF_SUCCESS;
3549 try
3550 {
3551 /** @todo add support for removing nodes and byte blobs. */
3552 /*
3553 * Get the next key
3554 */
3555 SafeArray<BSTR> aGlobalExtraDataKeys;
3556 SafeArray<BSTR> aMachineExtraDataKeys;
3557 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3558 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3559
3560 // remember the no. of global values so we can call the correct method below
3561 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3562
3563 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3564 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3565
3566 // build a combined list from global keys...
3567 std::list<Utf8Str> llExtraDataKeys;
3568
3569 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3570 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3571 // ... and machine keys
3572 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3573 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3574
3575 size_t i2 = 0;
3576 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3577 it != llExtraDataKeys.end();
3578 ++it, ++i2)
3579 {
3580 const Utf8Str &strKey = *it;
3581
3582 /*
3583 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3584 */
3585 if (!strKey.startsWith("VBoxInternal/"))
3586 continue;
3587
3588 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3589
3590 // get the value
3591 Bstr bstrExtraDataValue;
3592 if (i2 < cGlobalValues)
3593 // this is still one of the global values:
3594 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3595 bstrExtraDataValue.asOutParam());
3596 else
3597 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3598 bstrExtraDataValue.asOutParam());
3599 if (FAILED(hrc))
3600 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3601
3602 /*
3603 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3604 * Split the two and get the node, delete the value and create the node
3605 * if necessary.
3606 */
3607 PCFGMNODE pNode;
3608 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3609 if (pszCFGMValueName)
3610 {
3611 /* terminate the node and advance to the value (Utf8Str might not
3612 offically like this but wtf) */
3613 *(char*)pszCFGMValueName = '\0';
3614 ++pszCFGMValueName;
3615
3616 /* does the node already exist? */
3617 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3618 if (pNode)
3619 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3620 else
3621 {
3622 /* create the node */
3623 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3624 if (RT_FAILURE(rc))
3625 {
3626 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3627 continue;
3628 }
3629 Assert(pNode);
3630 }
3631 }
3632 else
3633 {
3634 /* root value (no node path). */
3635 pNode = pRoot;
3636 pszCFGMValueName = pszExtraDataKey;
3637 pszExtraDataKey--;
3638 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3639 }
3640
3641 /*
3642 * Now let's have a look at the value.
3643 * Empty strings means that we should remove the value, which we've
3644 * already done above.
3645 */
3646 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3647 if (!strCFGMValueUtf8.isEmpty())
3648 {
3649 uint64_t u64Value;
3650
3651 /* check for type prefix first. */
3652 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3653 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3654 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3655 {
3656 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3657 if (RT_SUCCESS(rc))
3658 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3659 }
3660 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3661 {
3662 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3663 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3664 if (cbValue > 0)
3665 {
3666 void *pvBytes = RTMemTmpAlloc(cbValue);
3667 if (pvBytes)
3668 {
3669 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3670 if (RT_SUCCESS(rc))
3671 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3672 RTMemTmpFree(pvBytes);
3673 }
3674 else
3675 rc = VERR_NO_TMP_MEMORY;
3676 }
3677 else if (cbValue == 0)
3678 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3679 else
3680 rc = VERR_INVALID_BASE64_ENCODING;
3681 }
3682 /* auto detect type. */
3683 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3684 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3685 else
3686 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3687 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3688 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3689 }
3690 }
3691 }
3692 catch (ConfigError &x)
3693 {
3694 // InsertConfig threw something:
3695 return x.m_vrc;
3696 }
3697 return rc;
3698}
3699
3700/**
3701 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3702 * values.
3703 *
3704 * @returns VBox status code.
3705 * @param pVirtualBox Pointer to the IVirtualBox interface.
3706 * @param pMachine Pointer to the IMachine interface.
3707 */
3708/* static */
3709int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3710{
3711 {
3712 SafeArray<BSTR> aGlobalExtraDataKeys;
3713 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3714 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3715 bool hasKey = false;
3716 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3717 {
3718 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3719 if (!strKey.startsWith("VBoxInternal2/"))
3720 continue;
3721
3722 Bstr bstrValue;
3723 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3724 bstrValue.asOutParam());
3725 if (FAILED(hrc))
3726 continue;
3727 if (!hasKey)
3728 LogRel(("Global extradata API settings:\n"));
3729 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3730 hasKey = true;
3731 }
3732 }
3733
3734 {
3735 SafeArray<BSTR> aMachineExtraDataKeys;
3736 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3737 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3738 bool hasKey = false;
3739 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3740 {
3741 Utf8Str strKey(aMachineExtraDataKeys[i]);
3742 if (!strKey.startsWith("VBoxInternal2/"))
3743 continue;
3744
3745 Bstr bstrValue;
3746 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3747 bstrValue.asOutParam());
3748 if (FAILED(hrc))
3749 continue;
3750 if (!hasKey)
3751 LogRel(("Per-VM extradata API settings:\n"));
3752 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3753 hasKey = true;
3754 }
3755 }
3756
3757 return VINF_SUCCESS;
3758}
3759
3760int Console::i_configGraphicsController(PCFGMNODE pDevices,
3761 const GraphicsControllerType_T enmGraphicsController,
3762 BusAssignmentManager *pBusMgr,
3763 const ComPtr<IMachine> &ptrMachine,
3764 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3765 bool fHMEnabled)
3766{
3767 // InsertConfig* throws
3768 try
3769 {
3770 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3771 HRESULT hrc;
3772 Bstr bstr;
3773 const char *pcszDevice = "vga";
3774
3775#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3776 InsertConfigNode(pDevices, pcszDevice, &pDev);
3777 InsertConfigNode(pDev, "0", &pInst);
3778 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3779
3780 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3781 InsertConfigNode(pInst, "Config", &pCfg);
3782 ULONG cVRamMBs;
3783 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3784 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3785 ULONG cMonitorCount;
3786 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3787 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3788#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3789 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3790#else
3791 NOREF(fHMEnabled);
3792#endif
3793 BOOL f3DEnabled;
3794 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3795 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3796
3797 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3798
3799#ifdef VBOX_WITH_VMSVGA
3800 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3801 {
3802 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3803#ifdef VBOX_WITH_VMSVGA3D
3804 IFramebuffer *pFramebuffer = NULL;
3805 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3806 if (SUCCEEDED(hrc) && pFramebuffer)
3807 {
3808 LONG64 winId = 0;
3809 /** @todo deal with multimonitor setup */
3810 Assert(cMonitorCount == 1);
3811 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3812 InsertConfigInteger(pCfg, "HostWindowId", winId);
3813 pFramebuffer->Release();
3814 }
3815 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3816#else
3817 LogRel(("VMSVGA3d not available in this build!\n"));
3818#endif
3819 }
3820#endif
3821
3822 /* Custom VESA mode list */
3823 unsigned cModes = 0;
3824 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3825 {
3826 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3827 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3828 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3829 if (bstr.isEmpty())
3830 break;
3831 InsertConfigString(pCfg, szExtraDataKey, bstr);
3832 ++cModes;
3833 }
3834 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3835
3836 /* VESA height reduction */
3837 ULONG ulHeightReduction;
3838 IFramebuffer *pFramebuffer = NULL;
3839 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3840 if (SUCCEEDED(hrc) && pFramebuffer)
3841 {
3842 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3843 pFramebuffer->Release();
3844 pFramebuffer = NULL;
3845 }
3846 else
3847 {
3848 /* If framebuffer is not available, there is no height reduction. */
3849 ulHeightReduction = 0;
3850 }
3851 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3852
3853 /*
3854 * BIOS logo
3855 */
3856 BOOL fFadeIn;
3857 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3858 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3859 BOOL fFadeOut;
3860 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3861 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3862 ULONG logoDisplayTime;
3863 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3864 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3865 Bstr logoImagePath;
3866 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3867 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3868
3869 /*
3870 * Boot menu
3871 */
3872 BIOSBootMenuMode_T eBootMenuMode;
3873 int iShowBootMenu;
3874 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3875 switch (eBootMenuMode)
3876 {
3877 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3878 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3879 default: iShowBootMenu = 2; break;
3880 }
3881 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3882
3883 /* Attach the display. */
3884 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3885 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3886 InsertConfigNode(pLunL0, "Config", &pCfg);
3887 Display *pDisplay = mDisplay;
3888 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3889 }
3890 catch (ConfigError &x)
3891 {
3892 // InsertConfig threw something:
3893 return x.m_vrc;
3894 }
3895
3896#undef H
3897
3898 return VINF_SUCCESS;
3899}
3900
3901
3902/**
3903 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3904 */
3905void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3906{
3907 va_list va;
3908 va_start(va, pszFormat);
3909 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3910 va_end(va);
3911}
3912
3913/* XXX introduce RT format specifier */
3914static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3915{
3916 if (u64Size > INT64_C(5000)*_1G)
3917 {
3918 *pszUnit = "TB";
3919 return u64Size / _1T;
3920 }
3921 else if (u64Size > INT64_C(5000)*_1M)
3922 {
3923 *pszUnit = "GB";
3924 return u64Size / _1G;
3925 }
3926 else
3927 {
3928 *pszUnit = "MB";
3929 return u64Size / _1M;
3930 }
3931}
3932
3933/**
3934 * Checks the location of the given medium for known bugs affecting the usage
3935 * of the host I/O cache setting.
3936 *
3937 * @returns VBox status code.
3938 * @param pMedium The medium to check.
3939 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3940 */
3941int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3942{
3943#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3944 /*
3945 * Some sanity checks.
3946 */
3947 RT_NOREF(pfUseHostIOCache);
3948 ComPtr<IMediumFormat> pMediumFormat;
3949 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3950 ULONG uCaps = 0;
3951 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3952 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3953
3954 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3955 uCaps |= mediumFormatCap[j];
3956
3957 if (uCaps & MediumFormatCapabilities_File)
3958 {
3959 Bstr strFile;
3960 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3961 Utf8Str utfFile = Utf8Str(strFile);
3962 Bstr strSnap;
3963 ComPtr<IMachine> pMachine = i_machine();
3964 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3965 Utf8Str utfSnap = Utf8Str(strSnap);
3966 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3967 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3968 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3969 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3970 /* Ignore the error code. On error, the file system type is still 'unknown' so
3971 * none of the following paths are taken. This can happen for new VMs which
3972 * still don't have a snapshot folder. */
3973 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3974 if (!mfSnapshotFolderDiskTypeShown)
3975 {
3976 LogRel(("File system of '%s' (snapshots) is %s\n",
3977 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3978 mfSnapshotFolderDiskTypeShown = true;
3979 }
3980 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3981 LONG64 i64Size;
3982 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3983#ifdef RT_OS_WINDOWS
3984 if ( enmFsTypeFile == RTFSTYPE_FAT
3985 && i64Size >= _4G)
3986 {
3987 const char *pszUnit;
3988 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3989 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3990 N_("The medium '%ls' has a logical size of %RU64%s "
3991 "but the file system the medium is located on seems "
3992 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3993 "We strongly recommend to put all your virtual disk images and "
3994 "the snapshot folder onto an NTFS partition"),
3995 strFile.raw(), u64Print, pszUnit);
3996 }
3997#else /* !RT_OS_WINDOWS */
3998 if ( enmFsTypeFile == RTFSTYPE_FAT
3999 || enmFsTypeFile == RTFSTYPE_EXT
4000 || enmFsTypeFile == RTFSTYPE_EXT2
4001 || enmFsTypeFile == RTFSTYPE_EXT3
4002 || enmFsTypeFile == RTFSTYPE_EXT4)
4003 {
4004 RTFILE file;
4005 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4006 if (RT_SUCCESS(rc))
4007 {
4008 RTFOFF maxSize;
4009 /* Careful: This function will work only on selected local file systems! */
4010 rc = RTFileGetMaxSizeEx(file, &maxSize);
4011 RTFileClose(file);
4012 if ( RT_SUCCESS(rc)
4013 && maxSize > 0
4014 && i64Size > (LONG64)maxSize)
4015 {
4016 const char *pszUnitSiz;
4017 const char *pszUnitMax;
4018 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4019 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4020 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4021 N_("The medium '%ls' has a logical size of %RU64%s "
4022 "but the file system the medium is located on can "
4023 "only handle files up to %RU64%s in theory.\n"
4024 "We strongly recommend to put all your virtual disk "
4025 "images and the snapshot folder onto a proper "
4026 "file system (e.g. ext3) with a sufficient size"),
4027 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4028 }
4029 }
4030 }
4031#endif /* !RT_OS_WINDOWS */
4032
4033 /*
4034 * Snapshot folder:
4035 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4036 */
4037 if ( enmFsTypeSnap == RTFSTYPE_FAT
4038 && i64Size >= _4G
4039 && !mfSnapshotFolderSizeWarningShown)
4040 {
4041 const char *pszUnit;
4042 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4043 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4044#ifdef RT_OS_WINDOWS
4045 N_("The snapshot folder of this VM '%ls' seems to be located on "
4046 "a FAT(32) file system. The logical size of the medium '%ls' "
4047 "(%RU64%s) is bigger than the maximum file size this file "
4048 "system can handle (4GB).\n"
4049 "We strongly recommend to put all your virtual disk images and "
4050 "the snapshot folder onto an NTFS partition"),
4051#else
4052 N_("The snapshot folder of this VM '%ls' seems to be located on "
4053 "a FAT(32) file system. The logical size of the medium '%ls' "
4054 "(%RU64%s) is bigger than the maximum file size this file "
4055 "system can handle (4GB).\n"
4056 "We strongly recommend to put all your virtual disk images and "
4057 "the snapshot folder onto a proper file system (e.g. ext3)"),
4058#endif
4059 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4060 /* Show this particular warning only once */
4061 mfSnapshotFolderSizeWarningShown = true;
4062 }
4063
4064#ifdef RT_OS_LINUX
4065 /*
4066 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4067 * on an ext4 partition.
4068 * This bug apparently applies to the XFS file system as well.
4069 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4070 */
4071
4072 char szOsRelease[128];
4073 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4074 bool fKernelHasODirectBug = RT_FAILURE(rc)
4075 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4076
4077 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4078 && !*pfUseHostIOCache
4079 && fKernelHasODirectBug)
4080 {
4081 if ( enmFsTypeFile == RTFSTYPE_EXT4
4082 || enmFsTypeFile == RTFSTYPE_XFS)
4083 {
4084 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4085 N_("The host I/O cache for at least one controller is disabled "
4086 "and the medium '%ls' for this VM "
4087 "is located on an %s partition. There is a known Linux "
4088 "kernel bug which can lead to the corruption of the virtual "
4089 "disk image under these conditions.\n"
4090 "Either enable the host I/O cache permanently in the VM "
4091 "settings or put the disk image and the snapshot folder "
4092 "onto a different file system.\n"
4093 "The host I/O cache will now be enabled for this medium"),
4094 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4095 *pfUseHostIOCache = true;
4096 }
4097 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4098 || enmFsTypeSnap == RTFSTYPE_XFS)
4099 && !mfSnapshotFolderExt4WarningShown)
4100 {
4101 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4102 N_("The host I/O cache for at least one controller is disabled "
4103 "and the snapshot folder for this VM "
4104 "is located on an %s partition. There is a known Linux "
4105 "kernel bug which can lead to the corruption of the virtual "
4106 "disk image under these conditions.\n"
4107 "Either enable the host I/O cache permanently in the VM "
4108 "settings or put the disk image and the snapshot folder "
4109 "onto a different file system.\n"
4110 "The host I/O cache will now be enabled for this medium"),
4111 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4112 *pfUseHostIOCache = true;
4113 mfSnapshotFolderExt4WarningShown = true;
4114 }
4115 }
4116
4117 /*
4118 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4119 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4120 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4121 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4122 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4123 */
4124 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4125 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4126 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4127 && !*pfUseHostIOCache
4128 && fKernelAsyncUnreliable)
4129 {
4130 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4131 N_("The host I/O cache for at least one controller is disabled. "
4132 "There is a known Linux kernel bug which can lead to kernel "
4133 "oopses under heavy load. To our knowledge this bug affects "
4134 "all 2.6.18 kernels.\n"
4135 "Either enable the host I/O cache permanently in the VM "
4136 "settings or switch to a newer host kernel.\n"
4137 "The host I/O cache will now be enabled for this medium"));
4138 *pfUseHostIOCache = true;
4139 }
4140#endif
4141 }
4142#undef H
4143
4144 return VINF_SUCCESS;
4145}
4146
4147/**
4148 * Unmounts the specified medium from the specified device.
4149 *
4150 * @returns VBox status code.
4151 * @param pUVM The usermode VM handle.
4152 * @param enmBus The storage bus.
4153 * @param enmDevType The device type.
4154 * @param pcszDevice The device emulation.
4155 * @param uInstance Instance of the device.
4156 * @param uLUN The LUN on the device.
4157 * @param fForceUnmount Whether to force unmounting.
4158 */
4159int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4160 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4161 bool fForceUnmount)
4162{
4163 /* Unmount existing media only for floppy and DVD drives. */
4164 int rc = VINF_SUCCESS;
4165 PPDMIBASE pBase;
4166 if (enmBus == StorageBus_USB)
4167 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4168 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4169 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4170 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4171 else /* IDE or Floppy */
4172 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4173
4174 if (RT_FAILURE(rc))
4175 {
4176 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4177 rc = VINF_SUCCESS;
4178 AssertRC(rc);
4179 }
4180 else
4181 {
4182 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4183 AssertReturn(pIMount, VERR_INVALID_POINTER);
4184
4185 /* Unmount the media (but do not eject the medium!) */
4186 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4187 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4188 rc = VINF_SUCCESS;
4189 /* for example if the medium is locked */
4190 else if (RT_FAILURE(rc))
4191 return rc;
4192 }
4193
4194 return rc;
4195}
4196
4197/**
4198 * Removes the currently attached medium driver form the specified device
4199 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4200 *
4201 * @returns VBox status code.
4202 * @param pCtlInst The controler instance node in the CFGM tree.
4203 * @param pcszDevice The device name.
4204 * @param uInstance The device instance.
4205 * @param uLUN The device LUN.
4206 * @param enmBus The storage bus.
4207 * @param fAttachDetach Flag whether this is a change while the VM is running
4208 * @param fHotplug Flag whether the guest should be notified about the device change.
4209 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4210 * @param pUVM The usermode VM handle.
4211 * @param enmDevType The device type.
4212 * @param ppLunL0 Where to store the node to attach the new config to on success.
4213 */
4214int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4215 const char *pcszDevice,
4216 unsigned uInstance,
4217 unsigned uLUN,
4218 StorageBus_T enmBus,
4219 bool fAttachDetach,
4220 bool fHotplug,
4221 bool fForceUnmount,
4222 PUVM pUVM,
4223 DeviceType_T enmDevType,
4224 PCFGMNODE *ppLunL0)
4225{
4226 int rc = VINF_SUCCESS;
4227 bool fAddLun = false;
4228
4229 /* First check if the LUN already exists. */
4230 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4231 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4232
4233 if (pLunL0)
4234 {
4235 /*
4236 * Unmount the currently mounted medium if we don't just hot remove the
4237 * complete device (SATA) and it supports unmounting (DVD).
4238 */
4239 if ( (enmDevType != DeviceType_HardDisk)
4240 && !fHotplug)
4241 {
4242 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4243 uInstance, uLUN, fForceUnmount);
4244 if (RT_FAILURE(rc))
4245 return rc;
4246 }
4247
4248 /*
4249 * Don't detach the SCSI driver when unmounting the current medium
4250 * (we are not ripping out the device but only eject the medium).
4251 */
4252 char *pszDriverDetach = NULL;
4253 if ( !fHotplug
4254 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4255 || enmBus == StorageBus_SAS
4256 || enmBus == StorageBus_SCSI
4257 || enmBus == StorageBus_USB))
4258 {
4259 /* Get the current attached driver we have to detach. */
4260 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4261 if (pDrvLun)
4262 {
4263 char szDriver[128];
4264 RT_ZERO(szDriver);
4265 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4266 if (RT_SUCCESS(rc))
4267 pszDriverDetach = RTStrDup(&szDriver[0]);
4268
4269 pLunL0 = pDrvLun;
4270 }
4271 }
4272
4273 if (enmBus == StorageBus_USB)
4274 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4275 pszDriverDetach, 0 /* iOccurence */,
4276 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4277 else
4278 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4279 pszDriverDetach, 0 /* iOccurence */,
4280 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4281
4282 if (pszDriverDetach)
4283 {
4284 RTStrFree(pszDriverDetach);
4285 /* Remove the complete node and create new for the new config. */
4286 CFGMR3RemoveNode(pLunL0);
4287 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4288 if (pLunL0)
4289 {
4290 try
4291 {
4292 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4293 }
4294 catch (ConfigError &x)
4295 {
4296 // InsertConfig threw something:
4297 return x.m_vrc;
4298 }
4299 }
4300 }
4301 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4302 rc = VINF_SUCCESS;
4303 AssertRCReturn(rc, rc);
4304
4305 /*
4306 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4307 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4308 */
4309 if ( fHotplug
4310 || enmBus == StorageBus_IDE
4311 || enmBus == StorageBus_Floppy
4312 || enmBus == StorageBus_PCIe
4313 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4314 {
4315 fAddLun = true;
4316 CFGMR3RemoveNode(pLunL0);
4317 }
4318 }
4319 else
4320 fAddLun = true;
4321
4322 try
4323 {
4324 if (fAddLun)
4325 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4326 }
4327 catch (ConfigError &x)
4328 {
4329 // InsertConfig threw something:
4330 return x.m_vrc;
4331 }
4332
4333 if (ppLunL0)
4334 *ppLunL0 = pLunL0;
4335
4336 return rc;
4337}
4338
4339int Console::i_configMediumAttachment(const char *pcszDevice,
4340 unsigned uInstance,
4341 StorageBus_T enmBus,
4342 bool fUseHostIOCache,
4343 bool fBuiltinIOCache,
4344 bool fInsertDiskIntegrityDrv,
4345 bool fSetupMerge,
4346 unsigned uMergeSource,
4347 unsigned uMergeTarget,
4348 IMediumAttachment *pMediumAtt,
4349 MachineState_T aMachineState,
4350 HRESULT *phrc,
4351 bool fAttachDetach,
4352 bool fForceUnmount,
4353 bool fHotplug,
4354 PUVM pUVM,
4355 DeviceType_T *paLedDevType,
4356 PCFGMNODE *ppLunL0)
4357{
4358 // InsertConfig* throws
4359 try
4360 {
4361 int rc = VINF_SUCCESS;
4362 HRESULT hrc;
4363 Bstr bstr;
4364 PCFGMNODE pCtlInst = NULL;
4365
4366// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4367#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4368
4369 LONG lDev;
4370 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4371 LONG lPort;
4372 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4373 DeviceType_T lType;
4374 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4375 BOOL fNonRotational;
4376 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4377 BOOL fDiscard;
4378 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4379
4380 if (lType == DeviceType_DVD)
4381 fInsertDiskIntegrityDrv = false;
4382
4383 unsigned uLUN;
4384 PCFGMNODE pLunL0 = NULL;
4385 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4386
4387 /* Determine the base path for the device instance. */
4388 if (enmBus != StorageBus_USB)
4389 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4390 else
4391 {
4392 /* If we hotplug a USB device create a new CFGM tree. */
4393 if (!fHotplug)
4394 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4395 else
4396 pCtlInst = CFGMR3CreateTree(pUVM);
4397 }
4398 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4399
4400 if (enmBus == StorageBus_USB)
4401 {
4402 PCFGMNODE pCfg = NULL;
4403
4404 /* Create correct instance. */
4405 if (!fHotplug)
4406 {
4407 if (!fAttachDetach)
4408 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4409 else
4410 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4411 }
4412
4413 if (!fAttachDetach)
4414 InsertConfigNode(pCtlInst, "Config", &pCfg);
4415
4416 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4417
4418 if (!fHotplug && !fAttachDetach)
4419 {
4420 char aszUuid[RTUUID_STR_LENGTH + 1];
4421 USBStorageDevice UsbMsd = USBStorageDevice();
4422
4423 memset(aszUuid, 0, sizeof(aszUuid));
4424 rc = RTUuidCreate(&UsbMsd.mUuid);
4425 AssertRCReturn(rc, rc);
4426 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4427 AssertRCReturn(rc, rc);
4428
4429 UsbMsd.iPort = uInstance;
4430
4431 InsertConfigString(pCtlInst, "UUID", aszUuid);
4432 mUSBStorageDevices.push_back(UsbMsd);
4433
4434 /** @todo No LED after hotplugging. */
4435 /* Attach the status driver */
4436 Assert(cLedUsb >= 8);
4437 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4438 &mapMediumAttachments, pcszDevice, 0);
4439 paLedDevType = &maStorageDevType[iLedUsb];
4440 }
4441 }
4442
4443 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4444 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4445 if (RT_FAILURE(rc))
4446 return rc;
4447 if (ppLunL0)
4448 *ppLunL0 = pLunL0;
4449
4450 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4451 mapMediumAttachments[devicePath] = pMediumAtt;
4452
4453 ComPtr<IMedium> pMedium;
4454 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4455
4456 /*
4457 * 1. Only check this for hard disk images.
4458 * 2. Only check during VM creation and not later, especially not during
4459 * taking an online snapshot!
4460 */
4461 if ( lType == DeviceType_HardDisk
4462 && ( aMachineState == MachineState_Starting
4463 || aMachineState == MachineState_Restoring))
4464 {
4465 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4466 if (RT_FAILURE(rc))
4467 return rc;
4468 }
4469
4470 BOOL fPassthrough = FALSE;
4471 if (pMedium)
4472 {
4473 BOOL fHostDrive;
4474 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4475 if ( ( lType == DeviceType_DVD
4476 || lType == DeviceType_Floppy)
4477 && !fHostDrive)
4478 {
4479 /*
4480 * Informative logging.
4481 */
4482 Bstr strFile;
4483 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4484 Utf8Str utfFile = Utf8Str(strFile);
4485 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4486 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4487 LogRel(("File system of '%s' (%s) is %s\n",
4488 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4489 RTFsTypeName(enmFsTypeFile)));
4490 }
4491
4492 if (fHostDrive)
4493 {
4494 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4495 }
4496 }
4497
4498 ComObjPtr<IBandwidthGroup> pBwGroup;
4499 Bstr strBwGroup;
4500 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4501
4502 if (!pBwGroup.isNull())
4503 {
4504 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4505 }
4506
4507 /*
4508 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4509 * or for SATA if the new device is a CD/DVD drive.
4510 */
4511 if ( (fHotplug || !fAttachDetach)
4512 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4513 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4514 {
4515 InsertConfigString(pLunL0, "Driver", "SCSI");
4516 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4517 }
4518
4519 rc = i_configMedium(pLunL0,
4520 !!fPassthrough,
4521 lType,
4522 fUseHostIOCache,
4523 fBuiltinIOCache,
4524 fInsertDiskIntegrityDrv,
4525 fSetupMerge,
4526 uMergeSource,
4527 uMergeTarget,
4528 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4529 !!fDiscard,
4530 !!fNonRotational,
4531 pMedium,
4532 aMachineState,
4533 phrc);
4534 if (RT_FAILURE(rc))
4535 return rc;
4536
4537 if (fAttachDetach)
4538 {
4539 /* Attach the new driver. */
4540 if (enmBus == StorageBus_USB)
4541 {
4542 if (fHotplug)
4543 {
4544 USBStorageDevice UsbMsd = USBStorageDevice();
4545 RTUuidCreate(&UsbMsd.mUuid);
4546 UsbMsd.iPort = uInstance;
4547 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4548 if (RT_SUCCESS(rc))
4549 mUSBStorageDevices.push_back(UsbMsd);
4550 }
4551 else
4552 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4553 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4554 }
4555 else if ( !fHotplug
4556 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4557 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4558 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4559 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4560 else
4561 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4562 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4563 AssertRCReturn(rc, rc);
4564
4565 /*
4566 * Make the secret key helper interface known to the VD driver if it is attached,
4567 * so we can get notified about missing keys.
4568 */
4569 PPDMIBASE pIBase = NULL;
4570 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4571 if (RT_SUCCESS(rc) && pIBase)
4572 {
4573 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4574 if (pIMedium)
4575 {
4576 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4577 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4578 }
4579 }
4580
4581 /* There is no need to handle removable medium mounting, as we
4582 * unconditionally replace everthing including the block driver level.
4583 * This means the new medium will be picked up automatically. */
4584 }
4585
4586 if (paLedDevType)
4587 paLedDevType[uLUN] = lType;
4588
4589 /* Dump the changed LUN if possible, dump the complete device otherwise */
4590 if ( aMachineState != MachineState_Starting
4591 && aMachineState != MachineState_Restoring)
4592 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4593 }
4594 catch (ConfigError &x)
4595 {
4596 // InsertConfig threw something:
4597 return x.m_vrc;
4598 }
4599
4600#undef H
4601
4602 return VINF_SUCCESS;
4603}
4604
4605int Console::i_configMedium(PCFGMNODE pLunL0,
4606 bool fPassthrough,
4607 DeviceType_T enmType,
4608 bool fUseHostIOCache,
4609 bool fBuiltinIOCache,
4610 bool fInsertDiskIntegrityDrv,
4611 bool fSetupMerge,
4612 unsigned uMergeSource,
4613 unsigned uMergeTarget,
4614 const char *pcszBwGroup,
4615 bool fDiscard,
4616 bool fNonRotational,
4617 IMedium *pMedium,
4618 MachineState_T aMachineState,
4619 HRESULT *phrc)
4620{
4621 // InsertConfig* throws
4622 try
4623 {
4624 HRESULT hrc;
4625 Bstr bstr;
4626 PCFGMNODE pCfg = NULL;
4627
4628#define H() \
4629 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4630
4631
4632 BOOL fHostDrive = FALSE;
4633 MediumType_T mediumType = MediumType_Normal;
4634 if (pMedium)
4635 {
4636 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4637 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4638 }
4639
4640 if (fHostDrive)
4641 {
4642 Assert(pMedium);
4643 if (enmType == DeviceType_DVD)
4644 {
4645 InsertConfigString(pLunL0, "Driver", "HostDVD");
4646 InsertConfigNode(pLunL0, "Config", &pCfg);
4647
4648 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4649 InsertConfigString(pCfg, "Path", bstr);
4650
4651 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4652 }
4653 else if (enmType == DeviceType_Floppy)
4654 {
4655 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4656 InsertConfigNode(pLunL0, "Config", &pCfg);
4657
4658 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4659 InsertConfigString(pCfg, "Path", bstr);
4660 }
4661 }
4662 else
4663 {
4664 if (fInsertDiskIntegrityDrv)
4665 {
4666 /*
4667 * The actual configuration is done through CFGM extra data
4668 * for each inserted driver separately.
4669 */
4670 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4671 InsertConfigNode(pLunL0, "Config", &pCfg);
4672 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4673 }
4674
4675 InsertConfigString(pLunL0, "Driver", "VD");
4676 InsertConfigNode(pLunL0, "Config", &pCfg);
4677 switch (enmType)
4678 {
4679 case DeviceType_DVD:
4680 InsertConfigString(pCfg, "Type", "DVD");
4681 InsertConfigInteger(pCfg, "Mountable", 1);
4682 break;
4683 case DeviceType_Floppy:
4684 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4685 InsertConfigInteger(pCfg, "Mountable", 1);
4686 break;
4687 case DeviceType_HardDisk:
4688 default:
4689 InsertConfigString(pCfg, "Type", "HardDisk");
4690 InsertConfigInteger(pCfg, "Mountable", 0);
4691 }
4692
4693 if ( pMedium
4694 && ( enmType == DeviceType_DVD
4695 || enmType == DeviceType_Floppy)
4696 )
4697 {
4698 // if this medium represents an ISO image and this image is inaccessible,
4699 // the ignore it instead of causing a failure; this can happen when we
4700 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4701 // Additions were mounted and the user upgraded VirtualBox. Previously
4702 // we failed on startup, but that's not good because the only way out then
4703 // would be to discard the VM state...
4704 MediumState_T mediumState;
4705 hrc = pMedium->RefreshState(&mediumState); H();
4706 if (mediumState == MediumState_Inaccessible)
4707 {
4708 Bstr loc;
4709 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4710 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4711 "The image file '%ls' is inaccessible and is being ignored. "
4712 "Please select a different image file for the virtual %s drive.",
4713 loc.raw(),
4714 enmType == DeviceType_DVD ? "DVD" : "floppy");
4715 pMedium = NULL;
4716 }
4717 }
4718
4719 if (pMedium)
4720 {
4721 /* Start with length of parent chain, as the list is reversed */
4722 unsigned uImage = 0;
4723 IMedium *pTmp = pMedium;
4724 while (pTmp)
4725 {
4726 uImage++;
4727 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4728 }
4729 /* Index of last image */
4730 uImage--;
4731
4732# ifdef VBOX_WITH_EXTPACK
4733 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4734 {
4735 /* Configure loading the VDPlugin. */
4736 static const char s_szVDPlugin[] = "VDPluginCrypt";
4737 PCFGMNODE pCfgPlugins = NULL;
4738 PCFGMNODE pCfgPlugin = NULL;
4739 Utf8Str strPlugin;
4740 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4741 // Don't fail, this is optional!
4742 if (SUCCEEDED(hrc))
4743 {
4744 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4745 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4746 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4747 }
4748 }
4749# endif
4750
4751 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4752 InsertConfigString(pCfg, "Path", bstr);
4753
4754 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4755 InsertConfigString(pCfg, "Format", bstr);
4756
4757 if (mediumType == MediumType_Readonly)
4758 InsertConfigInteger(pCfg, "ReadOnly", 1);
4759 else if (enmType == DeviceType_Floppy)
4760 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4761
4762 /* Start without exclusive write access to the images. */
4763 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4764 * we're resuming the VM if some 3rd dude have any of the VDIs open
4765 * with write sharing denied. However, if the two VMs are sharing a
4766 * image it really is necessary....
4767 *
4768 * So, on the "lock-media" command, the target teleporter should also
4769 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4770 * that. Grumble. */
4771 if ( enmType == DeviceType_HardDisk
4772 && ( aMachineState == MachineState_TeleportingIn
4773 || aMachineState == MachineState_FaultTolerantSyncing))
4774 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4775
4776 /* Flag for opening the medium for sharing between VMs. This
4777 * is done at the moment only for the first (and only) medium
4778 * in the chain, as shared media can have no diffs. */
4779 if (mediumType == MediumType_Shareable)
4780 InsertConfigInteger(pCfg, "Shareable", 1);
4781
4782 if (!fUseHostIOCache)
4783 {
4784 InsertConfigInteger(pCfg, "UseNewIo", 1);
4785 /*
4786 * Activate the builtin I/O cache for harddisks only.
4787 * It caches writes only which doesn't make sense for DVD drives
4788 * and just increases the overhead.
4789 */
4790 if ( fBuiltinIOCache
4791 && (enmType == DeviceType_HardDisk))
4792 InsertConfigInteger(pCfg, "BlockCache", 1);
4793 }
4794
4795 if (fSetupMerge)
4796 {
4797 InsertConfigInteger(pCfg, "SetupMerge", 1);
4798 if (uImage == uMergeSource)
4799 InsertConfigInteger(pCfg, "MergeSource", 1);
4800 else if (uImage == uMergeTarget)
4801 InsertConfigInteger(pCfg, "MergeTarget", 1);
4802 }
4803
4804 if (pcszBwGroup)
4805 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4806
4807 if (fDiscard)
4808 InsertConfigInteger(pCfg, "Discard", 1);
4809
4810 if (fNonRotational)
4811 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4812
4813 /* Pass all custom parameters. */
4814 bool fHostIP = true;
4815 bool fEncrypted = false;
4816 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4817
4818 /* Create an inverted list of parents. */
4819 uImage--;
4820 IMedium *pParentMedium = pMedium;
4821 for (PCFGMNODE pParent = pCfg;; uImage--)
4822 {
4823 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4824 if (!pMedium)
4825 break;
4826
4827 PCFGMNODE pCur;
4828 InsertConfigNode(pParent, "Parent", &pCur);
4829 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4830 InsertConfigString(pCur, "Path", bstr);
4831
4832 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4833 InsertConfigString(pCur, "Format", bstr);
4834
4835 if (fSetupMerge)
4836 {
4837 if (uImage == uMergeSource)
4838 InsertConfigInteger(pCur, "MergeSource", 1);
4839 else if (uImage == uMergeTarget)
4840 InsertConfigInteger(pCur, "MergeTarget", 1);
4841 }
4842
4843 /* Configure medium properties. */
4844 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4845
4846 /* next */
4847 pParent = pCur;
4848 pParentMedium = pMedium;
4849 }
4850
4851 /* Custom code: put marker to not use host IP stack to driver
4852 * configuration node. Simplifies life of DrvVD a bit. */
4853 if (!fHostIP)
4854 InsertConfigInteger(pCfg, "HostIPStack", 0);
4855
4856 if (fEncrypted)
4857 m_cDisksEncrypted++;
4858 }
4859 else
4860 {
4861 /* Set empty drive flag for DVD or floppy without media. */
4862 if ( enmType == DeviceType_DVD
4863 || enmType == DeviceType_Floppy)
4864 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4865 }
4866 }
4867#undef H
4868 }
4869 catch (ConfigError &x)
4870 {
4871 // InsertConfig threw something:
4872 return x.m_vrc;
4873 }
4874
4875 return VINF_SUCCESS;
4876}
4877
4878/**
4879 * Adds the medium properties to the CFGM tree.
4880 *
4881 * @returns VBox status code.
4882 * @param pCur The current CFGM node.
4883 * @param pMedium The medium object to configure.
4884 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4885 * @param pfEncrypted Where to return whether the medium is encrypted.
4886 */
4887int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4888{
4889 /* Pass all custom parameters. */
4890 SafeArray<BSTR> aNames;
4891 SafeArray<BSTR> aValues;
4892 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4893 ComSafeArrayAsOutParam(aValues));
4894
4895 if ( SUCCEEDED(hrc)
4896 && aNames.size() != 0)
4897 {
4898 PCFGMNODE pVDC;
4899 InsertConfigNode(pCur, "VDConfig", &pVDC);
4900 for (size_t ii = 0; ii < aNames.size(); ++ii)
4901 {
4902 if (aValues[ii] && *aValues[ii])
4903 {
4904 Utf8Str name = aNames[ii];
4905 Utf8Str value = aValues[ii];
4906 size_t offSlash = name.find("/", 0);
4907 if ( offSlash != name.npos
4908 && !name.startsWith("Special/"))
4909 {
4910 com::Utf8Str strFilter;
4911 com::Utf8Str strKey;
4912
4913 hrc = strFilter.assignEx(name, 0, offSlash);
4914 if (FAILED(hrc))
4915 break;
4916
4917 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4918 if (FAILED(hrc))
4919 break;
4920
4921 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4922 if (!pCfgFilterConfig)
4923 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4924
4925 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4926 }
4927 else
4928 {
4929 InsertConfigString(pVDC, name.c_str(), value);
4930 if ( name.compare("HostIPStack") == 0
4931 && value.compare("0") == 0)
4932 *pfHostIP = false;
4933 }
4934
4935 if ( name.compare("CRYPT/KeyId") == 0
4936 && pfEncrypted)
4937 *pfEncrypted = true;
4938 }
4939 }
4940 }
4941
4942 return hrc;
4943}
4944
4945
4946/**
4947 * Construct the Network configuration tree
4948 *
4949 * @returns VBox status code.
4950 *
4951 * @param pszDevice The PDM device name.
4952 * @param uInstance The PDM device instance.
4953 * @param uLun The PDM LUN number of the drive.
4954 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4955 * @param pCfg Configuration node for the device
4956 * @param pLunL0 To store the pointer to the LUN#0.
4957 * @param pInst The instance CFGM node
4958 * @param fAttachDetach To determine if the network attachment should
4959 * be attached/detached after/before
4960 * configuration.
4961 * @param fIgnoreConnectFailure
4962 * True if connection failures should be ignored
4963 * (makes only sense for bridged/host-only networks).
4964 *
4965 * @note Locks this object for writing.
4966 * @thread EMT
4967 */
4968int Console::i_configNetwork(const char *pszDevice,
4969 unsigned uInstance,
4970 unsigned uLun,
4971 INetworkAdapter *aNetworkAdapter,
4972 PCFGMNODE pCfg,
4973 PCFGMNODE pLunL0,
4974 PCFGMNODE pInst,
4975 bool fAttachDetach,
4976 bool fIgnoreConnectFailure)
4977{
4978 RT_NOREF(fIgnoreConnectFailure);
4979 AutoCaller autoCaller(this);
4980 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4981
4982 // InsertConfig* throws
4983 try
4984 {
4985 int rc = VINF_SUCCESS;
4986 HRESULT hrc;
4987 Bstr bstr;
4988
4989#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4990
4991 /*
4992 * Locking the object before doing VMR3* calls is quite safe here, since
4993 * we're on EMT. Write lock is necessary because we indirectly modify the
4994 * meAttachmentType member.
4995 */
4996 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4997
4998 ComPtr<IMachine> pMachine = i_machine();
4999
5000 ComPtr<IVirtualBox> virtualBox;
5001 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5002
5003 ComPtr<IHost> host;
5004 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5005
5006 BOOL fSniffer;
5007 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5008
5009 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5010 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5011 const char *pszPromiscuousGuestPolicy;
5012 switch (enmPromiscModePolicy)
5013 {
5014 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5015 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5016 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5017 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5018 }
5019
5020 if (fAttachDetach)
5021 {
5022 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5023 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5024 rc = VINF_SUCCESS;
5025 AssertLogRelRCReturn(rc, rc);
5026
5027 /* Nuke anything which might have been left behind. */
5028 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5029 }
5030
5031#ifdef VBOX_WITH_NETSHAPER
5032 ComObjPtr<IBandwidthGroup> pBwGroup;
5033 Bstr strBwGroup;
5034 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5035
5036 if (!pBwGroup.isNull())
5037 {
5038 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5039 }
5040#endif /* VBOX_WITH_NETSHAPER */
5041
5042 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5043 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5044
5045#ifdef VBOX_WITH_NETSHAPER
5046 if (!strBwGroup.isEmpty())
5047 {
5048 InsertConfigString(pLunL0, "Driver", "NetShaper");
5049 InsertConfigNode(pLunL0, "Config", &pCfg);
5050 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5051 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5052 }
5053#endif /* VBOX_WITH_NETSHAPER */
5054
5055 if (fSniffer)
5056 {
5057 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5058 InsertConfigNode(pLunL0, "Config", &pCfg);
5059 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5060 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5061 InsertConfigString(pCfg, "File", bstr);
5062 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5063 }
5064
5065
5066 Bstr networkName, trunkName, trunkType;
5067 NetworkAttachmentType_T eAttachmentType;
5068 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5069 switch (eAttachmentType)
5070 {
5071 case NetworkAttachmentType_Null:
5072 break;
5073
5074 case NetworkAttachmentType_NAT:
5075 {
5076 ComPtr<INATEngine> natEngine;
5077 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5078 InsertConfigString(pLunL0, "Driver", "NAT");
5079 InsertConfigNode(pLunL0, "Config", &pCfg);
5080
5081 /* Configure TFTP prefix and boot filename. */
5082 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5083 if (!bstr.isEmpty())
5084 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5085 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5086 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5087
5088 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5089 if (!bstr.isEmpty())
5090 InsertConfigString(pCfg, "Network", bstr);
5091 else
5092 {
5093 ULONG uSlot;
5094 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5095 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5096 }
5097 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5098 if (!bstr.isEmpty())
5099 InsertConfigString(pCfg, "BindIP", bstr);
5100 ULONG mtu = 0;
5101 ULONG sockSnd = 0;
5102 ULONG sockRcv = 0;
5103 ULONG tcpSnd = 0;
5104 ULONG tcpRcv = 0;
5105 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5106 if (mtu)
5107 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5108 if (sockRcv)
5109 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5110 if (sockSnd)
5111 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5112 if (tcpRcv)
5113 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5114 if (tcpSnd)
5115 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5116 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5117 if (!bstr.isEmpty())
5118 {
5119 RemoveConfigValue(pCfg, "TFTPPrefix");
5120 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5121 }
5122 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5123 if (!bstr.isEmpty())
5124 {
5125 RemoveConfigValue(pCfg, "BootFile");
5126 InsertConfigString(pCfg, "BootFile", bstr);
5127 }
5128 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5129 if (!bstr.isEmpty())
5130 InsertConfigString(pCfg, "NextServer", bstr);
5131 BOOL fDNSFlag;
5132 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5133 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5134 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5135 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5136 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5137 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5138
5139 ULONG aliasMode;
5140 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5141 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5142
5143 /* port-forwarding */
5144 SafeArray<BSTR> pfs;
5145 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5146
5147 PCFGMNODE pPFTree = NULL;
5148 if (pfs.size() > 0)
5149 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5150
5151 for (unsigned int i = 0; i < pfs.size(); ++i)
5152 {
5153 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5154
5155 uint16_t port = 0;
5156 BSTR r = pfs[i];
5157 Utf8Str utf = Utf8Str(r);
5158 Utf8Str strName;
5159 Utf8Str strProto;
5160 Utf8Str strHostPort;
5161 Utf8Str strHostIP;
5162 Utf8Str strGuestPort;
5163 Utf8Str strGuestIP;
5164 size_t pos, ppos;
5165 pos = ppos = 0;
5166#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5167 { \
5168 pos = str.find(",", ppos); \
5169 if (pos == Utf8Str::npos) \
5170 { \
5171 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5172 continue; \
5173 } \
5174 res = str.substr(ppos, pos - ppos); \
5175 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5176 ppos = pos + 1; \
5177 } /* no do { ... } while because of 'continue' */
5178 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5179 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5180 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5181 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5182 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5183 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5184#undef ITERATE_TO_NEXT_TERM
5185
5186 uint32_t proto = strProto.toUInt32();
5187 bool fValid = true;
5188 switch (proto)
5189 {
5190 case NATProtocol_UDP:
5191 strProto = "UDP";
5192 break;
5193 case NATProtocol_TCP:
5194 strProto = "TCP";
5195 break;
5196 default:
5197 fValid = false;
5198 }
5199 /* continue with next rule if no valid proto was passed */
5200 if (!fValid)
5201 continue;
5202
5203 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5204
5205 if (!strName.isEmpty())
5206 InsertConfigString(pPF, "Name", strName);
5207
5208 InsertConfigString(pPF, "Protocol", strProto);
5209
5210 if (!strHostIP.isEmpty())
5211 InsertConfigString(pPF, "BindIP", strHostIP);
5212
5213 if (!strGuestIP.isEmpty())
5214 InsertConfigString(pPF, "GuestIP", strGuestIP);
5215
5216 port = RTStrToUInt16(strHostPort.c_str());
5217 if (port)
5218 InsertConfigInteger(pPF, "HostPort", port);
5219
5220 port = RTStrToUInt16(strGuestPort.c_str());
5221 if (port)
5222 InsertConfigInteger(pPF, "GuestPort", port);
5223 }
5224 break;
5225 }
5226
5227 case NetworkAttachmentType_Bridged:
5228 {
5229#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5230 hrc = i_attachToTapInterface(aNetworkAdapter);
5231 if (FAILED(hrc))
5232 {
5233 switch (hrc)
5234 {
5235 case VERR_ACCESS_DENIED:
5236 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5237 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5238 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5239 "change the group of that node and make yourself a member of that group. Make "
5240 "sure that these changes are permanent, especially if you are "
5241 "using udev"));
5242 default:
5243 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5244 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5245 "Failed to initialize Host Interface Networking"));
5246 }
5247 }
5248
5249 Assert((intptr_t)maTapFD[uInstance] >= 0);
5250 if ((intptr_t)maTapFD[uInstance] >= 0)
5251 {
5252 InsertConfigString(pLunL0, "Driver", "HostInterface");
5253 InsertConfigNode(pLunL0, "Config", &pCfg);
5254 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5255 }
5256
5257#elif defined(VBOX_WITH_NETFLT)
5258 /*
5259 * This is the new VBoxNetFlt+IntNet stuff.
5260 */
5261 Bstr BridgedIfName;
5262 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5263 if (FAILED(hrc))
5264 {
5265 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5266 H();
5267 }
5268
5269 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5270 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5271
5272 ComPtr<IHostNetworkInterface> hostInterface;
5273 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5274 hostInterface.asOutParam());
5275 if (!SUCCEEDED(hrc))
5276 {
5277 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5278 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5279 N_("Nonexistent host networking interface, name '%ls'"),
5280 BridgedIfName.raw());
5281 }
5282
5283# if defined(RT_OS_DARWIN)
5284 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5285 char szTrunk[8];
5286 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5287 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5288// Quick fix for @bugref{5633}
5289// if (!pszColon)
5290// {
5291// /*
5292// * Dynamic changing of attachment causes an attempt to configure
5293// * network with invalid host adapter (as it is must be changed before
5294// * the attachment), calling Detach here will cause a deadlock.
5295// * See @bugref{4750}.
5296// * hrc = aNetworkAdapter->Detach(); H();
5297// */
5298// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5299// N_("Malformed host interface networking name '%ls'"),
5300// BridgedIfName.raw());
5301// }
5302 if (pszColon)
5303 *pszColon = '\0';
5304 const char *pszTrunk = szTrunk;
5305
5306# elif defined(RT_OS_SOLARIS)
5307 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5308 char szTrunk[256];
5309 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5310 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5311
5312 /*
5313 * Currently don't bother about malformed names here for the sake of people using
5314 * VBoxManage and setting only the NIC name from there. If there is a space we
5315 * chop it off and proceed, otherwise just use whatever we've got.
5316 */
5317 if (pszSpace)
5318 *pszSpace = '\0';
5319
5320 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5321 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5322 if (pszColon)
5323 *pszColon = '\0';
5324
5325 const char *pszTrunk = szTrunk;
5326
5327# elif defined(RT_OS_WINDOWS)
5328 HostNetworkInterfaceType_T eIfType;
5329 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5330 if (FAILED(hrc))
5331 {
5332 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5333 H();
5334 }
5335
5336 if (eIfType != HostNetworkInterfaceType_Bridged)
5337 {
5338 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5339 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5340 BridgedIfName.raw());
5341 }
5342
5343 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5344 if (FAILED(hrc))
5345 {
5346 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5347 H();
5348 }
5349 Guid hostIFGuid(bstr);
5350
5351 INetCfg *pNc;
5352 ComPtr<INetCfgComponent> pAdaptorComponent;
5353 LPWSTR pszApp;
5354
5355 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5356 Assert(hrc == S_OK);
5357 if (hrc != S_OK)
5358 {
5359 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5360 H();
5361 }
5362
5363 /* get the adapter's INetCfgComponent*/
5364 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5365 pAdaptorComponent.asOutParam());
5366 if (hrc != S_OK)
5367 {
5368 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5369 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5370 H();
5371 }
5372# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5373 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5374 char *pszTrunkName = szTrunkName;
5375 wchar_t * pswzBindName;
5376 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5377 Assert(hrc == S_OK);
5378 if (hrc == S_OK)
5379 {
5380 int cwBindName = (int)wcslen(pswzBindName) + 1;
5381 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5382 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5383 {
5384 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5385 pszTrunkName += cbFullBindNamePrefix-1;
5386 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5387 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5388 {
5389 DWORD err = GetLastError();
5390 hrc = HRESULT_FROM_WIN32(err);
5391 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5392 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5393 hrc, hrc, err));
5394 }
5395 }
5396 else
5397 {
5398 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5399 /** @todo set appropriate error code */
5400 hrc = E_FAIL;
5401 }
5402
5403 if (hrc != S_OK)
5404 {
5405 AssertFailed();
5406 CoTaskMemFree(pswzBindName);
5407 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5408 H();
5409 }
5410
5411 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5412 }
5413 else
5414 {
5415 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5416 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5417 hrc));
5418 H();
5419 }
5420
5421 const char *pszTrunk = szTrunkName;
5422 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5423
5424# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5425# if defined(RT_OS_FREEBSD)
5426 /*
5427 * If we bridge to a tap interface open it the `old' direct way.
5428 * This works and performs better than bridging a physical
5429 * interface via the current FreeBSD vboxnetflt implementation.
5430 */
5431 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5432 hrc = i_attachToTapInterface(aNetworkAdapter);
5433 if (FAILED(hrc))
5434 {
5435 switch (hrc)
5436 {
5437 case VERR_ACCESS_DENIED:
5438 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5439 "Failed to open '/dev/%s' for read/write access. Please check the "
5440 "permissions of that node, and that the net.link.tap.user_open "
5441 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5442 "change the group of that node to vboxusers and make yourself "
5443 "a member of that group. Make sure that these changes are permanent."),
5444 pszBridgedIfName, pszBridgedIfName);
5445 default:
5446 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5447 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5448 "Failed to initialize Host Interface Networking"));
5449 }
5450 }
5451
5452 Assert((intptr_t)maTapFD[uInstance] >= 0);
5453 if ((intptr_t)maTapFD[uInstance] >= 0)
5454 {
5455 InsertConfigString(pLunL0, "Driver", "HostInterface");
5456 InsertConfigNode(pLunL0, "Config", &pCfg);
5457 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5458 }
5459 break;
5460 }
5461# endif
5462 /** @todo Check for malformed names. */
5463 const char *pszTrunk = pszBridgedIfName;
5464
5465 /* Issue a warning if the interface is down */
5466 {
5467 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5468 if (iSock >= 0)
5469 {
5470 struct ifreq Req;
5471 RT_ZERO(Req);
5472 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5473 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5474 if ((Req.ifr_flags & IFF_UP) == 0)
5475 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5476 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5477 pszBridgedIfName);
5478
5479 close(iSock);
5480 }
5481 }
5482
5483# else
5484# error "PORTME (VBOX_WITH_NETFLT)"
5485# endif
5486
5487 InsertConfigString(pLunL0, "Driver", "IntNet");
5488 InsertConfigNode(pLunL0, "Config", &pCfg);
5489 InsertConfigString(pCfg, "Trunk", pszTrunk);
5490 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5491 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5492 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5493 char szNetwork[INTNET_MAX_NETWORK_NAME];
5494
5495# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5496 /*
5497 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5498 * interface name + optional description. We must not pass any description to the VM as it can differ
5499 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5500 */
5501 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5502# else
5503 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5504# endif
5505 InsertConfigString(pCfg, "Network", szNetwork);
5506 networkName = Bstr(szNetwork);
5507 trunkName = Bstr(pszTrunk);
5508 trunkType = Bstr(TRUNKTYPE_NETFLT);
5509
5510 BOOL fSharedMacOnWire = false;
5511 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5512 if (FAILED(hrc))
5513 {
5514 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5515 H();
5516 }
5517 else if (fSharedMacOnWire)
5518 {
5519 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5520 Log(("Set SharedMacOnWire\n"));
5521 }
5522
5523# if defined(RT_OS_SOLARIS)
5524# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5525 /* Zone access restriction, don't allow snooping the global zone. */
5526 zoneid_t ZoneId = getzoneid();
5527 if (ZoneId != GLOBAL_ZONEID)
5528 {
5529 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5530 }
5531# endif
5532# endif
5533
5534#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5535 /* NOTHING TO DO HERE */
5536#elif defined(RT_OS_LINUX)
5537/// @todo aleksey: is there anything to be done here?
5538#elif defined(RT_OS_FREEBSD)
5539/** @todo FreeBSD: Check out this later (HIF networking). */
5540#else
5541# error "Port me"
5542#endif
5543 break;
5544 }
5545
5546 case NetworkAttachmentType_Internal:
5547 {
5548 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5549 if (!bstr.isEmpty())
5550 {
5551 InsertConfigString(pLunL0, "Driver", "IntNet");
5552 InsertConfigNode(pLunL0, "Config", &pCfg);
5553 InsertConfigString(pCfg, "Network", bstr);
5554 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5555 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5556 networkName = bstr;
5557 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5558 }
5559 break;
5560 }
5561
5562 case NetworkAttachmentType_HostOnly:
5563 {
5564 InsertConfigString(pLunL0, "Driver", "IntNet");
5565 InsertConfigNode(pLunL0, "Config", &pCfg);
5566
5567 Bstr HostOnlyName;
5568 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5569 if (FAILED(hrc))
5570 {
5571 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5572 H();
5573 }
5574
5575 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5576 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5577 ComPtr<IHostNetworkInterface> hostInterface;
5578 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5579 hostInterface.asOutParam());
5580 if (!SUCCEEDED(rc))
5581 {
5582 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5583 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5584 N_("Nonexistent host networking interface, name '%ls'"),
5585 HostOnlyName.raw());
5586 }
5587
5588 char szNetwork[INTNET_MAX_NETWORK_NAME];
5589 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5590
5591#if defined(RT_OS_WINDOWS)
5592# ifndef VBOX_WITH_NETFLT
5593 hrc = E_NOTIMPL;
5594 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5595 H();
5596# else /* defined VBOX_WITH_NETFLT*/
5597 /** @todo r=bird: Put this in a function. */
5598
5599 HostNetworkInterfaceType_T eIfType;
5600 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5601 if (FAILED(hrc))
5602 {
5603 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5604 H();
5605 }
5606
5607 if (eIfType != HostNetworkInterfaceType_HostOnly)
5608 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5609 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5610 HostOnlyName.raw());
5611
5612 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5613 if (FAILED(hrc))
5614 {
5615 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5616 H();
5617 }
5618 Guid hostIFGuid(bstr);
5619
5620 INetCfg *pNc;
5621 ComPtr<INetCfgComponent> pAdaptorComponent;
5622 LPWSTR pszApp;
5623 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5624 Assert(hrc == S_OK);
5625 if (hrc != S_OK)
5626 {
5627 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5628 H();
5629 }
5630
5631 /* get the adapter's INetCfgComponent*/
5632 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5633 pAdaptorComponent.asOutParam());
5634 if (hrc != S_OK)
5635 {
5636 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5637 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5638 H();
5639 }
5640# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5641 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5642 bool fNdis6 = false;
5643 wchar_t * pwszHelpText;
5644 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5645 Assert(hrc == S_OK);
5646 if (hrc == S_OK)
5647 {
5648 Log(("help-text=%ls\n", pwszHelpText));
5649 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5650 fNdis6 = true;
5651 CoTaskMemFree(pwszHelpText);
5652 }
5653 if (fNdis6)
5654 {
5655 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5656 Log(("trunk=%s\n", szTrunkName));
5657 }
5658 else
5659 {
5660 char *pszTrunkName = szTrunkName;
5661 wchar_t * pswzBindName;
5662 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5663 Assert(hrc == S_OK);
5664 if (hrc == S_OK)
5665 {
5666 int cwBindName = (int)wcslen(pswzBindName) + 1;
5667 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5668 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5669 {
5670 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5671 pszTrunkName += cbFullBindNamePrefix-1;
5672 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5673 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5674 {
5675 DWORD err = GetLastError();
5676 hrc = HRESULT_FROM_WIN32(err);
5677 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5678 hrc, hrc, err));
5679 }
5680 }
5681 else
5682 {
5683 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5684 /** @todo set appropriate error code */
5685 hrc = E_FAIL;
5686 }
5687
5688 if (hrc != S_OK)
5689 {
5690 AssertFailed();
5691 CoTaskMemFree(pswzBindName);
5692 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5693 H();
5694 }
5695 }
5696 else
5697 {
5698 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5699 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5700 hrc, hrc));
5701 H();
5702 }
5703
5704
5705 CoTaskMemFree(pswzBindName);
5706 }
5707
5708 trunkType = TRUNKTYPE_NETADP;
5709 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5710
5711 pAdaptorComponent.setNull();
5712 /* release the pNc finally */
5713 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5714
5715 const char *pszTrunk = szTrunkName;
5716
5717 InsertConfigString(pCfg, "Trunk", pszTrunk);
5718 InsertConfigString(pCfg, "Network", szNetwork);
5719 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5720 windows only?? */
5721 networkName = Bstr(szNetwork);
5722 trunkName = Bstr(pszTrunk);
5723# endif /* defined VBOX_WITH_NETFLT*/
5724#elif defined(RT_OS_DARWIN)
5725 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5726 InsertConfigString(pCfg, "Network", szNetwork);
5727 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5728 networkName = Bstr(szNetwork);
5729 trunkName = Bstr(pszHostOnlyName);
5730 trunkType = TRUNKTYPE_NETADP;
5731#else
5732 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5733 InsertConfigString(pCfg, "Network", szNetwork);
5734 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5735 networkName = Bstr(szNetwork);
5736 trunkName = Bstr(pszHostOnlyName);
5737 trunkType = TRUNKTYPE_NETFLT;
5738#endif
5739 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5740
5741#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5742
5743 Bstr tmpAddr, tmpMask;
5744
5745 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5746 pszHostOnlyName).raw(),
5747 tmpAddr.asOutParam());
5748 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5749 {
5750 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5751 pszHostOnlyName).raw(),
5752 tmpMask.asOutParam());
5753 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5754 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5755 tmpMask.raw());
5756 else
5757 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5758 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5759 }
5760 else
5761 {
5762 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5763 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5764 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5765 }
5766
5767 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5768
5769 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5770 pszHostOnlyName).raw(),
5771 tmpAddr.asOutParam());
5772 if (SUCCEEDED(hrc))
5773 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5774 tmpMask.asOutParam());
5775 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5776 {
5777 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5778 Utf8Str(tmpMask).toUInt32());
5779 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5780 }
5781#endif
5782 break;
5783 }
5784
5785 case NetworkAttachmentType_Generic:
5786 {
5787 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5788 SafeArray<BSTR> names;
5789 SafeArray<BSTR> values;
5790 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5791 ComSafeArrayAsOutParam(names),
5792 ComSafeArrayAsOutParam(values)); H();
5793
5794 InsertConfigString(pLunL0, "Driver", bstr);
5795 InsertConfigNode(pLunL0, "Config", &pCfg);
5796 for (size_t ii = 0; ii < names.size(); ++ii)
5797 {
5798 if (values[ii] && *values[ii])
5799 {
5800 Utf8Str name = names[ii];
5801 Utf8Str value = values[ii];
5802 InsertConfigString(pCfg, name.c_str(), value);
5803 }
5804 }
5805 break;
5806 }
5807
5808 case NetworkAttachmentType_NATNetwork:
5809 {
5810 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5811 if (!bstr.isEmpty())
5812 {
5813 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5814 InsertConfigString(pLunL0, "Driver", "IntNet");
5815 InsertConfigNode(pLunL0, "Config", &pCfg);
5816 InsertConfigString(pCfg, "Network", bstr);
5817 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5818 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5819 networkName = bstr;
5820 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5821 }
5822 break;
5823 }
5824
5825 default:
5826 AssertMsgFailed(("should not get here!\n"));
5827 break;
5828 }
5829
5830 /*
5831 * Attempt to attach the driver.
5832 */
5833 switch (eAttachmentType)
5834 {
5835 case NetworkAttachmentType_Null:
5836 break;
5837
5838 case NetworkAttachmentType_Bridged:
5839 case NetworkAttachmentType_Internal:
5840 case NetworkAttachmentType_HostOnly:
5841 case NetworkAttachmentType_NAT:
5842 case NetworkAttachmentType_Generic:
5843 case NetworkAttachmentType_NATNetwork:
5844 {
5845 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5846 {
5847 if (fAttachDetach)
5848 {
5849 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5850 //AssertRC(rc);
5851 }
5852
5853 {
5854 /** @todo pritesh: get the dhcp server name from the
5855 * previous network configuration and then stop the server
5856 * else it may conflict with the dhcp server running with
5857 * the current attachment type
5858 */
5859 /* Stop the hostonly DHCP Server */
5860 }
5861
5862 /*
5863 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5864 */
5865 if ( !networkName.isEmpty()
5866 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5867 {
5868 /*
5869 * Until we implement service reference counters DHCP Server will be stopped
5870 * by DHCPServerRunner destructor.
5871 */
5872 ComPtr<IDHCPServer> dhcpServer;
5873 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5874 dhcpServer.asOutParam());
5875 if (SUCCEEDED(hrc))
5876 {
5877 /* there is a DHCP server available for this network */
5878 BOOL fEnabledDhcp;
5879 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5880 if (FAILED(hrc))
5881 {
5882 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5883 H();
5884 }
5885
5886 if (fEnabledDhcp)
5887 hrc = dhcpServer->Start(networkName.raw(),
5888 trunkName.raw(),
5889 trunkType.raw());
5890 }
5891 else
5892 hrc = S_OK;
5893 }
5894 }
5895
5896 break;
5897 }
5898
5899 default:
5900 AssertMsgFailed(("should not get here!\n"));
5901 break;
5902 }
5903
5904 meAttachmentType[uInstance] = eAttachmentType;
5905 }
5906 catch (ConfigError &x)
5907 {
5908 // InsertConfig threw something:
5909 return x.m_vrc;
5910 }
5911
5912#undef H
5913
5914 return VINF_SUCCESS;
5915}
5916
5917
5918/**
5919 * Configures the serial port at the given CFGM node with the supplied parameters.
5920 *
5921 * @returns VBox status code.
5922 * @param pInst The instance CFGM node.
5923 * @param ePortMode The port mode to sue.
5924 * @param pszPath The serial port path.
5925 * @param fServer Flag whether the port should act as a server
5926 * for the pipe and TCP mode or connect as a client.
5927 */
5928int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
5929{
5930 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5931 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
5932 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
5933
5934 try
5935 {
5936 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5937 if (ePortMode == PortMode_HostPipe)
5938 {
5939 InsertConfigString(pLunL0, "Driver", "Char");
5940 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5941 InsertConfigString(pLunL1, "Driver", "NamedPipe");
5942 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5943 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5944 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5945 }
5946 else if (ePortMode == PortMode_HostDevice)
5947 {
5948 InsertConfigString(pLunL0, "Driver", "Host Serial");
5949 InsertConfigNode(pLunL0, "Config", &pLunL1);
5950 InsertConfigString(pLunL1, "DevicePath", pszPath);
5951 }
5952 else if (ePortMode == PortMode_TCP)
5953 {
5954 InsertConfigString(pLunL0, "Driver", "Char");
5955 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5956 InsertConfigString(pLunL1, "Driver", "TCP");
5957 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5958 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5959 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5960 }
5961 else if (ePortMode == PortMode_RawFile)
5962 {
5963 InsertConfigString(pLunL0, "Driver", "Char");
5964 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5965 InsertConfigString(pLunL1, "Driver", "RawFile");
5966 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5967 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5968 }
5969 }
5970 catch (ConfigError &x)
5971 {
5972 /* InsertConfig threw something */
5973 return x.m_vrc;
5974 }
5975
5976 return VINF_SUCCESS;
5977}
5978
5979
5980#ifdef VBOX_WITH_GUEST_PROPS
5981
5982/**
5983 * Set an array of guest properties
5984 */
5985static void configSetProperties(VMMDev * const pVMMDev,
5986 void *names,
5987 void *values,
5988 void *timestamps,
5989 void *flags)
5990{
5991 VBOXHGCMSVCPARM parms[4];
5992
5993 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5994 parms[0].u.pointer.addr = names;
5995 parms[0].u.pointer.size = 0; /* We don't actually care. */
5996 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5997 parms[1].u.pointer.addr = values;
5998 parms[1].u.pointer.size = 0; /* We don't actually care. */
5999 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
6000 parms[2].u.pointer.addr = timestamps;
6001 parms[2].u.pointer.size = 0; /* We don't actually care. */
6002 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
6003 parms[3].u.pointer.addr = flags;
6004 parms[3].u.pointer.size = 0; /* We don't actually care. */
6005
6006 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROPS, 4, &parms[0]);
6007}
6008
6009/**
6010 * Set a single guest property
6011 */
6012static void configSetProperty(VMMDev * const pVMMDev,
6013 const char *pszName,
6014 const char *pszValue,
6015 const char *pszFlags)
6016{
6017 VBOXHGCMSVCPARM parms[4];
6018
6019 AssertPtrReturnVoid(pszName);
6020 AssertPtrReturnVoid(pszValue);
6021 AssertPtrReturnVoid(pszFlags);
6022 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
6023 parms[0].u.pointer.addr = (void *)pszName;
6024 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
6025 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
6026 parms[1].u.pointer.addr = (void *)pszValue;
6027 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
6028 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
6029 parms[2].u.pointer.addr = (void *)pszFlags;
6030 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
6031 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP, 3, &parms[0]);
6032}
6033
6034/**
6035 * Set the global flags value by calling the service
6036 * @returns the status returned by the call to the service
6037 *
6038 * @param pTable the service instance handle
6039 * @param eFlags the flags to set
6040 */
6041int configSetGlobalPropertyFlags(VMMDev * const pVMMDev, uint32_t fFlags)
6042{
6043 VBOXHGCMSVCPARM paParm;
6044 paParm.setUInt32(fFlags);
6045 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS, 1, &paParm);
6046 if (RT_FAILURE(rc))
6047 {
6048 char szFlags[GUEST_PROP_MAX_FLAGS_LEN];
6049 if (RT_FAILURE(GuestPropWriteFlags(fFlags, szFlags)))
6050 Log(("Failed to set the global flags.\n"));
6051 else
6052 Log(("Failed to set the global flags \"%s\".\n", szFlags));
6053 }
6054 return rc;
6055}
6056
6057#endif /* VBOX_WITH_GUEST_PROPS */
6058
6059/**
6060 * Set up the Guest Property service, populate it with properties read from
6061 * the machine XML and set a couple of initial properties.
6062 */
6063/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
6064{
6065#ifdef VBOX_WITH_GUEST_PROPS
6066 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6067 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6068 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
6069
6070 /* Load the service */
6071 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
6072
6073 if (RT_FAILURE(rc))
6074 {
6075 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
6076 /* That is not a fatal failure. */
6077 rc = VINF_SUCCESS;
6078 }
6079 else
6080 {
6081 /*
6082 * Initialize built-in properties that can be changed and saved.
6083 *
6084 * These are typically transient properties that the guest cannot
6085 * change.
6086 */
6087
6088 {
6089 VBOXHGCMSVCPARM Params[2];
6090 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_GET_DBGF_INFO, 2, &Params[0]);
6091 if (RT_SUCCESS(rc2))
6092 {
6093 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
6094 void *pvService = Params[1].u.pointer.addr;
6095 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pvService);
6096 }
6097 }
6098
6099 /* Sysprep execution by VBoxService. */
6100 configSetProperty(pConsole->m_pVMMDev,
6101 "/VirtualBox/HostGuest/SysprepExec", "",
6102 "TRANSIENT, RDONLYGUEST");
6103 configSetProperty(pConsole->m_pVMMDev,
6104 "/VirtualBox/HostGuest/SysprepArgs", "",
6105 "TRANSIENT, RDONLYGUEST");
6106
6107 /*
6108 * Pull over the properties from the server.
6109 */
6110 SafeArray<BSTR> namesOut;
6111 SafeArray<BSTR> valuesOut;
6112 SafeArray<LONG64> timestampsOut;
6113 SafeArray<BSTR> flagsOut;
6114 HRESULT hrc;
6115 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
6116 ComSafeArrayAsOutParam(valuesOut),
6117 ComSafeArrayAsOutParam(timestampsOut),
6118 ComSafeArrayAsOutParam(flagsOut));
6119 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6120 size_t cProps = namesOut.size();
6121 size_t cAlloc = cProps + 1;
6122 if ( valuesOut.size() != cProps
6123 || timestampsOut.size() != cProps
6124 || flagsOut.size() != cProps
6125 )
6126 AssertFailedReturn(VERR_INVALID_PARAMETER);
6127
6128 char **papszNames, **papszValues, **papszFlags;
6129 char szEmpty[] = "";
6130 LONG64 *pai64Timestamps;
6131 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6132 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6133 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
6134 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6135 if (papszNames && papszValues && pai64Timestamps && papszFlags)
6136 {
6137 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
6138 {
6139 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
6140 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
6141 if (RT_FAILURE(rc))
6142 break;
6143 if (valuesOut[i])
6144 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6145 else
6146 papszValues[i] = szEmpty;
6147 if (RT_FAILURE(rc))
6148 break;
6149 pai64Timestamps[i] = timestampsOut[i];
6150 if (flagsOut[i])
6151 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6152 else
6153 papszFlags[i] = szEmpty;
6154 }
6155 if (RT_SUCCESS(rc))
6156 configSetProperties(pConsole->m_pVMMDev,
6157 (void *)papszNames,
6158 (void *)papszValues,
6159 (void *)pai64Timestamps,
6160 (void *)papszFlags);
6161 for (unsigned i = 0; i < cProps; ++i)
6162 {
6163 RTStrFree(papszNames[i]);
6164 if (valuesOut[i])
6165 RTStrFree(papszValues[i]);
6166 if (flagsOut[i])
6167 RTStrFree(papszFlags[i]);
6168 }
6169 }
6170 else
6171 rc = VERR_NO_MEMORY;
6172 RTMemTmpFree(papszNames);
6173 RTMemTmpFree(papszValues);
6174 RTMemTmpFree(pai64Timestamps);
6175 RTMemTmpFree(papszFlags);
6176 AssertRCReturn(rc, rc);
6177
6178 /*
6179 * These properties have to be set before pulling over the properties
6180 * from the machine XML, to ensure that properties saved in the XML
6181 * will override them.
6182 */
6183 /* Set the raw VBox version string as a guest property. Used for host/guest
6184 * version comparison. */
6185 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6186 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6187 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6188 * information/branding and/or pre-release tags. */
6189 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6190 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6191 /* Set the VBox SVN revision as a guest property */
6192 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6193 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6194
6195 /*
6196 * Register the host notification callback
6197 */
6198 HGCMSVCEXTHANDLE hDummy;
6199 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6200 Console::i_doGuestPropNotification,
6201 pvConsole);
6202
6203#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6204 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev, GUEST_PROP_F_RDONLYGUEST);
6205 AssertRCReturn(rc, rc);
6206#endif
6207
6208 Log(("Set VBoxGuestPropSvc property store\n"));
6209 }
6210 return VINF_SUCCESS;
6211#else /* !VBOX_WITH_GUEST_PROPS */
6212 return VERR_NOT_SUPPORTED;
6213#endif /* !VBOX_WITH_GUEST_PROPS */
6214}
6215
6216/**
6217 * Set up the Guest Control service.
6218 */
6219/* static */ int Console::i_configGuestControl(void *pvConsole)
6220{
6221#ifdef VBOX_WITH_GUEST_CONTROL
6222 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6223 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6224
6225 /* Load the service */
6226 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6227
6228 if (RT_FAILURE(rc))
6229 {
6230 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6231 /* That is not a fatal failure. */
6232 rc = VINF_SUCCESS;
6233 }
6234 else
6235 {
6236 HGCMSVCEXTHANDLE hDummy;
6237 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6238 &Guest::i_notifyCtrlDispatcher,
6239 pConsole->i_getGuest());
6240 if (RT_FAILURE(rc))
6241 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6242 else
6243 LogRel(("Guest Control service loaded\n"));
6244 }
6245
6246 return rc;
6247#else /* !VBOX_WITH_GUEST_CONTROL */
6248 return VERR_NOT_SUPPORTED;
6249#endif /* !VBOX_WITH_GUEST_CONTROL */
6250}
Note: See TracBrowser for help on using the repository browser.

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