VirtualBox

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

Last change on this file since 49016 was 48985, checked in by vboxsync, 11 years ago

Main, Frontends: Make the port count of the SAS controller configurable and support up to 255 storage devices

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