VirtualBox

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

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

Main/ConsoleImpl: announce the MCFG area to EFI

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