VirtualBox

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

Last change on this file since 61100 was 61100, checked in by vboxsync, 9 years ago

Main/Console: limit the firmware APIC level to what the hardware can do, giving an appropriate message in the release log

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