VirtualBox

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

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

Main/Console: move APIC CPU feature configuration to the right place

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