VirtualBox

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

最後變更 在這個檔案從60060是 60045,由 vboxsync 提交於 9 年 前

Main/ConsoleImpl2: warnings (found by PVS)

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

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