VirtualBox

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

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

Main,Devices: Graphics controller updates. bugref:8893

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

© 2023 Oracle
ContactPrivacy policyTerms of Use