VirtualBox

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

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

VMM,ConsoleImpl2: Added 386 profile, adding IEM code for some obvious 386isms (EFLAGS and CR0/MSW).

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

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