VirtualBox

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

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

Main,Frontends: Support for the USB storage controller

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