VirtualBox

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

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

Use the iprt/win/netioapi.h and iprt/win/ntddndis.h wrappers to deal with preprocessor warnings.

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