VirtualBox

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

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

Main: Modified Utf8Str::parseKeyValue implementation to never return npos when returning the last pair. That simplifies using the method and seemingly reflects the original author's intentions.

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

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