VirtualBox

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

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

ACPI: Allow two more serial ports.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 240.9 KB
Line 
1/* $Id: ConsoleImpl2.cpp 59918 2016-03-04 10:06:52Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - VM Configuration Bits.
4 *
5 * @remark We've split out the code that the 64-bit VC++ v8 compiler finds
6 * problematic to optimize so we can disable optimizations and later,
7 * perhaps, find a real solution for it (like rewriting the code and
8 * to stop resemble a tonne of spaghetti).
9 */
10
11/*
12 * Copyright (C) 2006-2015 Oracle Corporation
13 *
14 * This file is part of VirtualBox Open Source Edition (OSE), as
15 * available from http://www.215389.xyz. This file is free software;
16 * you can redistribute it and/or modify it under the terms of the GNU
17 * General Public License (GPL) as published by the Free Software
18 * Foundation, in version 2 as it comes in the "COPYING" file of the
19 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
20 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21 */
22
23
24/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27/* For some reason Windows burns in sdk\...\winsock.h if this isn't included first. */
28#include "VBox/com/ptr.h"
29
30#include "ConsoleImpl.h"
31#include "DisplayImpl.h"
32#ifdef VBOX_WITH_GUEST_CONTROL
33# include "GuestImpl.h"
34#endif
35#ifdef VBOX_WITH_DRAG_AND_DROP
36# include "GuestDnDPrivate.h"
37#endif
38#include "VMMDev.h"
39#include "Global.h"
40#ifdef VBOX_WITH_PCI_PASSTHROUGH
41# include "PCIRawDevImpl.h"
42#endif
43
44// generated header
45#include "SchemaDefs.h"
46
47#include "AutoCaller.h"
48#include "Logging.h"
49
50#include <iprt/base64.h>
51#include <iprt/buildconfig.h>
52#include <iprt/ctype.h>
53#include <iprt/dir.h>
54#include <iprt/file.h>
55#include <iprt/param.h>
56#include <iprt/path.h>
57#include <iprt/string.h>
58#include <iprt/system.h>
59#include <iprt/cpp/exception.h>
60#if 0 /* enable to play with lots of memory. */
61# include <iprt/env.h>
62#endif
63#include <iprt/stream.h>
64
65#include <VBox/vmm/vmapi.h>
66#include <VBox/err.h>
67#include <VBox/param.h>
68#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
69#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
70#include <VBox/vmm/pdmstorageifs.h>
71#include <VBox/version.h>
72#include <VBox/HostServices/VBoxClipboardSvc.h>
73#ifdef VBOX_WITH_CROGL
74# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
75#include <VBox/VBoxOGL.h>
76#endif
77#ifdef VBOX_WITH_GUEST_PROPS
78# include <VBox/HostServices/GuestPropertySvc.h>
79# include <VBox/com/defs.h>
80# include <VBox/com/array.h>
81# include "HGCM.h" /** @todo It should be possible to register a service
82 * extension using a VMMDev callback. */
83# include <vector>
84#endif /* VBOX_WITH_GUEST_PROPS */
85#include <VBox/intnet.h>
86
87#include <VBox/com/com.h>
88#include <VBox/com/string.h>
89#include <VBox/com/array.h>
90
91#ifdef VBOX_WITH_NETFLT
92# if defined(RT_OS_SOLARIS)
93# include <zone.h>
94# elif defined(RT_OS_LINUX)
95# include <unistd.h>
96# include <sys/ioctl.h>
97# include <sys/socket.h>
98# include <linux/types.h>
99# include <linux/if.h>
100# include <linux/wireless.h>
101# elif defined(RT_OS_FREEBSD)
102# include <unistd.h>
103# include <sys/types.h>
104# include <sys/ioctl.h>
105# include <sys/socket.h>
106# include <net/if.h>
107# include <net80211/ieee80211_ioctl.h>
108# endif
109# if defined(RT_OS_WINDOWS)
110# include <VBox/VBoxNetCfg-win.h>
111# include <Ntddndis.h>
112# include <devguid.h>
113# else
114# include <HostNetworkInterfaceImpl.h>
115# include <netif.h>
116# include <stdlib.h>
117# endif
118#endif /* VBOX_WITH_NETFLT */
119
120#include "NetworkServiceRunner.h"
121#include "BusAssignmentManager.h"
122#ifdef VBOX_WITH_EXTPACK
123# include "ExtPackManagerImpl.h"
124#endif
125
126
127/*********************************************************************************************************************************
128* Internal Functions *
129*********************************************************************************************************************************/
130static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);
131
132
133/* Darwin compile kludge */
134#undef PVM
135
136/* Comment out the following line to remove VMWare compatibility hack. */
137#define VMWARE_NET_IN_SLOT_11
138
139/**
140 * Translate IDE StorageControllerType_T to string representation.
141 */
142const char* controllerString(StorageControllerType_T enmType)
143{
144 switch (enmType)
145 {
146 case StorageControllerType_PIIX3:
147 return "PIIX3";
148 case StorageControllerType_PIIX4:
149 return "PIIX4";
150 case StorageControllerType_ICH6:
151 return "ICH6";
152 default:
153 return "Unknown";
154 }
155}
156
157/**
158 * Simple class for storing network boot information.
159 */
160struct BootNic
161{
162 ULONG mInstance;
163 PCIBusAddress mPCIAddress;
164
165 ULONG mBootPrio;
166 bool operator < (const BootNic &rhs) const
167 {
168 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
169 ULONG rval = rhs.mBootPrio - 1;
170 return lval < rval; /* Zero compares as highest number (lowest prio). */
171 }
172};
173
174static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
175{
176 Bstr aFilePath, empty;
177 BOOL fPresent = FALSE;
178 HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),
179 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
180 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
181
182 if (!fPresent)
183 {
184 LogRel(("Failed to find an EFI ROM file.\n"));
185 return VERR_FILE_NOT_FOUND;
186 }
187
188 *pEfiRomFile = Utf8Str(aFilePath);
189
190 return VINF_SUCCESS;
191}
192
193/**
194 * @throws HRESULT on extra data retrival error.
195 */
196static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
197{
198 *pfGetKeyFromRealSMC = false;
199
200 /*
201 * The extra data takes precedence (if non-zero).
202 */
203 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
204 if (pStrKey->isNotEmpty())
205 return VINF_SUCCESS;
206
207#ifdef RT_OS_DARWIN
208
209 /*
210 * Work done in EFI/DevSmc
211 */
212 *pfGetKeyFromRealSMC = true;
213 int rc = VINF_SUCCESS;
214
215#else
216 /*
217 * Is it apple hardware in bootcamp?
218 */
219 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
220 * Currently falling back on the product name. */
221 char szManufacturer[256];
222 szManufacturer[0] = '\0';
223 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
224 if (szManufacturer[0] != '\0')
225 {
226 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
227 || !strcmp(szManufacturer, "Apple Inc.")
228 )
229 *pfGetKeyFromRealSMC = true;
230 }
231 else
232 {
233 char szProdName[256];
234 szProdName[0] = '\0';
235 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
236 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
237 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
238 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
239 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
240 )
241 && !strchr(szProdName, ' ') /* no spaces */
242 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
243 )
244 *pfGetKeyFromRealSMC = true;
245 }
246
247 int rc = VINF_SUCCESS;
248#endif
249
250 return rc;
251}
252
253
254/*
255 * VC++ 8 / amd64 has some serious trouble with the next functions.
256 * As a temporary measure, we'll drop global optimizations.
257 */
258#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
259# pragma optimize("g", off)
260#endif
261
262static const char *const g_apszIDEDrives[4] =
263 { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
264
265class ConfigError : public RTCError
266{
267public:
268
269 ConfigError(const char *pcszFunction,
270 int vrc,
271 const char *pcszName)
272 : RTCError(Utf8StrFmt("%s failed: rc=%Rrc, pcszName=%s", pcszFunction, vrc, pcszName)),
273 m_vrc(vrc)
274 {
275 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here
276 }
277
278 int m_vrc;
279};
280
281
282/**
283 * Helper that calls CFGMR3InsertString and throws an RTCError if that
284 * fails (C-string variant).
285 * @param pParent See CFGMR3InsertStringN.
286 * @param pcszNodeName See CFGMR3InsertStringN.
287 * @param pcszValue The string value.
288 */
289static void InsertConfigString(PCFGMNODE pNode,
290 const char *pcszName,
291 const char *pcszValue)
292{
293 int vrc = CFGMR3InsertString(pNode,
294 pcszName,
295 pcszValue);
296 if (RT_FAILURE(vrc))
297 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
298}
299
300/**
301 * Helper that calls CFGMR3InsertString and throws an RTCError if that
302 * fails (Utf8Str variant).
303 * @param pParent See CFGMR3InsertStringN.
304 * @param pcszNodeName See CFGMR3InsertStringN.
305 * @param rStrValue The string value.
306 */
307static void InsertConfigString(PCFGMNODE pNode,
308 const char *pcszName,
309 const Utf8Str &rStrValue)
310{
311 int vrc = CFGMR3InsertStringN(pNode,
312 pcszName,
313 rStrValue.c_str(),
314 rStrValue.length());
315 if (RT_FAILURE(vrc))
316 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
317}
318
319/**
320 * Helper that calls CFGMR3InsertString and throws an RTCError if that
321 * fails (Bstr variant).
322 *
323 * @param pParent See CFGMR3InsertStringN.
324 * @param pcszNodeName See CFGMR3InsertStringN.
325 * @param rBstrValue The string value.
326 */
327static void InsertConfigString(PCFGMNODE pNode,
328 const char *pcszName,
329 const Bstr &rBstrValue)
330{
331 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
332}
333
334/**
335 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
336 *
337 * @param pNode See CFGMR3InsertBytes.
338 * @param pcszName See CFGMR3InsertBytes.
339 * @param pvBytes See CFGMR3InsertBytes.
340 * @param cbBytes See CFGMR3InsertBytes.
341 */
342static void InsertConfigBytes(PCFGMNODE pNode,
343 const char *pcszName,
344 const void *pvBytes,
345 size_t cbBytes)
346{
347 int vrc = CFGMR3InsertBytes(pNode,
348 pcszName,
349 pvBytes,
350 cbBytes);
351 if (RT_FAILURE(vrc))
352 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
353}
354
355/**
356 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
357 * fails.
358 *
359 * @param pNode See CFGMR3InsertInteger.
360 * @param pcszName See CFGMR3InsertInteger.
361 * @param u64Integer See CFGMR3InsertInteger.
362 */
363static void InsertConfigInteger(PCFGMNODE pNode,
364 const char *pcszName,
365 uint64_t u64Integer)
366{
367 int vrc = CFGMR3InsertInteger(pNode,
368 pcszName,
369 u64Integer);
370 if (RT_FAILURE(vrc))
371 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
372}
373
374/**
375 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
376 *
377 * @param pNode See CFGMR3InsertNode.
378 * @param pcszName See CFGMR3InsertNode.
379 * @param ppChild See CFGMR3InsertNode.
380 */
381static void InsertConfigNode(PCFGMNODE pNode,
382 const char *pcszName,
383 PCFGMNODE *ppChild)
384{
385 int vrc = CFGMR3InsertNode(pNode, pcszName, ppChild);
386 if (RT_FAILURE(vrc))
387 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
388}
389
390/**
391 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
392 *
393 * @param pNode See CFGMR3RemoveValue.
394 * @param pcszName See CFGMR3RemoveValue.
395 */
396static void RemoveConfigValue(PCFGMNODE pNode,
397 const char *pcszName)
398{
399 int vrc = CFGMR3RemoveValue(pNode, pcszName);
400 if (RT_FAILURE(vrc))
401 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
402}
403
404/**
405 * Gets an extra data value, consulting both machine and global extra data.
406 *
407 * @throws HRESULT on failure
408 * @returns pStrValue for the callers convenience.
409 * @param pVirtualBox Pointer to the IVirtualBox interface.
410 * @param pMachine Pointer to the IMachine interface.
411 * @param pszName The value to get.
412 * @param pStrValue Where to return it's value (empty string if not
413 * found).
414 */
415static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
416{
417 pStrValue->setNull();
418
419 Bstr bstrName(pszName);
420 Bstr bstrValue;
421 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
422 if (FAILED(hrc))
423 throw hrc;
424 if (bstrValue.isEmpty())
425 {
426 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
427 if (FAILED(hrc))
428 throw hrc;
429 }
430
431 if (bstrValue.isNotEmpty())
432 *pStrValue = bstrValue;
433 return pStrValue;
434}
435
436
437/** Helper that finds out the next HBA port used
438 */
439static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
440{
441 LONG lNextPortUsed = 30;
442 for (size_t j = 0; j < u32Size; ++j)
443 {
444 if ( aPortUsed[j] > lBaseVal
445 && aPortUsed[j] <= lNextPortUsed)
446 lNextPortUsed = aPortUsed[j];
447 }
448 return lNextPortUsed;
449}
450
451#define MAX_BIOS_LUN_COUNT 4
452
453static int SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
454 Bstr controllerName, const char * const s_apszBiosConfig[4])
455{
456 HRESULT hrc;
457#define MAX_DEVICES 30
458#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
459
460 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
461 LONG lPortUsed[MAX_DEVICES];
462 uint32_t u32HDCount = 0;
463
464 /* init to max value */
465 lPortLUN[0] = MAX_DEVICES;
466
467 com::SafeIfaceArray<IMediumAttachment> atts;
468 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
469 ComSafeArrayAsOutParam(atts)); H();
470 size_t uNumAttachments = atts.size();
471 if (uNumAttachments > MAX_DEVICES)
472 {
473 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
474 uNumAttachments = MAX_DEVICES;
475 }
476
477 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
478 for (size_t j = 0; j < uNumAttachments; ++j)
479 {
480 IMediumAttachment *pMediumAtt = atts[j];
481 LONG lPortNum = 0;
482 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
483 if (SUCCEEDED(hrc))
484 {
485 DeviceType_T lType;
486 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
487 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
488 {
489 /* find min port number used for HD */
490 if (lPortNum < lPortLUN[0])
491 lPortLUN[0] = lPortNum;
492 lPortUsed[u32HDCount++] = lPortNum;
493 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
494 }
495
496 /* 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 if (auSerialIoPortBase[2])
3046 {
3047 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3048 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3049 }
3050
3051 if (auSerialIoPortBase[3])
3052 {
3053 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3054 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3055 }
3056
3057 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3058 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3059
3060 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3061 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3062
3063 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3064 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3065 InsertConfigNode(pLunL0, "Config", &pCfg);
3066
3067 /* Attach the dummy CPU drivers */
3068 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3069 {
3070 BOOL fCpuAttached = true;
3071
3072 if (fCpuHotPlug)
3073 {
3074 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3075 }
3076
3077 if (fCpuAttached)
3078 {
3079 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3080 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3081 InsertConfigNode(pLunL0, "Config", &pCfg);
3082 }
3083 }
3084 }
3085
3086 /*
3087 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3088 */
3089 {
3090 PCFGMNODE pDbgf;
3091 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3092
3093 /* Paths to search for debug info and such things. */
3094 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3095 Utf8Str strSettingsPath(bstr);
3096 bstr.setNull();
3097 strSettingsPath.stripFilename();
3098 strSettingsPath.append("/");
3099
3100 char szHomeDir[RTPATH_MAX + 1];
3101 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3102 if (RT_FAILURE(rc2))
3103 szHomeDir[0] = '\0';
3104 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3105
3106
3107 Utf8Str strPath;
3108 strPath.append(strSettingsPath).append("debug/;");
3109 strPath.append(strSettingsPath).append(";");
3110 strPath.append(szHomeDir);
3111
3112 InsertConfigString(pDbgf, "Path", strPath.c_str());
3113
3114 /* Tracing configuration. */
3115 BOOL fTracingEnabled;
3116 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3117 if (fTracingEnabled)
3118 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3119
3120 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3121 if (fTracingEnabled)
3122 InsertConfigString(pDbgf, "TracingConfig", bstr);
3123
3124 BOOL fAllowTracingToAccessVM;
3125 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3126 if (fAllowTracingToAccessVM)
3127 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3128
3129 /* Debugger console config. */
3130 PCFGMNODE pDbgc;
3131 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3132
3133 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3134 Utf8Str strVBoxHome = bstr;
3135 bstr.setNull();
3136 if (strVBoxHome.isNotEmpty())
3137 strVBoxHome.append("/");
3138 else
3139 {
3140 strVBoxHome = szHomeDir;
3141 strVBoxHome.append("/.vbox");
3142 }
3143
3144 Utf8Str strFile(strVBoxHome);
3145 strFile.append("dbgc-history");
3146 InsertConfigString(pDbgc, "HistoryFile", strFile);
3147
3148 strFile = strSettingsPath;
3149 strFile.append("dbgc-init");
3150 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3151
3152 strFile = strVBoxHome;
3153 strFile.append("dbgc-init");
3154 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3155 }
3156 }
3157 catch (ConfigError &x)
3158 {
3159 // InsertConfig threw something:
3160 return x.m_vrc;
3161 }
3162 catch (HRESULT hrcXcpt)
3163 {
3164 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3165 }
3166
3167#ifdef VBOX_WITH_EXTPACK
3168 /*
3169 * Call the extension pack hooks if everything went well thus far.
3170 */
3171 if (RT_SUCCESS(rc))
3172 {
3173 pAlock->release();
3174 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3175 pAlock->acquire();
3176 }
3177#endif
3178
3179 /*
3180 * Apply the CFGM overlay.
3181 */
3182 if (RT_SUCCESS(rc))
3183 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3184
3185 /*
3186 * Dump all extradata API settings tweaks, both global and per VM.
3187 */
3188 if (RT_SUCCESS(rc))
3189 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3190
3191#undef H
3192
3193 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3194
3195 /*
3196 * Register VM state change handler.
3197 */
3198 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3199 AssertRC(rc2);
3200 if (RT_SUCCESS(rc))
3201 rc = rc2;
3202
3203 /*
3204 * Register VM runtime error handler.
3205 */
3206 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_setVMRuntimeErrorCallback, this);
3207 AssertRC(rc2);
3208 if (RT_SUCCESS(rc))
3209 rc = rc2;
3210
3211 pAlock->acquire();
3212
3213 LogFlowFunc(("vrc = %Rrc\n", rc));
3214 LogFlowFuncLeave();
3215
3216 return rc;
3217}
3218
3219/**
3220 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3221 * values.
3222 *
3223 * @returns VBox status code.
3224 * @param pRoot The root of the configuration tree.
3225 * @param pVirtualBox Pointer to the IVirtualBox interface.
3226 * @param pMachine Pointer to the IMachine interface.
3227 */
3228/* static */
3229int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3230{
3231 /*
3232 * CFGM overlay handling.
3233 *
3234 * Here we check the extra data entries for CFGM values
3235 * and create the nodes and insert the values on the fly. Existing
3236 * values will be removed and reinserted. CFGM is typed, so by default
3237 * we will guess whether it's a string or an integer (byte arrays are
3238 * not currently supported). It's possible to override this autodetection
3239 * by adding "string:", "integer:" or "bytes:" (future).
3240 *
3241 * We first perform a run on global extra data, then on the machine
3242 * extra data to support global settings with local overrides.
3243 */
3244 int rc = VINF_SUCCESS;
3245 try
3246 {
3247 /** @todo add support for removing nodes and byte blobs. */
3248 /*
3249 * Get the next key
3250 */
3251 SafeArray<BSTR> aGlobalExtraDataKeys;
3252 SafeArray<BSTR> aMachineExtraDataKeys;
3253 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3254 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3255
3256 // remember the no. of global values so we can call the correct method below
3257 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3258
3259 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3260 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3261
3262 // build a combined list from global keys...
3263 std::list<Utf8Str> llExtraDataKeys;
3264
3265 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3266 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3267 // ... and machine keys
3268 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3269 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3270
3271 size_t i2 = 0;
3272 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3273 it != llExtraDataKeys.end();
3274 ++it, ++i2)
3275 {
3276 const Utf8Str &strKey = *it;
3277
3278 /*
3279 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3280 */
3281 if (!strKey.startsWith("VBoxInternal/"))
3282 continue;
3283
3284 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3285
3286 // get the value
3287 Bstr bstrExtraDataValue;
3288 if (i2 < cGlobalValues)
3289 // this is still one of the global values:
3290 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3291 bstrExtraDataValue.asOutParam());
3292 else
3293 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3294 bstrExtraDataValue.asOutParam());
3295 if (FAILED(hrc))
3296 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3297
3298 /*
3299 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3300 * Split the two and get the node, delete the value and create the node
3301 * if necessary.
3302 */
3303 PCFGMNODE pNode;
3304 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3305 if (pszCFGMValueName)
3306 {
3307 /* terminate the node and advance to the value (Utf8Str might not
3308 offically like this but wtf) */
3309 *(char*)pszCFGMValueName = '\0';
3310 ++pszCFGMValueName;
3311
3312 /* does the node already exist? */
3313 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3314 if (pNode)
3315 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3316 else
3317 {
3318 /* create the node */
3319 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3320 if (RT_FAILURE(rc))
3321 {
3322 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3323 continue;
3324 }
3325 Assert(pNode);
3326 }
3327 }
3328 else
3329 {
3330 /* root value (no node path). */
3331 pNode = pRoot;
3332 pszCFGMValueName = pszExtraDataKey;
3333 pszExtraDataKey--;
3334 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3335 }
3336
3337 /*
3338 * Now let's have a look at the value.
3339 * Empty strings means that we should remove the value, which we've
3340 * already done above.
3341 */
3342 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3343 if (!strCFGMValueUtf8.isEmpty())
3344 {
3345 uint64_t u64Value;
3346
3347 /* check for type prefix first. */
3348 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3349 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3350 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3351 {
3352 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3353 if (RT_SUCCESS(rc))
3354 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3355 }
3356 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3357 {
3358 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3359 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3360 if (cbValue > 0)
3361 {
3362 void *pvBytes = RTMemTmpAlloc(cbValue);
3363 if (pvBytes)
3364 {
3365 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3366 if (RT_SUCCESS(rc))
3367 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3368 RTMemTmpFree(pvBytes);
3369 }
3370 else
3371 rc = VERR_NO_TMP_MEMORY;
3372 }
3373 else if (cbValue == 0)
3374 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3375 else
3376 rc = VERR_INVALID_BASE64_ENCODING;
3377 }
3378 /* auto detect type. */
3379 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3380 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3381 else
3382 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3383 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3384 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3385 }
3386 }
3387 }
3388 catch (ConfigError &x)
3389 {
3390 // InsertConfig threw something:
3391 return x.m_vrc;
3392 }
3393 return rc;
3394}
3395
3396/**
3397 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3398 * values.
3399 *
3400 * @returns VBox status code.
3401 * @param pVirtualBox Pointer to the IVirtualBox interface.
3402 * @param pMachine Pointer to the IMachine interface.
3403 */
3404/* static */
3405int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3406{
3407 {
3408 SafeArray<BSTR> aGlobalExtraDataKeys;
3409 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3410 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3411 bool hasKey = false;
3412 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3413 {
3414 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3415 if (!strKey.startsWith("VBoxInternal2/"))
3416 continue;
3417
3418 Bstr bstrValue;
3419 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3420 bstrValue.asOutParam());
3421 if (FAILED(hrc))
3422 continue;
3423 if (!hasKey)
3424 LogRel(("Global extradata API settings:\n"));
3425 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3426 hasKey = true;
3427 }
3428 }
3429
3430 {
3431 SafeArray<BSTR> aMachineExtraDataKeys;
3432 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3433 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3434 bool hasKey = false;
3435 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3436 {
3437 Utf8Str strKey(aMachineExtraDataKeys[i]);
3438 if (!strKey.startsWith("VBoxInternal2/"))
3439 continue;
3440
3441 Bstr bstrValue;
3442 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3443 bstrValue.asOutParam());
3444 if (FAILED(hrc))
3445 continue;
3446 if (!hasKey)
3447 LogRel(("Per-VM extradata API settings:\n"));
3448 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3449 hasKey = true;
3450 }
3451 }
3452
3453 return VINF_SUCCESS;
3454}
3455
3456int Console::i_configGraphicsController(PCFGMNODE pDevices,
3457 const GraphicsControllerType_T enmGraphicsController,
3458 BusAssignmentManager *pBusMgr,
3459 const ComPtr<IMachine> &ptrMachine,
3460 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3461 bool fHMEnabled)
3462{
3463 // InsertConfig* throws
3464 try
3465 {
3466 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3467 HRESULT hrc;
3468 Bstr bstr;
3469 const char *pcszDevice = "vga";
3470
3471#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3472 InsertConfigNode(pDevices, pcszDevice, &pDev);
3473 InsertConfigNode(pDev, "0", &pInst);
3474 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3475
3476 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3477 InsertConfigNode(pInst, "Config", &pCfg);
3478 ULONG cVRamMBs;
3479 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3480 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3481 ULONG cMonitorCount;
3482 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3483 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3484#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3485 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3486#else
3487 NOREF(fHMEnabled);
3488#endif
3489
3490 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3491
3492#ifdef VBOX_WITH_VMSVGA
3493 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3494 {
3495 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3496#ifdef VBOX_WITH_VMSVGA3D
3497 IFramebuffer *pFramebuffer = NULL;
3498 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3499 if (SUCCEEDED(hrc) && pFramebuffer)
3500 {
3501 LONG64 winId = 0;
3502 /* @todo deal with multimonitor setup */
3503 Assert(cMonitorCount == 1);
3504 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3505 InsertConfigInteger(pCfg, "HostWindowId", winId);
3506 pFramebuffer->Release();
3507 }
3508 BOOL f3DEnabled;
3509 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3510 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3511#endif
3512 }
3513#endif
3514
3515 /* Custom VESA mode list */
3516 unsigned cModes = 0;
3517 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3518 {
3519 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3520 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3521 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3522 if (bstr.isEmpty())
3523 break;
3524 InsertConfigString(pCfg, szExtraDataKey, bstr);
3525 ++cModes;
3526 }
3527 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3528
3529 /* VESA height reduction */
3530 ULONG ulHeightReduction;
3531 IFramebuffer *pFramebuffer = NULL;
3532 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3533 if (SUCCEEDED(hrc) && pFramebuffer)
3534 {
3535 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3536 pFramebuffer->Release();
3537 pFramebuffer = NULL;
3538 }
3539 else
3540 {
3541 /* If framebuffer is not available, there is no height reduction. */
3542 ulHeightReduction = 0;
3543 }
3544 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3545
3546 /*
3547 * BIOS logo
3548 */
3549 BOOL fFadeIn;
3550 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3551 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3552 BOOL fFadeOut;
3553 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3554 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3555 ULONG logoDisplayTime;
3556 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3557 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3558 Bstr logoImagePath;
3559 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3560 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3561
3562 /*
3563 * Boot menu
3564 */
3565 BIOSBootMenuMode_T eBootMenuMode;
3566 int iShowBootMenu;
3567 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3568 switch (eBootMenuMode)
3569 {
3570 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3571 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3572 default: iShowBootMenu = 2; break;
3573 }
3574 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3575
3576 /* Attach the display. */
3577 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3578 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3579 InsertConfigNode(pLunL0, "Config", &pCfg);
3580 Display *pDisplay = mDisplay;
3581 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3582 }
3583 catch (ConfigError &x)
3584 {
3585 // InsertConfig threw something:
3586 return x.m_vrc;
3587 }
3588
3589#undef H
3590
3591 return VINF_SUCCESS;
3592}
3593
3594
3595/**
3596 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3597 */
3598void Console::i_setVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3599{
3600 va_list va;
3601 va_start(va, pszFormat);
3602 i_setVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3603 va_end(va);
3604}
3605
3606/* XXX introduce RT format specifier */
3607static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3608{
3609 if (u64Size > INT64_C(5000)*_1G)
3610 {
3611 *pszUnit = "TB";
3612 return u64Size / _1T;
3613 }
3614 else if (u64Size > INT64_C(5000)*_1M)
3615 {
3616 *pszUnit = "GB";
3617 return u64Size / _1G;
3618 }
3619 else
3620 {
3621 *pszUnit = "MB";
3622 return u64Size / _1M;
3623 }
3624}
3625
3626int Console::i_configMediumAttachment(const char *pcszDevice,
3627 unsigned uInstance,
3628 StorageBus_T enmBus,
3629 bool fUseHostIOCache,
3630 bool fBuiltinIOCache,
3631 bool fSetupMerge,
3632 unsigned uMergeSource,
3633 unsigned uMergeTarget,
3634 IMediumAttachment *pMediumAtt,
3635 MachineState_T aMachineState,
3636 HRESULT *phrc,
3637 bool fAttachDetach,
3638 bool fForceUnmount,
3639 bool fHotplug,
3640 PUVM pUVM,
3641 DeviceType_T *paLedDevType,
3642 PCFGMNODE *ppLunL0)
3643{
3644 // InsertConfig* throws
3645 try
3646 {
3647 int rc = VINF_SUCCESS;
3648 HRESULT hrc;
3649 Bstr bstr;
3650 PCFGMNODE pCtlInst = NULL;
3651
3652// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
3653#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3654
3655 LONG lDev;
3656 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
3657 LONG lPort;
3658 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
3659 DeviceType_T lType;
3660 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
3661 BOOL fNonRotational;
3662 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
3663 BOOL fDiscard;
3664 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
3665
3666 unsigned uLUN;
3667 PCFGMNODE pLunL0 = NULL;
3668 hrc = Console::i_convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
3669
3670 /* Determine the base path for the device instance. */
3671 if (enmBus != StorageBus_USB)
3672 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
3673 else
3674 {
3675 /* If we hotplug a USB device create a new CFGM tree. */
3676 if (!fHotplug)
3677 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
3678 else
3679 pCtlInst = CFGMR3CreateTree(pUVM);
3680 }
3681 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
3682
3683 if (enmBus == StorageBus_USB)
3684 {
3685 PCFGMNODE pCfg = NULL;
3686
3687 /* Create correct instance. */
3688 if (!fHotplug)
3689 {
3690 if (!fAttachDetach)
3691 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
3692 else
3693 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
3694 }
3695
3696 if (!fAttachDetach)
3697 InsertConfigNode(pCtlInst, "Config", &pCfg);
3698
3699 uInstance = lPort; /* Overwrite uInstance with the correct one. */
3700
3701 if (!fHotplug && !fAttachDetach)
3702 {
3703 char aszUuid[RTUUID_STR_LENGTH + 1];
3704 USBStorageDevice UsbMsd = USBStorageDevice();
3705
3706 memset(aszUuid, 0, sizeof(aszUuid));
3707 rc = RTUuidCreate(&UsbMsd.mUuid);
3708 AssertRCReturn(rc, rc);
3709 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
3710 AssertRCReturn(rc, rc);
3711
3712 UsbMsd.iPort = uInstance;
3713
3714 InsertConfigString(pCtlInst, "UUID", aszUuid);
3715 mUSBStorageDevices.push_back(UsbMsd);
3716
3717 /** @todo: No LED after hotplugging. */
3718 /* Attach the status driver */
3719 Assert(cLedUsb >= 8);
3720 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
3721 &mapMediumAttachments, pcszDevice, 0);
3722 paLedDevType = &maStorageDevType[iLedUsb];
3723 }
3724 }
3725
3726 /* First check if the LUN already exists. */
3727 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
3728 if (pLunL0)
3729 {
3730 if (fAttachDetach)
3731 {
3732 if (lType != DeviceType_HardDisk)
3733 {
3734 /* Unmount existing media only for floppy and DVD drives. */
3735 PPDMIBASE pBase;
3736 if (enmBus == StorageBus_USB)
3737 rc = PDMR3UsbQueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
3738 else
3739 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
3740 if (RT_FAILURE(rc))
3741 {
3742 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
3743 rc = VINF_SUCCESS;
3744 AssertRC(rc);
3745 }
3746 else
3747 {
3748 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
3749 AssertReturn(pIMount, VERR_INVALID_POINTER);
3750
3751 /* Unmount the media (but do not eject the medium!) */
3752 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
3753 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
3754 rc = VINF_SUCCESS;
3755 /* for example if the medium is locked */
3756 else if (RT_FAILURE(rc))
3757 return rc;
3758 }
3759 }
3760
3761 if (enmBus == StorageBus_USB)
3762 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN, NULL, 0,
3763 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
3764 else
3765 rc = PDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
3766 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
3767 rc = VINF_SUCCESS;
3768 AssertRCReturn(rc, rc);
3769
3770 CFGMR3RemoveNode(pLunL0);
3771 }
3772 else
3773 AssertFailedReturn(VERR_INTERNAL_ERROR);
3774 }
3775
3776 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
3777 if (ppLunL0)
3778 *ppLunL0 = pLunL0;
3779
3780 PCFGMNODE pCfg = CFGMR3GetChild(pCtlInst, "Config");
3781 if (pCfg)
3782 {
3783 if (!strcmp(pcszDevice, "piix3ide"))
3784 {
3785 PCFGMNODE pDrive = CFGMR3GetChild(pCfg, g_apszIDEDrives[uLUN]);
3786 if (!pDrive)
3787 InsertConfigNode(pCfg, g_apszIDEDrives[uLUN], &pDrive);
3788 /* Don't use the RemoveConfigValue wrapper above, as we don't
3789 * know if the leaf is present or not. */
3790 CFGMR3RemoveValue(pDrive, "NonRotationalMedium");
3791 InsertConfigInteger(pDrive, "NonRotationalMedium", !!fNonRotational);
3792 }
3793 else if (!strcmp(pcszDevice, "ahci"))
3794 {
3795 Utf8Str strPort = Utf8StrFmt("Port%u", uLUN);
3796 PCFGMNODE pDrive = CFGMR3GetChild(pCfg, strPort.c_str());
3797 if (!pDrive)
3798 InsertConfigNode(pCfg, strPort.c_str(), &pDrive);
3799 /* Don't use the RemoveConfigValue wrapper above, as we don't
3800 * know if the leaf is present or not. */
3801 CFGMR3RemoveValue(pDrive, "NonRotationalMedium");
3802 InsertConfigInteger(pDrive, "NonRotationalMedium", !!fNonRotational);
3803 }
3804 }
3805
3806 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
3807 mapMediumAttachments[devicePath] = pMediumAtt;
3808
3809 /* SCSI has a another driver between device and block. */
3810 if (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
3811 {
3812 InsertConfigString(pLunL0, "Driver", "SCSI");
3813 PCFGMNODE pL1Cfg = NULL;
3814 InsertConfigNode(pLunL0, "Config", &pL1Cfg);
3815 InsertConfigInteger(pL1Cfg, "NonRotationalMedium", !!fNonRotational);
3816
3817 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
3818 }
3819
3820 ComPtr<IMedium> pMedium;
3821 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
3822
3823 /*
3824 * 1. Only check this for hard disk images.
3825 * 2. Only check during VM creation and not later, especially not during
3826 * taking an online snapshot!
3827 */
3828 if ( lType == DeviceType_HardDisk
3829 && ( aMachineState == MachineState_Starting
3830 || aMachineState == MachineState_Restoring))
3831 {
3832 /*
3833 * Some sanity checks.
3834 */
3835 ComPtr<IMediumFormat> pMediumFormat;
3836 hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3837 ULONG uCaps = 0;
3838 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3839 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3840
3841 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3842 uCaps |= mediumFormatCap[j];
3843
3844 if (uCaps & MediumFormatCapabilities_File)
3845 {
3846 Bstr strFile;
3847 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3848 Utf8Str utfFile = Utf8Str(strFile);
3849 Bstr strSnap;
3850 ComPtr<IMachine> pMachine = i_machine();
3851 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3852 Utf8Str utfSnap = Utf8Str(strSnap);
3853 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3854 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3855 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3856 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3857 /* Ignore the error code. On error, the file system type is still 'unknown' so
3858 * none of the following paths are taken. This can happen for new VMs which
3859 * still don't have a snapshot folder. */
3860 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3861 if (!mfSnapshotFolderDiskTypeShown)
3862 {
3863 LogRel(("File system of '%s' (snapshots) is %s\n",
3864 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3865 mfSnapshotFolderDiskTypeShown = true;
3866 }
3867 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3868 LONG64 i64Size;
3869 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3870#ifdef RT_OS_WINDOWS
3871 if ( enmFsTypeFile == RTFSTYPE_FAT
3872 && i64Size >= _4G)
3873 {
3874 const char *pszUnit;
3875 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3876 i_setVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3877 N_("The medium '%ls' has a logical size of %RU64%s "
3878 "but the file system the medium is located on seems "
3879 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3880 "We strongly recommend to put all your virtual disk images and "
3881 "the snapshot folder onto an NTFS partition"),
3882 strFile.raw(), u64Print, pszUnit);
3883 }
3884#else /* !RT_OS_WINDOWS */
3885 if ( enmFsTypeFile == RTFSTYPE_FAT
3886 || enmFsTypeFile == RTFSTYPE_EXT
3887 || enmFsTypeFile == RTFSTYPE_EXT2
3888 || enmFsTypeFile == RTFSTYPE_EXT3
3889 || enmFsTypeFile == RTFSTYPE_EXT4)
3890 {
3891 RTFILE file;
3892 rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3893 if (RT_SUCCESS(rc))
3894 {
3895 RTFOFF maxSize;
3896 /* Careful: This function will work only on selected local file systems! */
3897 rc = RTFileGetMaxSizeEx(file, &maxSize);
3898 RTFileClose(file);
3899 if ( RT_SUCCESS(rc)
3900 && maxSize > 0
3901 && i64Size > (LONG64)maxSize)
3902 {
3903 const char *pszUnitSiz;
3904 const char *pszUnitMax;
3905 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3906 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3907 i_setVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3908 N_("The medium '%ls' has a logical size of %RU64%s "
3909 "but the file system the medium is located on can "
3910 "only handle files up to %RU64%s in theory.\n"
3911 "We strongly recommend to put all your virtual disk "
3912 "images and the snapshot folder onto a proper "
3913 "file system (e.g. ext3) with a sufficient size"),
3914 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3915 }
3916 }
3917 }
3918#endif /* !RT_OS_WINDOWS */
3919
3920 /*
3921 * Snapshot folder:
3922 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3923 */
3924 if ( enmFsTypeSnap == RTFSTYPE_FAT
3925 && i64Size >= _4G
3926 && !mfSnapshotFolderSizeWarningShown)
3927 {
3928 const char *pszUnit;
3929 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3930 i_setVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3931#ifdef RT_OS_WINDOWS
3932 N_("The snapshot folder of this VM '%ls' seems to be located on "
3933 "a FAT(32) file system. The logical size of the medium '%ls' "
3934 "(%RU64%s) is bigger than the maximum file size this file "
3935 "system can handle (4GB).\n"
3936 "We strongly recommend to put all your virtual disk images and "
3937 "the snapshot folder onto an NTFS partition"),
3938#else
3939 N_("The snapshot folder of this VM '%ls' seems to be located on "
3940 "a FAT(32) file system. The logical size of the medium '%ls' "
3941 "(%RU64%s) is bigger than the maximum file size this file "
3942 "system can handle (4GB).\n"
3943 "We strongly recommend to put all your virtual disk images and "
3944 "the snapshot folder onto a proper file system (e.g. ext3)"),
3945#endif
3946 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3947 /* Show this particular warning only once */
3948 mfSnapshotFolderSizeWarningShown = true;
3949 }
3950
3951#ifdef RT_OS_LINUX
3952 /*
3953 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3954 * on an ext4 partition. Later we have to check the Linux kernel version!
3955 * This bug apparently applies to the XFS file system as well.
3956 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3957 */
3958
3959 char szOsRelease[128];
3960 rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3961 bool fKernelHasODirectBug = RT_FAILURE(rc)
3962 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3963
3964 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3965 && !fUseHostIOCache
3966 && fKernelHasODirectBug)
3967 {
3968 if ( enmFsTypeFile == RTFSTYPE_EXT4
3969 || enmFsTypeFile == RTFSTYPE_XFS)
3970 {
3971 i_setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3972 N_("The host I/O cache for at least one controller is disabled "
3973 "and the medium '%ls' for this VM "
3974 "is located on an %s partition. There is a known Linux "
3975 "kernel bug which can lead to the corruption of the virtual "
3976 "disk image under these conditions.\n"
3977 "Either enable the host I/O cache permanently in the VM "
3978 "settings or put the disk image and the snapshot folder "
3979 "onto a different file system.\n"
3980 "The host I/O cache will now be enabled for this medium"),
3981 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3982 fUseHostIOCache = true;
3983 }
3984 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
3985 || enmFsTypeSnap == RTFSTYPE_XFS)
3986 && !mfSnapshotFolderExt4WarningShown)
3987 {
3988 i_setVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3989 N_("The host I/O cache for at least one controller is disabled "
3990 "and the snapshot folder for this VM "
3991 "is located on an %s partition. There is a known Linux "
3992 "kernel bug which can lead to the corruption of the virtual "
3993 "disk image under these conditions.\n"
3994 "Either enable the host I/O cache permanently in the VM "
3995 "settings or put the disk image and the snapshot folder "
3996 "onto a different file system.\n"
3997 "The host I/O cache will now be enabled for this medium"),
3998 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3999 fUseHostIOCache = true;
4000 mfSnapshotFolderExt4WarningShown = true;
4001 }
4002 }
4003#endif
4004 }
4005 }
4006
4007 if (pMedium)
4008 {
4009 BOOL fHostDrive;
4010 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4011 if ( ( lType == DeviceType_DVD
4012 || lType == DeviceType_Floppy)
4013 && !fHostDrive)
4014 {
4015 /*
4016 * Informative logging.
4017 */
4018 Bstr strFile;
4019 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4020 Utf8Str utfFile = Utf8Str(strFile);
4021 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4022 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4023 LogRel(("File system of '%s' (%s) is %s\n",
4024 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4025 RTFsTypeName(enmFsTypeFile)));
4026 }
4027 }
4028
4029 BOOL fPassthrough;
4030 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4031
4032 ComObjPtr<IBandwidthGroup> pBwGroup;
4033 Bstr strBwGroup;
4034 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4035
4036 if (!pBwGroup.isNull())
4037 {
4038 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4039 }
4040
4041 rc = i_configMedium(pLunL0,
4042 !!fPassthrough,
4043 lType,
4044 fUseHostIOCache,
4045 fBuiltinIOCache,
4046 fSetupMerge,
4047 uMergeSource,
4048 uMergeTarget,
4049 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4050 !!fDiscard,
4051 pMedium,
4052 aMachineState,
4053 phrc);
4054 if (RT_FAILURE(rc))
4055 return rc;
4056
4057 if (fAttachDetach)
4058 {
4059 /* Attach the new driver. */
4060 if (enmBus == StorageBus_USB)
4061 {
4062 if (fHotplug)
4063 {
4064 USBStorageDevice UsbMsd = USBStorageDevice();
4065 RTUuidCreate(&UsbMsd.mUuid);
4066 UsbMsd.iPort = uInstance;
4067 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4068 if (RT_SUCCESS(rc))
4069 mUSBStorageDevices.push_back(UsbMsd);
4070 }
4071 else
4072 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4073 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4074 }
4075 else
4076 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4077 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4078 AssertRCReturn(rc, rc);
4079
4080 /*
4081 * Make the secret key helper interface known to the VD driver if it is attached,
4082 * so we can get notified about missing keys.
4083 */
4084 PPDMIBASE pIBase = NULL;
4085 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4086 if (RT_SUCCESS(rc) && pIBase)
4087 {
4088 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4089 if (pIMedium)
4090 {
4091 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4092 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4093 }
4094 }
4095
4096 /* There is no need to handle removable medium mounting, as we
4097 * unconditionally replace everthing including the block driver level.
4098 * This means the new medium will be picked up automatically. */
4099 }
4100
4101 if (paLedDevType)
4102 paLedDevType[uLUN] = lType;
4103
4104 /* Dump the changed LUN if possible, dump the complete device otherwise */
4105 if ( aMachineState != MachineState_Starting
4106 && aMachineState != MachineState_Restoring)
4107 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4108 }
4109 catch (ConfigError &x)
4110 {
4111 // InsertConfig threw something:
4112 return x.m_vrc;
4113 }
4114
4115#undef H
4116
4117 return VINF_SUCCESS;
4118}
4119
4120int Console::i_configMedium(PCFGMNODE pLunL0,
4121 bool fPassthrough,
4122 DeviceType_T enmType,
4123 bool fUseHostIOCache,
4124 bool fBuiltinIOCache,
4125 bool fSetupMerge,
4126 unsigned uMergeSource,
4127 unsigned uMergeTarget,
4128 const char *pcszBwGroup,
4129 bool fDiscard,
4130 IMedium *pMedium,
4131 MachineState_T aMachineState,
4132 HRESULT *phrc)
4133{
4134 // InsertConfig* throws
4135 try
4136 {
4137 int rc = VINF_SUCCESS;
4138 HRESULT hrc;
4139 Bstr bstr;
4140 PCFGMNODE pLunL1 = NULL;
4141 PCFGMNODE pCfg = NULL;
4142
4143#define H() \
4144 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4145
4146
4147 BOOL fHostDrive = FALSE;
4148 MediumType_T mediumType = MediumType_Normal;
4149 if (pMedium)
4150 {
4151 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4152 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4153 }
4154
4155 if (fHostDrive)
4156 {
4157 Assert(pMedium);
4158 if (enmType == DeviceType_DVD)
4159 {
4160 InsertConfigString(pLunL0, "Driver", "HostDVD");
4161 InsertConfigNode(pLunL0, "Config", &pCfg);
4162
4163 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4164 InsertConfigString(pCfg, "Path", bstr);
4165
4166 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4167 }
4168 else if (enmType == DeviceType_Floppy)
4169 {
4170 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4171 InsertConfigNode(pLunL0, "Config", &pCfg);
4172
4173 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4174 InsertConfigString(pCfg, "Path", bstr);
4175 }
4176 }
4177 else
4178 {
4179#if 0 /* Enable for I/O debugging */
4180 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4181 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4182 InsertConfigNode(pLunL0, "Config", &pCfg);
4183 InsertConfigInteger(pCfg, "CheckConsistency", 0);
4184 InsertConfigInteger(pCfg, "CheckDoubleCompletions", 1);
4185#endif
4186
4187 InsertConfigString(pLunL0, "Driver", "VD");
4188 InsertConfigNode(pLunL0, "Config", &pCfg);
4189 switch (enmType)
4190 {
4191 case DeviceType_DVD:
4192 InsertConfigString(pCfg, "Type", "DVD");
4193 InsertConfigInteger(pCfg, "Mountable", 1);
4194 break;
4195 case DeviceType_Floppy:
4196 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4197 InsertConfigInteger(pCfg, "Mountable", 1);
4198 break;
4199 case DeviceType_HardDisk:
4200 default:
4201 InsertConfigString(pCfg, "Type", "HardDisk");
4202 InsertConfigInteger(pCfg, "Mountable", 0);
4203 }
4204
4205 if ( pMedium
4206 && ( enmType == DeviceType_DVD
4207 || enmType == DeviceType_Floppy)
4208 )
4209 {
4210 // if this medium represents an ISO image and this image is inaccessible,
4211 // the ignore it instead of causing a failure; this can happen when we
4212 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4213 // Additions were mounted and the user upgraded VirtualBox. Previously
4214 // we failed on startup, but that's not good because the only way out then
4215 // would be to discard the VM state...
4216 MediumState_T mediumState;
4217 hrc = pMedium->RefreshState(&mediumState); H();
4218 if (mediumState == MediumState_Inaccessible)
4219 {
4220 Bstr loc;
4221 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4222 i_setVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4223 "The image file '%ls' is inaccessible and is being ignored. "
4224 "Please select a different image file for the virtual %s drive.",
4225 loc.raw(),
4226 enmType == DeviceType_DVD ? "DVD" : "floppy");
4227 pMedium = NULL;
4228 }
4229 }
4230
4231 if (pMedium)
4232 {
4233 /* Start with length of parent chain, as the list is reversed */
4234 unsigned uImage = 0;
4235 IMedium *pTmp = pMedium;
4236 while (pTmp)
4237 {
4238 uImage++;
4239 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4240 }
4241 /* Index of last image */
4242 uImage--;
4243
4244# ifdef VBOX_WITH_EXTPACK
4245 static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack");
4246 static const char *s_pszVDPlugin = "VDPluginCrypt";
4247 if (mptrExtPackManager->i_isExtPackUsable(strExtPackPuel.c_str()))
4248 {
4249 /* Configure loading the VDPlugin. */
4250 PCFGMNODE pCfgPlugins = NULL;
4251 PCFGMNODE pCfgPlugin = NULL;
4252 Utf8Str strPlugin;
4253 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_pszVDPlugin, &strExtPackPuel, &strPlugin);
4254 // Don't fail, this is optional!
4255 if (SUCCEEDED(hrc))
4256 {
4257 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4258 InsertConfigNode(pCfgPlugins, s_pszVDPlugin, &pCfgPlugin);
4259 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4260 }
4261 }
4262# endif
4263
4264 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4265 InsertConfigString(pCfg, "Path", bstr);
4266
4267 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4268 InsertConfigString(pCfg, "Format", bstr);
4269
4270 if (mediumType == MediumType_Readonly)
4271 InsertConfigInteger(pCfg, "ReadOnly", 1);
4272 else if (enmType == DeviceType_Floppy)
4273 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4274
4275 /* Start without exclusive write access to the images. */
4276 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4277 * we're resuming the VM if some 3rd dude have any of the VDIs open
4278 * with write sharing denied. However, if the two VMs are sharing a
4279 * image it really is necessary....
4280 *
4281 * So, on the "lock-media" command, the target teleporter should also
4282 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4283 * that. Grumble. */
4284 if ( enmType == DeviceType_HardDisk
4285 && ( aMachineState == MachineState_TeleportingIn
4286 || aMachineState == MachineState_FaultTolerantSyncing))
4287 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4288
4289 /* Flag for opening the medium for sharing between VMs. This
4290 * is done at the moment only for the first (and only) medium
4291 * in the chain, as shared media can have no diffs. */
4292 if (mediumType == MediumType_Shareable)
4293 InsertConfigInteger(pCfg, "Shareable", 1);
4294
4295 if (!fUseHostIOCache)
4296 {
4297 InsertConfigInteger(pCfg, "UseNewIo", 1);
4298 /*
4299 * Activate the builtin I/O cache for harddisks only.
4300 * It caches writes only which doesn't make sense for DVD drives
4301 * and just increases the overhead.
4302 */
4303 if ( fBuiltinIOCache
4304 && (enmType == DeviceType_HardDisk))
4305 InsertConfigInteger(pCfg, "BlockCache", 1);
4306 }
4307
4308 if (fSetupMerge)
4309 {
4310 InsertConfigInteger(pCfg, "SetupMerge", 1);
4311 if (uImage == uMergeSource)
4312 InsertConfigInteger(pCfg, "MergeSource", 1);
4313 else if (uImage == uMergeTarget)
4314 InsertConfigInteger(pCfg, "MergeTarget", 1);
4315 }
4316
4317 if (pcszBwGroup)
4318 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4319
4320 if (fDiscard)
4321 InsertConfigInteger(pCfg, "Discard", 1);
4322
4323 /* Pass all custom parameters. */
4324 bool fHostIP = true;
4325 bool fEncrypted = false;
4326 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4327
4328 /* Create an inverted list of parents. */
4329 uImage--;
4330 IMedium *pParentMedium = pMedium;
4331 for (PCFGMNODE pParent = pCfg;; uImage--)
4332 {
4333 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4334 if (!pMedium)
4335 break;
4336
4337 PCFGMNODE pCur;
4338 InsertConfigNode(pParent, "Parent", &pCur);
4339 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4340 InsertConfigString(pCur, "Path", bstr);
4341
4342 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4343 InsertConfigString(pCur, "Format", bstr);
4344
4345 if (fSetupMerge)
4346 {
4347 if (uImage == uMergeSource)
4348 InsertConfigInteger(pCur, "MergeSource", 1);
4349 else if (uImage == uMergeTarget)
4350 InsertConfigInteger(pCur, "MergeTarget", 1);
4351 }
4352
4353 /* Configure medium properties. */
4354 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4355
4356 /* next */
4357 pParent = pCur;
4358 pParentMedium = pMedium;
4359 }
4360
4361 /* Custom code: put marker to not use host IP stack to driver
4362 * configuration node. Simplifies life of DrvVD a bit. */
4363 if (!fHostIP)
4364 InsertConfigInteger(pCfg, "HostIPStack", 0);
4365
4366 if (fEncrypted)
4367 m_cDisksEncrypted++;
4368 }
4369 else
4370 {
4371 /* Set empty drive flag for DVD or floppy without media. */
4372 if ( enmType == DeviceType_DVD
4373 || enmType == DeviceType_Floppy)
4374 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4375 }
4376 }
4377#undef H
4378 }
4379 catch (ConfigError &x)
4380 {
4381 // InsertConfig threw something:
4382 return x.m_vrc;
4383 }
4384
4385 return VINF_SUCCESS;
4386}
4387
4388/**
4389 * Adds the medium properties to the CFGM tree.
4390 *
4391 * @returns VBox status code.
4392 * @param pCur The current CFGM node.
4393 * @param pMedium The medium object to configure.
4394 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4395 * @param pfEncrypted Where to return whether the medium is encrypted.
4396 */
4397int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4398{
4399 /* Pass all custom parameters. */
4400 SafeArray<BSTR> aNames;
4401 SafeArray<BSTR> aValues;
4402 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4403 ComSafeArrayAsOutParam(aValues));
4404
4405 if ( SUCCEEDED(hrc)
4406 && aNames.size() != 0)
4407 {
4408 PCFGMNODE pVDC;
4409 InsertConfigNode(pCur, "VDConfig", &pVDC);
4410 for (size_t ii = 0; ii < aNames.size(); ++ii)
4411 {
4412 if (aValues[ii] && *aValues[ii])
4413 {
4414 Utf8Str name = aNames[ii];
4415 Utf8Str value = aValues[ii];
4416 size_t offSlash = name.find("/", 0);
4417 if ( offSlash != name.npos
4418 && !name.startsWith("Special/"))
4419 {
4420 com::Utf8Str strFilter;
4421 com::Utf8Str strKey;
4422
4423 hrc = strFilter.assignEx(name, 0, offSlash);
4424 if (FAILED(hrc))
4425 break;
4426
4427 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4428 if (FAILED(hrc))
4429 break;
4430
4431 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4432 if (!pCfgFilterConfig)
4433 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4434
4435 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4436 }
4437 else
4438 {
4439 InsertConfigString(pVDC, name.c_str(), value);
4440 if ( name.compare("HostIPStack") == 0
4441 && value.compare("0") == 0)
4442 *pfHostIP = false;
4443 }
4444
4445 if ( name.compare("CRYPT/KeyId") == 0
4446 && pfEncrypted)
4447 *pfEncrypted = true;
4448 }
4449 }
4450 }
4451
4452 return hrc;
4453}
4454
4455
4456#ifdef RT_OS_WINDOWS
4457DECLINLINE(bool) IsNdis6(void)
4458{
4459 LogFlowFunc(("entry\n"));
4460 HANDLE hFile = CreateFile(L"\\\\.\\VBoxNetLwf",
4461 0,
4462 FILE_SHARE_READ | FILE_SHARE_WRITE,
4463 NULL,
4464 OPEN_EXISTING,
4465 0,
4466 NULL);
4467 bool fNdis6 = hFile != INVALID_HANDLE_VALUE;
4468 if (fNdis6)
4469 CloseHandle(hFile);
4470 else
4471 LogFunc(("CreateFile failed with 0x%x\n", GetLastError()));
4472 LogFlowFunc(("return %s\n", fNdis6 ? "true" : "false"));
4473 return fNdis6;
4474}
4475#endif /* RT_OS_WINDOWS */
4476
4477
4478/**
4479 * Construct the Network configuration tree
4480 *
4481 * @returns VBox status code.
4482 *
4483 * @param pszDevice The PDM device name.
4484 * @param uInstance The PDM device instance.
4485 * @param uLun The PDM LUN number of the drive.
4486 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4487 * @param pCfg Configuration node for the device
4488 * @param pLunL0 To store the pointer to the LUN#0.
4489 * @param pInst The instance CFGM node
4490 * @param fAttachDetach To determine if the network attachment should
4491 * be attached/detached after/before
4492 * configuration.
4493 * @param fIgnoreConnectFailure
4494 * True if connection failures should be ignored
4495 * (makes only sense for bridged/host-only networks).
4496 *
4497 * @note Locks this object for writing.
4498 * @thread EMT
4499 */
4500int Console::i_configNetwork(const char *pszDevice,
4501 unsigned uInstance,
4502 unsigned uLun,
4503 INetworkAdapter *aNetworkAdapter,
4504 PCFGMNODE pCfg,
4505 PCFGMNODE pLunL0,
4506 PCFGMNODE pInst,
4507 bool fAttachDetach,
4508 bool fIgnoreConnectFailure)
4509{
4510 AutoCaller autoCaller(this);
4511 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4512
4513 // InsertConfig* throws
4514 try
4515 {
4516 int rc = VINF_SUCCESS;
4517 HRESULT hrc;
4518 Bstr bstr;
4519
4520#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4521
4522 /*
4523 * Locking the object before doing VMR3* calls is quite safe here, since
4524 * we're on EMT. Write lock is necessary because we indirectly modify the
4525 * meAttachmentType member.
4526 */
4527 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4528
4529 ComPtr<IMachine> pMachine = i_machine();
4530
4531 ComPtr<IVirtualBox> virtualBox;
4532 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4533
4534 ComPtr<IHost> host;
4535 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4536
4537 BOOL fSniffer;
4538 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4539
4540 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4541 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4542 const char *pszPromiscuousGuestPolicy;
4543 switch (enmPromiscModePolicy)
4544 {
4545 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4546 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4547 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4548 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4549 }
4550
4551 if (fAttachDetach)
4552 {
4553 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4554 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4555 rc = VINF_SUCCESS;
4556 AssertLogRelRCReturn(rc, rc);
4557
4558 /* nuke anything which might have been left behind. */
4559 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4560 }
4561
4562#ifdef VBOX_WITH_NETSHAPER
4563 ComObjPtr<IBandwidthGroup> pBwGroup;
4564 Bstr strBwGroup;
4565 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4566
4567 if (!pBwGroup.isNull())
4568 {
4569 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4570 }
4571#endif /* VBOX_WITH_NETSHAPER */
4572
4573 Utf8Str strNetDriver;
4574
4575
4576 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4577
4578#ifdef VBOX_WITH_NETSHAPER
4579 if (!strBwGroup.isEmpty())
4580 {
4581 InsertConfigString(pLunL0, "Driver", "NetShaper");
4582 InsertConfigNode(pLunL0, "Config", &pCfg);
4583 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4584 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4585 }
4586#endif /* VBOX_WITH_NETSHAPER */
4587
4588 if (fSniffer)
4589 {
4590 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4591 InsertConfigNode(pLunL0, "Config", &pCfg);
4592 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4593 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4594 InsertConfigString(pCfg, "File", bstr);
4595 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4596 }
4597
4598
4599 Bstr networkName, trunkName, trunkType;
4600 NetworkAttachmentType_T eAttachmentType;
4601 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4602 switch (eAttachmentType)
4603 {
4604 case NetworkAttachmentType_Null:
4605 break;
4606
4607 case NetworkAttachmentType_NAT:
4608 {
4609 ComPtr<INATEngine> natEngine;
4610 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4611 InsertConfigString(pLunL0, "Driver", "NAT");
4612 InsertConfigNode(pLunL0, "Config", &pCfg);
4613
4614 /* Configure TFTP prefix and boot filename. */
4615 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4616 if (!bstr.isEmpty())
4617 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
4618 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
4619 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
4620
4621 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
4622 if (!bstr.isEmpty())
4623 InsertConfigString(pCfg, "Network", bstr);
4624 else
4625 {
4626 ULONG uSlot;
4627 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
4628 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
4629 }
4630 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
4631 if (!bstr.isEmpty())
4632 InsertConfigString(pCfg, "BindIP", bstr);
4633 ULONG mtu = 0;
4634 ULONG sockSnd = 0;
4635 ULONG sockRcv = 0;
4636 ULONG tcpSnd = 0;
4637 ULONG tcpRcv = 0;
4638 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
4639 if (mtu)
4640 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
4641 if (sockRcv)
4642 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
4643 if (sockSnd)
4644 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
4645 if (tcpRcv)
4646 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
4647 if (tcpSnd)
4648 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
4649 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
4650 if (!bstr.isEmpty())
4651 {
4652 RemoveConfigValue(pCfg, "TFTPPrefix");
4653 InsertConfigString(pCfg, "TFTPPrefix", bstr);
4654 }
4655 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
4656 if (!bstr.isEmpty())
4657 {
4658 RemoveConfigValue(pCfg, "BootFile");
4659 InsertConfigString(pCfg, "BootFile", bstr);
4660 }
4661 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
4662 if (!bstr.isEmpty())
4663 InsertConfigString(pCfg, "NextServer", bstr);
4664 BOOL fDNSFlag;
4665 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
4666 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
4667 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
4668 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
4669 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
4670 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
4671
4672 ULONG aliasMode;
4673 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
4674 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
4675
4676 /* port-forwarding */
4677 SafeArray<BSTR> pfs;
4678 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
4679 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PF#0/ */
4680 for (unsigned int i = 0; i < pfs.size(); ++i)
4681 {
4682 uint16_t port = 0;
4683 BSTR r = pfs[i];
4684 Utf8Str utf = Utf8Str(r);
4685 Utf8Str strName;
4686 Utf8Str strProto;
4687 Utf8Str strHostPort;
4688 Utf8Str strHostIP;
4689 Utf8Str strGuestPort;
4690 Utf8Str strGuestIP;
4691 size_t pos, ppos;
4692 pos = ppos = 0;
4693#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
4694 do { \
4695 pos = str.find(",", ppos); \
4696 if (pos == Utf8Str::npos) \
4697 { \
4698 Log(( #res " extracting from %s is failed\n", str.c_str())); \
4699 continue; \
4700 } \
4701 res = str.substr(ppos, pos - ppos); \
4702 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
4703 ppos = pos + 1; \
4704 } while (0)
4705 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
4706 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
4707 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
4708 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
4709 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
4710 strGuestPort = utf.substr(ppos, utf.length() - ppos);
4711#undef ITERATE_TO_NEXT_TERM
4712
4713 uint32_t proto = strProto.toUInt32();
4714 bool fValid = true;
4715 switch (proto)
4716 {
4717 case NATProtocol_UDP:
4718 strProto = "UDP";
4719 break;
4720 case NATProtocol_TCP:
4721 strProto = "TCP";
4722 break;
4723 default:
4724 fValid = false;
4725 }
4726 /* continue with next rule if no valid proto was passed */
4727 if (!fValid)
4728 continue;
4729
4730 if (strName.isEmpty())
4731 VMSetError(VMR3GetVM(mpUVM), VERR_CFGM_NO_NODE, RT_SRC_POS,
4732 N_("NAT redirection rule without a name"));
4733
4734 InsertConfigNode(pCfg, strName.c_str(), &pPF);
4735 InsertConfigString(pPF, "Protocol", strProto);
4736
4737 if (!strHostIP.isEmpty())
4738 InsertConfigString(pPF, "BindIP", strHostIP);
4739
4740 if (!strGuestIP.isEmpty())
4741 InsertConfigString(pPF, "GuestIP", strGuestIP);
4742
4743 port = RTStrToUInt16(strHostPort.c_str());
4744 if (port)
4745 InsertConfigInteger(pPF, "HostPort", port);
4746
4747 port = RTStrToUInt16(strGuestPort.c_str());
4748 if (port)
4749 InsertConfigInteger(pPF, "GuestPort", port);
4750 }
4751 break;
4752 }
4753
4754 case NetworkAttachmentType_Bridged:
4755 {
4756#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
4757 hrc = i_attachToTapInterface(aNetworkAdapter);
4758 if (FAILED(hrc))
4759 {
4760 switch (hrc)
4761 {
4762 case VERR_ACCESS_DENIED:
4763 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4764 "Failed to open '/dev/net/tun' for read/write access. Please check the "
4765 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
4766 "change the group of that node and make yourself a member of that group. Make "
4767 "sure that these changes are permanent, especially if you are "
4768 "using udev"));
4769 default:
4770 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
4771 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4772 "Failed to initialize Host Interface Networking"));
4773 }
4774 }
4775
4776 Assert((intptr_t)maTapFD[uInstance] >= 0);
4777 if ((intptr_t)maTapFD[uInstance] >= 0)
4778 {
4779 InsertConfigString(pLunL0, "Driver", "HostInterface");
4780 InsertConfigNode(pLunL0, "Config", &pCfg);
4781 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
4782 }
4783
4784#elif defined(VBOX_WITH_NETFLT)
4785 /*
4786 * This is the new VBoxNetFlt+IntNet stuff.
4787 */
4788 Bstr BridgedIfName;
4789 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
4790 if (FAILED(hrc))
4791 {
4792 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
4793 H();
4794 }
4795
4796 Utf8Str BridgedIfNameUtf8(BridgedIfName);
4797 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
4798
4799# if defined(RT_OS_DARWIN)
4800 /* The name is on the form 'ifX: long name', chop it off at the colon. */
4801 char szTrunk[8];
4802 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
4803 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
4804// Quick fix for @bugref{5633}
4805// if (!pszColon)
4806// {
4807// /*
4808// * Dynamic changing of attachment causes an attempt to configure
4809// * network with invalid host adapter (as it is must be changed before
4810// * the attachment), calling Detach here will cause a deadlock.
4811// * See @bugref{4750}.
4812// * hrc = aNetworkAdapter->Detach(); H();
4813// */
4814// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
4815// N_("Malformed host interface networking name '%ls'"),
4816// BridgedIfName.raw());
4817// }
4818 if (pszColon)
4819 *pszColon = '\0';
4820 const char *pszTrunk = szTrunk;
4821
4822# elif defined(RT_OS_SOLARIS)
4823 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
4824 char szTrunk[256];
4825 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
4826 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
4827
4828 /*
4829 * Currently don't bother about malformed names here for the sake of people using
4830 * VBoxManage and setting only the NIC name from there. If there is a space we
4831 * chop it off and proceed, otherwise just use whatever we've got.
4832 */
4833 if (pszSpace)
4834 *pszSpace = '\0';
4835
4836 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
4837 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
4838 if (pszColon)
4839 *pszColon = '\0';
4840
4841 const char *pszTrunk = szTrunk;
4842
4843# elif defined(RT_OS_WINDOWS)
4844 ComPtr<IHostNetworkInterface> hostInterface;
4845 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
4846 hostInterface.asOutParam());
4847 if (!SUCCEEDED(hrc))
4848 {
4849 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
4850 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
4851 N_("Nonexistent host networking interface, name '%ls'"),
4852 BridgedIfName.raw());
4853 }
4854
4855 HostNetworkInterfaceType_T eIfType;
4856 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
4857 if (FAILED(hrc))
4858 {
4859 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
4860 H();
4861 }
4862
4863 if (eIfType != HostNetworkInterfaceType_Bridged)
4864 {
4865 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
4866 N_("Interface ('%ls') is not a Bridged Adapter interface"),
4867 BridgedIfName.raw());
4868 }
4869
4870 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
4871 if (FAILED(hrc))
4872 {
4873 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
4874 H();
4875 }
4876 Guid hostIFGuid(bstr);
4877
4878 INetCfg *pNc;
4879 ComPtr<INetCfgComponent> pAdaptorComponent;
4880 LPWSTR pszApp;
4881
4882 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
4883 Assert(hrc == S_OK);
4884 if (hrc != S_OK)
4885 {
4886 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
4887 H();
4888 }
4889
4890 /* get the adapter's INetCfgComponent*/
4891 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
4892 pAdaptorComponent.asOutParam());
4893 if (hrc != S_OK)
4894 {
4895 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4896 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
4897 H();
4898 }
4899#define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
4900 char szTrunkName[INTNET_MAX_TRUNK_NAME];
4901 char *pszTrunkName = szTrunkName;
4902 wchar_t * pswzBindName;
4903 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
4904 Assert(hrc == S_OK);
4905 if (hrc == S_OK)
4906 {
4907 int cwBindName = (int)wcslen(pswzBindName) + 1;
4908 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
4909 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
4910 {
4911 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
4912 pszTrunkName += cbFullBindNamePrefix-1;
4913 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
4914 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
4915 {
4916 DWORD err = GetLastError();
4917 hrc = HRESULT_FROM_WIN32(err);
4918 AssertMsgFailed(("%hrc=%Rhrc %#x\n", hrc, hrc));
4919 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
4920 hrc, hrc, err));
4921 }
4922 }
4923 else
4924 {
4925 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
4926 /** @todo set appropriate error code */
4927 hrc = E_FAIL;
4928 }
4929
4930 if (hrc != S_OK)
4931 {
4932 AssertFailed();
4933 CoTaskMemFree(pswzBindName);
4934 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4935 H();
4936 }
4937
4938 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
4939 }
4940 else
4941 {
4942 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4943 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
4944 hrc));
4945 H();
4946 }
4947
4948 const char *pszTrunk = szTrunkName;
4949 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
4950
4951# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
4952# if defined(RT_OS_FREEBSD)
4953 /*
4954 * If we bridge to a tap interface open it the `old' direct way.
4955 * This works and performs better than bridging a physical
4956 * interface via the current FreeBSD vboxnetflt implementation.
4957 */
4958 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
4959 hrc = i_attachToTapInterface(aNetworkAdapter);
4960 if (FAILED(hrc))
4961 {
4962 switch (hrc)
4963 {
4964 case VERR_ACCESS_DENIED:
4965 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4966 "Failed to open '/dev/%s' for read/write access. Please check the "
4967 "permissions of that node, and that the net.link.tap.user_open "
4968 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
4969 "change the group of that node to vboxusers and make yourself "
4970 "a member of that group. Make sure that these changes are permanent."),
4971 pszBridgedIfName, pszBridgedIfName);
4972 default:
4973 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
4974 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
4975 "Failed to initialize Host Interface Networking"));
4976 }
4977 }
4978
4979 Assert((intptr_t)maTapFD[uInstance] >= 0);
4980 if ((intptr_t)maTapFD[uInstance] >= 0)
4981 {
4982 InsertConfigString(pLunL0, "Driver", "HostInterface");
4983 InsertConfigNode(pLunL0, "Config", &pCfg);
4984 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
4985 }
4986 break;
4987 }
4988# endif
4989 /** @todo Check for malformed names. */
4990 const char *pszTrunk = pszBridgedIfName;
4991
4992 /* Issue a warning if the interface is down */
4993 {
4994 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
4995 if (iSock >= 0)
4996 {
4997 struct ifreq Req;
4998 RT_ZERO(Req);
4999 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5000 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5001 if ((Req.ifr_flags & IFF_UP) == 0)
5002 i_setVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5003 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5004 pszBridgedIfName);
5005
5006 close(iSock);
5007 }
5008 }
5009
5010# else
5011# error "PORTME (VBOX_WITH_NETFLT)"
5012# endif
5013
5014 InsertConfigString(pLunL0, "Driver", "IntNet");
5015 InsertConfigNode(pLunL0, "Config", &pCfg);
5016 InsertConfigString(pCfg, "Trunk", pszTrunk);
5017 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5018 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5019 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5020 char szNetwork[INTNET_MAX_NETWORK_NAME];
5021
5022#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5023 /*
5024 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5025 * interface name + optional description. We must not pass any description to the VM as it can differ
5026 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5027 */
5028 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5029#else
5030 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5031#endif
5032 InsertConfigString(pCfg, "Network", szNetwork);
5033 networkName = Bstr(szNetwork);
5034 trunkName = Bstr(pszTrunk);
5035 trunkType = Bstr(TRUNKTYPE_NETFLT);
5036
5037# if defined(RT_OS_DARWIN)
5038 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
5039 if ( strstr(pszBridgedIfName, "Wireless")
5040 || strstr(pszBridgedIfName, "AirPort" ))
5041 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5042# elif defined(RT_OS_LINUX)
5043 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5044 if (iSock >= 0)
5045 {
5046 struct iwreq WRq;
5047
5048 RT_ZERO(WRq);
5049 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
5050 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
5051 close(iSock);
5052 if (fSharedMacOnWire)
5053 {
5054 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5055 Log(("Set SharedMacOnWire\n"));
5056 }
5057 else
5058 Log(("Failed to get wireless name\n"));
5059 }
5060 else
5061 Log(("Failed to open wireless socket\n"));
5062# elif defined(RT_OS_FREEBSD)
5063 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5064 if (iSock >= 0)
5065 {
5066 struct ieee80211req WReq;
5067 uint8_t abData[32];
5068
5069 RT_ZERO(WReq);
5070 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
5071 WReq.i_type = IEEE80211_IOC_SSID;
5072 WReq.i_val = -1;
5073 WReq.i_data = abData;
5074 WReq.i_len = sizeof(abData);
5075
5076 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
5077 close(iSock);
5078 if (fSharedMacOnWire)
5079 {
5080 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5081 Log(("Set SharedMacOnWire\n"));
5082 }
5083 else
5084 Log(("Failed to get wireless name\n"));
5085 }
5086 else
5087 Log(("Failed to open wireless socket\n"));
5088# elif defined(RT_OS_WINDOWS)
5089# define DEVNAME_PREFIX L"\\\\.\\"
5090 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
5091 * there is a pretty long way till there though since we need to obtain the symbolic link name
5092 * for the adapter device we are going to query given the device Guid */
5093
5094
5095 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
5096
5097 wchar_t FileName[MAX_PATH];
5098 wcscpy(FileName, DEVNAME_PREFIX);
5099 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
5100
5101 /* open the device */
5102 HANDLE hDevice = CreateFile(FileName,
5103 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5104 NULL,
5105 OPEN_EXISTING,
5106 FILE_ATTRIBUTE_NORMAL,
5107 NULL);
5108
5109 if (hDevice != INVALID_HANDLE_VALUE)
5110 {
5111 bool fSharedMacOnWire = false;
5112
5113 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
5114 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
5115 NDIS_PHYSICAL_MEDIUM PhMedium;
5116 DWORD cbResult;
5117 if (DeviceIoControl(hDevice,
5118 IOCTL_NDIS_QUERY_GLOBAL_STATS,
5119 &Oid,
5120 sizeof(Oid),
5121 &PhMedium,
5122 sizeof(PhMedium),
5123 &cbResult,
5124 NULL))
5125 {
5126 /* that was simple, now examine PhMedium */
5127 if ( PhMedium == NdisPhysicalMediumWirelessWan
5128 || PhMedium == NdisPhysicalMediumWirelessLan
5129 || PhMedium == NdisPhysicalMediumNative802_11
5130 || PhMedium == NdisPhysicalMediumBluetooth)
5131 fSharedMacOnWire = true;
5132 }
5133 else
5134 {
5135 int winEr = GetLastError();
5136 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
5137 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
5138 }
5139 CloseHandle(hDevice);
5140
5141 if (fSharedMacOnWire)
5142 {
5143 Log(("this is a wireless adapter"));
5144 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5145 Log(("Set SharedMacOnWire\n"));
5146 }
5147 else
5148 Log(("this is NOT a wireless adapter"));
5149 }
5150 else
5151 {
5152 int winEr = GetLastError();
5153 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
5154 }
5155
5156 CoTaskMemFree(pswzBindName);
5157
5158 pAdaptorComponent.setNull();
5159 /* release the pNc finally */
5160 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5161# else
5162 /** @todo PORTME: wireless detection */
5163# endif
5164
5165# if defined(RT_OS_SOLARIS)
5166# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5167 /* Zone access restriction, don't allow snooping the global zone. */
5168 zoneid_t ZoneId = getzoneid();
5169 if (ZoneId != GLOBAL_ZONEID)
5170 {
5171 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5172 }
5173# endif
5174# endif
5175
5176#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5177 /* NOTHING TO DO HERE */
5178#elif defined(RT_OS_LINUX)
5179/// @todo aleksey: is there anything to be done here?
5180#elif defined(RT_OS_FREEBSD)
5181/** @todo FreeBSD: Check out this later (HIF networking). */
5182#else
5183# error "Port me"
5184#endif
5185 break;
5186 }
5187
5188 case NetworkAttachmentType_Internal:
5189 {
5190 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5191 if (!bstr.isEmpty())
5192 {
5193 InsertConfigString(pLunL0, "Driver", "IntNet");
5194 InsertConfigNode(pLunL0, "Config", &pCfg);
5195 InsertConfigString(pCfg, "Network", bstr);
5196 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5197 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5198 networkName = bstr;
5199 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5200 }
5201 break;
5202 }
5203
5204 case NetworkAttachmentType_HostOnly:
5205 {
5206 InsertConfigString(pLunL0, "Driver", "IntNet");
5207 InsertConfigNode(pLunL0, "Config", &pCfg);
5208
5209 Bstr HostOnlyName;
5210 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5211 if (FAILED(hrc))
5212 {
5213 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5214 H();
5215 }
5216
5217 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5218 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5219 ComPtr<IHostNetworkInterface> hostInterface;
5220 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5221 hostInterface.asOutParam());
5222 if (!SUCCEEDED(rc))
5223 {
5224 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5225 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5226 N_("Nonexistent host networking interface, name '%ls'"),
5227 HostOnlyName.raw());
5228 }
5229
5230 char szNetwork[INTNET_MAX_NETWORK_NAME];
5231 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5232
5233#if defined(RT_OS_WINDOWS)
5234# ifndef VBOX_WITH_NETFLT
5235 hrc = E_NOTIMPL;
5236 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5237 H();
5238# else /* defined VBOX_WITH_NETFLT*/
5239 /** @todo r=bird: Put this in a function. */
5240
5241 HostNetworkInterfaceType_T eIfType;
5242 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5243 if (FAILED(hrc))
5244 {
5245 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5246 H();
5247 }
5248
5249 if (eIfType != HostNetworkInterfaceType_HostOnly)
5250 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5251 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5252 HostOnlyName.raw());
5253
5254 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5255 if (FAILED(hrc))
5256 {
5257 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5258 H();
5259 }
5260 Guid hostIFGuid(bstr);
5261
5262 INetCfg *pNc;
5263 ComPtr<INetCfgComponent> pAdaptorComponent;
5264 LPWSTR pszApp;
5265 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5266 Assert(hrc == S_OK);
5267 if (hrc != S_OK)
5268 {
5269 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5270 H();
5271 }
5272
5273 /* get the adapter's INetCfgComponent*/
5274 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5275 pAdaptorComponent.asOutParam());
5276 if (hrc != S_OK)
5277 {
5278 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5279 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5280 H();
5281 }
5282# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5283 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5284 char *pszTrunkName = szTrunkName;
5285 wchar_t * pswzBindName;
5286 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5287 Assert(hrc == S_OK);
5288 if (hrc == S_OK)
5289 {
5290 int cwBindName = (int)wcslen(pswzBindName) + 1;
5291 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5292 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5293 {
5294 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5295 pszTrunkName += cbFullBindNamePrefix-1;
5296 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5297 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5298 {
5299 DWORD err = GetLastError();
5300 hrc = HRESULT_FROM_WIN32(err);
5301 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5302 hrc, hrc, err));
5303 }
5304 }
5305 else
5306 {
5307 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5308 /** @todo set appropriate error code */
5309 hrc = E_FAIL;
5310 }
5311
5312 if (hrc != S_OK)
5313 {
5314 AssertFailed();
5315 CoTaskMemFree(pswzBindName);
5316 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5317 H();
5318 }
5319 }
5320 else
5321 {
5322 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5323 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5324 hrc, hrc));
5325 H();
5326 }
5327
5328
5329 CoTaskMemFree(pswzBindName);
5330
5331 /* The old NDIS5.1 version of driver uses TRUNKTYPE_NETADP */
5332 trunkType = IsNdis6() ? TRUNKTYPE_NETFLT : TRUNKTYPE_NETADP;
5333 InsertConfigInteger(pCfg, "TrunkType", trunkType == TRUNKTYPE_NETFLT ? kIntNetTrunkType_NetFlt : kIntNetTrunkType_NetAdp);
5334
5335 pAdaptorComponent.setNull();
5336 /* release the pNc finally */
5337 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5338
5339 const char *pszTrunk = szTrunkName;
5340
5341 InsertConfigString(pCfg, "Trunk", pszTrunk);
5342 InsertConfigString(pCfg, "Network", szNetwork);
5343 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5344 windows only?? */
5345 networkName = Bstr(szNetwork);
5346 trunkName = Bstr(pszTrunk);
5347# endif /* defined VBOX_WITH_NETFLT*/
5348#elif defined(RT_OS_DARWIN)
5349 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5350 InsertConfigString(pCfg, "Network", szNetwork);
5351 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5352 networkName = Bstr(szNetwork);
5353 trunkName = Bstr(pszHostOnlyName);
5354 trunkType = TRUNKTYPE_NETADP;
5355#else
5356 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5357 InsertConfigString(pCfg, "Network", szNetwork);
5358 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5359 networkName = Bstr(szNetwork);
5360 trunkName = Bstr(pszHostOnlyName);
5361 trunkType = TRUNKTYPE_NETFLT;
5362#endif
5363 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5364
5365#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5366
5367 Bstr tmpAddr, tmpMask;
5368
5369 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5370 pszHostOnlyName).raw(),
5371 tmpAddr.asOutParam());
5372 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5373 {
5374 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5375 pszHostOnlyName).raw(),
5376 tmpMask.asOutParam());
5377 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5378 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5379 tmpMask.raw());
5380 else
5381 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5382 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5383 }
5384 else
5385 {
5386 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5387 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5388 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5389 }
5390
5391 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5392
5393 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5394 pszHostOnlyName).raw(),
5395 tmpAddr.asOutParam());
5396 if (SUCCEEDED(hrc))
5397 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5398 tmpMask.asOutParam());
5399 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5400 {
5401 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5402 Utf8Str(tmpMask).toUInt32());
5403 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5404 }
5405#endif
5406 break;
5407 }
5408
5409 case NetworkAttachmentType_Generic:
5410 {
5411 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5412 SafeArray<BSTR> names;
5413 SafeArray<BSTR> values;
5414 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5415 ComSafeArrayAsOutParam(names),
5416 ComSafeArrayAsOutParam(values)); H();
5417
5418 InsertConfigString(pLunL0, "Driver", bstr);
5419 InsertConfigNode(pLunL0, "Config", &pCfg);
5420 for (size_t ii = 0; ii < names.size(); ++ii)
5421 {
5422 if (values[ii] && *values[ii])
5423 {
5424 Utf8Str name = names[ii];
5425 Utf8Str value = values[ii];
5426 InsertConfigString(pCfg, name.c_str(), value);
5427 }
5428 }
5429 break;
5430 }
5431
5432 case NetworkAttachmentType_NATNetwork:
5433 {
5434 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5435 if (!bstr.isEmpty())
5436 {
5437 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5438 InsertConfigString(pLunL0, "Driver", "IntNet");
5439 InsertConfigNode(pLunL0, "Config", &pCfg);
5440 InsertConfigString(pCfg, "Network", bstr);
5441 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5442 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5443 networkName = bstr;
5444 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5445 }
5446 break;
5447 }
5448
5449 default:
5450 AssertMsgFailed(("should not get here!\n"));
5451 break;
5452 }
5453
5454 /*
5455 * Attempt to attach the driver.
5456 */
5457 switch (eAttachmentType)
5458 {
5459 case NetworkAttachmentType_Null:
5460 break;
5461
5462 case NetworkAttachmentType_Bridged:
5463 case NetworkAttachmentType_Internal:
5464 case NetworkAttachmentType_HostOnly:
5465 case NetworkAttachmentType_NAT:
5466 case NetworkAttachmentType_Generic:
5467 case NetworkAttachmentType_NATNetwork:
5468 {
5469 if (SUCCEEDED(hrc) && SUCCEEDED(rc))
5470 {
5471 if (fAttachDetach)
5472 {
5473 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5474 //AssertRC(rc);
5475 }
5476
5477 {
5478 /** @todo pritesh: get the dhcp server name from the
5479 * previous network configuration and then stop the server
5480 * else it may conflict with the dhcp server running with
5481 * the current attachment type
5482 */
5483 /* Stop the hostonly DHCP Server */
5484 }
5485
5486 /*
5487 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5488 */
5489 if ( !networkName.isEmpty()
5490 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5491 {
5492 /*
5493 * Until we implement service reference counters DHCP Server will be stopped
5494 * by DHCPServerRunner destructor.
5495 */
5496 ComPtr<IDHCPServer> dhcpServer;
5497 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5498 dhcpServer.asOutParam());
5499 if (SUCCEEDED(hrc))
5500 {
5501 /* there is a DHCP server available for this network */
5502 BOOL fEnabledDhcp;
5503 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5504 if (FAILED(hrc))
5505 {
5506 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5507 H();
5508 }
5509
5510 if (fEnabledDhcp)
5511 hrc = dhcpServer->Start(networkName.raw(),
5512 trunkName.raw(),
5513 trunkType.raw());
5514 }
5515 else
5516 hrc = S_OK;
5517 }
5518 }
5519
5520 break;
5521 }
5522
5523 default:
5524 AssertMsgFailed(("should not get here!\n"));
5525 break;
5526 }
5527
5528 meAttachmentType[uInstance] = eAttachmentType;
5529 }
5530 catch (ConfigError &x)
5531 {
5532 // InsertConfig threw something:
5533 return x.m_vrc;
5534 }
5535
5536#undef H
5537
5538 return VINF_SUCCESS;
5539}
5540
5541#ifdef VBOX_WITH_GUEST_PROPS
5542/**
5543 * Set an array of guest properties
5544 */
5545static void configSetProperties(VMMDev * const pVMMDev,
5546 void *names,
5547 void *values,
5548 void *timestamps,
5549 void *flags)
5550{
5551 VBOXHGCMSVCPARM parms[4];
5552
5553 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5554 parms[0].u.pointer.addr = names;
5555 parms[0].u.pointer.size = 0; /* We don't actually care. */
5556 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5557 parms[1].u.pointer.addr = values;
5558 parms[1].u.pointer.size = 0; /* We don't actually care. */
5559 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5560 parms[2].u.pointer.addr = timestamps;
5561 parms[2].u.pointer.size = 0; /* We don't actually care. */
5562 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5563 parms[3].u.pointer.addr = flags;
5564 parms[3].u.pointer.size = 0; /* We don't actually care. */
5565
5566 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5567 guestProp::SET_PROPS_HOST,
5568 4,
5569 &parms[0]);
5570}
5571
5572/**
5573 * Set a single guest property
5574 */
5575static void configSetProperty(VMMDev * const pVMMDev,
5576 const char *pszName,
5577 const char *pszValue,
5578 const char *pszFlags)
5579{
5580 VBOXHGCMSVCPARM parms[4];
5581
5582 AssertPtrReturnVoid(pszName);
5583 AssertPtrReturnVoid(pszValue);
5584 AssertPtrReturnVoid(pszFlags);
5585 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5586 parms[0].u.pointer.addr = (void *)pszName;
5587 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5588 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5589 parms[1].u.pointer.addr = (void *)pszValue;
5590 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5591 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5592 parms[2].u.pointer.addr = (void *)pszFlags;
5593 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
5594 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
5595 &parms[0]);
5596}
5597
5598/**
5599 * Set the global flags value by calling the service
5600 * @returns the status returned by the call to the service
5601 *
5602 * @param pTable the service instance handle
5603 * @param eFlags the flags to set
5604 */
5605int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
5606 guestProp::ePropFlags eFlags)
5607{
5608 VBOXHGCMSVCPARM paParm;
5609 paParm.setUInt32(eFlags);
5610 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5611 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
5612 &paParm);
5613 if (RT_FAILURE(rc))
5614 {
5615 char szFlags[guestProp::MAX_FLAGS_LEN];
5616 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
5617 Log(("Failed to set the global flags.\n"));
5618 else
5619 Log(("Failed to set the global flags \"%s\".\n", szFlags));
5620 }
5621 return rc;
5622}
5623#endif /* VBOX_WITH_GUEST_PROPS */
5624
5625/**
5626 * Set up the Guest Property service, populate it with properties read from
5627 * the machine XML and set a couple of initial properties.
5628 */
5629/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
5630{
5631#ifdef VBOX_WITH_GUEST_PROPS
5632 AssertReturn(pvConsole, VERR_INVALID_POINTER);
5633 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
5634 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
5635
5636 /* Load the service */
5637 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
5638
5639 if (RT_FAILURE(rc))
5640 {
5641 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
5642 /* That is not a fatal failure. */
5643 rc = VINF_SUCCESS;
5644 }
5645 else
5646 {
5647 /*
5648 * Initialize built-in properties that can be changed and saved.
5649 *
5650 * These are typically transient properties that the guest cannot
5651 * change.
5652 */
5653
5654 {
5655 VBOXHGCMSVCPARM Params[2];
5656 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
5657 if (RT_SUCCESS(rc2))
5658 {
5659 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
5660 void *pService = (void*)Params[1].u.pointer.addr;
5661 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
5662 }
5663 }
5664
5665 /* Sysprep execution by VBoxService. */
5666 configSetProperty(pConsole->m_pVMMDev,
5667 "/VirtualBox/HostGuest/SysprepExec", "",
5668 "TRANSIENT, RDONLYGUEST");
5669 configSetProperty(pConsole->m_pVMMDev,
5670 "/VirtualBox/HostGuest/SysprepArgs", "",
5671 "TRANSIENT, RDONLYGUEST");
5672
5673 /*
5674 * Pull over the properties from the server.
5675 */
5676 SafeArray<BSTR> namesOut;
5677 SafeArray<BSTR> valuesOut;
5678 SafeArray<LONG64> timestampsOut;
5679 SafeArray<BSTR> flagsOut;
5680 HRESULT hrc;
5681 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
5682 ComSafeArrayAsOutParam(valuesOut),
5683 ComSafeArrayAsOutParam(timestampsOut),
5684 ComSafeArrayAsOutParam(flagsOut));
5685 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
5686 size_t cProps = namesOut.size();
5687 size_t cAlloc = cProps + 1;
5688 if ( valuesOut.size() != cProps
5689 || timestampsOut.size() != cProps
5690 || flagsOut.size() != cProps
5691 )
5692 AssertFailedReturn(VERR_INVALID_PARAMETER);
5693
5694 char **papszNames, **papszValues, **papszFlags;
5695 char szEmpty[] = "";
5696 LONG64 *pai64Timestamps;
5697 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5698 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5699 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
5700 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
5701 if (papszNames && papszValues && pai64Timestamps && papszFlags)
5702 {
5703 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
5704 {
5705 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
5706 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
5707 if (RT_FAILURE(rc))
5708 break;
5709 if (valuesOut[i])
5710 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
5711 else
5712 papszValues[i] = szEmpty;
5713 if (RT_FAILURE(rc))
5714 break;
5715 pai64Timestamps[i] = timestampsOut[i];
5716 if (flagsOut[i])
5717 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
5718 else
5719 papszFlags[i] = szEmpty;
5720 }
5721 if (RT_SUCCESS(rc))
5722 configSetProperties(pConsole->m_pVMMDev,
5723 (void *)papszNames,
5724 (void *)papszValues,
5725 (void *)pai64Timestamps,
5726 (void *)papszFlags);
5727 for (unsigned i = 0; i < cProps; ++i)
5728 {
5729 RTStrFree(papszNames[i]);
5730 if (valuesOut[i])
5731 RTStrFree(papszValues[i]);
5732 if (flagsOut[i])
5733 RTStrFree(papszFlags[i]);
5734 }
5735 }
5736 else
5737 rc = VERR_NO_MEMORY;
5738 RTMemTmpFree(papszNames);
5739 RTMemTmpFree(papszValues);
5740 RTMemTmpFree(pai64Timestamps);
5741 RTMemTmpFree(papszFlags);
5742 AssertRCReturn(rc, rc);
5743
5744 /*
5745 * These properties have to be set before pulling over the properties
5746 * from the machine XML, to ensure that properties saved in the XML
5747 * will override them.
5748 */
5749 /* Set the raw VBox version string as a guest property. Used for host/guest
5750 * version comparison. */
5751 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
5752 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
5753 /* Set the full VBox version string as a guest property. Can contain vendor-specific
5754 * information/branding and/or pre-release tags. */
5755 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
5756 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
5757 /* Set the VBox SVN revision as a guest property */
5758 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
5759 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
5760
5761 /*
5762 * Register the host notification callback
5763 */
5764 HGCMSVCEXTHANDLE hDummy;
5765 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
5766 Console::i_doGuestPropNotification,
5767 pvConsole);
5768
5769#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
5770 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
5771 guestProp::RDONLYGUEST);
5772 AssertRCReturn(rc, rc);
5773#endif
5774
5775 Log(("Set VBoxGuestPropSvc property store\n"));
5776 }
5777 return VINF_SUCCESS;
5778#else /* !VBOX_WITH_GUEST_PROPS */
5779 return VERR_NOT_SUPPORTED;
5780#endif /* !VBOX_WITH_GUEST_PROPS */
5781}
5782
5783/**
5784 * Set up the Guest Control service.
5785 */
5786/* static */ int Console::i_configGuestControl(void *pvConsole)
5787{
5788#ifdef VBOX_WITH_GUEST_CONTROL
5789 AssertReturn(pvConsole, VERR_INVALID_POINTER);
5790 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
5791
5792 /* Load the service */
5793 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
5794
5795 if (RT_FAILURE(rc))
5796 {
5797 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
5798 /* That is not a fatal failure. */
5799 rc = VINF_SUCCESS;
5800 }
5801 else
5802 {
5803 HGCMSVCEXTHANDLE hDummy;
5804 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
5805 &Guest::i_notifyCtrlDispatcher,
5806 pConsole->i_getGuest());
5807 if (RT_FAILURE(rc))
5808 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
5809 else
5810 LogRel(("Guest Control service loaded\n"));
5811 }
5812
5813 return rc;
5814#else /* !VBOX_WITH_GUEST_CONTROL */
5815 return VERR_NOT_SUPPORTED;
5816#endif /* !VBOX_WITH_GUEST_CONTROL */
5817}
Note: See TracBrowser for help on using the repository browser.

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