VirtualBox

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

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

Get VBoxInternal2 variables from both machine leveal as well as global level extra data.

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

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