VirtualBox

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

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

ConsoleImpl2: Fail if invalid Hyper-V debugging options are configured for the VM.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette