VirtualBox

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

Last change on this file since 65850 was 65850, checked in by vboxsync, 8 years ago

Devices/Main: don't set RamSize and RamHole explicitly for DevACPI, DevEFI, DevPcBios and VMMDev but use the MMR3Phys* API for that. This simplifies and unifies the calculation of RAM below 4GB and RAM above 4GB. Also renamed PciPref64Limit to PciPref64LimitGB to show that the limit is in GB.

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

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