VirtualBox

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

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

pdmifs.h: Move the storage related interfaces (PDMIMEDIA, PDMIMOUNT, PDMISCSICONNECTOR, etc.) into a separate header to reduce the overall size of the header a bit

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