VirtualBox

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

Last change on this file since 49629 was 49625, checked in by vboxsync, 11 years ago

Main: make the USB tablet device instance 0 again.

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