VirtualBox

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

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

ConsoleImpl2.cpp: No APIC and I/O APIC for pre 386 profiles.

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

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