VirtualBox

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

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

Main: trailing spaces and a wrong indent

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 254.8 KB
Line 
1/* $Id: ConsoleImpl2.cpp 66105 2017-03-15 10:06:38Z 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.215389.xyz. This file is free software;
16 * you can redistribute it and/or modify it under the terms of the GNU
17 * General Public License (GPL) as published by the Free Software
18 * Foundation, in version 2 as it comes in the "COPYING" file of the
19 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
20 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21 */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27
28// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
29// header file includes Windows.h.
30#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
31# include <VBox/VBoxNetCfg-win.h>
32#endif
33
34#include "ConsoleImpl.h"
35#include "DisplayImpl.h"
36#ifdef VBOX_WITH_GUEST_CONTROL
37# include "GuestImpl.h"
38#endif
39#ifdef VBOX_WITH_DRAG_AND_DROP
40# include "GuestDnDPrivate.h"
41#endif
42#include "VMMDev.h"
43#include "Global.h"
44#ifdef VBOX_WITH_PCI_PASSTHROUGH
45# include "PCIRawDevImpl.h"
46#endif
47
48// generated header
49#include "SchemaDefs.h"
50
51#include "AutoCaller.h"
52#include "Logging.h"
53
54#include <iprt/base64.h>
55#include <iprt/buildconfig.h>
56#include <iprt/ctype.h>
57#include <iprt/dir.h>
58#include <iprt/file.h>
59#include <iprt/param.h>
60#include <iprt/path.h>
61#include <iprt/string.h>
62#include <iprt/system.h>
63#include <iprt/cpp/exception.h>
64#if 0 /* enable to play with lots of memory. */
65# include <iprt/env.h>
66#endif
67#include <iprt/stream.h>
68
69#include <VBox/vmm/vmapi.h>
70#include <VBox/err.h>
71#include <VBox/param.h>
72#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
73#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
74#include <VBox/vmm/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 /* fall thru */
1450 case ChipsetType_PIIX3:
1451 InsertConfigNode(pDevices, "pci", &pDev);
1452 uHbcPCIAddress = (0x0 << 16) | 0;
1453 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1454 break;
1455 case ChipsetType_ICH9:
1456 InsertConfigNode(pDevices, "ich9pci", &pDev);
1457 uHbcPCIAddress = (0x1e << 16) | 0;
1458 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1459 break;
1460 }
1461 InsertConfigNode(pDev, "0", &pInst);
1462 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1463 InsertConfigNode(pInst, "Config", &pCfg);
1464 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1465 if (chipsetType == ChipsetType_ICH9)
1466 {
1467 /* Provide MCFG info */
1468 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1469 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1470
1471
1472 /* And register 2 bridges */
1473 InsertConfigNode(pDevices, "ich9pcibridge", &pDev);
1474 InsertConfigNode(pDev, "0", &pInst);
1475 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1476 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H();
1477
1478 InsertConfigNode(pDev, "1", &pInst);
1479 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1480 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H();
1481
1482#ifdef VBOX_WITH_PCI_PASSTHROUGH
1483 /* Add PCI passthrough devices */
1484 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1485#endif
1486 }
1487
1488 /*
1489 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1490 */
1491
1492 /*
1493 * High Precision Event Timer (HPET)
1494 */
1495 BOOL fHPETEnabled;
1496 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1497 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1498 /* so always enable HPET in extended profile */
1499 fHPETEnabled |= fOsXGuest;
1500 /* HPET is always present on ICH9 */
1501 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1502 if (fHPETEnabled)
1503 {
1504 InsertConfigNode(pDevices, "hpet", &pDev);
1505 InsertConfigNode(pDev, "0", &pInst);
1506 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1507 InsertConfigNode(pInst, "Config", &pCfg);
1508 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1509 }
1510
1511 /*
1512 * System Management Controller (SMC)
1513 */
1514 BOOL fSmcEnabled;
1515 fSmcEnabled = fOsXGuest;
1516 if (fSmcEnabled)
1517 {
1518 InsertConfigNode(pDevices, "smc", &pDev);
1519 InsertConfigNode(pDev, "0", &pInst);
1520 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1521 InsertConfigNode(pInst, "Config", &pCfg);
1522
1523 bool fGetKeyFromRealSMC;
1524 Utf8Str strKey;
1525 rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1526 AssertRCReturn(rc, rc);
1527
1528 if (!fGetKeyFromRealSMC)
1529 InsertConfigString(pCfg, "DeviceKey", strKey);
1530 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1531 }
1532
1533 /*
1534 * Low Pin Count (LPC) bus
1535 */
1536 BOOL fLpcEnabled;
1537 /** @todo implement appropriate getter */
1538 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1539 if (fLpcEnabled)
1540 {
1541 InsertConfigNode(pDevices, "lpc", &pDev);
1542 InsertConfigNode(pDev, "0", &pInst);
1543 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1544 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1545 }
1546
1547 BOOL fShowRtc;
1548 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1549
1550 /*
1551 * PS/2 keyboard & mouse.
1552 */
1553 InsertConfigNode(pDevices, "pckbd", &pDev);
1554 InsertConfigNode(pDev, "0", &pInst);
1555 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1556 InsertConfigNode(pInst, "Config", &pCfg);
1557
1558 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1559 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1560 InsertConfigNode(pLunL0, "Config", &pCfg);
1561 InsertConfigInteger(pCfg, "QueueSize", 64);
1562
1563 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1564 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1565 InsertConfigNode(pLunL1, "Config", &pCfg);
1566 Keyboard *pKeyboard = mKeyboard;
1567 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
1568
1569 Mouse *pMouse = mMouse;
1570 PointingHIDType_T aPointingHID;
1571 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1572 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1573 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1574 InsertConfigNode(pLunL0, "Config", &pCfg);
1575 InsertConfigInteger(pCfg, "QueueSize", 128);
1576
1577 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1578 InsertConfigString(pLunL1, "Driver", "MainMouse");
1579 InsertConfigNode(pLunL1, "Config", &pCfg);
1580 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
1581
1582 /*
1583 * i8254 Programmable Interval Timer And Dummy Speaker
1584 */
1585 InsertConfigNode(pDevices, "i8254", &pDev);
1586 InsertConfigNode(pDev, "0", &pInst);
1587 InsertConfigNode(pInst, "Config", &pCfg);
1588#ifdef DEBUG
1589 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1590#endif
1591
1592 /*
1593 * i8259 Programmable Interrupt Controller.
1594 */
1595 InsertConfigNode(pDevices, "i8259", &pDev);
1596 InsertConfigNode(pDev, "0", &pInst);
1597 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1598 InsertConfigNode(pInst, "Config", &pCfg);
1599
1600 /*
1601 * Advanced Programmable Interrupt Controller.
1602 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1603 * thus only single insert
1604 */
1605 if (fEnableAPIC)
1606 {
1607 InsertConfigNode(pDevices, "apic", &pDev);
1608 InsertConfigNode(pDev, "0", &pInst);
1609 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1610 InsertConfigNode(pInst, "Config", &pCfg);
1611 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1612 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1613 if (fEnableX2APIC)
1614 enmAPICMode = PDMAPICMODE_X2APIC;
1615 else if (!fEnableAPIC)
1616 enmAPICMode = PDMAPICMODE_NONE;
1617 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1618 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1619
1620 if (fIOAPIC)
1621 {
1622 /*
1623 * I/O Advanced Programmable Interrupt Controller.
1624 */
1625 InsertConfigNode(pDevices, "ioapic", &pDev);
1626 InsertConfigNode(pDev, "0", &pInst);
1627 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1628 InsertConfigNode(pInst, "Config", &pCfg);
1629 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1630 }
1631 }
1632
1633 /*
1634 * RTC MC146818.
1635 */
1636 InsertConfigNode(pDevices, "mc146818", &pDev);
1637 InsertConfigNode(pDev, "0", &pInst);
1638 InsertConfigNode(pInst, "Config", &pCfg);
1639 BOOL fRTCUseUTC;
1640 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1641 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1642
1643 /*
1644 * VGA.
1645 */
1646 GraphicsControllerType_T enmGraphicsController;
1647 hrc = pMachine->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1648 switch (enmGraphicsController)
1649 {
1650 case GraphicsControllerType_Null:
1651 break;
1652 case GraphicsControllerType_VBoxVGA:
1653#ifdef VBOX_WITH_VMSVGA
1654 case GraphicsControllerType_VMSVGA:
1655#endif
1656 rc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, biosSettings,
1657 RT_BOOL(fHMEnabled));
1658 if (FAILED(rc))
1659 return rc;
1660 break;
1661 default:
1662 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1663 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1664 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1665 }
1666
1667 /*
1668 * Firmware.
1669 */
1670 FirmwareType_T eFwType = FirmwareType_BIOS;
1671 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1672
1673#ifdef VBOX_WITH_EFI
1674 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1675#else
1676 BOOL fEfiEnabled = false;
1677#endif
1678 if (!fEfiEnabled)
1679 {
1680 /*
1681 * PC Bios.
1682 */
1683 InsertConfigNode(pDevices, "pcbios", &pDev);
1684 InsertConfigNode(pDev, "0", &pInst);
1685 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1686 InsertConfigNode(pInst, "Config", &pBiosCfg);
1687 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1688 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1689 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1690 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1691 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1692 BOOL fPXEDebug;
1693 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1694 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1695 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1696 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1697 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1698 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1699
1700 DeviceType_T bootDevice;
1701 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1702 VERR_INVALID_PARAMETER);
1703
1704 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1705 {
1706 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
1707
1708 char szParamName[] = "BootDeviceX";
1709 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1710
1711 const char *pszBootDevice;
1712 switch (bootDevice)
1713 {
1714 case DeviceType_Null:
1715 pszBootDevice = "NONE";
1716 break;
1717 case DeviceType_HardDisk:
1718 pszBootDevice = "IDE";
1719 break;
1720 case DeviceType_DVD:
1721 pszBootDevice = "DVD";
1722 break;
1723 case DeviceType_Floppy:
1724 pszBootDevice = "FLOPPY";
1725 break;
1726 case DeviceType_Network:
1727 pszBootDevice = "LAN";
1728 break;
1729 default:
1730 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
1731 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1732 N_("Invalid boot device '%d'"), bootDevice);
1733 }
1734 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1735 }
1736
1737 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1738 * this is required for Windows 2012 guests. */
1739 if (osTypeId == "Windows2012_64")
1740 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1741 }
1742 else
1743 {
1744 /* Autodetect firmware type, basing on guest type */
1745 if (eFwType == FirmwareType_EFI)
1746 {
1747 eFwType = fIsGuest64Bit
1748 ? (FirmwareType_T)FirmwareType_EFI64
1749 : (FirmwareType_T)FirmwareType_EFI32;
1750 }
1751 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1752
1753 Utf8Str efiRomFile;
1754 rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
1755 AssertRCReturn(rc, rc);
1756
1757 /* Get boot args */
1758 Utf8Str bootArgs;
1759 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1760
1761 /* Get device props */
1762 Utf8Str deviceProps;
1763 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1764
1765 /* Get GOP mode settings */
1766 uint32_t u32GopMode = UINT32_MAX;
1767 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1768 if (!strTmp.isEmpty())
1769 u32GopMode = strTmp.toUInt32();
1770
1771 /* UGA mode settings */
1772 uint32_t u32UgaHorizontal = 0;
1773 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1774 if (!strTmp.isEmpty())
1775 u32UgaHorizontal = strTmp.toUInt32();
1776
1777 uint32_t u32UgaVertical = 0;
1778 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1779 if (!strTmp.isEmpty())
1780 u32UgaVertical = strTmp.toUInt32();
1781
1782 /*
1783 * EFI subtree.
1784 */
1785 InsertConfigNode(pDevices, "efi", &pDev);
1786 InsertConfigNode(pDev, "0", &pInst);
1787 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1788 InsertConfigNode(pInst, "Config", &pCfg);
1789 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1790 InsertConfigString(pCfg, "EfiRom", efiRomFile);
1791 InsertConfigString(pCfg, "BootArgs", bootArgs);
1792 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1793 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1794 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1795 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1796 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1797 InsertConfigInteger(pCfg, "GopMode", u32GopMode);
1798 InsertConfigInteger(pCfg, "UgaHorizontalResolution", u32UgaHorizontal);
1799 InsertConfigInteger(pCfg, "UgaVerticalResolution", u32UgaVertical);
1800
1801 /* For OS X guests we'll force passing host's DMI info to the guest */
1802 if (fOsXGuest)
1803 {
1804 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1805 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1806 }
1807 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1808 InsertConfigString(pLunL0, "Driver", "NvramStorage");
1809 InsertConfigNode(pLunL0, "Config", &pCfg);
1810 InsertConfigInteger(pCfg, "Object", (uintptr_t)mNvram);
1811#ifdef DEBUG_vvl
1812 InsertConfigInteger(pCfg, "PermanentSave", 1);
1813#endif
1814 }
1815
1816 /*
1817 * The USB Controllers.
1818 */
1819 com::SafeIfaceArray<IUSBController> usbCtrls;
1820 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
1821 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
1822 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
1823
1824 if (SUCCEEDED(hrc))
1825 {
1826 for (size_t i = 0; i < usbCtrls.size(); ++i)
1827 {
1828 USBControllerType_T enmCtrlType;
1829 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1830 if (enmCtrlType == USBControllerType_OHCI)
1831 {
1832 fOhciPresent = true;
1833 break;
1834 }
1835 else if (enmCtrlType == USBControllerType_XHCI)
1836 {
1837 fXhciPresent = true;
1838 break;
1839 }
1840 }
1841 }
1842 else if (hrc != E_NOTIMPL)
1843 {
1844 H();
1845 }
1846
1847 /*
1848 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
1849 */
1850 if (fOhciPresent || fXhciPresent)
1851 mfVMHasUsbController = true;
1852
1853 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
1854 if (mfVMHasUsbController)
1855 {
1856 for (size_t i = 0; i < usbCtrls.size(); ++i)
1857 {
1858 USBControllerType_T enmCtrlType;
1859 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1860
1861 if (enmCtrlType == USBControllerType_OHCI)
1862 {
1863 InsertConfigNode(pDevices, "usb-ohci", &pDev);
1864 InsertConfigNode(pDev, "0", &pInst);
1865 InsertConfigNode(pInst, "Config", &pCfg);
1866 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1867 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
1868 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1869 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1870 InsertConfigNode(pLunL0, "Config", &pCfg);
1871
1872 /*
1873 * Attach the status driver.
1874 */
1875 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0);
1876 }
1877#ifdef VBOX_WITH_EHCI
1878 else if (enmCtrlType == USBControllerType_EHCI)
1879 {
1880 /*
1881 * USB 2.0 is only available if the proper ExtPack is installed.
1882 *
1883 * Note. Configuring EHCI here and providing messages about
1884 * the missing extpack isn't exactly clean, but it is a
1885 * necessary evil to patch over legacy compatability issues
1886 * introduced by the new distribution model.
1887 */
1888# ifdef VBOX_WITH_EXTPACK
1889 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1890 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1891# endif
1892 {
1893 InsertConfigNode(pDevices, "usb-ehci", &pDev);
1894 InsertConfigNode(pDev, "0", &pInst);
1895 InsertConfigNode(pInst, "Config", &pCfg);
1896 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1897 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
1898
1899 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1900 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1901 InsertConfigNode(pLunL0, "Config", &pCfg);
1902
1903 /*
1904 * Attach the status driver.
1905 */
1906 i_attachStatusDriver(pInst, &mapUSBLed[1], 0, 0, NULL, NULL, 0);
1907 }
1908# ifdef VBOX_WITH_EXTPACK
1909 else
1910 {
1911 /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
1912 * but this induced problems when the user saved + restored the VM! */
1913 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1914 N_("Implementation of the USB 2.0 controller not found!\n"
1915 "Because the USB 2.0 controller state is part of the saved "
1916 "VM state, the VM cannot be started. To fix "
1917 "this problem, either install the '%s' or disable USB 2.0 "
1918 "support in the VM settings.\n"
1919 "Note! This error could also mean that an incompatible version of "
1920 "the '%s' is installed"),
1921 s_pszUsbExtPackName, s_pszUsbExtPackName);
1922 }
1923# endif
1924 }
1925#endif
1926 else if (enmCtrlType == USBControllerType_XHCI)
1927 {
1928 /*
1929 * USB 3.0 is only available if the proper ExtPack is installed.
1930 *
1931 * Note. Configuring EHCI here and providing messages about
1932 * the missing extpack isn't exactly clean, but it is a
1933 * necessary evil to patch over legacy compatability issues
1934 * introduced by the new distribution model.
1935 */
1936# ifdef VBOX_WITH_EXTPACK
1937 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1938 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1939# endif
1940 {
1941 InsertConfigNode(pDevices, "usb-xhci", &pDev);
1942 InsertConfigNode(pDev, "0", &pInst);
1943 InsertConfigNode(pInst, "Config", &pCfg);
1944 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1945 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
1946
1947 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1948 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1949 InsertConfigNode(pLunL0, "Config", &pCfg);
1950
1951 InsertConfigNode(pInst, "LUN#1", &pLunL1);
1952 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
1953 InsertConfigNode(pLunL1, "Config", &pCfg);
1954
1955 /*
1956 * Attach the status driver.
1957 */
1958 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 1, NULL, NULL, 0);
1959 }
1960# ifdef VBOX_WITH_EXTPACK
1961 else
1962 {
1963 /* Always fatal. */
1964 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1965 N_("Implementation of the USB 3.0 controller not found!\n"
1966 "Because the USB 3.0 controller state is part of the saved "
1967 "VM state, the VM cannot be started. To fix "
1968 "this problem, either install the '%s' or disable USB 3.0 "
1969 "support in the VM settings"),
1970 s_pszUsbExtPackName);
1971 }
1972# endif
1973 }
1974 } /* for every USB controller. */
1975
1976
1977 /*
1978 * Virtual USB Devices.
1979 */
1980 InsertConfigNode(pRoot, "USB", &pUsbDevices);
1981
1982#ifdef VBOX_WITH_USB
1983 {
1984 /*
1985 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
1986 * on a per device level now.
1987 */
1988 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
1989 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
1990 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
1991 //InsertConfigInteger(pCfg, "Force11Device", true);
1992 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
1993 // that it's documented somewhere.) Users needing it can use:
1994 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
1995 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
1996 }
1997#endif
1998
1999#ifdef VBOX_WITH_USB_CARDREADER
2000 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
2001 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
2002 if (aEmulatedUSBCardReaderEnabled)
2003 {
2004 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
2005 InsertConfigNode(pDev, "0", &pInst);
2006 InsertConfigNode(pInst, "Config", &pCfg);
2007
2008 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2009# ifdef VBOX_WITH_USB_CARDREADER_TEST
2010 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
2011 InsertConfigNode(pLunL0, "Config", &pCfg);
2012# else
2013 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
2014 InsertConfigNode(pLunL0, "Config", &pCfg);
2015 InsertConfigInteger(pCfg, "Object", (uintptr_t)mUsbCardReader);
2016# endif
2017 }
2018#endif
2019
2020 /* Virtual USB Mouse/Tablet */
2021 if ( aPointingHID == PointingHIDType_USBMouse
2022 || aPointingHID == PointingHIDType_USBTablet
2023 || aPointingHID == PointingHIDType_USBMultiTouch)
2024 {
2025 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
2026 InsertConfigNode(pDev, "0", &pInst);
2027 InsertConfigNode(pInst, "Config", &pCfg);
2028
2029 if (aPointingHID == PointingHIDType_USBMouse)
2030 InsertConfigString(pCfg, "Mode", "relative");
2031 else
2032 InsertConfigString(pCfg, "Mode", "absolute");
2033 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2034 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2035 InsertConfigNode(pLunL0, "Config", &pCfg);
2036 InsertConfigInteger(pCfg, "QueueSize", 128);
2037
2038 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2039 InsertConfigString(pLunL1, "Driver", "MainMouse");
2040 InsertConfigNode(pLunL1, "Config", &pCfg);
2041 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2042 }
2043 if (aPointingHID == PointingHIDType_USBMultiTouch)
2044 {
2045 InsertConfigNode(pDev, "1", &pInst);
2046 InsertConfigNode(pInst, "Config", &pCfg);
2047
2048 InsertConfigString(pCfg, "Mode", "multitouch");
2049 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2050 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2051 InsertConfigNode(pLunL0, "Config", &pCfg);
2052 InsertConfigInteger(pCfg, "QueueSize", 128);
2053
2054 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2055 InsertConfigString(pLunL1, "Driver", "MainMouse");
2056 InsertConfigNode(pLunL1, "Config", &pCfg);
2057 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2058 }
2059
2060 /* Virtual USB Keyboard */
2061 KeyboardHIDType_T aKbdHID;
2062 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
2063 if (aKbdHID == KeyboardHIDType_USBKeyboard)
2064 {
2065 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
2066 InsertConfigNode(pDev, "0", &pInst);
2067 InsertConfigNode(pInst, "Config", &pCfg);
2068
2069 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2070 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
2071 InsertConfigNode(pLunL0, "Config", &pCfg);
2072 InsertConfigInteger(pCfg, "QueueSize", 64);
2073
2074 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2075 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
2076 InsertConfigNode(pLunL1, "Config", &pCfg);
2077 pKeyboard = mKeyboard;
2078 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
2079 }
2080 }
2081
2082 /*
2083 * Storage controllers.
2084 */
2085 com::SafeIfaceArray<IStorageController> ctrls;
2086 PCFGMNODE aCtrlNodes[StorageControllerType_NVMe + 1] = {};
2087 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
2088
2089 bool fFdcEnabled = false;
2090 for (size_t i = 0; i < ctrls.size(); ++i)
2091 {
2092 DeviceType_T *paLedDevType = NULL;
2093
2094 StorageControllerType_T enmCtrlType;
2095 rc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
2096 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
2097 || enmCtrlType == StorageControllerType_USB);
2098
2099 StorageBus_T enmBus;
2100 rc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
2101
2102 Bstr controllerName;
2103 rc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
2104
2105 ULONG ulInstance = 999;
2106 rc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
2107
2108 BOOL fUseHostIOCache;
2109 rc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
2110
2111 BOOL fBootable;
2112 rc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
2113
2114 PCFGMNODE pCtlInst = NULL;
2115 const char *pszCtrlDev = i_convertControllerTypeToDev(enmCtrlType);
2116 if (enmCtrlType != StorageControllerType_USB)
2117 {
2118 /* /Devices/<ctrldev>/ */
2119 pDev = aCtrlNodes[enmCtrlType];
2120 if (!pDev)
2121 {
2122 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
2123 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
2124 }
2125
2126 /* /Devices/<ctrldev>/<instance>/ */
2127 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
2128
2129 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
2130 InsertConfigInteger(pCtlInst, "Trusted", 1);
2131 InsertConfigNode(pCtlInst, "Config", &pCfg);
2132 }
2133
2134 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
2135 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
2136
2137 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
2138 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
2139
2140 switch (enmCtrlType)
2141 {
2142 case StorageControllerType_LsiLogic:
2143 {
2144 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
2145
2146 InsertConfigInteger(pCfg, "Bootable", fBootable);
2147
2148 /* BIOS configuration values, first SCSI controller only. */
2149 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
2150 && !pBusMgr->hasPCIDevice("buslogic", 0)
2151 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2152 && pBiosCfg)
2153 {
2154 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
2155 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2156 }
2157
2158 /* Attach the status driver */
2159 Assert(cLedScsi >= 16);
2160 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2161 &mapMediumAttachments, pszCtrlDev, ulInstance);
2162 paLedDevType = &maStorageDevType[iLedScsi];
2163 break;
2164 }
2165
2166 case StorageControllerType_BusLogic:
2167 {
2168 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
2169
2170 InsertConfigInteger(pCfg, "Bootable", fBootable);
2171
2172 /* BIOS configuration values, first SCSI controller only. */
2173 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2174 && !pBusMgr->hasPCIDevice("buslogic", 1)
2175 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2176 && pBiosCfg)
2177 {
2178 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
2179 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2180 }
2181
2182 /* Attach the status driver */
2183 Assert(cLedScsi >= 16);
2184 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2185 &mapMediumAttachments, pszCtrlDev, ulInstance);
2186 paLedDevType = &maStorageDevType[iLedScsi];
2187 break;
2188 }
2189
2190 case StorageControllerType_IntelAhci:
2191 {
2192 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2193
2194 ULONG cPorts = 0;
2195 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2196 InsertConfigInteger(pCfg, "PortCount", cPorts);
2197 InsertConfigInteger(pCfg, "Bootable", fBootable);
2198
2199 com::SafeIfaceArray<IMediumAttachment> atts;
2200 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2201 ComSafeArrayAsOutParam(atts)); H();
2202
2203 /* Configure the hotpluggable flag for the port. */
2204 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2205 {
2206 IMediumAttachment *pMediumAtt = atts[idxAtt];
2207
2208 LONG lPortNum = 0;
2209 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2210
2211 BOOL fHotPluggable = FALSE;
2212 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2213 if (SUCCEEDED(hrc))
2214 {
2215 PCFGMNODE pPortCfg;
2216 char szName[24];
2217 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2218
2219 InsertConfigNode(pCfg, szName, &pPortCfg);
2220 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2221 }
2222 }
2223
2224 /* BIOS configuration values, first AHCI controller only. */
2225 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2226 && pBiosCfg)
2227 {
2228 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2229 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2230 }
2231
2232 /* Attach the status driver */
2233 AssertRelease(cPorts <= cLedSata);
2234 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSata], 0, cPorts - 1,
2235 &mapMediumAttachments, pszCtrlDev, ulInstance);
2236 paLedDevType = &maStorageDevType[iLedSata];
2237 break;
2238 }
2239
2240 case StorageControllerType_PIIX3:
2241 case StorageControllerType_PIIX4:
2242 case StorageControllerType_ICH6:
2243 {
2244 /*
2245 * IDE (update this when the main interface changes)
2246 */
2247 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2248 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2249 /* Attach the status driver */
2250 Assert(cLedIde >= 4);
2251 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedIde], 0, 3,
2252 &mapMediumAttachments, pszCtrlDev, ulInstance);
2253 paLedDevType = &maStorageDevType[iLedIde];
2254
2255 /* IDE flavors */
2256 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2257 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2258 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2259 break;
2260 }
2261
2262 case StorageControllerType_I82078:
2263 {
2264 /*
2265 * i82078 Floppy drive controller
2266 */
2267 fFdcEnabled = true;
2268 InsertConfigInteger(pCfg, "IRQ", 6);
2269 InsertConfigInteger(pCfg, "DMA", 2);
2270 InsertConfigInteger(pCfg, "MemMapped", 0 );
2271 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2272
2273 /* Attach the status driver */
2274 Assert(cLedFloppy >= 2);
2275 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedFloppy], 0, 1,
2276 &mapMediumAttachments, pszCtrlDev, ulInstance);
2277 paLedDevType = &maStorageDevType[iLedFloppy];
2278 break;
2279 }
2280
2281 case StorageControllerType_LsiLogicSas:
2282 {
2283 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2284
2285 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2286 InsertConfigInteger(pCfg, "Bootable", fBootable);
2287
2288 /* BIOS configuration values, first SCSI controller only. */
2289 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2290 && !pBusMgr->hasPCIDevice("buslogic", 0)
2291 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2292 && pBiosCfg)
2293 {
2294 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2295 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2296 }
2297
2298 ULONG cPorts = 0;
2299 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2300 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2301
2302 /* Attach the status driver */
2303 Assert(cLedSas >= 8);
2304 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSas], 0, 7,
2305 &mapMediumAttachments, pszCtrlDev, ulInstance);
2306 paLedDevType = &maStorageDevType[iLedSas];
2307 break;
2308 }
2309
2310 case StorageControllerType_USB:
2311 {
2312 if (pUsbDevices)
2313 {
2314 /*
2315 * USB MSDs are handled a bit different as the device instance
2316 * doesn't match the storage controller instance but the port.
2317 */
2318 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2319 pCtlInst = pDev;
2320 }
2321 else
2322 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2323 N_("There is no USB controller enabled but there\n"
2324 "is at least one USB storage device configured for this VM.\n"
2325 "To fix this problem either enable the USB controller or remove\n"
2326 "the storage device from the VM"));
2327 break;
2328 }
2329
2330 case StorageControllerType_NVMe:
2331 {
2332 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2333
2334 ULONG cPorts = 0;
2335 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2336 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2337
2338 /* For ICH9 we need to create a new PCI bridge if there is more than one NVMe instance. */
2339 if ( ulInstance > 0
2340 && chipsetType == ChipsetType_ICH9
2341 && !pBusMgr->hasPCIDevice("ich9pcibridge", 2))
2342 {
2343 PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
2344 Assert(pBridges);
2345
2346 InsertConfigNode(pBridges, "2", &pInst);
2347 InsertConfigInteger(pInst, "Trusted", 1);
2348 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);
2349 }
2350
2351 /* Attach the status driver */
2352 AssertRelease(cPorts <= cLedSata);
2353 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedNvme], 0, cPorts - 1,
2354 &mapMediumAttachments, pszCtrlDev, ulInstance);
2355 paLedDevType = &maStorageDevType[iLedNvme];
2356 break;
2357 }
2358
2359 default:
2360 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2361 }
2362
2363 /* Attach the media to the storage controllers. */
2364 com::SafeIfaceArray<IMediumAttachment> atts;
2365 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2366 ComSafeArrayAsOutParam(atts)); H();
2367
2368 /* Builtin I/O cache - per device setting. */
2369 BOOL fBuiltinIOCache = true;
2370 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2371
2372 bool fInsertDiskIntegrityDrv = false;
2373 Bstr strDiskIntegrityFlag;
2374 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
2375 strDiskIntegrityFlag.asOutParam());
2376 if ( hrc == S_OK
2377 && strDiskIntegrityFlag == "1")
2378 fInsertDiskIntegrityDrv = true;
2379
2380 for (size_t j = 0; j < atts.size(); ++j)
2381 {
2382 IMediumAttachment *pMediumAtt = atts[j];
2383 rc = i_configMediumAttachment(pszCtrlDev,
2384 ulInstance,
2385 enmBus,
2386 !!fUseHostIOCache,
2387 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2388 fInsertDiskIntegrityDrv,
2389 false /* fSetupMerge */,
2390 0 /* uMergeSource */,
2391 0 /* uMergeTarget */,
2392 pMediumAtt,
2393 mMachineState,
2394 NULL /* phrc */,
2395 false /* fAttachDetach */,
2396 false /* fForceUnmount */,
2397 false /* fHotplug */,
2398 pUVM,
2399 paLedDevType,
2400 NULL /* ppLunL0 */);
2401 if (RT_FAILURE(rc))
2402 return rc;
2403 }
2404 H();
2405 }
2406 H();
2407
2408 /*
2409 * Network adapters
2410 */
2411#ifdef VMWARE_NET_IN_SLOT_11
2412 bool fSwapSlots3and11 = false;
2413#endif
2414 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2415 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2416#ifdef VBOX_WITH_E1000
2417 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2418 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2419#endif
2420#ifdef VBOX_WITH_VIRTIO
2421 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2422 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2423#endif /* VBOX_WITH_VIRTIO */
2424 std::list<BootNic> llBootNics;
2425 for (ULONG ulInstance = 0; ulInstance < maxNetworkAdapters; ++ulInstance)
2426 {
2427 ComPtr<INetworkAdapter> networkAdapter;
2428 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
2429 BOOL fEnabledNetAdapter = FALSE;
2430 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2431 if (!fEnabledNetAdapter)
2432 continue;
2433
2434 /*
2435 * The virtual hardware type. Create appropriate device first.
2436 */
2437 const char *pszAdapterName = "pcnet";
2438 NetworkAdapterType_T adapterType;
2439 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2440 switch (adapterType)
2441 {
2442 case NetworkAdapterType_Am79C970A:
2443 case NetworkAdapterType_Am79C973:
2444 pDev = pDevPCNet;
2445 break;
2446#ifdef VBOX_WITH_E1000
2447 case NetworkAdapterType_I82540EM:
2448 case NetworkAdapterType_I82543GC:
2449 case NetworkAdapterType_I82545EM:
2450 pDev = pDevE1000;
2451 pszAdapterName = "e1000";
2452 break;
2453#endif
2454#ifdef VBOX_WITH_VIRTIO
2455 case NetworkAdapterType_Virtio:
2456 pDev = pDevVirtioNet;
2457 pszAdapterName = "virtio-net";
2458 break;
2459#endif /* VBOX_WITH_VIRTIO */
2460 default:
2461 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
2462 adapterType, ulInstance));
2463 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2464 N_("Invalid network adapter type '%d' for slot '%d'"),
2465 adapterType, ulInstance);
2466 }
2467
2468 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2469 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2470 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2471 * next 4 get 16..19. */
2472 int iPCIDeviceNo;
2473 switch (ulInstance)
2474 {
2475 case 0:
2476 iPCIDeviceNo = 3;
2477 break;
2478 case 1: case 2: case 3:
2479 iPCIDeviceNo = ulInstance - 1 + 8;
2480 break;
2481 case 4: case 5: case 6: case 7:
2482 iPCIDeviceNo = ulInstance - 4 + 16;
2483 break;
2484 default:
2485 /* auto assignment */
2486 iPCIDeviceNo = -1;
2487 break;
2488 }
2489#ifdef VMWARE_NET_IN_SLOT_11
2490 /*
2491 * Dirty hack for PCI slot compatibility with VMWare,
2492 * it assigns slot 0x11 to the first network controller.
2493 */
2494 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2495 {
2496 iPCIDeviceNo = 0x11;
2497 fSwapSlots3and11 = true;
2498 }
2499 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2500 iPCIDeviceNo = 3;
2501#endif
2502 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2503 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2504
2505 InsertConfigNode(pInst, "Config", &pCfg);
2506#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2507 if (pDev == pDevPCNet)
2508 {
2509 InsertConfigInteger(pCfg, "R0Enabled", false);
2510 }
2511#endif
2512 /*
2513 * Collect information needed for network booting and add it to the list.
2514 */
2515 BootNic nic;
2516
2517 nic.mInstance = ulInstance;
2518 /* Could be updated by reference, if auto assigned */
2519 nic.mPCIAddress = PCIAddr;
2520
2521 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2522
2523 llBootNics.push_back(nic);
2524
2525 /*
2526 * The virtual hardware type. PCNet supports two types, E1000 three,
2527 * but VirtIO only one.
2528 */
2529 switch (adapterType)
2530 {
2531 case NetworkAdapterType_Am79C970A:
2532 InsertConfigInteger(pCfg, "Am79C973", 0);
2533 break;
2534 case NetworkAdapterType_Am79C973:
2535 InsertConfigInteger(pCfg, "Am79C973", 1);
2536 break;
2537 case NetworkAdapterType_I82540EM:
2538 InsertConfigInteger(pCfg, "AdapterType", 0);
2539 break;
2540 case NetworkAdapterType_I82543GC:
2541 InsertConfigInteger(pCfg, "AdapterType", 1);
2542 break;
2543 case NetworkAdapterType_I82545EM:
2544 InsertConfigInteger(pCfg, "AdapterType", 2);
2545 break;
2546 case NetworkAdapterType_Virtio:
2547 break;
2548 case NetworkAdapterType_Null: AssertFailedBreak(); /* Shut up MSC */
2549 }
2550
2551 /*
2552 * Get the MAC address and convert it to binary representation
2553 */
2554 Bstr macAddr;
2555 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2556 Assert(!macAddr.isEmpty());
2557 Utf8Str macAddrUtf8 = macAddr;
2558 char *macStr = (char*)macAddrUtf8.c_str();
2559 Assert(strlen(macStr) == 12);
2560 RTMAC Mac;
2561 RT_ZERO(Mac);
2562 char *pMac = (char*)&Mac;
2563 for (uint32_t i = 0; i < 6; ++i)
2564 {
2565 int c1 = *macStr++ - '0';
2566 if (c1 > 9)
2567 c1 -= 7;
2568 int c2 = *macStr++ - '0';
2569 if (c2 > 9)
2570 c2 -= 7;
2571 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2572 }
2573 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2574
2575 /*
2576 * Check if the cable is supposed to be unplugged
2577 */
2578 BOOL fCableConnected;
2579 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2580 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2581
2582 /*
2583 * Line speed to report from custom drivers
2584 */
2585 ULONG ulLineSpeed;
2586 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2587 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2588
2589 /*
2590 * Attach the status driver.
2591 */
2592 i_attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
2593
2594 /*
2595 * Configure the network card now
2596 */
2597 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2598 rc = i_configNetwork(pszAdapterName,
2599 ulInstance,
2600 0,
2601 networkAdapter,
2602 pCfg,
2603 pLunL0,
2604 pInst,
2605 false /*fAttachDetach*/,
2606 fIgnoreConnectFailure);
2607 if (RT_FAILURE(rc))
2608 return rc;
2609 }
2610
2611 /*
2612 * Build network boot information and transfer it to the BIOS.
2613 */
2614 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2615 {
2616 llBootNics.sort(); /* Sort the list by boot priority. */
2617
2618 char achBootIdx[] = "0";
2619 unsigned uBootIdx = 0;
2620
2621 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2622 {
2623 /* A NIC with priority 0 is only used if it's first in the list. */
2624 if (it->mBootPrio == 0 && uBootIdx != 0)
2625 break;
2626
2627 PCFGMNODE pNetBtDevCfg;
2628 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2629 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2630 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2631 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2632 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2633 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2634 }
2635 }
2636
2637 /*
2638 * Serial (UART) Ports
2639 */
2640 /* serial enabled mask to be passed to dev ACPI */
2641 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2642 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2643 InsertConfigNode(pDevices, "serial", &pDev);
2644 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2645 {
2646 ComPtr<ISerialPort> serialPort;
2647 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2648 BOOL fEnabledSerPort = FALSE;
2649 if (serialPort)
2650 {
2651 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2652 }
2653 if (!fEnabledSerPort)
2654 continue;
2655
2656 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2657 InsertConfigNode(pInst, "Config", &pCfg);
2658
2659 ULONG ulIRQ;
2660 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2661 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2662 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2663
2664 ULONG ulIOBase;
2665 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2666 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2667 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2668
2669 BOOL fServer;
2670 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2671 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2672 PortMode_T eHostMode;
2673 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2674 if (eHostMode != PortMode_Disconnected)
2675 {
2676 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2677 if (eHostMode == PortMode_HostPipe)
2678 {
2679 InsertConfigString(pLunL0, "Driver", "Char");
2680 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2681 InsertConfigString(pLunL1, "Driver", "NamedPipe");
2682 InsertConfigNode(pLunL1, "Config", &pLunL2);
2683 InsertConfigString(pLunL2, "Location", bstr);
2684 InsertConfigInteger(pLunL2, "IsServer", fServer);
2685 }
2686 else if (eHostMode == PortMode_HostDevice)
2687 {
2688 InsertConfigString(pLunL0, "Driver", "Host Serial");
2689 InsertConfigNode(pLunL0, "Config", &pLunL1);
2690 InsertConfigString(pLunL1, "DevicePath", bstr);
2691 }
2692 else if (eHostMode == PortMode_TCP)
2693 {
2694 InsertConfigString(pLunL0, "Driver", "Char");
2695 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2696 InsertConfigString(pLunL1, "Driver", "TCP");
2697 InsertConfigNode(pLunL1, "Config", &pLunL2);
2698 InsertConfigString(pLunL2, "Location", bstr);
2699 InsertConfigInteger(pLunL2, "IsServer", fServer);
2700 }
2701 else if (eHostMode == PortMode_RawFile)
2702 {
2703 InsertConfigString(pLunL0, "Driver", "Char");
2704 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2705 InsertConfigString(pLunL1, "Driver", "RawFile");
2706 InsertConfigNode(pLunL1, "Config", &pLunL2);
2707 InsertConfigString(pLunL2, "Location", bstr);
2708 }
2709 }
2710 }
2711
2712 /*
2713 * Parallel (LPT) Ports
2714 */
2715 /* parallel enabled mask to be passed to dev ACPI */
2716 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2717 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2718 InsertConfigNode(pDevices, "parallel", &pDev);
2719 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2720 {
2721 ComPtr<IParallelPort> parallelPort;
2722 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2723 BOOL fEnabledParPort = FALSE;
2724 if (parallelPort)
2725 {
2726 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2727 }
2728 if (!fEnabledParPort)
2729 continue;
2730
2731 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2732 InsertConfigNode(pInst, "Config", &pCfg);
2733
2734 ULONG ulIRQ;
2735 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2736 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2737 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2738 ULONG ulIOBase;
2739 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2740 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2741 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2742
2743 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2744 if (!bstr.isEmpty())
2745 {
2746 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2747 InsertConfigString(pLunL0, "Driver", "HostParallel");
2748 InsertConfigNode(pLunL0, "Config", &pLunL1);
2749 InsertConfigString(pLunL1, "DevicePath", bstr);
2750 }
2751 }
2752
2753 /*
2754 * VMM Device
2755 */
2756 InsertConfigNode(pDevices, "VMMDev", &pDev);
2757 InsertConfigNode(pDev, "0", &pInst);
2758 InsertConfigNode(pInst, "Config", &pCfg);
2759 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2760 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
2761
2762 Bstr hwVersion;
2763 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
2764 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2765 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2766 Bstr snapshotFolder;
2767 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2768 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2769
2770 /* the VMM device's Main driver */
2771 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2772 InsertConfigString(pLunL0, "Driver", "HGCM");
2773 InsertConfigNode(pLunL0, "Config", &pCfg);
2774 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2775
2776 /*
2777 * Attach the status driver.
2778 */
2779 i_attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
2780
2781 /*
2782 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2783 */
2784 BOOL fAudioEnabled = FALSE;
2785 ComPtr<IAudioAdapter> audioAdapter;
2786 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2787 if (audioAdapter)
2788 {
2789 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2790 }
2791
2792 if (fAudioEnabled)
2793 {
2794 AudioControllerType_T audioController;
2795 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2796 AudioCodecType_T audioCodec;
2797 hrc = audioAdapter->COMGETTER(AudioCodec)(&audioCodec); H();
2798 switch (audioController)
2799 {
2800 case AudioControllerType_AC97:
2801 {
2802 /* Default: ICH AC97. */
2803 InsertConfigNode(pDevices, "ichac97", &pDev);
2804 InsertConfigNode(pDev, "0", &pInst);
2805 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2806 hrc = pBusMgr->assignPCIDevice("ichac97", pInst); H();
2807 InsertConfigNode(pInst, "Config", &pCfg);
2808 switch (audioCodec)
2809 {
2810 case AudioCodecType_STAC9700:
2811 InsertConfigString(pCfg, "Codec", "STAC9700");
2812 break;
2813 case AudioCodecType_AD1980:
2814 InsertConfigString(pCfg, "Codec", "AD1980");
2815 break;
2816 default: AssertFailedBreak();
2817 }
2818 break;
2819 }
2820 case AudioControllerType_SB16:
2821 {
2822 /* Legacy SoundBlaster16. */
2823 InsertConfigNode(pDevices, "sb16", &pDev);
2824 InsertConfigNode(pDev, "0", &pInst);
2825 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2826 InsertConfigNode(pInst, "Config", &pCfg);
2827 InsertConfigInteger(pCfg, "IRQ", 5);
2828 InsertConfigInteger(pCfg, "DMA", 1);
2829 InsertConfigInteger(pCfg, "DMA16", 5);
2830 InsertConfigInteger(pCfg, "Port", 0x220);
2831 InsertConfigInteger(pCfg, "Version", 0x0405);
2832 break;
2833 }
2834 case AudioControllerType_HDA:
2835 {
2836 /* Intel HD Audio. */
2837 InsertConfigNode(pDevices, "hda", &pDev);
2838 InsertConfigNode(pDev, "0", &pInst);
2839 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2840 hrc = pBusMgr->assignPCIDevice("hda", pInst); H();
2841 InsertConfigNode(pInst, "Config", &pCfg);
2842 }
2843 }
2844
2845 PCFGMNODE pCfgAudioSettings = NULL;
2846 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioSettings);
2847 SafeArray<BSTR> audioProps;
2848 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2849
2850 std::list<Utf8Str> audioPropertyNamesList;
2851 for (size_t i = 0; i < audioProps.size(); ++i)
2852 {
2853 Bstr bstrValue;
2854 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2855 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2856 Utf8Str strKey(audioProps[i]);
2857 InsertConfigString(pCfgAudioSettings, strKey.c_str(), bstrValue);
2858 }
2859
2860 /*
2861 * The audio driver.
2862 */
2863 uint8_t u8AudioLUN = 0;
2864
2865 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", u8AudioLUN++);
2866 InsertConfigString(pLunL0, "Driver", "AUDIO");
2867 InsertConfigNode(pLunL0, "Config", &pCfg);
2868
2869 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2870 InsertConfigNode(pLunL1, "Config", &pCfg);
2871
2872 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2873 InsertConfigString(pCfg, "StreamName", bstr);
2874
2875 AudioDriverType_T audioDriver;
2876 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2877 switch (audioDriver)
2878 {
2879 case AudioDriverType_Null:
2880 {
2881 InsertConfigString(pLunL1, "Driver", "NullAudio");
2882 break;
2883 }
2884#ifdef RT_OS_WINDOWS
2885# ifdef VBOX_WITH_WINMM
2886 case AudioDriverType_WinMM:
2887 {
2888 #error "Port WinMM audio backend!" /** @todo Still needed? */
2889 break;
2890 }
2891# endif
2892 case AudioDriverType_DirectSound:
2893 {
2894 InsertConfigString(pLunL1, "Driver", "DSoundAudio");
2895 break;
2896 }
2897#endif /* RT_OS_WINDOWS */
2898#ifdef RT_OS_SOLARIS
2899 case AudioDriverType_SolAudio:
2900 {
2901 /* Should not happen, as the Solaris Audio backend is not around anymore.
2902 * Remove this sometime later. */
2903 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2904 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2905
2906 /* Manually set backend to OSS for now. */
2907 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2908 break;
2909 }
2910#endif
2911#ifdef VBOX_WITH_AUDIO_OSS
2912 case AudioDriverType_OSS:
2913 {
2914 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2915 break;
2916 }
2917#endif
2918#ifdef VBOX_WITH_AUDIO_ALSA
2919 case AudioDriverType_ALSA:
2920 {
2921 InsertConfigString(pLunL1, "Driver", "ALSAAudio");
2922 break;
2923 }
2924#endif
2925#ifdef VBOX_WITH_AUDIO_PULSE
2926 case AudioDriverType_Pulse:
2927 {
2928 InsertConfigString(pLunL1, "Driver", "PulseAudio");
2929 break;
2930 }
2931#endif
2932#ifdef RT_OS_DARWIN
2933 case AudioDriverType_CoreAudio:
2934 {
2935 InsertConfigString(pLunL1, "Driver", "CoreAudio");
2936 break;
2937 }
2938#endif
2939 default: AssertFailedBreak();
2940 }
2941
2942 /** @todo Implement a prioritizing feature here, e.g. which driver to insert in which order? */
2943
2944#ifdef VBOX_WITH_VRDE_AUDIO
2945 /*
2946 * The VRDE audio backend driver.
2947 */
2948 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2949 InsertConfigString(pLunL1, "Driver", "AUDIO");
2950
2951 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2952 InsertConfigString(pLunL1, "Driver", "AudioVRDE");
2953
2954 InsertConfigNode(pLunL1, "Config", &pCfg);
2955 InsertConfigString(pCfg, "AudioDriver", "AudioVRDE");
2956 InsertConfigString(pCfg, "StreamName", bstr);
2957 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVRDE);
2958 InsertConfigInteger(pCfg, "ObjectVRDPServer", (uintptr_t)mConsoleVRDPServer);
2959#endif /* VBOX_WITH_VRDE_AUDIO */
2960
2961#ifdef VBOX_WITH_AUDIO_VIDEOREC
2962 /*
2963 * The video recording audio backend driver.
2964 * Currently being used with VPX video recording only.
2965 */
2966 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2967 InsertConfigString(pLunL1, "Driver", "AUDIO");
2968
2969 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2970 InsertConfigString(pLunL1, "Driver", "AudioVideoRec");
2971
2972 InsertConfigNode(pLunL1, "Config", &pCfg);
2973 InsertConfigString(pCfg, "AudioDriver", "AudioVideoRec");
2974 InsertConfigString(pCfg, "StreamName", bstr);
2975 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVideoRec);
2976 InsertConfigInteger(pCfg, "ObjectConsole", (uintptr_t)this /* Console */);
2977#endif /* VBOX_WITH_AUDIO_VIDEOREC */
2978
2979#ifdef VBOX_WITH_AUDIO_DEBUG
2980 /*
2981 * The audio debug backend. Only can be used in debug builds.
2982 */
2983 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2984 InsertConfigString(pLunL1, "Driver", "AUDIO");
2985
2986 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2987 InsertConfigString(pLunL1, "Driver", "DebugAudio");
2988
2989 InsertConfigNode(pLunL1, "Config", &pCfg);
2990 InsertConfigString(pCfg, "AudioDriver", "DebugAudio");
2991 InsertConfigString(pCfg, "StreamName", bstr);
2992#endif /* VBOX_WITH_AUDIO_DEBUG */
2993
2994#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
2995 /** @todo Make this a runtime-configurable entry! */
2996
2997 /*
2998 * The ValidationKit backend.
2999 */
3000 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
3001 InsertConfigString(pLunL1, "Driver", "AUDIO");
3002
3003 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
3004 InsertConfigString(pLunL1, "Driver", "ValidationKitAudio");
3005
3006 InsertConfigNode(pLunL1, "Config", &pCfg);
3007 InsertConfigString(pCfg, "AudioDriver", "ValidationKitAudio");
3008 InsertConfigString(pCfg, "StreamName", bstr);
3009#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3010
3011 /** @todo Add audio video recording driver here. */
3012 }
3013
3014 /*
3015 * Shared Clipboard.
3016 */
3017 {
3018 ClipboardMode_T mode = ClipboardMode_Disabled;
3019 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3020
3021 if (/* mode != ClipboardMode_Disabled */ true)
3022 {
3023 /* Load the service */
3024 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3025 if (RT_FAILURE(rc))
3026 {
3027 LogRel(("Shared clipboard is not available, rc=%Rrc\n", rc));
3028 /* That is not a fatal failure. */
3029 rc = VINF_SUCCESS;
3030 }
3031 else
3032 {
3033 LogRel(("Shared clipboard service loaded\n"));
3034
3035 i_changeClipboardMode(mode);
3036
3037 /* Setup the service. */
3038 VBOXHGCMSVCPARM parm;
3039 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
3040 parm.setUInt32(!i_useHostClipboard());
3041 pVMMDev->hgcmHostCall("VBoxSharedClipboard",
3042 VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3043 }
3044 }
3045 }
3046
3047 /*
3048 * HGCM HostChannel.
3049 */
3050 {
3051 Bstr value;
3052 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3053 value.asOutParam());
3054
3055 if ( hrc == S_OK
3056 && value == "1")
3057 {
3058 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3059 if (RT_FAILURE(rc))
3060 {
3061 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3062 /* That is not a fatal failure. */
3063 rc = VINF_SUCCESS;
3064 }
3065 }
3066 }
3067
3068#ifdef VBOX_WITH_DRAG_AND_DROP
3069 /*
3070 * Drag and Drop.
3071 */
3072 {
3073 DnDMode_T enmMode = DnDMode_Disabled;
3074 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3075
3076 /* Load the service */
3077 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3078 if (RT_FAILURE(rc))
3079 {
3080 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3081 /* That is not a fatal failure. */
3082 rc = VINF_SUCCESS;
3083 }
3084 else
3085 {
3086 HGCMSVCEXTHANDLE hDummy;
3087 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
3088 &GuestDnD::notifyDnDDispatcher,
3089 GuestDnDInst());
3090 if (RT_FAILURE(rc))
3091 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3092 else
3093 {
3094 LogRel(("Drag and drop service loaded\n"));
3095 rc = i_changeDnDMode(enmMode);
3096 }
3097 }
3098 }
3099#endif /* VBOX_WITH_DRAG_AND_DROP */
3100
3101#ifdef VBOX_WITH_CROGL
3102 /*
3103 * crOpenGL.
3104 */
3105 {
3106 BOOL fEnabled3D = false;
3107 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3108
3109 if ( fEnabled3D
3110# ifdef VBOX_WITH_VMSVGA3D
3111 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3112# endif
3113 )
3114 {
3115 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3116 if (!fSupports3D)
3117 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3118 N_("This VM was configured to use 3D acceleration. However, the "
3119 "3D support of the host is not working properly and the "
3120 "VM cannot be started. To fix this problem, either "
3121 "fix the host 3D support (update the host graphics driver?) "
3122 "or disable 3D acceleration in the VM settings"));
3123
3124 /* Load the service. */
3125 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3126 if (RT_FAILURE(rc))
3127 {
3128 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3129 /* That is not a fatal failure. */
3130 rc = VINF_SUCCESS;
3131 }
3132 else
3133 {
3134 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3135
3136 /* Setup the service. */
3137 VBOXHGCMSVCPARM parm;
3138 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3139
3140 parm.u.pointer.addr = (IConsole *)(Console *)this;
3141 parm.u.pointer.size = sizeof(IConsole *);
3142
3143 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3144 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3145 if (!RT_SUCCESS(rc))
3146 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3147
3148 parm.u.pointer.addr = pVM;
3149 parm.u.pointer.size = sizeof(pVM);
3150 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3151 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3152 if (!RT_SUCCESS(rc))
3153 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3154 }
3155 }
3156 }
3157#endif
3158
3159#ifdef VBOX_WITH_GUEST_PROPS
3160 /*
3161 * Guest property service.
3162 */
3163 rc = i_configGuestProperties(this, pUVM);
3164#endif /* VBOX_WITH_GUEST_PROPS defined */
3165
3166#ifdef VBOX_WITH_GUEST_CONTROL
3167 /*
3168 * Guest control service.
3169 */
3170 rc = i_configGuestControl(this);
3171#endif /* VBOX_WITH_GUEST_CONTROL defined */
3172
3173 /*
3174 * ACPI
3175 */
3176 BOOL fACPI;
3177 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3178 if (fACPI)
3179 {
3180 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3181 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3182 * intelppm driver refuses to register an idle state handler.
3183 * Always show CPU leafs for OS X guests. */
3184 BOOL fShowCpu = fOsXGuest;
3185 if (cCpus > 1 || fIOAPIC)
3186 fShowCpu = true;
3187
3188 BOOL fCpuHotPlug;
3189 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3190
3191 InsertConfigNode(pDevices, "acpi", &pDev);
3192 InsertConfigNode(pDev, "0", &pInst);
3193 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3194 InsertConfigNode(pInst, "Config", &pCfg);
3195 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3196
3197 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3198
3199 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3200 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3201 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3202 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3203 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3204 if (fOsXGuest && !llBootNics.empty())
3205 {
3206 BootNic aNic = llBootNics.front();
3207 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3208 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3209 }
3210 if (fOsXGuest && fAudioEnabled)
3211 {
3212 PCIBusAddress Address;
3213 if (pBusMgr->findPCIAddress("hda", 0, Address))
3214 {
3215 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3216 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3217 }
3218 }
3219 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3220 if (chipsetType == ChipsetType_ICH9)
3221 {
3222 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3223 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3224 /* 64-bit prefetch window root resource:
3225 * Only for ICH9 and if PAE or Long Mode is enabled.
3226 * And only with hardware virtualization (@bugref:5454). */
3227 if ( (fEnablePAE || fIsGuest64Bit)
3228 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3229 otherwise VMM falls back to raw mode */
3230 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3231 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3232 }
3233 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3234 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3235 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3236
3237 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3238 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3239
3240 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3241 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3242
3243 if (auSerialIoPortBase[2])
3244 {
3245 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3246 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3247 }
3248
3249 if (auSerialIoPortBase[3])
3250 {
3251 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3252 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3253 }
3254
3255 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3256 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3257
3258 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3259 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3260
3261 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3262 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3263 InsertConfigNode(pLunL0, "Config", &pCfg);
3264
3265 /* Attach the dummy CPU drivers */
3266 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3267 {
3268 BOOL fCpuAttached = true;
3269
3270 if (fCpuHotPlug)
3271 {
3272 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3273 }
3274
3275 if (fCpuAttached)
3276 {
3277 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3278 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3279 InsertConfigNode(pLunL0, "Config", &pCfg);
3280 }
3281 }
3282 }
3283
3284 /*
3285 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3286 */
3287 {
3288 PCFGMNODE pDbgf;
3289 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3290
3291 /* Paths to search for debug info and such things. */
3292 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3293 Utf8Str strSettingsPath(bstr);
3294 bstr.setNull();
3295 strSettingsPath.stripFilename();
3296 strSettingsPath.append("/");
3297
3298 char szHomeDir[RTPATH_MAX + 1];
3299 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3300 if (RT_FAILURE(rc2))
3301 szHomeDir[0] = '\0';
3302 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3303
3304
3305 Utf8Str strPath;
3306 strPath.append(strSettingsPath).append("debug/;");
3307 strPath.append(strSettingsPath).append(";");
3308 strPath.append(szHomeDir);
3309
3310 InsertConfigString(pDbgf, "Path", strPath.c_str());
3311
3312 /* Tracing configuration. */
3313 BOOL fTracingEnabled;
3314 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3315 if (fTracingEnabled)
3316 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3317
3318 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3319 if (fTracingEnabled)
3320 InsertConfigString(pDbgf, "TracingConfig", bstr);
3321
3322 BOOL fAllowTracingToAccessVM;
3323 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3324 if (fAllowTracingToAccessVM)
3325 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3326
3327 /* Debugger console config. */
3328 PCFGMNODE pDbgc;
3329 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3330
3331 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3332 Utf8Str strVBoxHome = bstr;
3333 bstr.setNull();
3334 if (strVBoxHome.isNotEmpty())
3335 strVBoxHome.append("/");
3336 else
3337 {
3338 strVBoxHome = szHomeDir;
3339 strVBoxHome.append("/.vbox");
3340 }
3341
3342 Utf8Str strFile(strVBoxHome);
3343 strFile.append("dbgc-history");
3344 InsertConfigString(pDbgc, "HistoryFile", strFile);
3345
3346 strFile = strSettingsPath;
3347 strFile.append("dbgc-init");
3348 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3349
3350 strFile = strVBoxHome;
3351 strFile.append("dbgc-init");
3352 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3353 }
3354 }
3355 catch (ConfigError &x)
3356 {
3357 // InsertConfig threw something:
3358 return x.m_vrc;
3359 }
3360 catch (HRESULT hrcXcpt)
3361 {
3362 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3363 }
3364
3365#ifdef VBOX_WITH_EXTPACK
3366 /*
3367 * Call the extension pack hooks if everything went well thus far.
3368 */
3369 if (RT_SUCCESS(rc))
3370 {
3371 pAlock->release();
3372 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3373 pAlock->acquire();
3374 }
3375#endif
3376
3377 /*
3378 * Apply the CFGM overlay.
3379 */
3380 if (RT_SUCCESS(rc))
3381 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3382
3383 /*
3384 * Dump all extradata API settings tweaks, both global and per VM.
3385 */
3386 if (RT_SUCCESS(rc))
3387 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3388
3389#undef H
3390
3391 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3392
3393 /*
3394 * Register VM state change handler.
3395 */
3396 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3397 AssertRC(rc2);
3398 if (RT_SUCCESS(rc))
3399 rc = rc2;
3400
3401 /*
3402 * Register VM runtime error handler.
3403 */
3404 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3405 AssertRC(rc2);
3406 if (RT_SUCCESS(rc))
3407 rc = rc2;
3408
3409 pAlock->acquire();
3410
3411 LogFlowFunc(("vrc = %Rrc\n", rc));
3412 LogFlowFuncLeave();
3413
3414 return rc;
3415}
3416
3417/**
3418 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3419 * values.
3420 *
3421 * @returns VBox status code.
3422 * @param pRoot The root of the configuration tree.
3423 * @param pVirtualBox Pointer to the IVirtualBox interface.
3424 * @param pMachine Pointer to the IMachine interface.
3425 */
3426/* static */
3427int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3428{
3429 /*
3430 * CFGM overlay handling.
3431 *
3432 * Here we check the extra data entries for CFGM values
3433 * and create the nodes and insert the values on the fly. Existing
3434 * values will be removed and reinserted. CFGM is typed, so by default
3435 * we will guess whether it's a string or an integer (byte arrays are
3436 * not currently supported). It's possible to override this autodetection
3437 * by adding "string:", "integer:" or "bytes:" (future).
3438 *
3439 * We first perform a run on global extra data, then on the machine
3440 * extra data to support global settings with local overrides.
3441 */
3442 int rc = VINF_SUCCESS;
3443 try
3444 {
3445 /** @todo add support for removing nodes and byte blobs. */
3446 /*
3447 * Get the next key
3448 */
3449 SafeArray<BSTR> aGlobalExtraDataKeys;
3450 SafeArray<BSTR> aMachineExtraDataKeys;
3451 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3452 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3453
3454 // remember the no. of global values so we can call the correct method below
3455 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3456
3457 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3458 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3459
3460 // build a combined list from global keys...
3461 std::list<Utf8Str> llExtraDataKeys;
3462
3463 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3464 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3465 // ... and machine keys
3466 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3467 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3468
3469 size_t i2 = 0;
3470 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3471 it != llExtraDataKeys.end();
3472 ++it, ++i2)
3473 {
3474 const Utf8Str &strKey = *it;
3475
3476 /*
3477 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3478 */
3479 if (!strKey.startsWith("VBoxInternal/"))
3480 continue;
3481
3482 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3483
3484 // get the value
3485 Bstr bstrExtraDataValue;
3486 if (i2 < cGlobalValues)
3487 // this is still one of the global values:
3488 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3489 bstrExtraDataValue.asOutParam());
3490 else
3491 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3492 bstrExtraDataValue.asOutParam());
3493 if (FAILED(hrc))
3494 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3495
3496 /*
3497 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3498 * Split the two and get the node, delete the value and create the node
3499 * if necessary.
3500 */
3501 PCFGMNODE pNode;
3502 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3503 if (pszCFGMValueName)
3504 {
3505 /* terminate the node and advance to the value (Utf8Str might not
3506 offically like this but wtf) */
3507 *(char*)pszCFGMValueName = '\0';
3508 ++pszCFGMValueName;
3509
3510 /* does the node already exist? */
3511 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3512 if (pNode)
3513 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3514 else
3515 {
3516 /* create the node */
3517 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3518 if (RT_FAILURE(rc))
3519 {
3520 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3521 continue;
3522 }
3523 Assert(pNode);
3524 }
3525 }
3526 else
3527 {
3528 /* root value (no node path). */
3529 pNode = pRoot;
3530 pszCFGMValueName = pszExtraDataKey;
3531 pszExtraDataKey--;
3532 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3533 }
3534
3535 /*
3536 * Now let's have a look at the value.
3537 * Empty strings means that we should remove the value, which we've
3538 * already done above.
3539 */
3540 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3541 if (!strCFGMValueUtf8.isEmpty())
3542 {
3543 uint64_t u64Value;
3544
3545 /* check for type prefix first. */
3546 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3547 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3548 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3549 {
3550 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3551 if (RT_SUCCESS(rc))
3552 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3553 }
3554 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3555 {
3556 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3557 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3558 if (cbValue > 0)
3559 {
3560 void *pvBytes = RTMemTmpAlloc(cbValue);
3561 if (pvBytes)
3562 {
3563 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3564 if (RT_SUCCESS(rc))
3565 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3566 RTMemTmpFree(pvBytes);
3567 }
3568 else
3569 rc = VERR_NO_TMP_MEMORY;
3570 }
3571 else if (cbValue == 0)
3572 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3573 else
3574 rc = VERR_INVALID_BASE64_ENCODING;
3575 }
3576 /* auto detect type. */
3577 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3578 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3579 else
3580 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3581 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3582 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3583 }
3584 }
3585 }
3586 catch (ConfigError &x)
3587 {
3588 // InsertConfig threw something:
3589 return x.m_vrc;
3590 }
3591 return rc;
3592}
3593
3594/**
3595 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3596 * values.
3597 *
3598 * @returns VBox status code.
3599 * @param pVirtualBox Pointer to the IVirtualBox interface.
3600 * @param pMachine Pointer to the IMachine interface.
3601 */
3602/* static */
3603int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3604{
3605 {
3606 SafeArray<BSTR> aGlobalExtraDataKeys;
3607 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3608 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3609 bool hasKey = false;
3610 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3611 {
3612 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3613 if (!strKey.startsWith("VBoxInternal2/"))
3614 continue;
3615
3616 Bstr bstrValue;
3617 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3618 bstrValue.asOutParam());
3619 if (FAILED(hrc))
3620 continue;
3621 if (!hasKey)
3622 LogRel(("Global extradata API settings:\n"));
3623 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3624 hasKey = true;
3625 }
3626 }
3627
3628 {
3629 SafeArray<BSTR> aMachineExtraDataKeys;
3630 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3631 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3632 bool hasKey = false;
3633 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3634 {
3635 Utf8Str strKey(aMachineExtraDataKeys[i]);
3636 if (!strKey.startsWith("VBoxInternal2/"))
3637 continue;
3638
3639 Bstr bstrValue;
3640 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3641 bstrValue.asOutParam());
3642 if (FAILED(hrc))
3643 continue;
3644 if (!hasKey)
3645 LogRel(("Per-VM extradata API settings:\n"));
3646 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3647 hasKey = true;
3648 }
3649 }
3650
3651 return VINF_SUCCESS;
3652}
3653
3654int Console::i_configGraphicsController(PCFGMNODE pDevices,
3655 const GraphicsControllerType_T enmGraphicsController,
3656 BusAssignmentManager *pBusMgr,
3657 const ComPtr<IMachine> &ptrMachine,
3658 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3659 bool fHMEnabled)
3660{
3661 // InsertConfig* throws
3662 try
3663 {
3664 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3665 HRESULT hrc;
3666 Bstr bstr;
3667 const char *pcszDevice = "vga";
3668
3669#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3670 InsertConfigNode(pDevices, pcszDevice, &pDev);
3671 InsertConfigNode(pDev, "0", &pInst);
3672 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3673
3674 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3675 InsertConfigNode(pInst, "Config", &pCfg);
3676 ULONG cVRamMBs;
3677 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3678 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3679 ULONG cMonitorCount;
3680 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3681 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3682#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3683 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3684#else
3685 NOREF(fHMEnabled);
3686#endif
3687
3688 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3689
3690#ifdef VBOX_WITH_VMSVGA
3691 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3692 {
3693 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3694#ifdef VBOX_WITH_VMSVGA3D
3695 IFramebuffer *pFramebuffer = NULL;
3696 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3697 if (SUCCEEDED(hrc) && pFramebuffer)
3698 {
3699 LONG64 winId = 0;
3700 /** @todo deal with multimonitor setup */
3701 Assert(cMonitorCount == 1);
3702 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3703 InsertConfigInteger(pCfg, "HostWindowId", winId);
3704 pFramebuffer->Release();
3705 }
3706 BOOL f3DEnabled;
3707 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3708 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3709#else
3710 LogRel(("VMSVGA3d not available in this build!\n"));
3711#endif
3712 }
3713#endif
3714
3715 /* Custom VESA mode list */
3716 unsigned cModes = 0;
3717 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3718 {
3719 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3720 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3721 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3722 if (bstr.isEmpty())
3723 break;
3724 InsertConfigString(pCfg, szExtraDataKey, bstr);
3725 ++cModes;
3726 }
3727 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3728
3729 /* VESA height reduction */
3730 ULONG ulHeightReduction;
3731 IFramebuffer *pFramebuffer = NULL;
3732 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3733 if (SUCCEEDED(hrc) && pFramebuffer)
3734 {
3735 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3736 pFramebuffer->Release();
3737 pFramebuffer = NULL;
3738 }
3739 else
3740 {
3741 /* If framebuffer is not available, there is no height reduction. */
3742 ulHeightReduction = 0;
3743 }
3744 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3745
3746 /*
3747 * BIOS logo
3748 */
3749 BOOL fFadeIn;
3750 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3751 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3752 BOOL fFadeOut;
3753 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3754 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3755 ULONG logoDisplayTime;
3756 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3757 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3758 Bstr logoImagePath;
3759 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3760 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3761
3762 /*
3763 * Boot menu
3764 */
3765 BIOSBootMenuMode_T eBootMenuMode;
3766 int iShowBootMenu;
3767 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3768 switch (eBootMenuMode)
3769 {
3770 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3771 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3772 default: iShowBootMenu = 2; break;
3773 }
3774 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3775
3776 /* Attach the display. */
3777 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3778 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3779 InsertConfigNode(pLunL0, "Config", &pCfg);
3780 Display *pDisplay = mDisplay;
3781 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3782 }
3783 catch (ConfigError &x)
3784 {
3785 // InsertConfig threw something:
3786 return x.m_vrc;
3787 }
3788
3789#undef H
3790
3791 return VINF_SUCCESS;
3792}
3793
3794
3795/**
3796 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3797 */
3798void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3799{
3800 va_list va;
3801 va_start(va, pszFormat);
3802 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3803 va_end(va);
3804}
3805
3806/* XXX introduce RT format specifier */
3807static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3808{
3809 if (u64Size > INT64_C(5000)*_1G)
3810 {
3811 *pszUnit = "TB";
3812 return u64Size / _1T;
3813 }
3814 else if (u64Size > INT64_C(5000)*_1M)
3815 {
3816 *pszUnit = "GB";
3817 return u64Size / _1G;
3818 }
3819 else
3820 {
3821 *pszUnit = "MB";
3822 return u64Size / _1M;
3823 }
3824}
3825
3826/**
3827 * Checks the location of the given medium for known bugs affecting the usage
3828 * of the host I/O cache setting.
3829 *
3830 * @returns VBox status code.
3831 * @param pMedium The medium to check.
3832 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3833 */
3834int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3835{
3836#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3837 /*
3838 * Some sanity checks.
3839 */
3840 RT_NOREF(pfUseHostIOCache);
3841 ComPtr<IMediumFormat> pMediumFormat;
3842 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3843 ULONG uCaps = 0;
3844 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3845 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3846
3847 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3848 uCaps |= mediumFormatCap[j];
3849
3850 if (uCaps & MediumFormatCapabilities_File)
3851 {
3852 Bstr strFile;
3853 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3854 Utf8Str utfFile = Utf8Str(strFile);
3855 Bstr strSnap;
3856 ComPtr<IMachine> pMachine = i_machine();
3857 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3858 Utf8Str utfSnap = Utf8Str(strSnap);
3859 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3860 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3861 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3862 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3863 /* Ignore the error code. On error, the file system type is still 'unknown' so
3864 * none of the following paths are taken. This can happen for new VMs which
3865 * still don't have a snapshot folder. */
3866 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3867 if (!mfSnapshotFolderDiskTypeShown)
3868 {
3869 LogRel(("File system of '%s' (snapshots) is %s\n",
3870 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3871 mfSnapshotFolderDiskTypeShown = true;
3872 }
3873 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3874 LONG64 i64Size;
3875 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3876#ifdef RT_OS_WINDOWS
3877 if ( enmFsTypeFile == RTFSTYPE_FAT
3878 && i64Size >= _4G)
3879 {
3880 const char *pszUnit;
3881 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3882 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3883 N_("The medium '%ls' has a logical size of %RU64%s "
3884 "but the file system the medium is located on seems "
3885 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3886 "We strongly recommend to put all your virtual disk images and "
3887 "the snapshot folder onto an NTFS partition"),
3888 strFile.raw(), u64Print, pszUnit);
3889 }
3890#else /* !RT_OS_WINDOWS */
3891 if ( enmFsTypeFile == RTFSTYPE_FAT
3892 || enmFsTypeFile == RTFSTYPE_EXT
3893 || enmFsTypeFile == RTFSTYPE_EXT2
3894 || enmFsTypeFile == RTFSTYPE_EXT3
3895 || enmFsTypeFile == RTFSTYPE_EXT4)
3896 {
3897 RTFILE file;
3898 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3899 if (RT_SUCCESS(rc))
3900 {
3901 RTFOFF maxSize;
3902 /* Careful: This function will work only on selected local file systems! */
3903 rc = RTFileGetMaxSizeEx(file, &maxSize);
3904 RTFileClose(file);
3905 if ( RT_SUCCESS(rc)
3906 && maxSize > 0
3907 && i64Size > (LONG64)maxSize)
3908 {
3909 const char *pszUnitSiz;
3910 const char *pszUnitMax;
3911 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3912 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3913 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3914 N_("The medium '%ls' has a logical size of %RU64%s "
3915 "but the file system the medium is located on can "
3916 "only handle files up to %RU64%s in theory.\n"
3917 "We strongly recommend to put all your virtual disk "
3918 "images and the snapshot folder onto a proper "
3919 "file system (e.g. ext3) with a sufficient size"),
3920 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3921 }
3922 }
3923 }
3924#endif /* !RT_OS_WINDOWS */
3925
3926 /*
3927 * Snapshot folder:
3928 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3929 */
3930 if ( enmFsTypeSnap == RTFSTYPE_FAT
3931 && i64Size >= _4G
3932 && !mfSnapshotFolderSizeWarningShown)
3933 {
3934 const char *pszUnit;
3935 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3936 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3937#ifdef RT_OS_WINDOWS
3938 N_("The snapshot folder of this VM '%ls' seems to be located on "
3939 "a FAT(32) file system. The logical size of the medium '%ls' "
3940 "(%RU64%s) is bigger than the maximum file size this file "
3941 "system can handle (4GB).\n"
3942 "We strongly recommend to put all your virtual disk images and "
3943 "the snapshot folder onto an NTFS partition"),
3944#else
3945 N_("The snapshot folder of this VM '%ls' seems to be located on "
3946 "a FAT(32) file system. The logical size of the medium '%ls' "
3947 "(%RU64%s) is bigger than the maximum file size this file "
3948 "system can handle (4GB).\n"
3949 "We strongly recommend to put all your virtual disk images and "
3950 "the snapshot folder onto a proper file system (e.g. ext3)"),
3951#endif
3952 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3953 /* Show this particular warning only once */
3954 mfSnapshotFolderSizeWarningShown = true;
3955 }
3956
3957#ifdef RT_OS_LINUX
3958 /*
3959 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3960 * on an ext4 partition.
3961 * This bug apparently applies to the XFS file system as well.
3962 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3963 */
3964
3965 char szOsRelease[128];
3966 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3967 bool fKernelHasODirectBug = RT_FAILURE(rc)
3968 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3969
3970 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3971 && !*pfUseHostIOCache
3972 && fKernelHasODirectBug)
3973 {
3974 if ( enmFsTypeFile == RTFSTYPE_EXT4
3975 || enmFsTypeFile == RTFSTYPE_XFS)
3976 {
3977 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3978 N_("The host I/O cache for at least one controller is disabled "
3979 "and the medium '%ls' for this VM "
3980 "is located on an %s partition. There is a known Linux "
3981 "kernel bug which can lead to the corruption of the virtual "
3982 "disk image under these conditions.\n"
3983 "Either enable the host I/O cache permanently in the VM "
3984 "settings or put the disk image and the snapshot folder "
3985 "onto a different file system.\n"
3986 "The host I/O cache will now be enabled for this medium"),
3987 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3988 *pfUseHostIOCache = true;
3989 }
3990 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
3991 || enmFsTypeSnap == RTFSTYPE_XFS)
3992 && !mfSnapshotFolderExt4WarningShown)
3993 {
3994 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3995 N_("The host I/O cache for at least one controller is disabled "
3996 "and the snapshot folder for this VM "
3997 "is located on an %s partition. There is a known Linux "
3998 "kernel bug which can lead to the corruption of the virtual "
3999 "disk image under these conditions.\n"
4000 "Either enable the host I/O cache permanently in the VM "
4001 "settings or put the disk image and the snapshot folder "
4002 "onto a different file system.\n"
4003 "The host I/O cache will now be enabled for this medium"),
4004 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4005 *pfUseHostIOCache = true;
4006 mfSnapshotFolderExt4WarningShown = true;
4007 }
4008 }
4009
4010 /*
4011 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4012 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4013 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4014 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4015 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4016 */
4017 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4018 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4019 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4020 && !*pfUseHostIOCache
4021 && fKernelAsyncUnreliable)
4022 {
4023 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4024 N_("The host I/O cache for at least one controller is disabled. "
4025 "There is a known Linux kernel bug which can lead to kernel "
4026 "oopses under heavy load. To our knowledge this bug affects "
4027 "all 2.6.18 kernels.\n"
4028 "Either enable the host I/O cache permanently in the VM "
4029 "settings or switch to a newer host kernel.\n"
4030 "The host I/O cache will now be enabled for this medium"));
4031 *pfUseHostIOCache = true;
4032 }
4033#endif
4034 }
4035#undef H
4036
4037 return VINF_SUCCESS;
4038}
4039
4040/**
4041 * Unmounts the specified medium from the specified device.
4042 *
4043 * @returns VBox status code.
4044 * @param pUVM The usermode VM handle.
4045 * @param enmBus The storage bus.
4046 * @param enmDevType The device type.
4047 * @param pcszDevice The device emulation.
4048 * @param uInstance Instance of the device.
4049 * @param uLUN The LUN on the device.
4050 * @param fForceUnmount Whether to force unmounting.
4051 */
4052int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4053 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4054 bool fForceUnmount)
4055{
4056 /* Unmount existing media only for floppy and DVD drives. */
4057 int rc = VINF_SUCCESS;
4058 PPDMIBASE pBase;
4059 if (enmBus == StorageBus_USB)
4060 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4061 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4062 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4063 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4064 else /* IDE or Floppy */
4065 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4066
4067 if (RT_FAILURE(rc))
4068 {
4069 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4070 rc = VINF_SUCCESS;
4071 AssertRC(rc);
4072 }
4073 else
4074 {
4075 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4076 AssertReturn(pIMount, VERR_INVALID_POINTER);
4077
4078 /* Unmount the media (but do not eject the medium!) */
4079 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4080 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4081 rc = VINF_SUCCESS;
4082 /* for example if the medium is locked */
4083 else if (RT_FAILURE(rc))
4084 return rc;
4085 }
4086
4087 return rc;
4088}
4089
4090/**
4091 * Removes the currently attached medium driver form the specified device
4092 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4093 *
4094 * @returns VBox status code.
4095 * @param pCtlInst The controler instance node in the CFGM tree.
4096 * @param pcszDevice The device name.
4097 * @param uInstance The device instance.
4098 * @param uLUN The device LUN.
4099 * @param enmBus The storage bus.
4100 * @param fAttachDetach Flag whether this is a change while the VM is running
4101 * @param fHotplug Flag whether the guest should be notified about the device change.
4102 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4103 * @param pUVM The usermode VM handle.
4104 * @param enmDevType The device type.
4105 * @param ppLunL0 Where to store the node to attach the new config to on success.
4106 */
4107int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4108 const char *pcszDevice,
4109 unsigned uInstance,
4110 unsigned uLUN,
4111 StorageBus_T enmBus,
4112 bool fAttachDetach,
4113 bool fHotplug,
4114 bool fForceUnmount,
4115 PUVM pUVM,
4116 DeviceType_T enmDevType,
4117 PCFGMNODE *ppLunL0)
4118{
4119 int rc = VINF_SUCCESS;
4120 bool fAddLun = false;
4121
4122 /* First check if the LUN already exists. */
4123 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4124 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4125
4126 if (pLunL0)
4127 {
4128 /*
4129 * Unmount the currently mounted medium if we don't just hot remove the
4130 * complete device (SATA) and it supports unmounting (DVD).
4131 */
4132 if ( (enmDevType != DeviceType_HardDisk)
4133 && !fHotplug)
4134 {
4135 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4136 uInstance, uLUN, fForceUnmount);
4137 if (RT_FAILURE(rc))
4138 return rc;
4139 }
4140
4141 /*
4142 * Don't detach the SCSI driver when unmounting the current medium
4143 * (we are not ripping out the device but only eject the medium).
4144 */
4145 char *pszDriverDetach = NULL;
4146 if ( !fHotplug
4147 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4148 || enmBus == StorageBus_SAS
4149 || enmBus == StorageBus_SCSI
4150 || enmBus == StorageBus_USB))
4151 {
4152 /* Get the current attached driver we have to detach. */
4153 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4154 if (pDrvLun)
4155 {
4156 char szDriver[128];
4157 RT_ZERO(szDriver);
4158 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4159 if (RT_SUCCESS(rc))
4160 pszDriverDetach = RTStrDup(&szDriver[0]);
4161
4162 pLunL0 = pDrvLun;
4163 }
4164 }
4165
4166 if (enmBus == StorageBus_USB)
4167 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4168 pszDriverDetach, 0 /* iOccurence */,
4169 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4170 else
4171 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4172 pszDriverDetach, 0 /* iOccurence */,
4173 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4174
4175 if (pszDriverDetach)
4176 {
4177 RTStrFree(pszDriverDetach);
4178 /* Remove the complete node and create new for the new config. */
4179 CFGMR3RemoveNode(pLunL0);
4180 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4181 if (pLunL0)
4182 {
4183 try
4184 {
4185 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4186 }
4187 catch (ConfigError &x)
4188 {
4189 // InsertConfig threw something:
4190 return x.m_vrc;
4191 }
4192 }
4193 }
4194 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4195 rc = VINF_SUCCESS;
4196 AssertRCReturn(rc, rc);
4197
4198 /*
4199 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4200 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4201 */
4202 if ( fHotplug
4203 || enmBus == StorageBus_IDE
4204 || enmBus == StorageBus_Floppy
4205 || enmBus == StorageBus_PCIe
4206 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4207 {
4208 fAddLun = true;
4209 CFGMR3RemoveNode(pLunL0);
4210 }
4211 }
4212 else
4213 fAddLun = true;
4214
4215 try
4216 {
4217 if (fAddLun)
4218 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4219 }
4220 catch (ConfigError &x)
4221 {
4222 // InsertConfig threw something:
4223 return x.m_vrc;
4224 }
4225
4226 if (ppLunL0)
4227 *ppLunL0 = pLunL0;
4228
4229 return rc;
4230}
4231
4232int Console::i_configMediumAttachment(const char *pcszDevice,
4233 unsigned uInstance,
4234 StorageBus_T enmBus,
4235 bool fUseHostIOCache,
4236 bool fBuiltinIOCache,
4237 bool fInsertDiskIntegrityDrv,
4238 bool fSetupMerge,
4239 unsigned uMergeSource,
4240 unsigned uMergeTarget,
4241 IMediumAttachment *pMediumAtt,
4242 MachineState_T aMachineState,
4243 HRESULT *phrc,
4244 bool fAttachDetach,
4245 bool fForceUnmount,
4246 bool fHotplug,
4247 PUVM pUVM,
4248 DeviceType_T *paLedDevType,
4249 PCFGMNODE *ppLunL0)
4250{
4251 // InsertConfig* throws
4252 try
4253 {
4254 int rc = VINF_SUCCESS;
4255 HRESULT hrc;
4256 Bstr bstr;
4257 PCFGMNODE pCtlInst = NULL;
4258
4259// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4260#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4261
4262 LONG lDev;
4263 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4264 LONG lPort;
4265 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4266 DeviceType_T lType;
4267 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4268 BOOL fNonRotational;
4269 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4270 BOOL fDiscard;
4271 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4272
4273 unsigned uLUN;
4274 PCFGMNODE pLunL0 = NULL;
4275 hrc = Console::i_convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4276
4277 /* Determine the base path for the device instance. */
4278 if (enmBus != StorageBus_USB)
4279 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4280 else
4281 {
4282 /* If we hotplug a USB device create a new CFGM tree. */
4283 if (!fHotplug)
4284 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4285 else
4286 pCtlInst = CFGMR3CreateTree(pUVM);
4287 }
4288 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4289
4290 if (enmBus == StorageBus_USB)
4291 {
4292 PCFGMNODE pCfg = NULL;
4293
4294 /* Create correct instance. */
4295 if (!fHotplug)
4296 {
4297 if (!fAttachDetach)
4298 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4299 else
4300 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4301 }
4302
4303 if (!fAttachDetach)
4304 InsertConfigNode(pCtlInst, "Config", &pCfg);
4305
4306 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4307
4308 if (!fHotplug && !fAttachDetach)
4309 {
4310 char aszUuid[RTUUID_STR_LENGTH + 1];
4311 USBStorageDevice UsbMsd = USBStorageDevice();
4312
4313 memset(aszUuid, 0, sizeof(aszUuid));
4314 rc = RTUuidCreate(&UsbMsd.mUuid);
4315 AssertRCReturn(rc, rc);
4316 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4317 AssertRCReturn(rc, rc);
4318
4319 UsbMsd.iPort = uInstance;
4320
4321 InsertConfigString(pCtlInst, "UUID", aszUuid);
4322 mUSBStorageDevices.push_back(UsbMsd);
4323
4324 /** @todo No LED after hotplugging. */
4325 /* Attach the status driver */
4326 Assert(cLedUsb >= 8);
4327 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4328 &mapMediumAttachments, pcszDevice, 0);
4329 paLedDevType = &maStorageDevType[iLedUsb];
4330 }
4331 }
4332
4333 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4334 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4335 if (RT_FAILURE(rc))
4336 return rc;
4337 if (ppLunL0)
4338 *ppLunL0 = pLunL0;
4339
4340 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4341 mapMediumAttachments[devicePath] = pMediumAtt;
4342
4343 ComPtr<IMedium> pMedium;
4344 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4345
4346 /*
4347 * 1. Only check this for hard disk images.
4348 * 2. Only check during VM creation and not later, especially not during
4349 * taking an online snapshot!
4350 */
4351 if ( lType == DeviceType_HardDisk
4352 && ( aMachineState == MachineState_Starting
4353 || aMachineState == MachineState_Restoring))
4354 {
4355 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4356 if (RT_FAILURE(rc))
4357 return rc;
4358 }
4359
4360 BOOL fPassthrough = FALSE;
4361 if (pMedium)
4362 {
4363 BOOL fHostDrive;
4364 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4365 if ( ( lType == DeviceType_DVD
4366 || lType == DeviceType_Floppy)
4367 && !fHostDrive)
4368 {
4369 /*
4370 * Informative logging.
4371 */
4372 Bstr strFile;
4373 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4374 Utf8Str utfFile = Utf8Str(strFile);
4375 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4376 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4377 LogRel(("File system of '%s' (%s) is %s\n",
4378 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4379 RTFsTypeName(enmFsTypeFile)));
4380 }
4381
4382 if (fHostDrive)
4383 {
4384 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4385 }
4386 }
4387
4388 ComObjPtr<IBandwidthGroup> pBwGroup;
4389 Bstr strBwGroup;
4390 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4391
4392 if (!pBwGroup.isNull())
4393 {
4394 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4395 }
4396
4397 /*
4398 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4399 * or for SATA if the new device is a CD/DVD drive.
4400 */
4401 if ( (fHotplug || !fAttachDetach)
4402 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4403 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4404 {
4405 InsertConfigString(pLunL0, "Driver", "SCSI");
4406 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4407 }
4408
4409 rc = i_configMedium(pLunL0,
4410 !!fPassthrough,
4411 lType,
4412 fUseHostIOCache,
4413 fBuiltinIOCache,
4414 fInsertDiskIntegrityDrv,
4415 fSetupMerge,
4416 uMergeSource,
4417 uMergeTarget,
4418 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4419 !!fDiscard,
4420 !!fNonRotational,
4421 pMedium,
4422 aMachineState,
4423 phrc);
4424 if (RT_FAILURE(rc))
4425 return rc;
4426
4427 if (fAttachDetach)
4428 {
4429 /* Attach the new driver. */
4430 if (enmBus == StorageBus_USB)
4431 {
4432 if (fHotplug)
4433 {
4434 USBStorageDevice UsbMsd = USBStorageDevice();
4435 RTUuidCreate(&UsbMsd.mUuid);
4436 UsbMsd.iPort = uInstance;
4437 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4438 if (RT_SUCCESS(rc))
4439 mUSBStorageDevices.push_back(UsbMsd);
4440 }
4441 else
4442 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4443 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4444 }
4445 else if ( !fHotplug
4446 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4447 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4448 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4449 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4450 else
4451 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4452 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4453 AssertRCReturn(rc, rc);
4454
4455 /*
4456 * Make the secret key helper interface known to the VD driver if it is attached,
4457 * so we can get notified about missing keys.
4458 */
4459 PPDMIBASE pIBase = NULL;
4460 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4461 if (RT_SUCCESS(rc) && pIBase)
4462 {
4463 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4464 if (pIMedium)
4465 {
4466 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4467 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4468 }
4469 }
4470
4471 /* There is no need to handle removable medium mounting, as we
4472 * unconditionally replace everthing including the block driver level.
4473 * This means the new medium will be picked up automatically. */
4474 }
4475
4476 if (paLedDevType)
4477 paLedDevType[uLUN] = lType;
4478
4479 /* Dump the changed LUN if possible, dump the complete device otherwise */
4480 if ( aMachineState != MachineState_Starting
4481 && aMachineState != MachineState_Restoring)
4482 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4483 }
4484 catch (ConfigError &x)
4485 {
4486 // InsertConfig threw something:
4487 return x.m_vrc;
4488 }
4489
4490#undef H
4491
4492 return VINF_SUCCESS;
4493}
4494
4495int Console::i_configMedium(PCFGMNODE pLunL0,
4496 bool fPassthrough,
4497 DeviceType_T enmType,
4498 bool fUseHostIOCache,
4499 bool fBuiltinIOCache,
4500 bool fInsertDiskIntegrityDrv,
4501 bool fSetupMerge,
4502 unsigned uMergeSource,
4503 unsigned uMergeTarget,
4504 const char *pcszBwGroup,
4505 bool fDiscard,
4506 bool fNonRotational,
4507 IMedium *pMedium,
4508 MachineState_T aMachineState,
4509 HRESULT *phrc)
4510{
4511 // InsertConfig* throws
4512 try
4513 {
4514 HRESULT hrc;
4515 Bstr bstr;
4516 PCFGMNODE pCfg = NULL;
4517
4518#define H() \
4519 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4520
4521
4522 BOOL fHostDrive = FALSE;
4523 MediumType_T mediumType = MediumType_Normal;
4524 if (pMedium)
4525 {
4526 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4527 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4528 }
4529
4530 if (fHostDrive)
4531 {
4532 Assert(pMedium);
4533 if (enmType == DeviceType_DVD)
4534 {
4535 InsertConfigString(pLunL0, "Driver", "HostDVD");
4536 InsertConfigNode(pLunL0, "Config", &pCfg);
4537
4538 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4539 InsertConfigString(pCfg, "Path", bstr);
4540
4541 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4542 }
4543 else if (enmType == DeviceType_Floppy)
4544 {
4545 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4546 InsertConfigNode(pLunL0, "Config", &pCfg);
4547
4548 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4549 InsertConfigString(pCfg, "Path", bstr);
4550 }
4551 }
4552 else
4553 {
4554 if (fInsertDiskIntegrityDrv)
4555 {
4556 /*
4557 * The actual configuration is done through CFGM extra data
4558 * for each inserted driver separately.
4559 */
4560 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4561 InsertConfigNode(pLunL0, "Config", &pCfg);
4562 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4563 }
4564
4565 InsertConfigString(pLunL0, "Driver", "VD");
4566 InsertConfigNode(pLunL0, "Config", &pCfg);
4567 switch (enmType)
4568 {
4569 case DeviceType_DVD:
4570 InsertConfigString(pCfg, "Type", "DVD");
4571 InsertConfigInteger(pCfg, "Mountable", 1);
4572 break;
4573 case DeviceType_Floppy:
4574 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4575 InsertConfigInteger(pCfg, "Mountable", 1);
4576 break;
4577 case DeviceType_HardDisk:
4578 default:
4579 InsertConfigString(pCfg, "Type", "HardDisk");
4580 InsertConfigInteger(pCfg, "Mountable", 0);
4581 }
4582
4583 if ( pMedium
4584 && ( enmType == DeviceType_DVD
4585 || enmType == DeviceType_Floppy)
4586 )
4587 {
4588 // if this medium represents an ISO image and this image is inaccessible,
4589 // the ignore it instead of causing a failure; this can happen when we
4590 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4591 // Additions were mounted and the user upgraded VirtualBox. Previously
4592 // we failed on startup, but that's not good because the only way out then
4593 // would be to discard the VM state...
4594 MediumState_T mediumState;
4595 hrc = pMedium->RefreshState(&mediumState); H();
4596 if (mediumState == MediumState_Inaccessible)
4597 {
4598 Bstr loc;
4599 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4600 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4601 "The image file '%ls' is inaccessible and is being ignored. "
4602 "Please select a different image file for the virtual %s drive.",
4603 loc.raw(),
4604 enmType == DeviceType_DVD ? "DVD" : "floppy");
4605 pMedium = NULL;
4606 }
4607 }
4608
4609 if (pMedium)
4610 {
4611 /* Start with length of parent chain, as the list is reversed */
4612 unsigned uImage = 0;
4613 IMedium *pTmp = pMedium;
4614 while (pTmp)
4615 {
4616 uImage++;
4617 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4618 }
4619 /* Index of last image */
4620 uImage--;
4621
4622# ifdef VBOX_WITH_EXTPACK
4623 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4624 {
4625 /* Configure loading the VDPlugin. */
4626 static const char s_szVDPlugin[] = "VDPluginCrypt";
4627 PCFGMNODE pCfgPlugins = NULL;
4628 PCFGMNODE pCfgPlugin = NULL;
4629 Utf8Str strPlugin;
4630 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4631 // Don't fail, this is optional!
4632 if (SUCCEEDED(hrc))
4633 {
4634 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4635 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4636 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4637 }
4638 }
4639# endif
4640
4641 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4642 InsertConfigString(pCfg, "Path", bstr);
4643
4644 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4645 InsertConfigString(pCfg, "Format", bstr);
4646
4647 if (mediumType == MediumType_Readonly)
4648 InsertConfigInteger(pCfg, "ReadOnly", 1);
4649 else if (enmType == DeviceType_Floppy)
4650 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4651
4652 /* Start without exclusive write access to the images. */
4653 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4654 * we're resuming the VM if some 3rd dude have any of the VDIs open
4655 * with write sharing denied. However, if the two VMs are sharing a
4656 * image it really is necessary....
4657 *
4658 * So, on the "lock-media" command, the target teleporter should also
4659 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4660 * that. Grumble. */
4661 if ( enmType == DeviceType_HardDisk
4662 && ( aMachineState == MachineState_TeleportingIn
4663 || aMachineState == MachineState_FaultTolerantSyncing))
4664 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4665
4666 /* Flag for opening the medium for sharing between VMs. This
4667 * is done at the moment only for the first (and only) medium
4668 * in the chain, as shared media can have no diffs. */
4669 if (mediumType == MediumType_Shareable)
4670 InsertConfigInteger(pCfg, "Shareable", 1);
4671
4672 if (!fUseHostIOCache)
4673 {
4674 InsertConfigInteger(pCfg, "UseNewIo", 1);
4675 /*
4676 * Activate the builtin I/O cache for harddisks only.
4677 * It caches writes only which doesn't make sense for DVD drives
4678 * and just increases the overhead.
4679 */
4680 if ( fBuiltinIOCache
4681 && (enmType == DeviceType_HardDisk))
4682 InsertConfigInteger(pCfg, "BlockCache", 1);
4683 }
4684
4685 if (fSetupMerge)
4686 {
4687 InsertConfigInteger(pCfg, "SetupMerge", 1);
4688 if (uImage == uMergeSource)
4689 InsertConfigInteger(pCfg, "MergeSource", 1);
4690 else if (uImage == uMergeTarget)
4691 InsertConfigInteger(pCfg, "MergeTarget", 1);
4692 }
4693
4694 if (pcszBwGroup)
4695 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4696
4697 if (fDiscard)
4698 InsertConfigInteger(pCfg, "Discard", 1);
4699
4700 if (fNonRotational)
4701 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4702
4703 /* Pass all custom parameters. */
4704 bool fHostIP = true;
4705 bool fEncrypted = false;
4706 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4707
4708 /* Create an inverted list of parents. */
4709 uImage--;
4710 IMedium *pParentMedium = pMedium;
4711 for (PCFGMNODE pParent = pCfg;; uImage--)
4712 {
4713 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4714 if (!pMedium)
4715 break;
4716
4717 PCFGMNODE pCur;
4718 InsertConfigNode(pParent, "Parent", &pCur);
4719 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4720 InsertConfigString(pCur, "Path", bstr);
4721
4722 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4723 InsertConfigString(pCur, "Format", bstr);
4724
4725 if (fSetupMerge)
4726 {
4727 if (uImage == uMergeSource)
4728 InsertConfigInteger(pCur, "MergeSource", 1);
4729 else if (uImage == uMergeTarget)
4730 InsertConfigInteger(pCur, "MergeTarget", 1);
4731 }
4732
4733 /* Configure medium properties. */
4734 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4735
4736 /* next */
4737 pParent = pCur;
4738 pParentMedium = pMedium;
4739 }
4740
4741 /* Custom code: put marker to not use host IP stack to driver
4742 * configuration node. Simplifies life of DrvVD a bit. */
4743 if (!fHostIP)
4744 InsertConfigInteger(pCfg, "HostIPStack", 0);
4745
4746 if (fEncrypted)
4747 m_cDisksEncrypted++;
4748 }
4749 else
4750 {
4751 /* Set empty drive flag for DVD or floppy without media. */
4752 if ( enmType == DeviceType_DVD
4753 || enmType == DeviceType_Floppy)
4754 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4755 }
4756 }
4757#undef H
4758 }
4759 catch (ConfigError &x)
4760 {
4761 // InsertConfig threw something:
4762 return x.m_vrc;
4763 }
4764
4765 return VINF_SUCCESS;
4766}
4767
4768/**
4769 * Adds the medium properties to the CFGM tree.
4770 *
4771 * @returns VBox status code.
4772 * @param pCur The current CFGM node.
4773 * @param pMedium The medium object to configure.
4774 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4775 * @param pfEncrypted Where to return whether the medium is encrypted.
4776 */
4777int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4778{
4779 /* Pass all custom parameters. */
4780 SafeArray<BSTR> aNames;
4781 SafeArray<BSTR> aValues;
4782 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4783 ComSafeArrayAsOutParam(aValues));
4784
4785 if ( SUCCEEDED(hrc)
4786 && aNames.size() != 0)
4787 {
4788 PCFGMNODE pVDC;
4789 InsertConfigNode(pCur, "VDConfig", &pVDC);
4790 for (size_t ii = 0; ii < aNames.size(); ++ii)
4791 {
4792 if (aValues[ii] && *aValues[ii])
4793 {
4794 Utf8Str name = aNames[ii];
4795 Utf8Str value = aValues[ii];
4796 size_t offSlash = name.find("/", 0);
4797 if ( offSlash != name.npos
4798 && !name.startsWith("Special/"))
4799 {
4800 com::Utf8Str strFilter;
4801 com::Utf8Str strKey;
4802
4803 hrc = strFilter.assignEx(name, 0, offSlash);
4804 if (FAILED(hrc))
4805 break;
4806
4807 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4808 if (FAILED(hrc))
4809 break;
4810
4811 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4812 if (!pCfgFilterConfig)
4813 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4814
4815 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4816 }
4817 else
4818 {
4819 InsertConfigString(pVDC, name.c_str(), value);
4820 if ( name.compare("HostIPStack") == 0
4821 && value.compare("0") == 0)
4822 *pfHostIP = false;
4823 }
4824
4825 if ( name.compare("CRYPT/KeyId") == 0
4826 && pfEncrypted)
4827 *pfEncrypted = true;
4828 }
4829 }
4830 }
4831
4832 return hrc;
4833}
4834
4835
4836/**
4837 * Construct the Network configuration tree
4838 *
4839 * @returns VBox status code.
4840 *
4841 * @param pszDevice The PDM device name.
4842 * @param uInstance The PDM device instance.
4843 * @param uLun The PDM LUN number of the drive.
4844 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4845 * @param pCfg Configuration node for the device
4846 * @param pLunL0 To store the pointer to the LUN#0.
4847 * @param pInst The instance CFGM node
4848 * @param fAttachDetach To determine if the network attachment should
4849 * be attached/detached after/before
4850 * configuration.
4851 * @param fIgnoreConnectFailure
4852 * True if connection failures should be ignored
4853 * (makes only sense for bridged/host-only networks).
4854 *
4855 * @note Locks this object for writing.
4856 * @thread EMT
4857 */
4858int Console::i_configNetwork(const char *pszDevice,
4859 unsigned uInstance,
4860 unsigned uLun,
4861 INetworkAdapter *aNetworkAdapter,
4862 PCFGMNODE pCfg,
4863 PCFGMNODE pLunL0,
4864 PCFGMNODE pInst,
4865 bool fAttachDetach,
4866 bool fIgnoreConnectFailure)
4867{
4868 RT_NOREF(fIgnoreConnectFailure);
4869 AutoCaller autoCaller(this);
4870 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4871
4872 // InsertConfig* throws
4873 try
4874 {
4875 int rc = VINF_SUCCESS;
4876 HRESULT hrc;
4877 Bstr bstr;
4878
4879#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4880
4881 /*
4882 * Locking the object before doing VMR3* calls is quite safe here, since
4883 * we're on EMT. Write lock is necessary because we indirectly modify the
4884 * meAttachmentType member.
4885 */
4886 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4887
4888 ComPtr<IMachine> pMachine = i_machine();
4889
4890 ComPtr<IVirtualBox> virtualBox;
4891 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4892
4893 ComPtr<IHost> host;
4894 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4895
4896 BOOL fSniffer;
4897 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4898
4899 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4900 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4901 const char *pszPromiscuousGuestPolicy;
4902 switch (enmPromiscModePolicy)
4903 {
4904 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4905 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4906 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4907 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4908 }
4909
4910 if (fAttachDetach)
4911 {
4912 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4913 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4914 rc = VINF_SUCCESS;
4915 AssertLogRelRCReturn(rc, rc);
4916
4917 /* nuke anything which might have been left behind. */
4918 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4919 }
4920
4921#ifdef VBOX_WITH_NETSHAPER
4922 ComObjPtr<IBandwidthGroup> pBwGroup;
4923 Bstr strBwGroup;
4924 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4925
4926 if (!pBwGroup.isNull())
4927 {
4928 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4929 }
4930#endif /* VBOX_WITH_NETSHAPER */
4931
4932 Utf8Str strNetDriver;
4933
4934
4935 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4936
4937#ifdef VBOX_WITH_NETSHAPER
4938 if (!strBwGroup.isEmpty())
4939 {
4940 InsertConfigString(pLunL0, "Driver", "NetShaper");
4941 InsertConfigNode(pLunL0, "Config", &pCfg);
4942 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4943 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4944 }
4945#endif /* VBOX_WITH_NETSHAPER */
4946
4947 if (fSniffer)
4948 {
4949 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4950 InsertConfigNode(pLunL0, "Config", &pCfg);
4951 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4952 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4953 InsertConfigString(pCfg, "File", bstr);
4954 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4955 }
4956
4957
4958 Bstr networkName, trunkName, trunkType;
4959 NetworkAttachmentType_T eAttachmentType;
4960 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4961 switch (eAttachmentType)
4962 {
4963 case NetworkAttachmentType_Null:
4964 break;
4965
4966 case NetworkAttachmentType_NAT:
4967 {
4968 ComPtr<INATEngine> natEngine;
4969 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4970 InsertConfigString(pLunL0, "Driver", "NAT");
4971 InsertConfigNode(pLunL0, "Config", &pCfg);
4972
4973 /* Configure TFTP prefix and boot filename. */
4974 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4975 if (!bstr.isEmpty())
4976 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
4977 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
4978 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
4979
4980 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
4981 if (!bstr.isEmpty())
4982 InsertConfigString(pCfg, "Network", bstr);
4983 else
4984 {
4985 ULONG uSlot;
4986 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
4987 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
4988 }
4989 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
4990 if (!bstr.isEmpty())
4991 InsertConfigString(pCfg, "BindIP", bstr);
4992 ULONG mtu = 0;
4993 ULONG sockSnd = 0;
4994 ULONG sockRcv = 0;
4995 ULONG tcpSnd = 0;
4996 ULONG tcpRcv = 0;
4997 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
4998 if (mtu)
4999 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5000 if (sockRcv)
5001 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5002 if (sockSnd)
5003 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5004 if (tcpRcv)
5005 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5006 if (tcpSnd)
5007 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5008 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5009 if (!bstr.isEmpty())
5010 {
5011 RemoveConfigValue(pCfg, "TFTPPrefix");
5012 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5013 }
5014 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5015 if (!bstr.isEmpty())
5016 {
5017 RemoveConfigValue(pCfg, "BootFile");
5018 InsertConfigString(pCfg, "BootFile", bstr);
5019 }
5020 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5021 if (!bstr.isEmpty())
5022 InsertConfigString(pCfg, "NextServer", bstr);
5023 BOOL fDNSFlag;
5024 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5025 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5026 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5027 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5028 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5029 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5030
5031 ULONG aliasMode;
5032 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5033 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5034
5035 /* port-forwarding */
5036 SafeArray<BSTR> pfs;
5037 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5038
5039 PCFGMNODE pPFTree = NULL;
5040 if (pfs.size() > 0)
5041 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5042
5043 for (unsigned int i = 0; i < pfs.size(); ++i)
5044 {
5045 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5046
5047 uint16_t port = 0;
5048 BSTR r = pfs[i];
5049 Utf8Str utf = Utf8Str(r);
5050 Utf8Str strName;
5051 Utf8Str strProto;
5052 Utf8Str strHostPort;
5053 Utf8Str strHostIP;
5054 Utf8Str strGuestPort;
5055 Utf8Str strGuestIP;
5056 size_t pos, ppos;
5057 pos = ppos = 0;
5058#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5059 { \
5060 pos = str.find(",", ppos); \
5061 if (pos == Utf8Str::npos) \
5062 { \
5063 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5064 continue; \
5065 } \
5066 res = str.substr(ppos, pos - ppos); \
5067 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5068 ppos = pos + 1; \
5069 } /* no do { ... } while because of 'continue' */
5070 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5071 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5072 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5073 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5074 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5075 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5076#undef ITERATE_TO_NEXT_TERM
5077
5078 uint32_t proto = strProto.toUInt32();
5079 bool fValid = true;
5080 switch (proto)
5081 {
5082 case NATProtocol_UDP:
5083 strProto = "UDP";
5084 break;
5085 case NATProtocol_TCP:
5086 strProto = "TCP";
5087 break;
5088 default:
5089 fValid = false;
5090 }
5091 /* continue with next rule if no valid proto was passed */
5092 if (!fValid)
5093 continue;
5094
5095 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5096
5097 if (!strName.isEmpty())
5098 InsertConfigString(pPF, "Name", strName);
5099
5100 InsertConfigString(pPF, "Protocol", strProto);
5101
5102 if (!strHostIP.isEmpty())
5103 InsertConfigString(pPF, "BindIP", strHostIP);
5104
5105 if (!strGuestIP.isEmpty())
5106 InsertConfigString(pPF, "GuestIP", strGuestIP);
5107
5108 port = RTStrToUInt16(strHostPort.c_str());
5109 if (port)
5110 InsertConfigInteger(pPF, "HostPort", port);
5111
5112 port = RTStrToUInt16(strGuestPort.c_str());
5113 if (port)
5114 InsertConfigInteger(pPF, "GuestPort", port);
5115 }
5116 break;
5117 }
5118
5119 case NetworkAttachmentType_Bridged:
5120 {
5121#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5122 hrc = i_attachToTapInterface(aNetworkAdapter);
5123 if (FAILED(hrc))
5124 {
5125 switch (hrc)
5126 {
5127 case VERR_ACCESS_DENIED:
5128 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5129 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5130 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5131 "change the group of that node and make yourself a member of that group. Make "
5132 "sure that these changes are permanent, especially if you are "
5133 "using udev"));
5134 default:
5135 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5136 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5137 "Failed to initialize Host Interface Networking"));
5138 }
5139 }
5140
5141 Assert((intptr_t)maTapFD[uInstance] >= 0);
5142 if ((intptr_t)maTapFD[uInstance] >= 0)
5143 {
5144 InsertConfigString(pLunL0, "Driver", "HostInterface");
5145 InsertConfigNode(pLunL0, "Config", &pCfg);
5146 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5147 }
5148
5149#elif defined(VBOX_WITH_NETFLT)
5150 /*
5151 * This is the new VBoxNetFlt+IntNet stuff.
5152 */
5153 Bstr BridgedIfName;
5154 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5155 if (FAILED(hrc))
5156 {
5157 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5158 H();
5159 }
5160
5161 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5162 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5163
5164# if defined(RT_OS_DARWIN)
5165 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5166 char szTrunk[8];
5167 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5168 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5169// Quick fix for @bugref{5633}
5170// if (!pszColon)
5171// {
5172// /*
5173// * Dynamic changing of attachment causes an attempt to configure
5174// * network with invalid host adapter (as it is must be changed before
5175// * the attachment), calling Detach here will cause a deadlock.
5176// * See @bugref{4750}.
5177// * hrc = aNetworkAdapter->Detach(); H();
5178// */
5179// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5180// N_("Malformed host interface networking name '%ls'"),
5181// BridgedIfName.raw());
5182// }
5183 if (pszColon)
5184 *pszColon = '\0';
5185 const char *pszTrunk = szTrunk;
5186
5187# elif defined(RT_OS_SOLARIS)
5188 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5189 char szTrunk[256];
5190 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5191 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5192
5193 /*
5194 * Currently don't bother about malformed names here for the sake of people using
5195 * VBoxManage and setting only the NIC name from there. If there is a space we
5196 * chop it off and proceed, otherwise just use whatever we've got.
5197 */
5198 if (pszSpace)
5199 *pszSpace = '\0';
5200
5201 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5202 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5203 if (pszColon)
5204 *pszColon = '\0';
5205
5206 const char *pszTrunk = szTrunk;
5207
5208# elif defined(RT_OS_WINDOWS)
5209 ComPtr<IHostNetworkInterface> hostInterface;
5210 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5211 hostInterface.asOutParam());
5212 if (!SUCCEEDED(hrc))
5213 {
5214 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5215 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5216 N_("Nonexistent host networking interface, name '%ls'"),
5217 BridgedIfName.raw());
5218 }
5219
5220 HostNetworkInterfaceType_T eIfType;
5221 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5222 if (FAILED(hrc))
5223 {
5224 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5225 H();
5226 }
5227
5228 if (eIfType != HostNetworkInterfaceType_Bridged)
5229 {
5230 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5231 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5232 BridgedIfName.raw());
5233 }
5234
5235 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5236 if (FAILED(hrc))
5237 {
5238 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5239 H();
5240 }
5241 Guid hostIFGuid(bstr);
5242
5243 INetCfg *pNc;
5244 ComPtr<INetCfgComponent> pAdaptorComponent;
5245 LPWSTR pszApp;
5246
5247 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5248 Assert(hrc == S_OK);
5249 if (hrc != S_OK)
5250 {
5251 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5252 H();
5253 }
5254
5255 /* get the adapter's INetCfgComponent*/
5256 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5257 pAdaptorComponent.asOutParam());
5258 if (hrc != S_OK)
5259 {
5260 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5261 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5262 H();
5263 }
5264# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5265 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5266 char *pszTrunkName = szTrunkName;
5267 wchar_t * pswzBindName;
5268 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5269 Assert(hrc == S_OK);
5270 if (hrc == S_OK)
5271 {
5272 int cwBindName = (int)wcslen(pswzBindName) + 1;
5273 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5274 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5275 {
5276 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5277 pszTrunkName += cbFullBindNamePrefix-1;
5278 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5279 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5280 {
5281 DWORD err = GetLastError();
5282 hrc = HRESULT_FROM_WIN32(err);
5283 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5284 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5285 hrc, hrc, err));
5286 }
5287 }
5288 else
5289 {
5290 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5291 /** @todo set appropriate error code */
5292 hrc = E_FAIL;
5293 }
5294
5295 if (hrc != S_OK)
5296 {
5297 AssertFailed();
5298 CoTaskMemFree(pswzBindName);
5299 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5300 H();
5301 }
5302
5303 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5304 }
5305 else
5306 {
5307 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5308 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5309 hrc));
5310 H();
5311 }
5312
5313 const char *pszTrunk = szTrunkName;
5314 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5315
5316# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5317# if defined(RT_OS_FREEBSD)
5318 /*
5319 * If we bridge to a tap interface open it the `old' direct way.
5320 * This works and performs better than bridging a physical
5321 * interface via the current FreeBSD vboxnetflt implementation.
5322 */
5323 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5324 hrc = i_attachToTapInterface(aNetworkAdapter);
5325 if (FAILED(hrc))
5326 {
5327 switch (hrc)
5328 {
5329 case VERR_ACCESS_DENIED:
5330 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5331 "Failed to open '/dev/%s' for read/write access. Please check the "
5332 "permissions of that node, and that the net.link.tap.user_open "
5333 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5334 "change the group of that node to vboxusers and make yourself "
5335 "a member of that group. Make sure that these changes are permanent."),
5336 pszBridgedIfName, pszBridgedIfName);
5337 default:
5338 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5339 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5340 "Failed to initialize Host Interface Networking"));
5341 }
5342 }
5343
5344 Assert((intptr_t)maTapFD[uInstance] >= 0);
5345 if ((intptr_t)maTapFD[uInstance] >= 0)
5346 {
5347 InsertConfigString(pLunL0, "Driver", "HostInterface");
5348 InsertConfigNode(pLunL0, "Config", &pCfg);
5349 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5350 }
5351 break;
5352 }
5353# endif
5354 /** @todo Check for malformed names. */
5355 const char *pszTrunk = pszBridgedIfName;
5356
5357 /* Issue a warning if the interface is down */
5358 {
5359 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5360 if (iSock >= 0)
5361 {
5362 struct ifreq Req;
5363 RT_ZERO(Req);
5364 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5365 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5366 if ((Req.ifr_flags & IFF_UP) == 0)
5367 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5368 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5369 pszBridgedIfName);
5370
5371 close(iSock);
5372 }
5373 }
5374
5375# else
5376# error "PORTME (VBOX_WITH_NETFLT)"
5377# endif
5378
5379 InsertConfigString(pLunL0, "Driver", "IntNet");
5380 InsertConfigNode(pLunL0, "Config", &pCfg);
5381 InsertConfigString(pCfg, "Trunk", pszTrunk);
5382 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5383 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5384 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5385 char szNetwork[INTNET_MAX_NETWORK_NAME];
5386
5387# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5388 /*
5389 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5390 * interface name + optional description. We must not pass any description to the VM as it can differ
5391 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5392 */
5393 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5394# else
5395 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5396# endif
5397 InsertConfigString(pCfg, "Network", szNetwork);
5398 networkName = Bstr(szNetwork);
5399 trunkName = Bstr(pszTrunk);
5400 trunkType = Bstr(TRUNKTYPE_NETFLT);
5401
5402# if defined(RT_OS_DARWIN)
5403 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
5404 if ( strstr(pszBridgedIfName, "Wireless")
5405 || strstr(pszBridgedIfName, "AirPort" ))
5406 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5407# elif defined(RT_OS_LINUX)
5408 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5409 if (iSock >= 0)
5410 {
5411 struct iwreq WRq;
5412
5413 RT_ZERO(WRq);
5414 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
5415 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
5416 close(iSock);
5417 if (fSharedMacOnWire)
5418 {
5419 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5420 Log(("Set SharedMacOnWire\n"));
5421 }
5422 else
5423 Log(("Failed to get wireless name\n"));
5424 }
5425 else
5426 Log(("Failed to open wireless socket\n"));
5427# elif defined(RT_OS_FREEBSD)
5428 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5429 if (iSock >= 0)
5430 {
5431 struct ieee80211req WReq;
5432 uint8_t abData[32];
5433
5434 RT_ZERO(WReq);
5435 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
5436 WReq.i_type = IEEE80211_IOC_SSID;
5437 WReq.i_val = -1;
5438 WReq.i_data = abData;
5439 WReq.i_len = sizeof(abData);
5440
5441 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
5442 close(iSock);
5443 if (fSharedMacOnWire)
5444 {
5445 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5446 Log(("Set SharedMacOnWire\n"));
5447 }
5448 else
5449 Log(("Failed to get wireless name\n"));
5450 }
5451 else
5452 Log(("Failed to open wireless socket\n"));
5453# elif defined(RT_OS_WINDOWS)
5454# define DEVNAME_PREFIX L"\\\\.\\"
5455 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
5456 * there is a pretty long way till there though since we need to obtain the symbolic link name
5457 * for the adapter device we are going to query given the device Guid */
5458
5459
5460 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
5461
5462 wchar_t FileName[MAX_PATH];
5463 wcscpy(FileName, DEVNAME_PREFIX);
5464 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
5465
5466 /* open the device */
5467 HANDLE hDevice = CreateFile(FileName,
5468 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5469 NULL,
5470 OPEN_EXISTING,
5471 FILE_ATTRIBUTE_NORMAL,
5472 NULL);
5473
5474 if (hDevice != INVALID_HANDLE_VALUE)
5475 {
5476 bool fSharedMacOnWire = false;
5477
5478 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
5479 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
5480 NDIS_PHYSICAL_MEDIUM PhMedium;
5481 DWORD cbResult;
5482 if (DeviceIoControl(hDevice,
5483 IOCTL_NDIS_QUERY_GLOBAL_STATS,
5484 &Oid,
5485 sizeof(Oid),
5486 &PhMedium,
5487 sizeof(PhMedium),
5488 &cbResult,
5489 NULL))
5490 {
5491 /* that was simple, now examine PhMedium */
5492 if ( PhMedium == NdisPhysicalMediumWirelessWan
5493 || PhMedium == NdisPhysicalMediumWirelessLan
5494 || PhMedium == NdisPhysicalMediumNative802_11
5495 || PhMedium == NdisPhysicalMediumBluetooth)
5496 fSharedMacOnWire = true;
5497 }
5498 else
5499 {
5500 int winEr = GetLastError();
5501 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
5502 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
5503 }
5504 CloseHandle(hDevice);
5505
5506 if (fSharedMacOnWire)
5507 {
5508 Log(("this is a wireless adapter"));
5509 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5510 Log(("Set SharedMacOnWire\n"));
5511 }
5512 else
5513 Log(("this is NOT a wireless adapter"));
5514 }
5515 else
5516 {
5517 int winEr = GetLastError();
5518 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
5519 }
5520
5521 CoTaskMemFree(pswzBindName);
5522
5523 pAdaptorComponent.setNull();
5524 /* release the pNc finally */
5525 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5526# else
5527 /** @todo PORTME: wireless detection */
5528# endif
5529
5530# if defined(RT_OS_SOLARIS)
5531# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5532 /* Zone access restriction, don't allow snooping the global zone. */
5533 zoneid_t ZoneId = getzoneid();
5534 if (ZoneId != GLOBAL_ZONEID)
5535 {
5536 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5537 }
5538# endif
5539# endif
5540
5541#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5542 /* NOTHING TO DO HERE */
5543#elif defined(RT_OS_LINUX)
5544/// @todo aleksey: is there anything to be done here?
5545#elif defined(RT_OS_FREEBSD)
5546/** @todo FreeBSD: Check out this later (HIF networking). */
5547#else
5548# error "Port me"
5549#endif
5550 break;
5551 }
5552
5553 case NetworkAttachmentType_Internal:
5554 {
5555 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5556 if (!bstr.isEmpty())
5557 {
5558 InsertConfigString(pLunL0, "Driver", "IntNet");
5559 InsertConfigNode(pLunL0, "Config", &pCfg);
5560 InsertConfigString(pCfg, "Network", bstr);
5561 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5562 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5563 networkName = bstr;
5564 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5565 }
5566 break;
5567 }
5568
5569 case NetworkAttachmentType_HostOnly:
5570 {
5571 InsertConfigString(pLunL0, "Driver", "IntNet");
5572 InsertConfigNode(pLunL0, "Config", &pCfg);
5573
5574 Bstr HostOnlyName;
5575 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5576 if (FAILED(hrc))
5577 {
5578 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5579 H();
5580 }
5581
5582 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5583 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5584 ComPtr<IHostNetworkInterface> hostInterface;
5585 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5586 hostInterface.asOutParam());
5587 if (!SUCCEEDED(rc))
5588 {
5589 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5590 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5591 N_("Nonexistent host networking interface, name '%ls'"),
5592 HostOnlyName.raw());
5593 }
5594
5595 char szNetwork[INTNET_MAX_NETWORK_NAME];
5596 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5597
5598#if defined(RT_OS_WINDOWS)
5599# ifndef VBOX_WITH_NETFLT
5600 hrc = E_NOTIMPL;
5601 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5602 H();
5603# else /* defined VBOX_WITH_NETFLT*/
5604 /** @todo r=bird: Put this in a function. */
5605
5606 HostNetworkInterfaceType_T eIfType;
5607 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5608 if (FAILED(hrc))
5609 {
5610 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5611 H();
5612 }
5613
5614 if (eIfType != HostNetworkInterfaceType_HostOnly)
5615 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5616 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5617 HostOnlyName.raw());
5618
5619 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5620 if (FAILED(hrc))
5621 {
5622 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5623 H();
5624 }
5625 Guid hostIFGuid(bstr);
5626
5627 INetCfg *pNc;
5628 ComPtr<INetCfgComponent> pAdaptorComponent;
5629 LPWSTR pszApp;
5630 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5631 Assert(hrc == S_OK);
5632 if (hrc != S_OK)
5633 {
5634 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5635 H();
5636 }
5637
5638 /* get the adapter's INetCfgComponent*/
5639 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5640 pAdaptorComponent.asOutParam());
5641 if (hrc != S_OK)
5642 {
5643 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5644 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5645 H();
5646 }
5647# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5648 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5649 bool fNdis6 = false;
5650 wchar_t * pwszHelpText;
5651 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5652 Assert(hrc == S_OK);
5653 if (hrc == S_OK)
5654 {
5655 Log(("help-text=%ls\n", pwszHelpText));
5656 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5657 fNdis6 = true;
5658 CoTaskMemFree(pwszHelpText);
5659 }
5660 if (fNdis6)
5661 {
5662 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5663 Log(("trunk=%s\n", szTrunkName));
5664 }
5665 else
5666 {
5667 char *pszTrunkName = szTrunkName;
5668 wchar_t * pswzBindName;
5669 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5670 Assert(hrc == S_OK);
5671 if (hrc == S_OK)
5672 {
5673 int cwBindName = (int)wcslen(pswzBindName) + 1;
5674 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5675 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5676 {
5677 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5678 pszTrunkName += cbFullBindNamePrefix-1;
5679 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5680 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5681 {
5682 DWORD err = GetLastError();
5683 hrc = HRESULT_FROM_WIN32(err);
5684 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5685 hrc, hrc, err));
5686 }
5687 }
5688 else
5689 {
5690 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5691 /** @todo set appropriate error code */
5692 hrc = E_FAIL;
5693 }
5694
5695 if (hrc != S_OK)
5696 {
5697 AssertFailed();
5698 CoTaskMemFree(pswzBindName);
5699 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5700 H();
5701 }
5702 }
5703 else
5704 {
5705 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5706 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5707 hrc, hrc));
5708 H();
5709 }
5710
5711
5712 CoTaskMemFree(pswzBindName);
5713 }
5714
5715 trunkType = TRUNKTYPE_NETADP;
5716 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5717
5718 pAdaptorComponent.setNull();
5719 /* release the pNc finally */
5720 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5721
5722 const char *pszTrunk = szTrunkName;
5723
5724 InsertConfigString(pCfg, "Trunk", pszTrunk);
5725 InsertConfigString(pCfg, "Network", szNetwork);
5726 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5727 windows only?? */
5728 networkName = Bstr(szNetwork);
5729 trunkName = Bstr(pszTrunk);
5730# endif /* defined VBOX_WITH_NETFLT*/
5731#elif defined(RT_OS_DARWIN)
5732 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5733 InsertConfigString(pCfg, "Network", szNetwork);
5734 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5735 networkName = Bstr(szNetwork);
5736 trunkName = Bstr(pszHostOnlyName);
5737 trunkType = TRUNKTYPE_NETADP;
5738#else
5739 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5740 InsertConfigString(pCfg, "Network", szNetwork);
5741 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5742 networkName = Bstr(szNetwork);
5743 trunkName = Bstr(pszHostOnlyName);
5744 trunkType = TRUNKTYPE_NETFLT;
5745#endif
5746 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5747
5748#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5749
5750 Bstr tmpAddr, tmpMask;
5751
5752 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5753 pszHostOnlyName).raw(),
5754 tmpAddr.asOutParam());
5755 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5756 {
5757 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5758 pszHostOnlyName).raw(),
5759 tmpMask.asOutParam());
5760 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5761 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5762 tmpMask.raw());
5763 else
5764 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5765 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5766 }
5767 else
5768 {
5769 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5770 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5771 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5772 }
5773
5774 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5775
5776 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5777 pszHostOnlyName).raw(),
5778 tmpAddr.asOutParam());
5779 if (SUCCEEDED(hrc))
5780 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5781 tmpMask.asOutParam());
5782 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5783 {
5784 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5785 Utf8Str(tmpMask).toUInt32());
5786 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5787 }
5788#endif
5789 break;
5790 }
5791
5792 case NetworkAttachmentType_Generic:
5793 {
5794 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5795 SafeArray<BSTR> names;
5796 SafeArray<BSTR> values;
5797 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5798 ComSafeArrayAsOutParam(names),
5799 ComSafeArrayAsOutParam(values)); H();
5800
5801 InsertConfigString(pLunL0, "Driver", bstr);
5802 InsertConfigNode(pLunL0, "Config", &pCfg);
5803 for (size_t ii = 0; ii < names.size(); ++ii)
5804 {
5805 if (values[ii] && *values[ii])
5806 {
5807 Utf8Str name = names[ii];
5808 Utf8Str value = values[ii];
5809 InsertConfigString(pCfg, name.c_str(), value);
5810 }
5811 }
5812 break;
5813 }
5814
5815 case NetworkAttachmentType_NATNetwork:
5816 {
5817 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5818 if (!bstr.isEmpty())
5819 {
5820 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5821 InsertConfigString(pLunL0, "Driver", "IntNet");
5822 InsertConfigNode(pLunL0, "Config", &pCfg);
5823 InsertConfigString(pCfg, "Network", bstr);
5824 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5825 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5826 networkName = bstr;
5827 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5828 }
5829 break;
5830 }
5831
5832 default:
5833 AssertMsgFailed(("should not get here!\n"));
5834 break;
5835 }
5836
5837 /*
5838 * Attempt to attach the driver.
5839 */
5840 switch (eAttachmentType)
5841 {
5842 case NetworkAttachmentType_Null:
5843 break;
5844
5845 case NetworkAttachmentType_Bridged:
5846 case NetworkAttachmentType_Internal:
5847 case NetworkAttachmentType_HostOnly:
5848 case NetworkAttachmentType_NAT:
5849 case NetworkAttachmentType_Generic:
5850 case NetworkAttachmentType_NATNetwork:
5851 {
5852 if (SUCCEEDED(hrc) && SUCCEEDED(rc))
5853 {
5854 if (fAttachDetach)
5855 {
5856 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5857 //AssertRC(rc);
5858 }
5859
5860 {
5861 /** @todo pritesh: get the dhcp server name from the
5862 * previous network configuration and then stop the server
5863 * else it may conflict with the dhcp server running with
5864 * the current attachment type
5865 */
5866 /* Stop the hostonly DHCP Server */
5867 }
5868
5869 /*
5870 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5871 */
5872 if ( !networkName.isEmpty()
5873 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5874 {
5875 /*
5876 * Until we implement service reference counters DHCP Server will be stopped
5877 * by DHCPServerRunner destructor.
5878 */
5879 ComPtr<IDHCPServer> dhcpServer;
5880 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5881 dhcpServer.asOutParam());
5882 if (SUCCEEDED(hrc))
5883 {
5884 /* there is a DHCP server available for this network */
5885 BOOL fEnabledDhcp;
5886 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5887 if (FAILED(hrc))
5888 {
5889 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5890 H();
5891 }
5892
5893 if (fEnabledDhcp)
5894 hrc = dhcpServer->Start(networkName.raw(),
5895 trunkName.raw(),
5896 trunkType.raw());
5897 }
5898 else
5899 hrc = S_OK;
5900 }
5901 }
5902
5903 break;
5904 }
5905
5906 default:
5907 AssertMsgFailed(("should not get here!\n"));
5908 break;
5909 }
5910
5911 meAttachmentType[uInstance] = eAttachmentType;
5912 }
5913 catch (ConfigError &x)
5914 {
5915 // InsertConfig threw something:
5916 return x.m_vrc;
5917 }
5918
5919#undef H
5920
5921 return VINF_SUCCESS;
5922}
5923
5924#ifdef VBOX_WITH_GUEST_PROPS
5925/**
5926 * Set an array of guest properties
5927 */
5928static void configSetProperties(VMMDev * const pVMMDev,
5929 void *names,
5930 void *values,
5931 void *timestamps,
5932 void *flags)
5933{
5934 VBOXHGCMSVCPARM parms[4];
5935
5936 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5937 parms[0].u.pointer.addr = names;
5938 parms[0].u.pointer.size = 0; /* We don't actually care. */
5939 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5940 parms[1].u.pointer.addr = values;
5941 parms[1].u.pointer.size = 0; /* We don't actually care. */
5942 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5943 parms[2].u.pointer.addr = timestamps;
5944 parms[2].u.pointer.size = 0; /* We don't actually care. */
5945 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5946 parms[3].u.pointer.addr = flags;
5947 parms[3].u.pointer.size = 0; /* We don't actually care. */
5948
5949 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5950 guestProp::SET_PROPS_HOST,
5951 4,
5952 &parms[0]);
5953}
5954
5955/**
5956 * Set a single guest property
5957 */
5958static void configSetProperty(VMMDev * const pVMMDev,
5959 const char *pszName,
5960 const char *pszValue,
5961 const char *pszFlags)
5962{
5963 VBOXHGCMSVCPARM parms[4];
5964
5965 AssertPtrReturnVoid(pszName);
5966 AssertPtrReturnVoid(pszValue);
5967 AssertPtrReturnVoid(pszFlags);
5968 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5969 parms[0].u.pointer.addr = (void *)pszName;
5970 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5971 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5972 parms[1].u.pointer.addr = (void *)pszValue;
5973 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5974 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5975 parms[2].u.pointer.addr = (void *)pszFlags;
5976 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
5977 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
5978 &parms[0]);
5979}
5980
5981/**
5982 * Set the global flags value by calling the service
5983 * @returns the status returned by the call to the service
5984 *
5985 * @param pTable the service instance handle
5986 * @param eFlags the flags to set
5987 */
5988int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
5989 guestProp::ePropFlags eFlags)
5990{
5991 VBOXHGCMSVCPARM paParm;
5992 paParm.setUInt32(eFlags);
5993 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5994 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
5995 &paParm);
5996 if (RT_FAILURE(rc))
5997 {
5998 char szFlags[guestProp::MAX_FLAGS_LEN];
5999 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
6000 Log(("Failed to set the global flags.\n"));
6001 else
6002 Log(("Failed to set the global flags \"%s\".\n", szFlags));
6003 }
6004 return rc;
6005}
6006#endif /* VBOX_WITH_GUEST_PROPS */
6007
6008/**
6009 * Set up the Guest Property service, populate it with properties read from
6010 * the machine XML and set a couple of initial properties.
6011 */
6012/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
6013{
6014#ifdef VBOX_WITH_GUEST_PROPS
6015 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6016 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6017 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
6018
6019 /* Load the service */
6020 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
6021
6022 if (RT_FAILURE(rc))
6023 {
6024 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
6025 /* That is not a fatal failure. */
6026 rc = VINF_SUCCESS;
6027 }
6028 else
6029 {
6030 /*
6031 * Initialize built-in properties that can be changed and saved.
6032 *
6033 * These are typically transient properties that the guest cannot
6034 * change.
6035 */
6036
6037 {
6038 VBOXHGCMSVCPARM Params[2];
6039 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
6040 if (RT_SUCCESS(rc2))
6041 {
6042 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
6043 void *pService = (void*)Params[1].u.pointer.addr;
6044 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
6045 }
6046 }
6047
6048 /* Sysprep execution by VBoxService. */
6049 configSetProperty(pConsole->m_pVMMDev,
6050 "/VirtualBox/HostGuest/SysprepExec", "",
6051 "TRANSIENT, RDONLYGUEST");
6052 configSetProperty(pConsole->m_pVMMDev,
6053 "/VirtualBox/HostGuest/SysprepArgs", "",
6054 "TRANSIENT, RDONLYGUEST");
6055
6056 /*
6057 * Pull over the properties from the server.
6058 */
6059 SafeArray<BSTR> namesOut;
6060 SafeArray<BSTR> valuesOut;
6061 SafeArray<LONG64> timestampsOut;
6062 SafeArray<BSTR> flagsOut;
6063 HRESULT hrc;
6064 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
6065 ComSafeArrayAsOutParam(valuesOut),
6066 ComSafeArrayAsOutParam(timestampsOut),
6067 ComSafeArrayAsOutParam(flagsOut));
6068 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6069 size_t cProps = namesOut.size();
6070 size_t cAlloc = cProps + 1;
6071 if ( valuesOut.size() != cProps
6072 || timestampsOut.size() != cProps
6073 || flagsOut.size() != cProps
6074 )
6075 AssertFailedReturn(VERR_INVALID_PARAMETER);
6076
6077 char **papszNames, **papszValues, **papszFlags;
6078 char szEmpty[] = "";
6079 LONG64 *pai64Timestamps;
6080 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6081 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6082 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
6083 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6084 if (papszNames && papszValues && pai64Timestamps && papszFlags)
6085 {
6086 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
6087 {
6088 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
6089 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
6090 if (RT_FAILURE(rc))
6091 break;
6092 if (valuesOut[i])
6093 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6094 else
6095 papszValues[i] = szEmpty;
6096 if (RT_FAILURE(rc))
6097 break;
6098 pai64Timestamps[i] = timestampsOut[i];
6099 if (flagsOut[i])
6100 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6101 else
6102 papszFlags[i] = szEmpty;
6103 }
6104 if (RT_SUCCESS(rc))
6105 configSetProperties(pConsole->m_pVMMDev,
6106 (void *)papszNames,
6107 (void *)papszValues,
6108 (void *)pai64Timestamps,
6109 (void *)papszFlags);
6110 for (unsigned i = 0; i < cProps; ++i)
6111 {
6112 RTStrFree(papszNames[i]);
6113 if (valuesOut[i])
6114 RTStrFree(papszValues[i]);
6115 if (flagsOut[i])
6116 RTStrFree(papszFlags[i]);
6117 }
6118 }
6119 else
6120 rc = VERR_NO_MEMORY;
6121 RTMemTmpFree(papszNames);
6122 RTMemTmpFree(papszValues);
6123 RTMemTmpFree(pai64Timestamps);
6124 RTMemTmpFree(papszFlags);
6125 AssertRCReturn(rc, rc);
6126
6127 /*
6128 * These properties have to be set before pulling over the properties
6129 * from the machine XML, to ensure that properties saved in the XML
6130 * will override them.
6131 */
6132 /* Set the raw VBox version string as a guest property. Used for host/guest
6133 * version comparison. */
6134 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6135 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6136 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6137 * information/branding and/or pre-release tags. */
6138 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6139 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6140 /* Set the VBox SVN revision as a guest property */
6141 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6142 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6143
6144 /*
6145 * Register the host notification callback
6146 */
6147 HGCMSVCEXTHANDLE hDummy;
6148 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6149 Console::i_doGuestPropNotification,
6150 pvConsole);
6151
6152#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6153 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
6154 guestProp::RDONLYGUEST);
6155 AssertRCReturn(rc, rc);
6156#endif
6157
6158 Log(("Set VBoxGuestPropSvc property store\n"));
6159 }
6160 return VINF_SUCCESS;
6161#else /* !VBOX_WITH_GUEST_PROPS */
6162 return VERR_NOT_SUPPORTED;
6163#endif /* !VBOX_WITH_GUEST_PROPS */
6164}
6165
6166/**
6167 * Set up the Guest Control service.
6168 */
6169/* static */ int Console::i_configGuestControl(void *pvConsole)
6170{
6171#ifdef VBOX_WITH_GUEST_CONTROL
6172 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6173 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6174
6175 /* Load the service */
6176 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6177
6178 if (RT_FAILURE(rc))
6179 {
6180 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6181 /* That is not a fatal failure. */
6182 rc = VINF_SUCCESS;
6183 }
6184 else
6185 {
6186 HGCMSVCEXTHANDLE hDummy;
6187 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6188 &Guest::i_notifyCtrlDispatcher,
6189 pConsole->i_getGuest());
6190 if (RT_FAILURE(rc))
6191 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6192 else
6193 LogRel(("Guest Control service loaded\n"));
6194 }
6195
6196 return rc;
6197#else /* !VBOX_WITH_GUEST_CONTROL */
6198 return VERR_NOT_SUPPORTED;
6199#endif /* !VBOX_WITH_GUEST_CONTROL */
6200}
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