VirtualBox

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

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

IMachine: Added CPUProfile attribute (read/write string). Added a modifyvm option for setting it. Show non-default values in showvminfo, but always show it starting with 6.0.

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