VirtualBox

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

Last change on this file since 49935 was 49785, checked in by vboxsync, 11 years ago

Main/ConsoleImpl2: always expose the DmiMemoryTable for Windows 2012 guests

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

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