VirtualBox

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

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

main: warnings in weird configs

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