VirtualBox

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

Last change on this file since 49130 was 49069, checked in by vboxsync, 12 years ago

API: Control and propagate triple fault reset/guru setting.

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

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