VirtualBox

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

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

Main: warnings

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

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