VirtualBox

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

Last change on this file since 70130 was 70130, checked in by vboxsync, 7 years ago

ConsoleImpl2: Put the ISA extension CFGM bits where CPUM wants them.

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

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