VirtualBox

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

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

ConsoleImpl2: Prevent launching VMs with invalid APIC combinations.

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

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