VirtualBox

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

Last change on this file since 65698 was 65698, checked in by vboxsync, 8 years ago

NetAdp/win (bugref:8488) standalone implementation, does not require NetLwf to be installed.

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