VirtualBox

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

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

gcc 7: fall thru

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 254.4 KB
Line 
1/* $Id: ConsoleImpl2.cpp 65919 2017-03-01 18:24:27Z 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 if (fEnablePAE || fIsGuest64Bit)
3227 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3228 }
3229 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3230 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3231 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3232
3233 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3234 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3235
3236 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3237 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3238
3239 if (auSerialIoPortBase[2])
3240 {
3241 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3242 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3243 }
3244
3245 if (auSerialIoPortBase[3])
3246 {
3247 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3248 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3249 }
3250
3251 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3252 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3253
3254 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3255 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3256
3257 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3258 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3259 InsertConfigNode(pLunL0, "Config", &pCfg);
3260
3261 /* Attach the dummy CPU drivers */
3262 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3263 {
3264 BOOL fCpuAttached = true;
3265
3266 if (fCpuHotPlug)
3267 {
3268 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3269 }
3270
3271 if (fCpuAttached)
3272 {
3273 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3274 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3275 InsertConfigNode(pLunL0, "Config", &pCfg);
3276 }
3277 }
3278 }
3279
3280 /*
3281 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3282 */
3283 {
3284 PCFGMNODE pDbgf;
3285 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3286
3287 /* Paths to search for debug info and such things. */
3288 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3289 Utf8Str strSettingsPath(bstr);
3290 bstr.setNull();
3291 strSettingsPath.stripFilename();
3292 strSettingsPath.append("/");
3293
3294 char szHomeDir[RTPATH_MAX + 1];
3295 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3296 if (RT_FAILURE(rc2))
3297 szHomeDir[0] = '\0';
3298 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3299
3300
3301 Utf8Str strPath;
3302 strPath.append(strSettingsPath).append("debug/;");
3303 strPath.append(strSettingsPath).append(";");
3304 strPath.append(szHomeDir);
3305
3306 InsertConfigString(pDbgf, "Path", strPath.c_str());
3307
3308 /* Tracing configuration. */
3309 BOOL fTracingEnabled;
3310 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3311 if (fTracingEnabled)
3312 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3313
3314 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3315 if (fTracingEnabled)
3316 InsertConfigString(pDbgf, "TracingConfig", bstr);
3317
3318 BOOL fAllowTracingToAccessVM;
3319 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3320 if (fAllowTracingToAccessVM)
3321 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3322
3323 /* Debugger console config. */
3324 PCFGMNODE pDbgc;
3325 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3326
3327 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3328 Utf8Str strVBoxHome = bstr;
3329 bstr.setNull();
3330 if (strVBoxHome.isNotEmpty())
3331 strVBoxHome.append("/");
3332 else
3333 {
3334 strVBoxHome = szHomeDir;
3335 strVBoxHome.append("/.vbox");
3336 }
3337
3338 Utf8Str strFile(strVBoxHome);
3339 strFile.append("dbgc-history");
3340 InsertConfigString(pDbgc, "HistoryFile", strFile);
3341
3342 strFile = strSettingsPath;
3343 strFile.append("dbgc-init");
3344 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3345
3346 strFile = strVBoxHome;
3347 strFile.append("dbgc-init");
3348 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3349 }
3350 }
3351 catch (ConfigError &x)
3352 {
3353 // InsertConfig threw something:
3354 return x.m_vrc;
3355 }
3356 catch (HRESULT hrcXcpt)
3357 {
3358 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3359 }
3360
3361#ifdef VBOX_WITH_EXTPACK
3362 /*
3363 * Call the extension pack hooks if everything went well thus far.
3364 */
3365 if (RT_SUCCESS(rc))
3366 {
3367 pAlock->release();
3368 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3369 pAlock->acquire();
3370 }
3371#endif
3372
3373 /*
3374 * Apply the CFGM overlay.
3375 */
3376 if (RT_SUCCESS(rc))
3377 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3378
3379 /*
3380 * Dump all extradata API settings tweaks, both global and per VM.
3381 */
3382 if (RT_SUCCESS(rc))
3383 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3384
3385#undef H
3386
3387 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3388
3389 /*
3390 * Register VM state change handler.
3391 */
3392 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3393 AssertRC(rc2);
3394 if (RT_SUCCESS(rc))
3395 rc = rc2;
3396
3397 /*
3398 * Register VM runtime error handler.
3399 */
3400 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3401 AssertRC(rc2);
3402 if (RT_SUCCESS(rc))
3403 rc = rc2;
3404
3405 pAlock->acquire();
3406
3407 LogFlowFunc(("vrc = %Rrc\n", rc));
3408 LogFlowFuncLeave();
3409
3410 return rc;
3411}
3412
3413/**
3414 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3415 * values.
3416 *
3417 * @returns VBox status code.
3418 * @param pRoot The root of the configuration tree.
3419 * @param pVirtualBox Pointer to the IVirtualBox interface.
3420 * @param pMachine Pointer to the IMachine interface.
3421 */
3422/* static */
3423int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3424{
3425 /*
3426 * CFGM overlay handling.
3427 *
3428 * Here we check the extra data entries for CFGM values
3429 * and create the nodes and insert the values on the fly. Existing
3430 * values will be removed and reinserted. CFGM is typed, so by default
3431 * we will guess whether it's a string or an integer (byte arrays are
3432 * not currently supported). It's possible to override this autodetection
3433 * by adding "string:", "integer:" or "bytes:" (future).
3434 *
3435 * We first perform a run on global extra data, then on the machine
3436 * extra data to support global settings with local overrides.
3437 */
3438 int rc = VINF_SUCCESS;
3439 try
3440 {
3441 /** @todo add support for removing nodes and byte blobs. */
3442 /*
3443 * Get the next key
3444 */
3445 SafeArray<BSTR> aGlobalExtraDataKeys;
3446 SafeArray<BSTR> aMachineExtraDataKeys;
3447 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3448 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3449
3450 // remember the no. of global values so we can call the correct method below
3451 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3452
3453 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3454 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3455
3456 // build a combined list from global keys...
3457 std::list<Utf8Str> llExtraDataKeys;
3458
3459 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3460 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3461 // ... and machine keys
3462 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3463 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3464
3465 size_t i2 = 0;
3466 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3467 it != llExtraDataKeys.end();
3468 ++it, ++i2)
3469 {
3470 const Utf8Str &strKey = *it;
3471
3472 /*
3473 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3474 */
3475 if (!strKey.startsWith("VBoxInternal/"))
3476 continue;
3477
3478 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3479
3480 // get the value
3481 Bstr bstrExtraDataValue;
3482 if (i2 < cGlobalValues)
3483 // this is still one of the global values:
3484 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3485 bstrExtraDataValue.asOutParam());
3486 else
3487 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3488 bstrExtraDataValue.asOutParam());
3489 if (FAILED(hrc))
3490 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3491
3492 /*
3493 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3494 * Split the two and get the node, delete the value and create the node
3495 * if necessary.
3496 */
3497 PCFGMNODE pNode;
3498 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3499 if (pszCFGMValueName)
3500 {
3501 /* terminate the node and advance to the value (Utf8Str might not
3502 offically like this but wtf) */
3503 *(char*)pszCFGMValueName = '\0';
3504 ++pszCFGMValueName;
3505
3506 /* does the node already exist? */
3507 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3508 if (pNode)
3509 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3510 else
3511 {
3512 /* create the node */
3513 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3514 if (RT_FAILURE(rc))
3515 {
3516 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3517 continue;
3518 }
3519 Assert(pNode);
3520 }
3521 }
3522 else
3523 {
3524 /* root value (no node path). */
3525 pNode = pRoot;
3526 pszCFGMValueName = pszExtraDataKey;
3527 pszExtraDataKey--;
3528 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3529 }
3530
3531 /*
3532 * Now let's have a look at the value.
3533 * Empty strings means that we should remove the value, which we've
3534 * already done above.
3535 */
3536 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3537 if (!strCFGMValueUtf8.isEmpty())
3538 {
3539 uint64_t u64Value;
3540
3541 /* check for type prefix first. */
3542 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3543 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3544 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3545 {
3546 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3547 if (RT_SUCCESS(rc))
3548 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3549 }
3550 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3551 {
3552 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3553 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3554 if (cbValue > 0)
3555 {
3556 void *pvBytes = RTMemTmpAlloc(cbValue);
3557 if (pvBytes)
3558 {
3559 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3560 if (RT_SUCCESS(rc))
3561 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3562 RTMemTmpFree(pvBytes);
3563 }
3564 else
3565 rc = VERR_NO_TMP_MEMORY;
3566 }
3567 else if (cbValue == 0)
3568 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3569 else
3570 rc = VERR_INVALID_BASE64_ENCODING;
3571 }
3572 /* auto detect type. */
3573 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3574 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3575 else
3576 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3577 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3578 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3579 }
3580 }
3581 }
3582 catch (ConfigError &x)
3583 {
3584 // InsertConfig threw something:
3585 return x.m_vrc;
3586 }
3587 return rc;
3588}
3589
3590/**
3591 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3592 * values.
3593 *
3594 * @returns VBox status code.
3595 * @param pVirtualBox Pointer to the IVirtualBox interface.
3596 * @param pMachine Pointer to the IMachine interface.
3597 */
3598/* static */
3599int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3600{
3601 {
3602 SafeArray<BSTR> aGlobalExtraDataKeys;
3603 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3604 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3605 bool hasKey = false;
3606 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3607 {
3608 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3609 if (!strKey.startsWith("VBoxInternal2/"))
3610 continue;
3611
3612 Bstr bstrValue;
3613 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3614 bstrValue.asOutParam());
3615 if (FAILED(hrc))
3616 continue;
3617 if (!hasKey)
3618 LogRel(("Global extradata API settings:\n"));
3619 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3620 hasKey = true;
3621 }
3622 }
3623
3624 {
3625 SafeArray<BSTR> aMachineExtraDataKeys;
3626 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3627 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3628 bool hasKey = false;
3629 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3630 {
3631 Utf8Str strKey(aMachineExtraDataKeys[i]);
3632 if (!strKey.startsWith("VBoxInternal2/"))
3633 continue;
3634
3635 Bstr bstrValue;
3636 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3637 bstrValue.asOutParam());
3638 if (FAILED(hrc))
3639 continue;
3640 if (!hasKey)
3641 LogRel(("Per-VM extradata API settings:\n"));
3642 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3643 hasKey = true;
3644 }
3645 }
3646
3647 return VINF_SUCCESS;
3648}
3649
3650int Console::i_configGraphicsController(PCFGMNODE pDevices,
3651 const GraphicsControllerType_T enmGraphicsController,
3652 BusAssignmentManager *pBusMgr,
3653 const ComPtr<IMachine> &ptrMachine,
3654 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3655 bool fHMEnabled)
3656{
3657 // InsertConfig* throws
3658 try
3659 {
3660 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3661 HRESULT hrc;
3662 Bstr bstr;
3663 const char *pcszDevice = "vga";
3664
3665#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3666 InsertConfigNode(pDevices, pcszDevice, &pDev);
3667 InsertConfigNode(pDev, "0", &pInst);
3668 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3669
3670 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3671 InsertConfigNode(pInst, "Config", &pCfg);
3672 ULONG cVRamMBs;
3673 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3674 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3675 ULONG cMonitorCount;
3676 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3677 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3678#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3679 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3680#else
3681 NOREF(fHMEnabled);
3682#endif
3683
3684 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3685
3686#ifdef VBOX_WITH_VMSVGA
3687 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3688 {
3689 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3690#ifdef VBOX_WITH_VMSVGA3D
3691 IFramebuffer *pFramebuffer = NULL;
3692 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3693 if (SUCCEEDED(hrc) && pFramebuffer)
3694 {
3695 LONG64 winId = 0;
3696 /** @todo deal with multimonitor setup */
3697 Assert(cMonitorCount == 1);
3698 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3699 InsertConfigInteger(pCfg, "HostWindowId", winId);
3700 pFramebuffer->Release();
3701 }
3702 BOOL f3DEnabled;
3703 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3704 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3705#else
3706 LogRel(("VMSVGA3d not available in this build!\n"));
3707#endif
3708 }
3709#endif
3710
3711 /* Custom VESA mode list */
3712 unsigned cModes = 0;
3713 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3714 {
3715 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3716 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3717 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3718 if (bstr.isEmpty())
3719 break;
3720 InsertConfigString(pCfg, szExtraDataKey, bstr);
3721 ++cModes;
3722 }
3723 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3724
3725 /* VESA height reduction */
3726 ULONG ulHeightReduction;
3727 IFramebuffer *pFramebuffer = NULL;
3728 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3729 if (SUCCEEDED(hrc) && pFramebuffer)
3730 {
3731 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3732 pFramebuffer->Release();
3733 pFramebuffer = NULL;
3734 }
3735 else
3736 {
3737 /* If framebuffer is not available, there is no height reduction. */
3738 ulHeightReduction = 0;
3739 }
3740 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3741
3742 /*
3743 * BIOS logo
3744 */
3745 BOOL fFadeIn;
3746 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3747 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3748 BOOL fFadeOut;
3749 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3750 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3751 ULONG logoDisplayTime;
3752 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3753 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3754 Bstr logoImagePath;
3755 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3756 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3757
3758 /*
3759 * Boot menu
3760 */
3761 BIOSBootMenuMode_T eBootMenuMode;
3762 int iShowBootMenu;
3763 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3764 switch (eBootMenuMode)
3765 {
3766 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3767 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3768 default: iShowBootMenu = 2; break;
3769 }
3770 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3771
3772 /* Attach the display. */
3773 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3774 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3775 InsertConfigNode(pLunL0, "Config", &pCfg);
3776 Display *pDisplay = mDisplay;
3777 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3778 }
3779 catch (ConfigError &x)
3780 {
3781 // InsertConfig threw something:
3782 return x.m_vrc;
3783 }
3784
3785#undef H
3786
3787 return VINF_SUCCESS;
3788}
3789
3790
3791/**
3792 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3793 */
3794void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3795{
3796 va_list va;
3797 va_start(va, pszFormat);
3798 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3799 va_end(va);
3800}
3801
3802/* XXX introduce RT format specifier */
3803static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3804{
3805 if (u64Size > INT64_C(5000)*_1G)
3806 {
3807 *pszUnit = "TB";
3808 return u64Size / _1T;
3809 }
3810 else if (u64Size > INT64_C(5000)*_1M)
3811 {
3812 *pszUnit = "GB";
3813 return u64Size / _1G;
3814 }
3815 else
3816 {
3817 *pszUnit = "MB";
3818 return u64Size / _1M;
3819 }
3820}
3821
3822/**
3823 * Checks the location of the given medium for known bugs affecting the usage
3824 * of the host I/O cache setting.
3825 *
3826 * @returns VBox status code.
3827 * @param pMedium The medium to check.
3828 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3829 */
3830int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3831{
3832#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3833 /*
3834 * Some sanity checks.
3835 */
3836 RT_NOREF(pfUseHostIOCache);
3837 ComPtr<IMediumFormat> pMediumFormat;
3838 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3839 ULONG uCaps = 0;
3840 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3841 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3842
3843 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3844 uCaps |= mediumFormatCap[j];
3845
3846 if (uCaps & MediumFormatCapabilities_File)
3847 {
3848 Bstr strFile;
3849 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3850 Utf8Str utfFile = Utf8Str(strFile);
3851 Bstr strSnap;
3852 ComPtr<IMachine> pMachine = i_machine();
3853 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3854 Utf8Str utfSnap = Utf8Str(strSnap);
3855 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3856 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3857 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3858 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3859 /* Ignore the error code. On error, the file system type is still 'unknown' so
3860 * none of the following paths are taken. This can happen for new VMs which
3861 * still don't have a snapshot folder. */
3862 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3863 if (!mfSnapshotFolderDiskTypeShown)
3864 {
3865 LogRel(("File system of '%s' (snapshots) is %s\n",
3866 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3867 mfSnapshotFolderDiskTypeShown = true;
3868 }
3869 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3870 LONG64 i64Size;
3871 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3872#ifdef RT_OS_WINDOWS
3873 if ( enmFsTypeFile == RTFSTYPE_FAT
3874 && i64Size >= _4G)
3875 {
3876 const char *pszUnit;
3877 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3878 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3879 N_("The medium '%ls' has a logical size of %RU64%s "
3880 "but the file system the medium is located on seems "
3881 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3882 "We strongly recommend to put all your virtual disk images and "
3883 "the snapshot folder onto an NTFS partition"),
3884 strFile.raw(), u64Print, pszUnit);
3885 }
3886#else /* !RT_OS_WINDOWS */
3887 if ( enmFsTypeFile == RTFSTYPE_FAT
3888 || enmFsTypeFile == RTFSTYPE_EXT
3889 || enmFsTypeFile == RTFSTYPE_EXT2
3890 || enmFsTypeFile == RTFSTYPE_EXT3
3891 || enmFsTypeFile == RTFSTYPE_EXT4)
3892 {
3893 RTFILE file;
3894 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3895 if (RT_SUCCESS(rc))
3896 {
3897 RTFOFF maxSize;
3898 /* Careful: This function will work only on selected local file systems! */
3899 rc = RTFileGetMaxSizeEx(file, &maxSize);
3900 RTFileClose(file);
3901 if ( RT_SUCCESS(rc)
3902 && maxSize > 0
3903 && i64Size > (LONG64)maxSize)
3904 {
3905 const char *pszUnitSiz;
3906 const char *pszUnitMax;
3907 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3908 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3909 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3910 N_("The medium '%ls' has a logical size of %RU64%s "
3911 "but the file system the medium is located on can "
3912 "only handle files up to %RU64%s in theory.\n"
3913 "We strongly recommend to put all your virtual disk "
3914 "images and the snapshot folder onto a proper "
3915 "file system (e.g. ext3) with a sufficient size"),
3916 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3917 }
3918 }
3919 }
3920#endif /* !RT_OS_WINDOWS */
3921
3922 /*
3923 * Snapshot folder:
3924 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3925 */
3926 if ( enmFsTypeSnap == RTFSTYPE_FAT
3927 && i64Size >= _4G
3928 && !mfSnapshotFolderSizeWarningShown)
3929 {
3930 const char *pszUnit;
3931 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3932 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3933#ifdef RT_OS_WINDOWS
3934 N_("The snapshot folder of this VM '%ls' seems to be located on "
3935 "a FAT(32) file system. The logical size of the medium '%ls' "
3936 "(%RU64%s) is bigger than the maximum file size this file "
3937 "system can handle (4GB).\n"
3938 "We strongly recommend to put all your virtual disk images and "
3939 "the snapshot folder onto an NTFS partition"),
3940#else
3941 N_("The snapshot folder of this VM '%ls' seems to be located on "
3942 "a FAT(32) file system. The logical size of the medium '%ls' "
3943 "(%RU64%s) is bigger than the maximum file size this file "
3944 "system can handle (4GB).\n"
3945 "We strongly recommend to put all your virtual disk images and "
3946 "the snapshot folder onto a proper file system (e.g. ext3)"),
3947#endif
3948 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3949 /* Show this particular warning only once */
3950 mfSnapshotFolderSizeWarningShown = true;
3951 }
3952
3953#ifdef RT_OS_LINUX
3954 /*
3955 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3956 * on an ext4 partition.
3957 * This bug apparently applies to the XFS file system as well.
3958 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3959 */
3960
3961 char szOsRelease[128];
3962 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3963 bool fKernelHasODirectBug = RT_FAILURE(rc)
3964 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3965
3966 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3967 && !*pfUseHostIOCache
3968 && fKernelHasODirectBug)
3969 {
3970 if ( enmFsTypeFile == RTFSTYPE_EXT4
3971 || enmFsTypeFile == RTFSTYPE_XFS)
3972 {
3973 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3974 N_("The host I/O cache for at least one controller is disabled "
3975 "and the medium '%ls' for this VM "
3976 "is located on an %s partition. There is a known Linux "
3977 "kernel bug which can lead to the corruption of the virtual "
3978 "disk image under these conditions.\n"
3979 "Either enable the host I/O cache permanently in the VM "
3980 "settings or put the disk image and the snapshot folder "
3981 "onto a different file system.\n"
3982 "The host I/O cache will now be enabled for this medium"),
3983 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3984 *pfUseHostIOCache = true;
3985 }
3986 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
3987 || enmFsTypeSnap == RTFSTYPE_XFS)
3988 && !mfSnapshotFolderExt4WarningShown)
3989 {
3990 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3991 N_("The host I/O cache for at least one controller is disabled "
3992 "and the snapshot folder for this VM "
3993 "is located on an %s partition. There is a known Linux "
3994 "kernel bug which can lead to the corruption of the virtual "
3995 "disk image under these conditions.\n"
3996 "Either enable the host I/O cache permanently in the VM "
3997 "settings or put the disk image and the snapshot folder "
3998 "onto a different file system.\n"
3999 "The host I/O cache will now be enabled for this medium"),
4000 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4001 *pfUseHostIOCache = true;
4002 mfSnapshotFolderExt4WarningShown = true;
4003 }
4004 }
4005
4006 /*
4007 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4008 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4009 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4010 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4011 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4012 */
4013 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4014 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4015 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4016 && !*pfUseHostIOCache
4017 && fKernelAsyncUnreliable)
4018 {
4019 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4020 N_("The host I/O cache for at least one controller is disabled. "
4021 "There is a known Linux kernel bug which can lead to kernel "
4022 "oopses under heavy load. To our knowledge this bug affects "
4023 "all 2.6.18 kernels.\n"
4024 "Either enable the host I/O cache permanently in the VM "
4025 "settings or switch to a newer host kernel.\n"
4026 "The host I/O cache will now be enabled for this medium"));
4027 *pfUseHostIOCache = true;
4028 }
4029#endif
4030 }
4031#undef H
4032
4033 return VINF_SUCCESS;
4034}
4035
4036/**
4037 * Unmounts the specified medium from the specified device.
4038 *
4039 * @returns VBox status code.
4040 * @param pUVM The usermode VM handle.
4041 * @param enmBus The storage bus.
4042 * @param enmDevType The device type.
4043 * @param pcszDevice The device emulation.
4044 * @param uInstance Instance of the device.
4045 * @param uLUN The LUN on the device.
4046 * @param fForceUnmount Whether to force unmounting.
4047 */
4048int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4049 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4050 bool fForceUnmount)
4051{
4052 /* Unmount existing media only for floppy and DVD drives. */
4053 int rc = VINF_SUCCESS;
4054 PPDMIBASE pBase;
4055 if (enmBus == StorageBus_USB)
4056 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4057 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4058 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4059 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4060 else /* IDE or Floppy */
4061 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4062
4063 if (RT_FAILURE(rc))
4064 {
4065 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4066 rc = VINF_SUCCESS;
4067 AssertRC(rc);
4068 }
4069 else
4070 {
4071 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4072 AssertReturn(pIMount, VERR_INVALID_POINTER);
4073
4074 /* Unmount the media (but do not eject the medium!) */
4075 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4076 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4077 rc = VINF_SUCCESS;
4078 /* for example if the medium is locked */
4079 else if (RT_FAILURE(rc))
4080 return rc;
4081 }
4082
4083 return rc;
4084}
4085
4086/**
4087 * Removes the currently attached medium driver form the specified device
4088 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4089 *
4090 * @returns VBox status code.
4091 * @param pCtlInst The controler instance node in the CFGM tree.
4092 * @param pcszDevice The device name.
4093 * @param uInstance The device instance.
4094 * @param uLUN The device LUN.
4095 * @param enmBus The storage bus.
4096 * @param fAttachDetach Flag whether this is a change while the VM is running
4097 * @param fHotplug Flag whether the guest should be notified about the device change.
4098 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4099 * @param pUVM The usermode VM handle.
4100 * @param enmDevType The device type.
4101 * @param ppLunL0 Where to store the node to attach the new config to on success.
4102 */
4103int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4104 const char *pcszDevice,
4105 unsigned uInstance,
4106 unsigned uLUN,
4107 StorageBus_T enmBus,
4108 bool fAttachDetach,
4109 bool fHotplug,
4110 bool fForceUnmount,
4111 PUVM pUVM,
4112 DeviceType_T enmDevType,
4113 PCFGMNODE *ppLunL0)
4114{
4115 int rc = VINF_SUCCESS;
4116 bool fAddLun = false;
4117
4118 /* First check if the LUN already exists. */
4119 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4120 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4121
4122 if (pLunL0)
4123 {
4124 /*
4125 * Unmount the currently mounted medium if we don't just hot remove the
4126 * complete device (SATA) and it supports unmounting (DVD).
4127 */
4128 if ( (enmDevType != DeviceType_HardDisk)
4129 && !fHotplug)
4130 {
4131 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4132 uInstance, uLUN, fForceUnmount);
4133 if (RT_FAILURE(rc))
4134 return rc;
4135 }
4136
4137 /*
4138 * Don't detach the SCSI driver when unmounting the current medium
4139 * (we are not ripping out the device but only eject the medium).
4140 */
4141 char *pszDriverDetach = NULL;
4142 if ( !fHotplug
4143 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4144 || enmBus == StorageBus_SAS
4145 || enmBus == StorageBus_SCSI
4146 || enmBus == StorageBus_USB))
4147 {
4148 /* Get the current attached driver we have to detach. */
4149 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4150 if (pDrvLun)
4151 {
4152 char szDriver[128];
4153 RT_ZERO(szDriver);
4154 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4155 if (RT_SUCCESS(rc))
4156 pszDriverDetach = RTStrDup(&szDriver[0]);
4157
4158 pLunL0 = pDrvLun;
4159 }
4160 }
4161
4162 if (enmBus == StorageBus_USB)
4163 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4164 pszDriverDetach, 0 /* iOccurence */,
4165 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4166 else
4167 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4168 pszDriverDetach, 0 /* iOccurence */,
4169 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4170
4171 if (pszDriverDetach)
4172 {
4173 RTStrFree(pszDriverDetach);
4174 /* Remove the complete node and create new for the new config. */
4175 CFGMR3RemoveNode(pLunL0);
4176 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4177 if (pLunL0)
4178 {
4179 try
4180 {
4181 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4182 }
4183 catch (ConfigError &x)
4184 {
4185 // InsertConfig threw something:
4186 return x.m_vrc;
4187 }
4188 }
4189 }
4190 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4191 rc = VINF_SUCCESS;
4192 AssertRCReturn(rc, rc);
4193
4194 /*
4195 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4196 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4197 */
4198 if ( fHotplug
4199 || enmBus == StorageBus_IDE
4200 || enmBus == StorageBus_Floppy
4201 || enmBus == StorageBus_PCIe
4202 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4203 {
4204 fAddLun = true;
4205 CFGMR3RemoveNode(pLunL0);
4206 }
4207 }
4208 else
4209 fAddLun = true;
4210
4211 try
4212 {
4213 if (fAddLun)
4214 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4215 }
4216 catch (ConfigError &x)
4217 {
4218 // InsertConfig threw something:
4219 return x.m_vrc;
4220 }
4221
4222 if (ppLunL0)
4223 *ppLunL0 = pLunL0;
4224
4225 return rc;
4226}
4227
4228int Console::i_configMediumAttachment(const char *pcszDevice,
4229 unsigned uInstance,
4230 StorageBus_T enmBus,
4231 bool fUseHostIOCache,
4232 bool fBuiltinIOCache,
4233 bool fInsertDiskIntegrityDrv,
4234 bool fSetupMerge,
4235 unsigned uMergeSource,
4236 unsigned uMergeTarget,
4237 IMediumAttachment *pMediumAtt,
4238 MachineState_T aMachineState,
4239 HRESULT *phrc,
4240 bool fAttachDetach,
4241 bool fForceUnmount,
4242 bool fHotplug,
4243 PUVM pUVM,
4244 DeviceType_T *paLedDevType,
4245 PCFGMNODE *ppLunL0)
4246{
4247 // InsertConfig* throws
4248 try
4249 {
4250 int rc = VINF_SUCCESS;
4251 HRESULT hrc;
4252 Bstr bstr;
4253 PCFGMNODE pCtlInst = NULL;
4254
4255// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4256#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4257
4258 LONG lDev;
4259 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4260 LONG lPort;
4261 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4262 DeviceType_T lType;
4263 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4264 BOOL fNonRotational;
4265 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4266 BOOL fDiscard;
4267 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4268
4269 unsigned uLUN;
4270 PCFGMNODE pLunL0 = NULL;
4271 hrc = Console::i_convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4272
4273 /* Determine the base path for the device instance. */
4274 if (enmBus != StorageBus_USB)
4275 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4276 else
4277 {
4278 /* If we hotplug a USB device create a new CFGM tree. */
4279 if (!fHotplug)
4280 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4281 else
4282 pCtlInst = CFGMR3CreateTree(pUVM);
4283 }
4284 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4285
4286 if (enmBus == StorageBus_USB)
4287 {
4288 PCFGMNODE pCfg = NULL;
4289
4290 /* Create correct instance. */
4291 if (!fHotplug)
4292 {
4293 if (!fAttachDetach)
4294 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4295 else
4296 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4297 }
4298
4299 if (!fAttachDetach)
4300 InsertConfigNode(pCtlInst, "Config", &pCfg);
4301
4302 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4303
4304 if (!fHotplug && !fAttachDetach)
4305 {
4306 char aszUuid[RTUUID_STR_LENGTH + 1];
4307 USBStorageDevice UsbMsd = USBStorageDevice();
4308
4309 memset(aszUuid, 0, sizeof(aszUuid));
4310 rc = RTUuidCreate(&UsbMsd.mUuid);
4311 AssertRCReturn(rc, rc);
4312 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4313 AssertRCReturn(rc, rc);
4314
4315 UsbMsd.iPort = uInstance;
4316
4317 InsertConfigString(pCtlInst, "UUID", aszUuid);
4318 mUSBStorageDevices.push_back(UsbMsd);
4319
4320 /** @todo No LED after hotplugging. */
4321 /* Attach the status driver */
4322 Assert(cLedUsb >= 8);
4323 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4324 &mapMediumAttachments, pcszDevice, 0);
4325 paLedDevType = &maStorageDevType[iLedUsb];
4326 }
4327 }
4328
4329 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4330 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4331 if (RT_FAILURE(rc))
4332 return rc;
4333 if (ppLunL0)
4334 *ppLunL0 = pLunL0;
4335
4336 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4337 mapMediumAttachments[devicePath] = pMediumAtt;
4338
4339 ComPtr<IMedium> pMedium;
4340 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4341
4342 /*
4343 * 1. Only check this for hard disk images.
4344 * 2. Only check during VM creation and not later, especially not during
4345 * taking an online snapshot!
4346 */
4347 if ( lType == DeviceType_HardDisk
4348 && ( aMachineState == MachineState_Starting
4349 || aMachineState == MachineState_Restoring))
4350 {
4351 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4352 if (RT_FAILURE(rc))
4353 return rc;
4354 }
4355
4356 if (pMedium)
4357 {
4358 BOOL fHostDrive;
4359 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4360 if ( ( lType == DeviceType_DVD
4361 || lType == DeviceType_Floppy)
4362 && !fHostDrive)
4363 {
4364 /*
4365 * Informative logging.
4366 */
4367 Bstr strFile;
4368 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4369 Utf8Str utfFile = Utf8Str(strFile);
4370 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4371 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4372 LogRel(("File system of '%s' (%s) is %s\n",
4373 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4374 RTFsTypeName(enmFsTypeFile)));
4375 }
4376 }
4377
4378 BOOL fPassthrough;
4379 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4380
4381 ComObjPtr<IBandwidthGroup> pBwGroup;
4382 Bstr strBwGroup;
4383 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4384
4385 if (!pBwGroup.isNull())
4386 {
4387 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4388 }
4389
4390 /*
4391 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4392 * or for SATA if the new device is a CD/DVD drive.
4393 */
4394 if ( (fHotplug || !fAttachDetach)
4395 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4396 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4397 {
4398 InsertConfigString(pLunL0, "Driver", "SCSI");
4399 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4400 }
4401
4402 rc = i_configMedium(pLunL0,
4403 !!fPassthrough,
4404 lType,
4405 fUseHostIOCache,
4406 fBuiltinIOCache,
4407 fInsertDiskIntegrityDrv,
4408 fSetupMerge,
4409 uMergeSource,
4410 uMergeTarget,
4411 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4412 !!fDiscard,
4413 !!fNonRotational,
4414 pMedium,
4415 aMachineState,
4416 phrc);
4417 if (RT_FAILURE(rc))
4418 return rc;
4419
4420 if (fAttachDetach)
4421 {
4422 /* Attach the new driver. */
4423 if (enmBus == StorageBus_USB)
4424 {
4425 if (fHotplug)
4426 {
4427 USBStorageDevice UsbMsd = USBStorageDevice();
4428 RTUuidCreate(&UsbMsd.mUuid);
4429 UsbMsd.iPort = uInstance;
4430 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4431 if (RT_SUCCESS(rc))
4432 mUSBStorageDevices.push_back(UsbMsd);
4433 }
4434 else
4435 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4436 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4437 }
4438 else if ( !fHotplug
4439 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4440 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4441 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4442 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4443 else
4444 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4445 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4446 AssertRCReturn(rc, rc);
4447
4448 /*
4449 * Make the secret key helper interface known to the VD driver if it is attached,
4450 * so we can get notified about missing keys.
4451 */
4452 PPDMIBASE pIBase = NULL;
4453 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4454 if (RT_SUCCESS(rc) && pIBase)
4455 {
4456 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4457 if (pIMedium)
4458 {
4459 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4460 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4461 }
4462 }
4463
4464 /* There is no need to handle removable medium mounting, as we
4465 * unconditionally replace everthing including the block driver level.
4466 * This means the new medium will be picked up automatically. */
4467 }
4468
4469 if (paLedDevType)
4470 paLedDevType[uLUN] = lType;
4471
4472 /* Dump the changed LUN if possible, dump the complete device otherwise */
4473 if ( aMachineState != MachineState_Starting
4474 && aMachineState != MachineState_Restoring)
4475 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4476 }
4477 catch (ConfigError &x)
4478 {
4479 // InsertConfig threw something:
4480 return x.m_vrc;
4481 }
4482
4483#undef H
4484
4485 return VINF_SUCCESS;
4486}
4487
4488int Console::i_configMedium(PCFGMNODE pLunL0,
4489 bool fPassthrough,
4490 DeviceType_T enmType,
4491 bool fUseHostIOCache,
4492 bool fBuiltinIOCache,
4493 bool fInsertDiskIntegrityDrv,
4494 bool fSetupMerge,
4495 unsigned uMergeSource,
4496 unsigned uMergeTarget,
4497 const char *pcszBwGroup,
4498 bool fDiscard,
4499 bool fNonRotational,
4500 IMedium *pMedium,
4501 MachineState_T aMachineState,
4502 HRESULT *phrc)
4503{
4504 // InsertConfig* throws
4505 try
4506 {
4507 HRESULT hrc;
4508 Bstr bstr;
4509 PCFGMNODE pCfg = NULL;
4510
4511#define H() \
4512 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4513
4514
4515 BOOL fHostDrive = FALSE;
4516 MediumType_T mediumType = MediumType_Normal;
4517 if (pMedium)
4518 {
4519 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4520 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4521 }
4522
4523 if (fHostDrive)
4524 {
4525 Assert(pMedium);
4526 if (enmType == DeviceType_DVD)
4527 {
4528 InsertConfigString(pLunL0, "Driver", "HostDVD");
4529 InsertConfigNode(pLunL0, "Config", &pCfg);
4530
4531 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4532 InsertConfigString(pCfg, "Path", bstr);
4533
4534 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4535 }
4536 else if (enmType == DeviceType_Floppy)
4537 {
4538 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4539 InsertConfigNode(pLunL0, "Config", &pCfg);
4540
4541 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4542 InsertConfigString(pCfg, "Path", bstr);
4543 }
4544 }
4545 else
4546 {
4547 if (fInsertDiskIntegrityDrv)
4548 {
4549 /*
4550 * The actual configuration is done through CFGM extra data
4551 * for each inserted driver separately.
4552 */
4553 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4554 InsertConfigNode(pLunL0, "Config", &pCfg);
4555 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4556 }
4557
4558 InsertConfigString(pLunL0, "Driver", "VD");
4559 InsertConfigNode(pLunL0, "Config", &pCfg);
4560 switch (enmType)
4561 {
4562 case DeviceType_DVD:
4563 InsertConfigString(pCfg, "Type", "DVD");
4564 InsertConfigInteger(pCfg, "Mountable", 1);
4565 break;
4566 case DeviceType_Floppy:
4567 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4568 InsertConfigInteger(pCfg, "Mountable", 1);
4569 break;
4570 case DeviceType_HardDisk:
4571 default:
4572 InsertConfigString(pCfg, "Type", "HardDisk");
4573 InsertConfigInteger(pCfg, "Mountable", 0);
4574 }
4575
4576 if ( pMedium
4577 && ( enmType == DeviceType_DVD
4578 || enmType == DeviceType_Floppy)
4579 )
4580 {
4581 // if this medium represents an ISO image and this image is inaccessible,
4582 // the ignore it instead of causing a failure; this can happen when we
4583 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4584 // Additions were mounted and the user upgraded VirtualBox. Previously
4585 // we failed on startup, but that's not good because the only way out then
4586 // would be to discard the VM state...
4587 MediumState_T mediumState;
4588 hrc = pMedium->RefreshState(&mediumState); H();
4589 if (mediumState == MediumState_Inaccessible)
4590 {
4591 Bstr loc;
4592 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4593 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4594 "The image file '%ls' is inaccessible and is being ignored. "
4595 "Please select a different image file for the virtual %s drive.",
4596 loc.raw(),
4597 enmType == DeviceType_DVD ? "DVD" : "floppy");
4598 pMedium = NULL;
4599 }
4600 }
4601
4602 if (pMedium)
4603 {
4604 /* Start with length of parent chain, as the list is reversed */
4605 unsigned uImage = 0;
4606 IMedium *pTmp = pMedium;
4607 while (pTmp)
4608 {
4609 uImage++;
4610 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4611 }
4612 /* Index of last image */
4613 uImage--;
4614
4615# ifdef VBOX_WITH_EXTPACK
4616 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4617 {
4618 /* Configure loading the VDPlugin. */
4619 static const char s_szVDPlugin[] = "VDPluginCrypt";
4620 PCFGMNODE pCfgPlugins = NULL;
4621 PCFGMNODE pCfgPlugin = NULL;
4622 Utf8Str strPlugin;
4623 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4624 // Don't fail, this is optional!
4625 if (SUCCEEDED(hrc))
4626 {
4627 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4628 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4629 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4630 }
4631 }
4632# endif
4633
4634 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4635 InsertConfigString(pCfg, "Path", bstr);
4636
4637 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4638 InsertConfigString(pCfg, "Format", bstr);
4639
4640 if (mediumType == MediumType_Readonly)
4641 InsertConfigInteger(pCfg, "ReadOnly", 1);
4642 else if (enmType == DeviceType_Floppy)
4643 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4644
4645 /* Start without exclusive write access to the images. */
4646 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4647 * we're resuming the VM if some 3rd dude have any of the VDIs open
4648 * with write sharing denied. However, if the two VMs are sharing a
4649 * image it really is necessary....
4650 *
4651 * So, on the "lock-media" command, the target teleporter should also
4652 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4653 * that. Grumble. */
4654 if ( enmType == DeviceType_HardDisk
4655 && ( aMachineState == MachineState_TeleportingIn
4656 || aMachineState == MachineState_FaultTolerantSyncing))
4657 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4658
4659 /* Flag for opening the medium for sharing between VMs. This
4660 * is done at the moment only for the first (and only) medium
4661 * in the chain, as shared media can have no diffs. */
4662 if (mediumType == MediumType_Shareable)
4663 InsertConfigInteger(pCfg, "Shareable", 1);
4664
4665 if (!fUseHostIOCache)
4666 {
4667 InsertConfigInteger(pCfg, "UseNewIo", 1);
4668 /*
4669 * Activate the builtin I/O cache for harddisks only.
4670 * It caches writes only which doesn't make sense for DVD drives
4671 * and just increases the overhead.
4672 */
4673 if ( fBuiltinIOCache
4674 && (enmType == DeviceType_HardDisk))
4675 InsertConfigInteger(pCfg, "BlockCache", 1);
4676 }
4677
4678 if (fSetupMerge)
4679 {
4680 InsertConfigInteger(pCfg, "SetupMerge", 1);
4681 if (uImage == uMergeSource)
4682 InsertConfigInteger(pCfg, "MergeSource", 1);
4683 else if (uImage == uMergeTarget)
4684 InsertConfigInteger(pCfg, "MergeTarget", 1);
4685 }
4686
4687 if (pcszBwGroup)
4688 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4689
4690 if (fDiscard)
4691 InsertConfigInteger(pCfg, "Discard", 1);
4692
4693 if (fNonRotational)
4694 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4695
4696 /* Pass all custom parameters. */
4697 bool fHostIP = true;
4698 bool fEncrypted = false;
4699 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4700
4701 /* Create an inverted list of parents. */
4702 uImage--;
4703 IMedium *pParentMedium = pMedium;
4704 for (PCFGMNODE pParent = pCfg;; uImage--)
4705 {
4706 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4707 if (!pMedium)
4708 break;
4709
4710 PCFGMNODE pCur;
4711 InsertConfigNode(pParent, "Parent", &pCur);
4712 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4713 InsertConfigString(pCur, "Path", bstr);
4714
4715 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4716 InsertConfigString(pCur, "Format", bstr);
4717
4718 if (fSetupMerge)
4719 {
4720 if (uImage == uMergeSource)
4721 InsertConfigInteger(pCur, "MergeSource", 1);
4722 else if (uImage == uMergeTarget)
4723 InsertConfigInteger(pCur, "MergeTarget", 1);
4724 }
4725
4726 /* Configure medium properties. */
4727 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4728
4729 /* next */
4730 pParent = pCur;
4731 pParentMedium = pMedium;
4732 }
4733
4734 /* Custom code: put marker to not use host IP stack to driver
4735 * configuration node. Simplifies life of DrvVD a bit. */
4736 if (!fHostIP)
4737 InsertConfigInteger(pCfg, "HostIPStack", 0);
4738
4739 if (fEncrypted)
4740 m_cDisksEncrypted++;
4741 }
4742 else
4743 {
4744 /* Set empty drive flag for DVD or floppy without media. */
4745 if ( enmType == DeviceType_DVD
4746 || enmType == DeviceType_Floppy)
4747 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4748 }
4749 }
4750#undef H
4751 }
4752 catch (ConfigError &x)
4753 {
4754 // InsertConfig threw something:
4755 return x.m_vrc;
4756 }
4757
4758 return VINF_SUCCESS;
4759}
4760
4761/**
4762 * Adds the medium properties to the CFGM tree.
4763 *
4764 * @returns VBox status code.
4765 * @param pCur The current CFGM node.
4766 * @param pMedium The medium object to configure.
4767 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4768 * @param pfEncrypted Where to return whether the medium is encrypted.
4769 */
4770int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4771{
4772 /* Pass all custom parameters. */
4773 SafeArray<BSTR> aNames;
4774 SafeArray<BSTR> aValues;
4775 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4776 ComSafeArrayAsOutParam(aValues));
4777
4778 if ( SUCCEEDED(hrc)
4779 && aNames.size() != 0)
4780 {
4781 PCFGMNODE pVDC;
4782 InsertConfigNode(pCur, "VDConfig", &pVDC);
4783 for (size_t ii = 0; ii < aNames.size(); ++ii)
4784 {
4785 if (aValues[ii] && *aValues[ii])
4786 {
4787 Utf8Str name = aNames[ii];
4788 Utf8Str value = aValues[ii];
4789 size_t offSlash = name.find("/", 0);
4790 if ( offSlash != name.npos
4791 && !name.startsWith("Special/"))
4792 {
4793 com::Utf8Str strFilter;
4794 com::Utf8Str strKey;
4795
4796 hrc = strFilter.assignEx(name, 0, offSlash);
4797 if (FAILED(hrc))
4798 break;
4799
4800 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4801 if (FAILED(hrc))
4802 break;
4803
4804 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4805 if (!pCfgFilterConfig)
4806 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4807
4808 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4809 }
4810 else
4811 {
4812 InsertConfigString(pVDC, name.c_str(), value);
4813 if ( name.compare("HostIPStack") == 0
4814 && value.compare("0") == 0)
4815 *pfHostIP = false;
4816 }
4817
4818 if ( name.compare("CRYPT/KeyId") == 0
4819 && pfEncrypted)
4820 *pfEncrypted = true;
4821 }
4822 }
4823 }
4824
4825 return hrc;
4826}
4827
4828
4829/**
4830 * Construct the Network configuration tree
4831 *
4832 * @returns VBox status code.
4833 *
4834 * @param pszDevice The PDM device name.
4835 * @param uInstance The PDM device instance.
4836 * @param uLun The PDM LUN number of the drive.
4837 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4838 * @param pCfg Configuration node for the device
4839 * @param pLunL0 To store the pointer to the LUN#0.
4840 * @param pInst The instance CFGM node
4841 * @param fAttachDetach To determine if the network attachment should
4842 * be attached/detached after/before
4843 * configuration.
4844 * @param fIgnoreConnectFailure
4845 * True if connection failures should be ignored
4846 * (makes only sense for bridged/host-only networks).
4847 *
4848 * @note Locks this object for writing.
4849 * @thread EMT
4850 */
4851int Console::i_configNetwork(const char *pszDevice,
4852 unsigned uInstance,
4853 unsigned uLun,
4854 INetworkAdapter *aNetworkAdapter,
4855 PCFGMNODE pCfg,
4856 PCFGMNODE pLunL0,
4857 PCFGMNODE pInst,
4858 bool fAttachDetach,
4859 bool fIgnoreConnectFailure)
4860{
4861 RT_NOREF(fIgnoreConnectFailure);
4862 AutoCaller autoCaller(this);
4863 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4864
4865 // InsertConfig* throws
4866 try
4867 {
4868 int rc = VINF_SUCCESS;
4869 HRESULT hrc;
4870 Bstr bstr;
4871
4872#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4873
4874 /*
4875 * Locking the object before doing VMR3* calls is quite safe here, since
4876 * we're on EMT. Write lock is necessary because we indirectly modify the
4877 * meAttachmentType member.
4878 */
4879 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4880
4881 ComPtr<IMachine> pMachine = i_machine();
4882
4883 ComPtr<IVirtualBox> virtualBox;
4884 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4885
4886 ComPtr<IHost> host;
4887 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4888
4889 BOOL fSniffer;
4890 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4891
4892 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4893 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4894 const char *pszPromiscuousGuestPolicy;
4895 switch (enmPromiscModePolicy)
4896 {
4897 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4898 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4899 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4900 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4901 }
4902
4903 if (fAttachDetach)
4904 {
4905 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4906 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4907 rc = VINF_SUCCESS;
4908 AssertLogRelRCReturn(rc, rc);
4909
4910 /* nuke anything which might have been left behind. */
4911 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4912 }
4913
4914#ifdef VBOX_WITH_NETSHAPER
4915 ComObjPtr<IBandwidthGroup> pBwGroup;
4916 Bstr strBwGroup;
4917 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4918
4919 if (!pBwGroup.isNull())
4920 {
4921 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4922 }
4923#endif /* VBOX_WITH_NETSHAPER */
4924
4925 Utf8Str strNetDriver;
4926
4927
4928 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4929
4930#ifdef VBOX_WITH_NETSHAPER
4931 if (!strBwGroup.isEmpty())
4932 {
4933 InsertConfigString(pLunL0, "Driver", "NetShaper");
4934 InsertConfigNode(pLunL0, "Config", &pCfg);
4935 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4936 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4937 }
4938#endif /* VBOX_WITH_NETSHAPER */
4939
4940 if (fSniffer)
4941 {
4942 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4943 InsertConfigNode(pLunL0, "Config", &pCfg);
4944 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4945 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4946 InsertConfigString(pCfg, "File", bstr);
4947 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4948 }
4949
4950
4951 Bstr networkName, trunkName, trunkType;
4952 NetworkAttachmentType_T eAttachmentType;
4953 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4954 switch (eAttachmentType)
4955 {
4956 case NetworkAttachmentType_Null:
4957 break;
4958
4959 case NetworkAttachmentType_NAT:
4960 {
4961 ComPtr<INATEngine> natEngine;
4962 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4963 InsertConfigString(pLunL0, "Driver", "NAT");
4964 InsertConfigNode(pLunL0, "Config", &pCfg);
4965
4966 /* Configure TFTP prefix and boot filename. */
4967 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4968 if (!bstr.isEmpty())
4969 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
4970 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
4971 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
4972
4973 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
4974 if (!bstr.isEmpty())
4975 InsertConfigString(pCfg, "Network", bstr);
4976 else
4977 {
4978 ULONG uSlot;
4979 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
4980 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
4981 }
4982 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
4983 if (!bstr.isEmpty())
4984 InsertConfigString(pCfg, "BindIP", bstr);
4985 ULONG mtu = 0;
4986 ULONG sockSnd = 0;
4987 ULONG sockRcv = 0;
4988 ULONG tcpSnd = 0;
4989 ULONG tcpRcv = 0;
4990 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
4991 if (mtu)
4992 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
4993 if (sockRcv)
4994 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
4995 if (sockSnd)
4996 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
4997 if (tcpRcv)
4998 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
4999 if (tcpSnd)
5000 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5001 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5002 if (!bstr.isEmpty())
5003 {
5004 RemoveConfigValue(pCfg, "TFTPPrefix");
5005 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5006 }
5007 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5008 if (!bstr.isEmpty())
5009 {
5010 RemoveConfigValue(pCfg, "BootFile");
5011 InsertConfigString(pCfg, "BootFile", bstr);
5012 }
5013 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5014 if (!bstr.isEmpty())
5015 InsertConfigString(pCfg, "NextServer", bstr);
5016 BOOL fDNSFlag;
5017 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5018 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5019 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5020 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5021 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5022 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5023
5024 ULONG aliasMode;
5025 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5026 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5027
5028 /* port-forwarding */
5029 SafeArray<BSTR> pfs;
5030 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5031
5032 PCFGMNODE pPFTree = NULL;
5033 if (pfs.size() > 0)
5034 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5035
5036 for (unsigned int i = 0; i < pfs.size(); ++i)
5037 {
5038 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5039
5040 uint16_t port = 0;
5041 BSTR r = pfs[i];
5042 Utf8Str utf = Utf8Str(r);
5043 Utf8Str strName;
5044 Utf8Str strProto;
5045 Utf8Str strHostPort;
5046 Utf8Str strHostIP;
5047 Utf8Str strGuestPort;
5048 Utf8Str strGuestIP;
5049 size_t pos, ppos;
5050 pos = ppos = 0;
5051#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5052 { \
5053 pos = str.find(",", ppos); \
5054 if (pos == Utf8Str::npos) \
5055 { \
5056 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5057 continue; \
5058 } \
5059 res = str.substr(ppos, pos - ppos); \
5060 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5061 ppos = pos + 1; \
5062 } /* no do { ... } while because of 'continue' */
5063 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5064 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5065 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5066 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5067 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5068 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5069#undef ITERATE_TO_NEXT_TERM
5070
5071 uint32_t proto = strProto.toUInt32();
5072 bool fValid = true;
5073 switch (proto)
5074 {
5075 case NATProtocol_UDP:
5076 strProto = "UDP";
5077 break;
5078 case NATProtocol_TCP:
5079 strProto = "TCP";
5080 break;
5081 default:
5082 fValid = false;
5083 }
5084 /* continue with next rule if no valid proto was passed */
5085 if (!fValid)
5086 continue;
5087
5088 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5089
5090 if (!strName.isEmpty())
5091 InsertConfigString(pPF, "Name", strName);
5092
5093 InsertConfigString(pPF, "Protocol", strProto);
5094
5095 if (!strHostIP.isEmpty())
5096 InsertConfigString(pPF, "BindIP", strHostIP);
5097
5098 if (!strGuestIP.isEmpty())
5099 InsertConfigString(pPF, "GuestIP", strGuestIP);
5100
5101 port = RTStrToUInt16(strHostPort.c_str());
5102 if (port)
5103 InsertConfigInteger(pPF, "HostPort", port);
5104
5105 port = RTStrToUInt16(strGuestPort.c_str());
5106 if (port)
5107 InsertConfigInteger(pPF, "GuestPort", port);
5108 }
5109 break;
5110 }
5111
5112 case NetworkAttachmentType_Bridged:
5113 {
5114#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5115 hrc = i_attachToTapInterface(aNetworkAdapter);
5116 if (FAILED(hrc))
5117 {
5118 switch (hrc)
5119 {
5120 case VERR_ACCESS_DENIED:
5121 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5122 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5123 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5124 "change the group of that node and make yourself a member of that group. Make "
5125 "sure that these changes are permanent, especially if you are "
5126 "using udev"));
5127 default:
5128 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5129 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5130 "Failed to initialize Host Interface Networking"));
5131 }
5132 }
5133
5134 Assert((intptr_t)maTapFD[uInstance] >= 0);
5135 if ((intptr_t)maTapFD[uInstance] >= 0)
5136 {
5137 InsertConfigString(pLunL0, "Driver", "HostInterface");
5138 InsertConfigNode(pLunL0, "Config", &pCfg);
5139 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5140 }
5141
5142#elif defined(VBOX_WITH_NETFLT)
5143 /*
5144 * This is the new VBoxNetFlt+IntNet stuff.
5145 */
5146 Bstr BridgedIfName;
5147 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5148 if (FAILED(hrc))
5149 {
5150 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5151 H();
5152 }
5153
5154 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5155 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5156
5157# if defined(RT_OS_DARWIN)
5158 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5159 char szTrunk[8];
5160 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5161 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5162// Quick fix for @bugref{5633}
5163// if (!pszColon)
5164// {
5165// /*
5166// * Dynamic changing of attachment causes an attempt to configure
5167// * network with invalid host adapter (as it is must be changed before
5168// * the attachment), calling Detach here will cause a deadlock.
5169// * See @bugref{4750}.
5170// * hrc = aNetworkAdapter->Detach(); H();
5171// */
5172// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5173// N_("Malformed host interface networking name '%ls'"),
5174// BridgedIfName.raw());
5175// }
5176 if (pszColon)
5177 *pszColon = '\0';
5178 const char *pszTrunk = szTrunk;
5179
5180# elif defined(RT_OS_SOLARIS)
5181 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5182 char szTrunk[256];
5183 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5184 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5185
5186 /*
5187 * Currently don't bother about malformed names here for the sake of people using
5188 * VBoxManage and setting only the NIC name from there. If there is a space we
5189 * chop it off and proceed, otherwise just use whatever we've got.
5190 */
5191 if (pszSpace)
5192 *pszSpace = '\0';
5193
5194 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5195 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5196 if (pszColon)
5197 *pszColon = '\0';
5198
5199 const char *pszTrunk = szTrunk;
5200
5201# elif defined(RT_OS_WINDOWS)
5202 ComPtr<IHostNetworkInterface> hostInterface;
5203 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5204 hostInterface.asOutParam());
5205 if (!SUCCEEDED(hrc))
5206 {
5207 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5208 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5209 N_("Nonexistent host networking interface, name '%ls'"),
5210 BridgedIfName.raw());
5211 }
5212
5213 HostNetworkInterfaceType_T eIfType;
5214 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5215 if (FAILED(hrc))
5216 {
5217 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5218 H();
5219 }
5220
5221 if (eIfType != HostNetworkInterfaceType_Bridged)
5222 {
5223 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5224 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5225 BridgedIfName.raw());
5226 }
5227
5228 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5229 if (FAILED(hrc))
5230 {
5231 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5232 H();
5233 }
5234 Guid hostIFGuid(bstr);
5235
5236 INetCfg *pNc;
5237 ComPtr<INetCfgComponent> pAdaptorComponent;
5238 LPWSTR pszApp;
5239
5240 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5241 Assert(hrc == S_OK);
5242 if (hrc != S_OK)
5243 {
5244 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5245 H();
5246 }
5247
5248 /* get the adapter's INetCfgComponent*/
5249 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5250 pAdaptorComponent.asOutParam());
5251 if (hrc != S_OK)
5252 {
5253 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5254 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5255 H();
5256 }
5257# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5258 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5259 char *pszTrunkName = szTrunkName;
5260 wchar_t * pswzBindName;
5261 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5262 Assert(hrc == S_OK);
5263 if (hrc == S_OK)
5264 {
5265 int cwBindName = (int)wcslen(pswzBindName) + 1;
5266 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5267 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5268 {
5269 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5270 pszTrunkName += cbFullBindNamePrefix-1;
5271 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5272 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5273 {
5274 DWORD err = GetLastError();
5275 hrc = HRESULT_FROM_WIN32(err);
5276 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5277 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5278 hrc, hrc, err));
5279 }
5280 }
5281 else
5282 {
5283 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5284 /** @todo set appropriate error code */
5285 hrc = E_FAIL;
5286 }
5287
5288 if (hrc != S_OK)
5289 {
5290 AssertFailed();
5291 CoTaskMemFree(pswzBindName);
5292 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5293 H();
5294 }
5295
5296 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5297 }
5298 else
5299 {
5300 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5301 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5302 hrc));
5303 H();
5304 }
5305
5306 const char *pszTrunk = szTrunkName;
5307 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5308
5309# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5310# if defined(RT_OS_FREEBSD)
5311 /*
5312 * If we bridge to a tap interface open it the `old' direct way.
5313 * This works and performs better than bridging a physical
5314 * interface via the current FreeBSD vboxnetflt implementation.
5315 */
5316 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5317 hrc = i_attachToTapInterface(aNetworkAdapter);
5318 if (FAILED(hrc))
5319 {
5320 switch (hrc)
5321 {
5322 case VERR_ACCESS_DENIED:
5323 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5324 "Failed to open '/dev/%s' for read/write access. Please check the "
5325 "permissions of that node, and that the net.link.tap.user_open "
5326 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5327 "change the group of that node to vboxusers and make yourself "
5328 "a member of that group. Make sure that these changes are permanent."),
5329 pszBridgedIfName, pszBridgedIfName);
5330 default:
5331 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5332 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5333 "Failed to initialize Host Interface Networking"));
5334 }
5335 }
5336
5337 Assert((intptr_t)maTapFD[uInstance] >= 0);
5338 if ((intptr_t)maTapFD[uInstance] >= 0)
5339 {
5340 InsertConfigString(pLunL0, "Driver", "HostInterface");
5341 InsertConfigNode(pLunL0, "Config", &pCfg);
5342 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5343 }
5344 break;
5345 }
5346# endif
5347 /** @todo Check for malformed names. */
5348 const char *pszTrunk = pszBridgedIfName;
5349
5350 /* Issue a warning if the interface is down */
5351 {
5352 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5353 if (iSock >= 0)
5354 {
5355 struct ifreq Req;
5356 RT_ZERO(Req);
5357 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5358 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5359 if ((Req.ifr_flags & IFF_UP) == 0)
5360 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5361 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5362 pszBridgedIfName);
5363
5364 close(iSock);
5365 }
5366 }
5367
5368# else
5369# error "PORTME (VBOX_WITH_NETFLT)"
5370# endif
5371
5372 InsertConfigString(pLunL0, "Driver", "IntNet");
5373 InsertConfigNode(pLunL0, "Config", &pCfg);
5374 InsertConfigString(pCfg, "Trunk", pszTrunk);
5375 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5376 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5377 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5378 char szNetwork[INTNET_MAX_NETWORK_NAME];
5379
5380# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5381 /*
5382 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5383 * interface name + optional description. We must not pass any description to the VM as it can differ
5384 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5385 */
5386 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5387# else
5388 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5389# endif
5390 InsertConfigString(pCfg, "Network", szNetwork);
5391 networkName = Bstr(szNetwork);
5392 trunkName = Bstr(pszTrunk);
5393 trunkType = Bstr(TRUNKTYPE_NETFLT);
5394
5395# if defined(RT_OS_DARWIN)
5396 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
5397 if ( strstr(pszBridgedIfName, "Wireless")
5398 || strstr(pszBridgedIfName, "AirPort" ))
5399 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5400# elif defined(RT_OS_LINUX)
5401 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5402 if (iSock >= 0)
5403 {
5404 struct iwreq WRq;
5405
5406 RT_ZERO(WRq);
5407 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
5408 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
5409 close(iSock);
5410 if (fSharedMacOnWire)
5411 {
5412 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5413 Log(("Set SharedMacOnWire\n"));
5414 }
5415 else
5416 Log(("Failed to get wireless name\n"));
5417 }
5418 else
5419 Log(("Failed to open wireless socket\n"));
5420# elif defined(RT_OS_FREEBSD)
5421 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5422 if (iSock >= 0)
5423 {
5424 struct ieee80211req WReq;
5425 uint8_t abData[32];
5426
5427 RT_ZERO(WReq);
5428 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
5429 WReq.i_type = IEEE80211_IOC_SSID;
5430 WReq.i_val = -1;
5431 WReq.i_data = abData;
5432 WReq.i_len = sizeof(abData);
5433
5434 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
5435 close(iSock);
5436 if (fSharedMacOnWire)
5437 {
5438 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5439 Log(("Set SharedMacOnWire\n"));
5440 }
5441 else
5442 Log(("Failed to get wireless name\n"));
5443 }
5444 else
5445 Log(("Failed to open wireless socket\n"));
5446# elif defined(RT_OS_WINDOWS)
5447# define DEVNAME_PREFIX L"\\\\.\\"
5448 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
5449 * there is a pretty long way till there though since we need to obtain the symbolic link name
5450 * for the adapter device we are going to query given the device Guid */
5451
5452
5453 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
5454
5455 wchar_t FileName[MAX_PATH];
5456 wcscpy(FileName, DEVNAME_PREFIX);
5457 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
5458
5459 /* open the device */
5460 HANDLE hDevice = CreateFile(FileName,
5461 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5462 NULL,
5463 OPEN_EXISTING,
5464 FILE_ATTRIBUTE_NORMAL,
5465 NULL);
5466
5467 if (hDevice != INVALID_HANDLE_VALUE)
5468 {
5469 bool fSharedMacOnWire = false;
5470
5471 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
5472 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
5473 NDIS_PHYSICAL_MEDIUM PhMedium;
5474 DWORD cbResult;
5475 if (DeviceIoControl(hDevice,
5476 IOCTL_NDIS_QUERY_GLOBAL_STATS,
5477 &Oid,
5478 sizeof(Oid),
5479 &PhMedium,
5480 sizeof(PhMedium),
5481 &cbResult,
5482 NULL))
5483 {
5484 /* that was simple, now examine PhMedium */
5485 if ( PhMedium == NdisPhysicalMediumWirelessWan
5486 || PhMedium == NdisPhysicalMediumWirelessLan
5487 || PhMedium == NdisPhysicalMediumNative802_11
5488 || PhMedium == NdisPhysicalMediumBluetooth)
5489 fSharedMacOnWire = true;
5490 }
5491 else
5492 {
5493 int winEr = GetLastError();
5494 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
5495 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
5496 }
5497 CloseHandle(hDevice);
5498
5499 if (fSharedMacOnWire)
5500 {
5501 Log(("this is a wireless adapter"));
5502 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5503 Log(("Set SharedMacOnWire\n"));
5504 }
5505 else
5506 Log(("this is NOT a wireless adapter"));
5507 }
5508 else
5509 {
5510 int winEr = GetLastError();
5511 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
5512 }
5513
5514 CoTaskMemFree(pswzBindName);
5515
5516 pAdaptorComponent.setNull();
5517 /* release the pNc finally */
5518 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5519# else
5520 /** @todo PORTME: wireless detection */
5521# endif
5522
5523# if defined(RT_OS_SOLARIS)
5524# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5525 /* Zone access restriction, don't allow snooping the global zone. */
5526 zoneid_t ZoneId = getzoneid();
5527 if (ZoneId != GLOBAL_ZONEID)
5528 {
5529 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5530 }
5531# endif
5532# endif
5533
5534#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5535 /* NOTHING TO DO HERE */
5536#elif defined(RT_OS_LINUX)
5537/// @todo aleksey: is there anything to be done here?
5538#elif defined(RT_OS_FREEBSD)
5539/** @todo FreeBSD: Check out this later (HIF networking). */
5540#else
5541# error "Port me"
5542#endif
5543 break;
5544 }
5545
5546 case NetworkAttachmentType_Internal:
5547 {
5548 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5549 if (!bstr.isEmpty())
5550 {
5551 InsertConfigString(pLunL0, "Driver", "IntNet");
5552 InsertConfigNode(pLunL0, "Config", &pCfg);
5553 InsertConfigString(pCfg, "Network", bstr);
5554 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5555 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5556 networkName = bstr;
5557 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5558 }
5559 break;
5560 }
5561
5562 case NetworkAttachmentType_HostOnly:
5563 {
5564 InsertConfigString(pLunL0, "Driver", "IntNet");
5565 InsertConfigNode(pLunL0, "Config", &pCfg);
5566
5567 Bstr HostOnlyName;
5568 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5569 if (FAILED(hrc))
5570 {
5571 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5572 H();
5573 }
5574
5575 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5576 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5577 ComPtr<IHostNetworkInterface> hostInterface;
5578 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5579 hostInterface.asOutParam());
5580 if (!SUCCEEDED(rc))
5581 {
5582 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5583 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5584 N_("Nonexistent host networking interface, name '%ls'"),
5585 HostOnlyName.raw());
5586 }
5587
5588 char szNetwork[INTNET_MAX_NETWORK_NAME];
5589 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5590
5591#if defined(RT_OS_WINDOWS)
5592# ifndef VBOX_WITH_NETFLT
5593 hrc = E_NOTIMPL;
5594 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5595 H();
5596# else /* defined VBOX_WITH_NETFLT*/
5597 /** @todo r=bird: Put this in a function. */
5598
5599 HostNetworkInterfaceType_T eIfType;
5600 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5601 if (FAILED(hrc))
5602 {
5603 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5604 H();
5605 }
5606
5607 if (eIfType != HostNetworkInterfaceType_HostOnly)
5608 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5609 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5610 HostOnlyName.raw());
5611
5612 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5613 if (FAILED(hrc))
5614 {
5615 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5616 H();
5617 }
5618 Guid hostIFGuid(bstr);
5619
5620 INetCfg *pNc;
5621 ComPtr<INetCfgComponent> pAdaptorComponent;
5622 LPWSTR pszApp;
5623 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5624 Assert(hrc == S_OK);
5625 if (hrc != S_OK)
5626 {
5627 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5628 H();
5629 }
5630
5631 /* get the adapter's INetCfgComponent*/
5632 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5633 pAdaptorComponent.asOutParam());
5634 if (hrc != S_OK)
5635 {
5636 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5637 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5638 H();
5639 }
5640# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5641 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5642 bool fNdis6 = false;
5643 wchar_t * pwszHelpText;
5644 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5645 Assert(hrc == S_OK);
5646 if (hrc == S_OK)
5647 {
5648 Log(("help-text=%ls\n", pwszHelpText));
5649 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5650 fNdis6 = true;
5651 CoTaskMemFree(pwszHelpText);
5652 }
5653 if (fNdis6)
5654 {
5655 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5656 Log(("trunk=%s\n", szTrunkName));
5657 }
5658 else
5659 {
5660 char *pszTrunkName = szTrunkName;
5661 wchar_t * pswzBindName;
5662 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5663 Assert(hrc == S_OK);
5664 if (hrc == S_OK)
5665 {
5666 int cwBindName = (int)wcslen(pswzBindName) + 1;
5667 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5668 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5669 {
5670 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5671 pszTrunkName += cbFullBindNamePrefix-1;
5672 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5673 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5674 {
5675 DWORD err = GetLastError();
5676 hrc = HRESULT_FROM_WIN32(err);
5677 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5678 hrc, hrc, err));
5679 }
5680 }
5681 else
5682 {
5683 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5684 /** @todo set appropriate error code */
5685 hrc = E_FAIL;
5686 }
5687
5688 if (hrc != S_OK)
5689 {
5690 AssertFailed();
5691 CoTaskMemFree(pswzBindName);
5692 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5693 H();
5694 }
5695 }
5696 else
5697 {
5698 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5699 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5700 hrc, hrc));
5701 H();
5702 }
5703
5704
5705 CoTaskMemFree(pswzBindName);
5706 }
5707
5708 trunkType = TRUNKTYPE_NETADP;
5709 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5710
5711 pAdaptorComponent.setNull();
5712 /* release the pNc finally */
5713 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5714
5715 const char *pszTrunk = szTrunkName;
5716
5717 InsertConfigString(pCfg, "Trunk", pszTrunk);
5718 InsertConfigString(pCfg, "Network", szNetwork);
5719 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5720 windows only?? */
5721 networkName = Bstr(szNetwork);
5722 trunkName = Bstr(pszTrunk);
5723# endif /* defined VBOX_WITH_NETFLT*/
5724#elif defined(RT_OS_DARWIN)
5725 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5726 InsertConfigString(pCfg, "Network", szNetwork);
5727 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5728 networkName = Bstr(szNetwork);
5729 trunkName = Bstr(pszHostOnlyName);
5730 trunkType = TRUNKTYPE_NETADP;
5731#else
5732 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5733 InsertConfigString(pCfg, "Network", szNetwork);
5734 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5735 networkName = Bstr(szNetwork);
5736 trunkName = Bstr(pszHostOnlyName);
5737 trunkType = TRUNKTYPE_NETFLT;
5738#endif
5739 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5740
5741#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5742
5743 Bstr tmpAddr, tmpMask;
5744
5745 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5746 pszHostOnlyName).raw(),
5747 tmpAddr.asOutParam());
5748 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5749 {
5750 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5751 pszHostOnlyName).raw(),
5752 tmpMask.asOutParam());
5753 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5754 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5755 tmpMask.raw());
5756 else
5757 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5758 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5759 }
5760 else
5761 {
5762 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5763 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5764 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5765 }
5766
5767 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5768
5769 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5770 pszHostOnlyName).raw(),
5771 tmpAddr.asOutParam());
5772 if (SUCCEEDED(hrc))
5773 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5774 tmpMask.asOutParam());
5775 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5776 {
5777 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5778 Utf8Str(tmpMask).toUInt32());
5779 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5780 }
5781#endif
5782 break;
5783 }
5784
5785 case NetworkAttachmentType_Generic:
5786 {
5787 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5788 SafeArray<BSTR> names;
5789 SafeArray<BSTR> values;
5790 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5791 ComSafeArrayAsOutParam(names),
5792 ComSafeArrayAsOutParam(values)); H();
5793
5794 InsertConfigString(pLunL0, "Driver", bstr);
5795 InsertConfigNode(pLunL0, "Config", &pCfg);
5796 for (size_t ii = 0; ii < names.size(); ++ii)
5797 {
5798 if (values[ii] && *values[ii])
5799 {
5800 Utf8Str name = names[ii];
5801 Utf8Str value = values[ii];
5802 InsertConfigString(pCfg, name.c_str(), value);
5803 }
5804 }
5805 break;
5806 }
5807
5808 case NetworkAttachmentType_NATNetwork:
5809 {
5810 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5811 if (!bstr.isEmpty())
5812 {
5813 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5814 InsertConfigString(pLunL0, "Driver", "IntNet");
5815 InsertConfigNode(pLunL0, "Config", &pCfg);
5816 InsertConfigString(pCfg, "Network", bstr);
5817 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5818 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5819 networkName = bstr;
5820 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5821 }
5822 break;
5823 }
5824
5825 default:
5826 AssertMsgFailed(("should not get here!\n"));
5827 break;
5828 }
5829
5830 /*
5831 * Attempt to attach the driver.
5832 */
5833 switch (eAttachmentType)
5834 {
5835 case NetworkAttachmentType_Null:
5836 break;
5837
5838 case NetworkAttachmentType_Bridged:
5839 case NetworkAttachmentType_Internal:
5840 case NetworkAttachmentType_HostOnly:
5841 case NetworkAttachmentType_NAT:
5842 case NetworkAttachmentType_Generic:
5843 case NetworkAttachmentType_NATNetwork:
5844 {
5845 if (SUCCEEDED(hrc) && SUCCEEDED(rc))
5846 {
5847 if (fAttachDetach)
5848 {
5849 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5850 //AssertRC(rc);
5851 }
5852
5853 {
5854 /** @todo pritesh: get the dhcp server name from the
5855 * previous network configuration and then stop the server
5856 * else it may conflict with the dhcp server running with
5857 * the current attachment type
5858 */
5859 /* Stop the hostonly DHCP Server */
5860 }
5861
5862 /*
5863 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5864 */
5865 if ( !networkName.isEmpty()
5866 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5867 {
5868 /*
5869 * Until we implement service reference counters DHCP Server will be stopped
5870 * by DHCPServerRunner destructor.
5871 */
5872 ComPtr<IDHCPServer> dhcpServer;
5873 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5874 dhcpServer.asOutParam());
5875 if (SUCCEEDED(hrc))
5876 {
5877 /* there is a DHCP server available for this network */
5878 BOOL fEnabledDhcp;
5879 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5880 if (FAILED(hrc))
5881 {
5882 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5883 H();
5884 }
5885
5886 if (fEnabledDhcp)
5887 hrc = dhcpServer->Start(networkName.raw(),
5888 trunkName.raw(),
5889 trunkType.raw());
5890 }
5891 else
5892 hrc = S_OK;
5893 }
5894 }
5895
5896 break;
5897 }
5898
5899 default:
5900 AssertMsgFailed(("should not get here!\n"));
5901 break;
5902 }
5903
5904 meAttachmentType[uInstance] = eAttachmentType;
5905 }
5906 catch (ConfigError &x)
5907 {
5908 // InsertConfig threw something:
5909 return x.m_vrc;
5910 }
5911
5912#undef H
5913
5914 return VINF_SUCCESS;
5915}
5916
5917#ifdef VBOX_WITH_GUEST_PROPS
5918/**
5919 * Set an array of guest properties
5920 */
5921static void configSetProperties(VMMDev * const pVMMDev,
5922 void *names,
5923 void *values,
5924 void *timestamps,
5925 void *flags)
5926{
5927 VBOXHGCMSVCPARM parms[4];
5928
5929 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5930 parms[0].u.pointer.addr = names;
5931 parms[0].u.pointer.size = 0; /* We don't actually care. */
5932 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5933 parms[1].u.pointer.addr = values;
5934 parms[1].u.pointer.size = 0; /* We don't actually care. */
5935 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5936 parms[2].u.pointer.addr = timestamps;
5937 parms[2].u.pointer.size = 0; /* We don't actually care. */
5938 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5939 parms[3].u.pointer.addr = flags;
5940 parms[3].u.pointer.size = 0; /* We don't actually care. */
5941
5942 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5943 guestProp::SET_PROPS_HOST,
5944 4,
5945 &parms[0]);
5946}
5947
5948/**
5949 * Set a single guest property
5950 */
5951static void configSetProperty(VMMDev * const pVMMDev,
5952 const char *pszName,
5953 const char *pszValue,
5954 const char *pszFlags)
5955{
5956 VBOXHGCMSVCPARM parms[4];
5957
5958 AssertPtrReturnVoid(pszName);
5959 AssertPtrReturnVoid(pszValue);
5960 AssertPtrReturnVoid(pszFlags);
5961 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5962 parms[0].u.pointer.addr = (void *)pszName;
5963 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5964 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5965 parms[1].u.pointer.addr = (void *)pszValue;
5966 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5967 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5968 parms[2].u.pointer.addr = (void *)pszFlags;
5969 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
5970 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
5971 &parms[0]);
5972}
5973
5974/**
5975 * Set the global flags value by calling the service
5976 * @returns the status returned by the call to the service
5977 *
5978 * @param pTable the service instance handle
5979 * @param eFlags the flags to set
5980 */
5981int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
5982 guestProp::ePropFlags eFlags)
5983{
5984 VBOXHGCMSVCPARM paParm;
5985 paParm.setUInt32(eFlags);
5986 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5987 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
5988 &paParm);
5989 if (RT_FAILURE(rc))
5990 {
5991 char szFlags[guestProp::MAX_FLAGS_LEN];
5992 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
5993 Log(("Failed to set the global flags.\n"));
5994 else
5995 Log(("Failed to set the global flags \"%s\".\n", szFlags));
5996 }
5997 return rc;
5998}
5999#endif /* VBOX_WITH_GUEST_PROPS */
6000
6001/**
6002 * Set up the Guest Property service, populate it with properties read from
6003 * the machine XML and set a couple of initial properties.
6004 */
6005/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
6006{
6007#ifdef VBOX_WITH_GUEST_PROPS
6008 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6009 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6010 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
6011
6012 /* Load the service */
6013 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
6014
6015 if (RT_FAILURE(rc))
6016 {
6017 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
6018 /* That is not a fatal failure. */
6019 rc = VINF_SUCCESS;
6020 }
6021 else
6022 {
6023 /*
6024 * Initialize built-in properties that can be changed and saved.
6025 *
6026 * These are typically transient properties that the guest cannot
6027 * change.
6028 */
6029
6030 {
6031 VBOXHGCMSVCPARM Params[2];
6032 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
6033 if (RT_SUCCESS(rc2))
6034 {
6035 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
6036 void *pService = (void*)Params[1].u.pointer.addr;
6037 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
6038 }
6039 }
6040
6041 /* Sysprep execution by VBoxService. */
6042 configSetProperty(pConsole->m_pVMMDev,
6043 "/VirtualBox/HostGuest/SysprepExec", "",
6044 "TRANSIENT, RDONLYGUEST");
6045 configSetProperty(pConsole->m_pVMMDev,
6046 "/VirtualBox/HostGuest/SysprepArgs", "",
6047 "TRANSIENT, RDONLYGUEST");
6048
6049 /*
6050 * Pull over the properties from the server.
6051 */
6052 SafeArray<BSTR> namesOut;
6053 SafeArray<BSTR> valuesOut;
6054 SafeArray<LONG64> timestampsOut;
6055 SafeArray<BSTR> flagsOut;
6056 HRESULT hrc;
6057 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
6058 ComSafeArrayAsOutParam(valuesOut),
6059 ComSafeArrayAsOutParam(timestampsOut),
6060 ComSafeArrayAsOutParam(flagsOut));
6061 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6062 size_t cProps = namesOut.size();
6063 size_t cAlloc = cProps + 1;
6064 if ( valuesOut.size() != cProps
6065 || timestampsOut.size() != cProps
6066 || flagsOut.size() != cProps
6067 )
6068 AssertFailedReturn(VERR_INVALID_PARAMETER);
6069
6070 char **papszNames, **papszValues, **papszFlags;
6071 char szEmpty[] = "";
6072 LONG64 *pai64Timestamps;
6073 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6074 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6075 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
6076 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6077 if (papszNames && papszValues && pai64Timestamps && papszFlags)
6078 {
6079 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
6080 {
6081 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
6082 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
6083 if (RT_FAILURE(rc))
6084 break;
6085 if (valuesOut[i])
6086 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6087 else
6088 papszValues[i] = szEmpty;
6089 if (RT_FAILURE(rc))
6090 break;
6091 pai64Timestamps[i] = timestampsOut[i];
6092 if (flagsOut[i])
6093 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6094 else
6095 papszFlags[i] = szEmpty;
6096 }
6097 if (RT_SUCCESS(rc))
6098 configSetProperties(pConsole->m_pVMMDev,
6099 (void *)papszNames,
6100 (void *)papszValues,
6101 (void *)pai64Timestamps,
6102 (void *)papszFlags);
6103 for (unsigned i = 0; i < cProps; ++i)
6104 {
6105 RTStrFree(papszNames[i]);
6106 if (valuesOut[i])
6107 RTStrFree(papszValues[i]);
6108 if (flagsOut[i])
6109 RTStrFree(papszFlags[i]);
6110 }
6111 }
6112 else
6113 rc = VERR_NO_MEMORY;
6114 RTMemTmpFree(papszNames);
6115 RTMemTmpFree(papszValues);
6116 RTMemTmpFree(pai64Timestamps);
6117 RTMemTmpFree(papszFlags);
6118 AssertRCReturn(rc, rc);
6119
6120 /*
6121 * These properties have to be set before pulling over the properties
6122 * from the machine XML, to ensure that properties saved in the XML
6123 * will override them.
6124 */
6125 /* Set the raw VBox version string as a guest property. Used for host/guest
6126 * version comparison. */
6127 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6128 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6129 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6130 * information/branding and/or pre-release tags. */
6131 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6132 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6133 /* Set the VBox SVN revision as a guest property */
6134 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6135 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6136
6137 /*
6138 * Register the host notification callback
6139 */
6140 HGCMSVCEXTHANDLE hDummy;
6141 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6142 Console::i_doGuestPropNotification,
6143 pvConsole);
6144
6145#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6146 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
6147 guestProp::RDONLYGUEST);
6148 AssertRCReturn(rc, rc);
6149#endif
6150
6151 Log(("Set VBoxGuestPropSvc property store\n"));
6152 }
6153 return VINF_SUCCESS;
6154#else /* !VBOX_WITH_GUEST_PROPS */
6155 return VERR_NOT_SUPPORTED;
6156#endif /* !VBOX_WITH_GUEST_PROPS */
6157}
6158
6159/**
6160 * Set up the Guest Control service.
6161 */
6162/* static */ int Console::i_configGuestControl(void *pvConsole)
6163{
6164#ifdef VBOX_WITH_GUEST_CONTROL
6165 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6166 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6167
6168 /* Load the service */
6169 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6170
6171 if (RT_FAILURE(rc))
6172 {
6173 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6174 /* That is not a fatal failure. */
6175 rc = VINF_SUCCESS;
6176 }
6177 else
6178 {
6179 HGCMSVCEXTHANDLE hDummy;
6180 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6181 &Guest::i_notifyCtrlDispatcher,
6182 pConsole->i_getGuest());
6183 if (RT_FAILURE(rc))
6184 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6185 else
6186 LogRel(("Guest Control service loaded\n"));
6187 }
6188
6189 return rc;
6190#else /* !VBOX_WITH_GUEST_CONTROL */
6191 return VERR_NOT_SUPPORTED;
6192#endif /* !VBOX_WITH_GUEST_CONTROL */
6193}
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