VirtualBox

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

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

ConsoleImpl2: whoops

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