VirtualBox

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

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

Main: warnings

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