VirtualBox

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

Last change on this file since 37200 was 37200, checked in by vboxsync, 13 years ago

API+Frontends: Generic network attachment driver support which obsoletes the special case for VDE. Big API cleanup in the same area. Adapt all frontends to these changes (full implementation in VBoxManage, minimum implementation in GUI).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 196.3 KB
Line 
1/* $Id: ConsoleImpl2.cpp 37200 2011-05-24 15:34:06Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation
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-2011 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#include "VMMDev.h"
35#include "Global.h"
36#ifdef VBOX_WITH_PCI_PASSTHROUGH
37# include "PciRawDevImpl.h"
38#endif
39
40// generated header
41#include "SchemaDefs.h"
42
43#include "AutoCaller.h"
44#include "Logging.h"
45
46#include <iprt/buildconfig.h>
47#include <iprt/ctype.h>
48#include <iprt/dir.h>
49#include <iprt/file.h>
50#include <iprt/param.h>
51#include <iprt/path.h>
52#include <iprt/string.h>
53#include <iprt/system.h>
54#include <iprt/cpp/exception.h>
55#if 0 /* enable to play with lots of memory. */
56# include <iprt/env.h>
57#endif
58#include <iprt/stream.h>
59
60#include <VBox/vmm/vmapi.h>
61#include <VBox/err.h>
62#include <VBox/param.h>
63#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach */
64#include <VBox/version.h>
65#include <VBox/HostServices/VBoxClipboardSvc.h>
66#ifdef VBOX_WITH_CROGL
67# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
68#endif
69#ifdef VBOX_WITH_GUEST_PROPS
70# include <VBox/HostServices/GuestPropertySvc.h>
71# include <VBox/com/defs.h>
72# include <VBox/com/array.h>
73# include "HGCM.h" /** @todo it should be possible to register a service
74 * extension using a VMMDev callback. */
75# include <vector>
76#endif /* VBOX_WITH_GUEST_PROPS */
77#include <VBox/intnet.h>
78
79#include <VBox/com/com.h>
80#include <VBox/com/string.h>
81#include <VBox/com/array.h>
82
83#ifdef VBOX_WITH_NETFLT
84# if defined(RT_OS_SOLARIS)
85# include <zone.h>
86# elif defined(RT_OS_LINUX)
87# include <unistd.h>
88# include <sys/ioctl.h>
89# include <sys/socket.h>
90# include <linux/types.h>
91# include <linux/if.h>
92# include <linux/wireless.h>
93# elif defined(RT_OS_FREEBSD)
94# include <unistd.h>
95# include <sys/types.h>
96# include <sys/ioctl.h>
97# include <sys/socket.h>
98# include <net/if.h>
99# include <net80211/ieee80211_ioctl.h>
100# endif
101# if defined(RT_OS_WINDOWS)
102# include <VBox/VBoxNetCfg-win.h>
103# include <Ntddndis.h>
104# include <devguid.h>
105# else
106# include <HostNetworkInterfaceImpl.h>
107# include <netif.h>
108# include <stdlib.h>
109# endif
110#endif /* VBOX_WITH_NETFLT */
111
112#include "DHCPServerRunner.h"
113#include "BusAssignmentManager.h"
114#ifdef VBOX_WITH_EXTPACK
115# include "ExtPackManagerImpl.h"
116#endif
117
118#if defined(RT_OS_DARWIN)
119
120# include "IOKit/IOKitLib.h"
121
122static int DarwinSmcKey(char *pabKey, uint32_t cbKey)
123{
124 /*
125 * Method as described in Amit Singh's article:
126 * http://osxbook.com/book/bonus/chapter7/tpmdrmmyth/
127 */
128 typedef struct
129 {
130 uint32_t key;
131 uint8_t pad0[22];
132 uint32_t datasize;
133 uint8_t pad1[10];
134 uint8_t cmd;
135 uint32_t pad2;
136 uint8_t data[32];
137 } AppleSMCBuffer;
138
139 AssertReturn(cbKey >= 65, VERR_INTERNAL_ERROR);
140
141 io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
142 IOServiceMatching("AppleSMC"));
143 if (!service)
144 return VERR_NOT_FOUND;
145
146 io_connect_t port = (io_connect_t)0;
147 kern_return_t kr = IOServiceOpen(service, mach_task_self(), 0, &port);
148 IOObjectRelease(service);
149
150 if (kr != kIOReturnSuccess)
151 return RTErrConvertFromDarwin(kr);
152
153 AppleSMCBuffer inputStruct = { 0, {0}, 32, {0}, 5, };
154 AppleSMCBuffer outputStruct;
155 size_t cbOutputStruct = sizeof(outputStruct);
156
157 for (int i = 0; i < 2; i++)
158 {
159 inputStruct.key = (uint32_t)((i == 0) ? 'OSK0' : 'OSK1');
160 kr = IOConnectCallStructMethod((mach_port_t)port,
161 (uint32_t)2,
162 (const void *)&inputStruct,
163 sizeof(inputStruct),
164 (void *)&outputStruct,
165 &cbOutputStruct);
166 if (kr != kIOReturnSuccess)
167 {
168 IOServiceClose(port);
169 return RTErrConvertFromDarwin(kr);
170 }
171
172 for (int j = 0; j < 32; j++)
173 pabKey[j + i*32] = outputStruct.data[j];
174 }
175
176 IOServiceClose(port);
177
178 pabKey[64] = 0;
179
180 return VINF_SUCCESS;
181}
182
183#endif /* RT_OS_DARWIN */
184
185/* Darwin compile kludge */
186#undef PVM
187
188/* Comment out the following line to remove VMWare compatibility hack. */
189#define VMWARE_NET_IN_SLOT_11
190
191/**
192 * Translate IDE StorageControllerType_T to string representation.
193 */
194const char* controllerString(StorageControllerType_T enmType)
195{
196 switch (enmType)
197 {
198 case StorageControllerType_PIIX3:
199 return "PIIX3";
200 case StorageControllerType_PIIX4:
201 return "PIIX4";
202 case StorageControllerType_ICH6:
203 return "ICH6";
204 default:
205 return "Unknown";
206 }
207}
208
209/**
210 * Simple class for storing network boot information.
211 */
212struct BootNic
213{
214 ULONG mInstance;
215 PciBusAddress mPciAddress;
216
217 ULONG mBootPrio;
218 bool operator < (const BootNic &rhs) const
219 {
220 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
221 ULONG rval = rhs.mBootPrio - 1;
222 return lval < rval; /* Zero compares as highest number (lowest prio). */
223 }
224};
225
226static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
227{
228 Bstr aFilePath, empty;
229 BOOL fPresent = FALSE;
230 HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),
231 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
232 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
233
234 if (!fPresent)
235 return VERR_FILE_NOT_FOUND;
236
237 *pEfiRomFile = Utf8Str(aFilePath);
238
239 return VINF_SUCCESS;
240}
241
242static int getSmcDeviceKey(IMachine *pMachine, BSTR *aKey, bool *pfGetKeyFromRealSMC)
243{
244 *pfGetKeyFromRealSMC = false;
245
246 /*
247 * The extra data takes precedence (if non-zero).
248 */
249 HRESULT hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/SmcDeviceKey").raw(),
250 aKey);
251 if (FAILED(hrc))
252 return Global::vboxStatusCodeFromCOM(hrc);
253 if ( SUCCEEDED(hrc)
254 && *aKey
255 && **aKey)
256 return VINF_SUCCESS;
257
258#ifdef RT_OS_DARWIN
259 /*
260 * Query it here and now.
261 */
262 char abKeyBuf[65];
263 int rc = DarwinSmcKey(abKeyBuf, sizeof(abKeyBuf));
264 if (SUCCEEDED(rc))
265 {
266 Bstr(abKeyBuf).detachTo(aKey);
267 return rc;
268 }
269 LogRel(("Warning: DarwinSmcKey failed with rc=%Rrc!\n", rc));
270
271#else
272 /*
273 * Is it apple hardware in bootcamp?
274 */
275 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
276 * Currently falling back on the product name. */
277 char szManufacturer[256];
278 szManufacturer[0] = '\0';
279 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
280 if (szManufacturer[0] != '\0')
281 {
282 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
283 || !strcmp(szManufacturer, "Apple Inc.")
284 )
285 *pfGetKeyFromRealSMC = true;
286 }
287 else
288 {
289 char szProdName[256];
290 szProdName[0] = '\0';
291 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
292 if ( ( !strncmp(szProdName, "Mac", 3)
293 || !strncmp(szProdName, "iMac", 4)
294 || !strncmp(szProdName, "iMac", 4)
295 || !strncmp(szProdName, "Xserve", 6)
296 )
297 && !strchr(szProdName, ' ') /* no spaces */
298 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
299 )
300 *pfGetKeyFromRealSMC = true;
301 }
302
303 int rc = VINF_SUCCESS;
304#endif
305
306 return rc;
307}
308
309
310/*
311 * VC++ 8 / amd64 has some serious trouble with the next functions.
312 * As a temporary measure, we'll drop global optimizations.
313 */
314#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
315# pragma optimize("g", off)
316#endif
317
318
319class ConfigError : public RTCError
320{
321public:
322
323 ConfigError(const char *pcszFunction,
324 int vrc,
325 const char *pcszName)
326 : RTCError(Utf8StrFmt("%s failed: rc=%Rrc, pcszName=%s", pcszFunction, vrc, pcszName)),
327 m_vrc(vrc)
328 {
329 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here
330 }
331
332 int m_vrc;
333};
334
335
336/**
337 * Helper that calls CFGMR3InsertString and throws an RTCError if that
338 * fails (C-string variant).
339 * @param pParent See CFGMR3InsertStringN.
340 * @param pcszNodeName See CFGMR3InsertStringN.
341 * @param pcszValue The string value.
342 */
343static void InsertConfigString(PCFGMNODE pNode,
344 const char *pcszName,
345 const char *pcszValue)
346{
347 int vrc = CFGMR3InsertString(pNode,
348 pcszName,
349 pcszValue);
350 if (RT_FAILURE(vrc))
351 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
352}
353
354/**
355 * Helper that calls CFGMR3InsertString and throws an RTCError if that
356 * fails (Utf8Str variant).
357 * @param pParent See CFGMR3InsertStringN.
358 * @param pcszNodeName See CFGMR3InsertStringN.
359 * @param rStrValue The string value.
360 */
361static void InsertConfigString(PCFGMNODE pNode,
362 const char *pcszName,
363 const Utf8Str &rStrValue)
364{
365 int vrc = CFGMR3InsertStringN(pNode,
366 pcszName,
367 rStrValue.c_str(),
368 rStrValue.length());
369 if (RT_FAILURE(vrc))
370 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
371}
372
373/**
374 * Helper that calls CFGMR3InsertString and throws an RTCError if that
375 * fails (Bstr variant).
376 *
377 * @param pParent See CFGMR3InsertStringN.
378 * @param pcszNodeName See CFGMR3InsertStringN.
379 * @param rBstrValue The string value.
380 */
381static void InsertConfigString(PCFGMNODE pNode,
382 const char *pcszName,
383 const Bstr &rBstrValue)
384{
385 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
386}
387
388/**
389 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
390 *
391 * @param pNode See CFGMR3InsertBytes.
392 * @param pcszName See CFGMR3InsertBytes.
393 * @param pvBytes See CFGMR3InsertBytes.
394 * @param cbBytes See CFGMR3InsertBytes.
395 */
396static void InsertConfigBytes(PCFGMNODE pNode,
397 const char *pcszName,
398 const void *pvBytes,
399 size_t cbBytes)
400{
401 int vrc = CFGMR3InsertBytes(pNode,
402 pcszName,
403 pvBytes,
404 cbBytes);
405 if (RT_FAILURE(vrc))
406 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
407}
408
409/**
410 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
411 * fails.
412 *
413 * @param pNode See CFGMR3InsertInteger.
414 * @param pcszName See CFGMR3InsertInteger.
415 * @param u64Integer See CFGMR3InsertInteger.
416 */
417static void InsertConfigInteger(PCFGMNODE pNode,
418 const char *pcszName,
419 uint64_t u64Integer)
420{
421 int vrc = CFGMR3InsertInteger(pNode,
422 pcszName,
423 u64Integer);
424 if (RT_FAILURE(vrc))
425 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
426}
427
428/**
429 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
430 *
431 * @param pNode See CFGMR3InsertNode.
432 * @param pcszName See CFGMR3InsertNode.
433 * @param ppChild See CFGMR3InsertNode.
434 */
435static void InsertConfigNode(PCFGMNODE pNode,
436 const char *pcszName,
437 PCFGMNODE *ppChild)
438{
439 int vrc = CFGMR3InsertNode(pNode, pcszName, ppChild);
440 if (RT_FAILURE(vrc))
441 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
442}
443
444/**
445 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
446 *
447 * @param pNode See CFGMR3RemoveValue.
448 * @param pcszName See CFGMR3RemoveValue.
449 */
450static void RemoveConfigValue(PCFGMNODE pNode,
451 const char *pcszName)
452{
453 int vrc = CFGMR3RemoveValue(pNode, pcszName);
454 if (RT_FAILURE(vrc))
455 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
456}
457
458#ifdef VBOX_WITH_PCI_PASSTHROUGH
459static HRESULT attachRawPciDevices(BusAssignmentManager* BusMgr,
460 PCFGMNODE pDevices,
461 Console* pConsole)
462{
463 HRESULT hrc = S_OK;
464 PCFGMNODE pDev, pInst, pCfg, pLunL0;
465
466 SafeIfaceArray<IPciDeviceAttachment> assignments;
467 ComPtr<IMachine> aMachine = pConsole->machine();
468
469 hrc = aMachine->COMGETTER(PciDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
470 if (hrc != S_OK)
471 return hrc;
472
473 PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
474 Assert(pBridges);
475
476 /* Find required bridges, and add missing ones */
477 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
478 {
479 ComPtr<IPciDeviceAttachment> assignment = assignments[iDev];
480 LONG guest = 0;
481 PciBusAddress GuestPciAddress;
482
483 assignment->COMGETTER(GuestAddress)(&guest);
484 GuestPciAddress.fromLong(guest);
485 Assert(GuestPciAddress.valid());
486
487 if (GuestPciAddress.miBus > 0)
488 {
489 int iBridgesMissed = 0;
490 int iBase = GuestPciAddress.miBus - 1;
491
492 while (!BusMgr->hasPciDevice("ich9pcibridge", iBase) && iBase > 0)
493 {
494 iBridgesMissed++; iBase--;
495 }
496 iBase++;
497
498 for (int iBridge = 0; iBridge < iBridgesMissed; iBridge++)
499 {
500 InsertConfigNode(pBridges, Utf8StrFmt("%d", iBase + iBridge).c_str(), &pInst);
501 InsertConfigInteger(pInst, "Trusted", 1);
502 hrc = BusMgr->assignPciDevice("ich9pcibridge", pInst);
503 }
504 }
505 }
506
507 /* Now actually add devices */
508 PCFGMNODE pPciDevs = NULL;
509
510 if (assignments.size() > 0)
511 {
512 InsertConfigNode(pDevices, "pciraw", &pPciDevs);
513
514 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
515
516 /* Tell PGM to tell GPciRaw about guest mappings. */
517 CFGMR3InsertNode(pRoot, "PGM", NULL);
518 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
519
520 /*
521 * Currently, using IOMMU needed for PCI passthrough
522 * requires RAM preallocation.
523 */
524 /** @todo: check if we can lift this requirement */
525 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
526 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
527 }
528
529 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
530 {
531 PciBusAddress HostPciAddress, GuestPciAddress;
532 ComPtr<IPciDeviceAttachment> assignment = assignments[iDev];
533 LONG host, guest;
534 Bstr aDevName;
535
536 assignment->COMGETTER(HostAddress)(&host);
537 assignment->COMGETTER(GuestAddress)(&guest);
538 assignment->COMGETTER(Name)(aDevName.asOutParam());
539
540 InsertConfigNode(pPciDevs, Utf8StrFmt("%d", iDev).c_str(), &pInst);
541 InsertConfigInteger(pInst, "Trusted", 1);
542
543 HostPciAddress.fromLong(host);
544 Assert(HostPciAddress.valid());
545 InsertConfigNode(pInst, "Config", &pCfg);
546 InsertConfigString(pCfg, "DeviceName", aDevName);
547
548 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
549 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPciAddress.miBus);
550 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPciAddress.miDevice);
551 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPciAddress.miFn);
552
553 GuestPciAddress.fromLong(guest);
554 Assert(GuestPciAddress.valid());
555 hrc = BusMgr->assignHostPciDevice("pciraw", pInst, HostPciAddress, GuestPciAddress, true);
556 if (hrc != S_OK)
557 return hrc;
558
559 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPciAddress.miBus);
560 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPciAddress.miDevice);
561 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPciAddress.miFn);
562
563 /* the Main driver */
564 PciRawDev* pMainDev = new PciRawDev(pConsole);
565 InsertConfigNode(pInst, "LUN#0", &pLunL0);
566 InsertConfigString(pLunL0, "Driver", "PciRawMain");
567 InsertConfigNode(pLunL0, "Config" , &pCfg);
568 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
569 }
570
571 return hrc;
572}
573#endif
574
575/**
576 * Construct the VM configuration tree (CFGM).
577 *
578 * This is a callback for VMR3Create() call. It is called from CFGMR3Init()
579 * in the emulation thread (EMT). Any per thread COM/XPCOM initialization
580 * is done here.
581 *
582 * @param pVM VM handle.
583 * @param pvConsole Pointer to the VMPowerUpTask object.
584 * @return VBox status code.
585 *
586 * @note Locks the Console object for writing.
587 */
588DECLCALLBACK(int) Console::configConstructor(PVM pVM, void *pvConsole)
589{
590 LogFlowFuncEnter();
591
592 AssertReturn(pvConsole, VERR_GENERAL_FAILURE);
593 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
594
595 AutoCaller autoCaller(pConsole);
596 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
597
598 /* lock the console because we widely use internal fields and methods */
599 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
600
601 /*
602 * Set the VM handle and do the rest of the job in an worker method so we
603 * can easily reset the VM handle on failure.
604 */
605 PUVM pUVM = pConsole->mpUVM = VMR3GetUVM(pVM);
606 VMR3RetainUVM(pUVM);
607 int vrc = pConsole->configConstructorInner(pVM, &alock);
608 if (RT_FAILURE(vrc))
609 {
610 pConsole->mpUVM = NULL;
611 VMR3ReleaseUVM(pUVM);
612 }
613
614 return vrc;
615}
616
617
618/**
619 * Worker for configConstructor.
620 *
621 * @return VBox status code.
622 * @param pVM The VM handle.
623 */
624int Console::configConstructorInner(PVM pVM, AutoWriteLock *pAlock)
625{
626 VMMDev *pVMMDev = m_pVMMDev;
627 Assert(pVMMDev);
628
629 ComPtr<IMachine> pMachine = machine();
630
631 int rc;
632 HRESULT hrc;
633 Bstr bstr;
634
635#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
636
637 /*
638 * Get necessary objects and frequently used parameters.
639 */
640 ComPtr<IVirtualBox> virtualBox;
641 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
642
643 ComPtr<IHost> host;
644 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
645
646 ComPtr<ISystemProperties> systemProperties;
647 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
648
649 ComPtr<IBIOSSettings> biosSettings;
650 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();
651
652 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
653 RTUUID HardwareUuid;
654 rc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
655 AssertRCReturn(rc, rc);
656
657 ULONG cRamMBs;
658 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
659#if 0 /* enable to play with lots of memory. */
660 if (RTEnvExist("VBOX_RAM_SIZE"))
661 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
662#endif
663 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
664 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
665 uint64_t uMcfgBase = 0;
666 uint32_t cbMcfgLength = 0;
667
668 ChipsetType_T chipsetType;
669 hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType); H();
670 if (chipsetType == ChipsetType_ICH9)
671 {
672 /* We'd better have 0x10000000 region, to cover 256 buses
673 but this put too much load on hypervisor heap */
674 cbMcfgLength = 0x4000000; //0x10000000;
675 cbRamHole += cbMcfgLength;
676 uMcfgBase = _4G - cbRamHole;
677 }
678
679 BusAssignmentManager* BusMgr = mBusMgr = BusAssignmentManager::createInstance(chipsetType);
680
681 ULONG cCpus = 1;
682 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
683
684 ULONG ulCpuExecutionCap = 100;
685 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
686
687 Bstr osTypeId;
688 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
689
690 BOOL fIOAPIC;
691 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
692
693 ComPtr<IGuestOSType> guestOSType;
694 hrc = virtualBox->GetGuestOSType(osTypeId.raw(), guestOSType.asOutParam()); H();
695
696 Bstr guestTypeFamilyId;
697 hrc = guestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
698 BOOL fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
699
700 /*
701 * Get root node first.
702 * This is the only node in the tree.
703 */
704 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
705 Assert(pRoot);
706
707 // InsertConfigString throws
708 try
709 {
710
711 /*
712 * Set the root (and VMM) level values.
713 */
714 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
715 InsertConfigString(pRoot, "Name", bstr);
716 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
717 InsertConfigInteger(pRoot, "RamSize", cbRam);
718 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
719 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
720 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
721 InsertConfigInteger(pRoot, "TimerMillies", 10);
722#ifdef VBOX_WITH_RAW_MODE
723 InsertConfigInteger(pRoot, "RawR3Enabled", 1); /* boolean */
724 InsertConfigInteger(pRoot, "RawR0Enabled", 1); /* boolean */
725 /** @todo Config: RawR0, PATMEnabled and CSAMEnabled needs attention later. */
726 InsertConfigInteger(pRoot, "PATMEnabled", 1); /* boolean */
727 InsertConfigInteger(pRoot, "CSAMEnabled", 1); /* boolean */
728#endif
729 /* Not necessary, but to make sure these two settings end up in the release log. */
730 BOOL fPageFusion = FALSE;
731 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
732 InsertConfigInteger(pRoot, "PageFusion", fPageFusion); /* boolean */
733 ULONG ulBalloonSize = 0;
734 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
735 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
736
737 /*
738 * CPUM values.
739 */
740 PCFGMNODE pCPUM;
741 InsertConfigNode(pRoot, "CPUM", &pCPUM);
742
743 /* cpuid leaf overrides. */
744 static uint32_t const s_auCpuIdRanges[] =
745 {
746 UINT32_C(0x00000000), UINT32_C(0x0000000a),
747 UINT32_C(0x80000000), UINT32_C(0x8000000a)
748 };
749 for (unsigned i = 0; i < RT_ELEMENTS(s_auCpuIdRanges); i += 2)
750 for (uint32_t uLeaf = s_auCpuIdRanges[i]; uLeaf < s_auCpuIdRanges[i + 1]; uLeaf++)
751 {
752 ULONG ulEax, ulEbx, ulEcx, ulEdx;
753 hrc = pMachine->GetCPUIDLeaf(uLeaf, &ulEax, &ulEbx, &ulEcx, &ulEdx);
754 if (SUCCEEDED(hrc))
755 {
756 PCFGMNODE pLeaf;
757 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
758
759 InsertConfigInteger(pLeaf, "eax", ulEax);
760 InsertConfigInteger(pLeaf, "ebx", ulEbx);
761 InsertConfigInteger(pLeaf, "ecx", ulEcx);
762 InsertConfigInteger(pLeaf, "edx", ulEdx);
763 }
764 else if (hrc != E_INVALIDARG) H();
765 }
766
767 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
768 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
769 if (osTypeId == "WindowsNT4")
770 {
771 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
772 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
773 }
774
775 /* Expose extended MWAIT features to Mac OS X guests. */
776 if (fOsXGuest)
777 {
778 LogRel(("Using MWAIT extensions\n"));
779 InsertConfigInteger(pCPUM, "MWaitExtensions", true);
780 }
781
782 /*
783 * Hardware virtualization extensions.
784 */
785 BOOL fHWVirtExEnabled;
786 BOOL fHwVirtExtForced = false;
787#ifdef VBOX_WITH_RAW_MODE
788 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHWVirtExEnabled); H();
789 if (cCpus > 1) /** @todo SMP: This isn't nice, but things won't work on mac otherwise. */
790 fHWVirtExEnabled = TRUE;
791# ifdef RT_OS_DARWIN
792 fHwVirtExtForced = fHWVirtExEnabled;
793# else
794 /* - With more than 4GB PGM will use different RAMRANGE sizes for raw
795 mode and hv mode to optimize lookup times.
796 - With more than one virtual CPU, raw-mode isn't a fallback option. */
797 fHwVirtExtForced = fHWVirtExEnabled
798 && ( cbRam + cbRamHole > _4G
799 || cCpus > 1);
800# endif
801#else /* !VBOX_WITH_RAW_MODE */
802 fHWVirtExEnabled = fHwVirtExtForced = true;
803#endif /* !VBOX_WITH_RAW_MODE */
804 /* only honor the property value if there was no other reason to enable it */
805 if (!fHwVirtExtForced)
806 {
807 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHwVirtExtForced); H();
808 }
809 InsertConfigInteger(pRoot, "HwVirtExtForced", fHwVirtExtForced);
810
811
812 /*
813 * MM values.
814 */
815 PCFGMNODE pMM;
816 InsertConfigNode(pRoot, "MM", &pMM);
817 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
818
819 /*
820 * Hardware virtualization settings.
821 */
822 BOOL fIsGuest64Bit = false;
823 PCFGMNODE pHWVirtExt;
824 InsertConfigNode(pRoot, "HWVirtExt", &pHWVirtExt);
825 if (fHWVirtExEnabled)
826 {
827 InsertConfigInteger(pHWVirtExt, "Enabled", 1);
828
829 /* Indicate whether 64-bit guests are supported or not. */
830 /** @todo This is currently only forced off on 32-bit hosts only because it
831 * makes a lof of difference there (REM and Solaris performance).
832 */
833 BOOL fSupportsLongMode = false;
834 hrc = host->GetProcessorFeature(ProcessorFeature_LongMode,
835 &fSupportsLongMode); H();
836 hrc = guestOSType->COMGETTER(Is64Bit)(&fIsGuest64Bit); H();
837
838 if (fSupportsLongMode && fIsGuest64Bit)
839 {
840 InsertConfigInteger(pHWVirtExt, "64bitEnabled", 1);
841#if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */
842 PCFGMNODE pREM;
843 InsertConfigNode(pRoot, "REM", &pREM);
844 InsertConfigInteger(pREM, "64bitEnabled", 1);
845#endif
846 }
847#if ARCH_BITS == 32 /* 32-bit guests only. */
848 else
849 {
850 InsertConfigInteger(pHWVirtExt, "64bitEnabled", 0);
851 }
852#endif
853
854 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better, but that requires quite a bit of API change in Main. */
855 if ( !fIsGuest64Bit
856 && fIOAPIC
857 && ( osTypeId == "WindowsNT4"
858 || osTypeId == "Windows2000"
859 || osTypeId == "WindowsXP"
860 || osTypeId == "Windows2003"))
861 {
862 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
863 * We may want to consider adding more guest OSes (Solaris) later on.
864 */
865 InsertConfigInteger(pHWVirtExt, "TPRPatchingEnabled", 1);
866 }
867 }
868
869 /* HWVirtEx exclusive mode */
870 BOOL fHWVirtExExclusive = true;
871 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Exclusive, &fHWVirtExExclusive); H();
872 InsertConfigInteger(pHWVirtExt, "Exclusive", fHWVirtExExclusive);
873
874 /* Nested paging (VT-x/AMD-V) */
875 BOOL fEnableNestedPaging = false;
876 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
877 InsertConfigInteger(pHWVirtExt, "EnableNestedPaging", fEnableNestedPaging);
878
879 /* Large pages; requires nested paging */
880 BOOL fEnableLargePages = false;
881 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
882 InsertConfigInteger(pHWVirtExt, "EnableLargePages", fEnableLargePages);
883
884 /* VPID (VT-x) */
885 BOOL fEnableVPID = false;
886 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
887 InsertConfigInteger(pHWVirtExt, "EnableVPID", fEnableVPID);
888
889 /* Physical Address Extension (PAE) */
890 BOOL fEnablePAE = false;
891 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();
892 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
893
894 /* Synthetic CPU */
895 BOOL fSyntheticCpu = false;
896 hrc = pMachine->GetCPUProperty(CPUPropertyType_Synthetic, &fSyntheticCpu); H();
897 InsertConfigInteger(pCPUM, "SyntheticCpu", fSyntheticCpu);
898
899 BOOL fPXEDebug;
900 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
901
902 /*
903 * PDM config.
904 * Load drivers in VBoxC.[so|dll]
905 */
906 PCFGMNODE pPDM;
907 PCFGMNODE pNode;
908 PCFGMNODE pMod;
909 InsertConfigNode(pRoot, "PDM", &pPDM);
910 InsertConfigNode(pPDM, "Devices", &pNode);
911 InsertConfigNode(pPDM, "Drivers", &pNode);
912 InsertConfigNode(pNode, "VBoxC", &pMod);
913#ifdef VBOX_WITH_XPCOM
914 // VBoxC is located in the components subdirectory
915 char szPathVBoxC[RTPATH_MAX];
916 rc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(rc);
917 strcat(szPathVBoxC, "/components/VBoxC");
918 InsertConfigString(pMod, "Path", szPathVBoxC);
919#else
920 InsertConfigString(pMod, "Path", "VBoxC");
921#endif
922
923
924 /*
925 * Block cache settings.
926 */
927 PCFGMNODE pPDMBlkCache;
928 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
929
930 /* I/O cache size */
931 ULONG ioCacheSize = 5;
932 hrc = pMachine->COMGETTER(IoCacheSize)(&ioCacheSize); H();
933 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
934
935 /*
936 * Bandwidth groups.
937 */
938 PCFGMNODE pAc;
939 PCFGMNODE pAcFile;
940 PCFGMNODE pAcFileBwGroups;
941 ComPtr<IBandwidthControl> bwCtrl;
942 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
943
944 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
945
946 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
947
948 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
949 InsertConfigNode(pAc, "File", &pAcFile);
950 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
951
952 for (size_t i = 0; i < bwGroups.size(); i++)
953 {
954 Bstr strName;
955 ULONG cMaxMbPerSec;
956 BandwidthGroupType_T enmType;
957
958 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
959 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
960 hrc = bwGroups[i]->COMGETTER(MaxMbPerSec)(&cMaxMbPerSec); H();
961
962 if (enmType == BandwidthGroupType_Disk)
963 {
964 PCFGMNODE pBwGroup;
965 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
966 InsertConfigInteger(pBwGroup, "Max", cMaxMbPerSec * _1M);
967 InsertConfigInteger(pBwGroup, "Start", cMaxMbPerSec * _1M);
968 InsertConfigInteger(pBwGroup, "Step", 0);
969 }
970 }
971
972 /*
973 * Devices
974 */
975 PCFGMNODE pDevices = NULL; /* /Devices */
976 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
977 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
978 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
979 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
980 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
981 PCFGMNODE pLunL2 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config/ */
982 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
983 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
984
985 InsertConfigNode(pRoot, "Devices", &pDevices);
986
987 /*
988 * PC Arch.
989 */
990 InsertConfigNode(pDevices, "pcarch", &pDev);
991 InsertConfigNode(pDev, "0", &pInst);
992 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
993 InsertConfigNode(pInst, "Config", &pCfg);
994
995 /*
996 * The time offset
997 */
998 LONG64 timeOffset;
999 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1000 PCFGMNODE pTMNode;
1001 InsertConfigNode(pRoot, "TM", &pTMNode);
1002 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1003
1004 /*
1005 * DMA
1006 */
1007 InsertConfigNode(pDevices, "8237A", &pDev);
1008 InsertConfigNode(pDev, "0", &pInst);
1009 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1010
1011 /*
1012 * PCI buses.
1013 */
1014 uint32_t uIocPciAddress, uHbcPciAddress;
1015 switch (chipsetType)
1016 {
1017 default:
1018 Assert(false);
1019 case ChipsetType_PIIX3:
1020 InsertConfigNode(pDevices, "pci", &pDev);
1021 uHbcPciAddress = (0x0 << 16) | 0;
1022 uIocPciAddress = (0x1 << 16) | 0; // ISA controller
1023 break;
1024 case ChipsetType_ICH9:
1025 InsertConfigNode(pDevices, "ich9pci", &pDev);
1026 uHbcPciAddress = (0x1e << 16) | 0;
1027 uIocPciAddress = (0x1f << 16) | 0; // LPC controller
1028 break;
1029 }
1030 InsertConfigNode(pDev, "0", &pInst);
1031 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1032 InsertConfigNode(pInst, "Config", &pCfg);
1033 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1034 if (chipsetType == ChipsetType_ICH9)
1035 {
1036 /* Provide MCFG info */
1037 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1038 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1039
1040
1041 /* And register 2 bridges */
1042 InsertConfigNode(pDevices, "ich9pcibridge", &pDev);
1043 InsertConfigNode(pDev, "0", &pInst);
1044 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1045 hrc = BusMgr->assignPciDevice("ich9pcibridge", pInst); H();
1046
1047 InsertConfigNode(pDev, "1", &pInst);
1048 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1049 hrc = BusMgr->assignPciDevice("ich9pcibridge", pInst); H();
1050
1051#ifdef VBOX_WITH_PCI_PASSTHROUGH
1052 /* Add PCI passthrough devices */
1053 hrc = attachRawPciDevices(BusMgr, pDevices, this); H();
1054#endif
1055 }
1056 /*
1057 * Enable 3 following devices: HPET, SMC, LPC on MacOS X guests or on ICH9 chipset
1058 */
1059 /*
1060 * High Precision Event Timer (HPET)
1061 */
1062 BOOL fHpetEnabled;
1063 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1064 hrc = pMachine->COMGETTER(HpetEnabled)(&fHpetEnabled); H();
1065 /* so always enable HPET in extended profile */
1066 fHpetEnabled |= fOsXGuest;
1067 /* HPET is always present on ICH9 */
1068 fHpetEnabled |= (chipsetType == ChipsetType_ICH9);
1069 if (fHpetEnabled)
1070 {
1071 InsertConfigNode(pDevices, "hpet", &pDev);
1072 InsertConfigNode(pDev, "0", &pInst);
1073 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1074 InsertConfigNode(pInst, "Config", &pCfg);
1075 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1076 }
1077
1078 /*
1079 * System Management Controller (SMC)
1080 */
1081 BOOL fSmcEnabled;
1082 fSmcEnabled = fOsXGuest;
1083 if (fSmcEnabled)
1084 {
1085 InsertConfigNode(pDevices, "smc", &pDev);
1086 InsertConfigNode(pDev, "0", &pInst);
1087 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1088 InsertConfigNode(pInst, "Config", &pCfg);
1089
1090 bool fGetKeyFromRealSMC;
1091 Bstr bstrKey;
1092 rc = getSmcDeviceKey(pMachine, bstrKey.asOutParam(), &fGetKeyFromRealSMC);
1093 AssertRCReturn(rc, rc);
1094
1095 InsertConfigString(pCfg, "DeviceKey", bstrKey);
1096 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1097 }
1098
1099 /*
1100 * Low Pin Count (LPC) bus
1101 */
1102 BOOL fLpcEnabled;
1103 /** @todo: implement appropriate getter */
1104 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1105 if (fLpcEnabled)
1106 {
1107 InsertConfigNode(pDevices, "lpc", &pDev);
1108 InsertConfigNode(pDev, "0", &pInst);
1109 hrc = BusMgr->assignPciDevice("lpc", pInst); H();
1110 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1111 }
1112
1113 BOOL fShowRtc;
1114 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1115
1116 /*
1117 * PS/2 keyboard & mouse.
1118 */
1119 InsertConfigNode(pDevices, "pckbd", &pDev);
1120 InsertConfigNode(pDev, "0", &pInst);
1121 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1122 InsertConfigNode(pInst, "Config", &pCfg);
1123
1124 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1125 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1126 InsertConfigNode(pLunL0, "Config", &pCfg);
1127 InsertConfigInteger(pCfg, "QueueSize", 64);
1128
1129 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1130 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1131 InsertConfigNode(pLunL1, "Config", &pCfg);
1132 Keyboard *pKeyboard = mKeyboard;
1133 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
1134
1135 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1136 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1137 InsertConfigNode(pLunL0, "Config", &pCfg);
1138 InsertConfigInteger(pCfg, "QueueSize", 128);
1139
1140 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1141 InsertConfigString(pLunL1, "Driver", "MainMouse");
1142 InsertConfigNode(pLunL1, "Config", &pCfg);
1143 Mouse *pMouse = mMouse;
1144 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
1145
1146 /*
1147 * i8254 Programmable Interval Timer And Dummy Speaker
1148 */
1149 InsertConfigNode(pDevices, "i8254", &pDev);
1150 InsertConfigNode(pDev, "0", &pInst);
1151 InsertConfigNode(pInst, "Config", &pCfg);
1152#ifdef DEBUG
1153 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1154#endif
1155
1156 /*
1157 * i8259 Programmable Interrupt Controller.
1158 */
1159 InsertConfigNode(pDevices, "i8259", &pDev);
1160 InsertConfigNode(pDev, "0", &pInst);
1161 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1162 InsertConfigNode(pInst, "Config", &pCfg);
1163
1164 /*
1165 * Advanced Programmable Interrupt Controller.
1166 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1167 * thus only single insert
1168 */
1169 InsertConfigNode(pDevices, "apic", &pDev);
1170 InsertConfigNode(pDev, "0", &pInst);
1171 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1172 InsertConfigNode(pInst, "Config", &pCfg);
1173 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1174 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1175
1176 if (fIOAPIC)
1177 {
1178 /*
1179 * I/O Advanced Programmable Interrupt Controller.
1180 */
1181 InsertConfigNode(pDevices, "ioapic", &pDev);
1182 InsertConfigNode(pDev, "0", &pInst);
1183 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1184 InsertConfigNode(pInst, "Config", &pCfg);
1185 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1186 }
1187
1188 /*
1189 * RTC MC146818.
1190 */
1191 InsertConfigNode(pDevices, "mc146818", &pDev);
1192 InsertConfigNode(pDev, "0", &pInst);
1193 InsertConfigNode(pInst, "Config", &pCfg);
1194 BOOL fRTCUseUTC;
1195 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1196 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1197
1198 /*
1199 * VGA.
1200 */
1201 InsertConfigNode(pDevices, "vga", &pDev);
1202 InsertConfigNode(pDev, "0", &pInst);
1203 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1204
1205 hrc = BusMgr->assignPciDevice("vga", pInst); H();
1206 InsertConfigNode(pInst, "Config", &pCfg);
1207 ULONG cVRamMBs;
1208 hrc = pMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
1209 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
1210 ULONG cMonitorCount;
1211 hrc = pMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
1212 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
1213#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
1214 InsertConfigInteger(pCfg, "R0Enabled", fHWVirtExEnabled);
1215#endif
1216
1217 /*
1218 * BIOS logo
1219 */
1220 BOOL fFadeIn;
1221 hrc = biosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
1222 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
1223 BOOL fFadeOut;
1224 hrc = biosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
1225 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
1226 ULONG logoDisplayTime;
1227 hrc = biosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
1228 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
1229 Bstr logoImagePath;
1230 hrc = biosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
1231 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
1232
1233 /*
1234 * Boot menu
1235 */
1236 BIOSBootMenuMode_T eBootMenuMode;
1237 int iShowBootMenu;
1238 biosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode);
1239 switch (eBootMenuMode)
1240 {
1241 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
1242 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
1243 default: iShowBootMenu = 2; break;
1244 }
1245 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
1246
1247 /* Custom VESA mode list */
1248 unsigned cModes = 0;
1249 for (unsigned iMode = 1; iMode <= 16; ++iMode)
1250 {
1251 char szExtraDataKey[sizeof("CustomVideoModeXX")];
1252 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
1253 hrc = pMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
1254 if (bstr.isEmpty())
1255 break;
1256 InsertConfigString(pCfg, szExtraDataKey, bstr);
1257 ++cModes;
1258 }
1259 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
1260
1261 /* VESA height reduction */
1262 ULONG ulHeightReduction;
1263 IFramebuffer *pFramebuffer = getDisplay()->getFramebuffer();
1264 if (pFramebuffer)
1265 {
1266 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
1267 }
1268 else
1269 {
1270 /* If framebuffer is not available, there is no height reduction. */
1271 ulHeightReduction = 0;
1272 }
1273 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
1274
1275 /* Attach the display. */
1276 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1277 InsertConfigString(pLunL0, "Driver", "MainDisplay");
1278 InsertConfigNode(pLunL0, "Config", &pCfg);
1279 Display *pDisplay = mDisplay;
1280 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
1281
1282
1283 /*
1284 * Firmware.
1285 */
1286 FirmwareType_T eFwType = FirmwareType_BIOS;
1287 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1288
1289#ifdef VBOX_WITH_EFI
1290 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1291#else
1292 BOOL fEfiEnabled = false;
1293#endif
1294 if (!fEfiEnabled)
1295 {
1296 /*
1297 * PC Bios.
1298 */
1299 InsertConfigNode(pDevices, "pcbios", &pDev);
1300 InsertConfigNode(pDev, "0", &pInst);
1301 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1302 InsertConfigNode(pInst, "Config", &pBiosCfg);
1303 InsertConfigInteger(pBiosCfg, "RamSize", cbRam);
1304 InsertConfigInteger(pBiosCfg, "RamHoleSize", cbRamHole);
1305 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1306 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1307 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1308 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1309 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1310 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1311 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1312 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1313 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1314
1315 DeviceType_T bootDevice;
1316 if (SchemaDefs::MaxBootPosition > 9)
1317 {
1318 AssertMsgFailed(("Too many boot devices %d\n",
1319 SchemaDefs::MaxBootPosition));
1320 return VERR_INVALID_PARAMETER;
1321 }
1322
1323 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1324 {
1325 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
1326
1327 char szParamName[] = "BootDeviceX";
1328 szParamName[sizeof(szParamName) - 2] = ((char (pos - 1)) + '0');
1329
1330 const char *pszBootDevice;
1331 switch (bootDevice)
1332 {
1333 case DeviceType_Null:
1334 pszBootDevice = "NONE";
1335 break;
1336 case DeviceType_HardDisk:
1337 pszBootDevice = "IDE";
1338 break;
1339 case DeviceType_DVD:
1340 pszBootDevice = "DVD";
1341 break;
1342 case DeviceType_Floppy:
1343 pszBootDevice = "FLOPPY";
1344 break;
1345 case DeviceType_Network:
1346 pszBootDevice = "LAN";
1347 break;
1348 default:
1349 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
1350 return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1351 N_("Invalid boot device '%d'"), bootDevice);
1352 }
1353 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1354 }
1355 }
1356 else
1357 {
1358 /* Autodetect firmware type, basing on guest type */
1359 if (eFwType == FirmwareType_EFI)
1360 {
1361 eFwType = fIsGuest64Bit
1362 ? (FirmwareType_T)FirmwareType_EFI64
1363 : (FirmwareType_T)FirmwareType_EFI32;
1364 }
1365 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1366
1367 Utf8Str efiRomFile;
1368 rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
1369 AssertRCReturn(rc, rc);
1370
1371 /* Get boot args */
1372 Bstr bootArgs;
1373 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiBootArgs").raw(), bootArgs.asOutParam()); H();
1374
1375 /* Get device props */
1376 Bstr deviceProps;
1377 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiDeviceProps").raw(), deviceProps.asOutParam()); H();
1378
1379 /* Get GOP mode settings */
1380 uint32_t u32GopMode = UINT32_MAX;
1381 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiGopMode").raw(), bstr.asOutParam()); H();
1382 if (!bstr.isEmpty())
1383 u32GopMode = Utf8Str(bstr).toUInt32();
1384
1385 /* UGA mode settings */
1386 uint32_t u32UgaHorisontal = 0;
1387 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiUgaHorizontalResolution").raw(), bstr.asOutParam()); H();
1388 if (!bstr.isEmpty())
1389 u32UgaHorisontal = Utf8Str(bstr).toUInt32();
1390
1391 uint32_t u32UgaVertical = 0;
1392 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EfiUgaVerticalResolution").raw(), bstr.asOutParam()); H();
1393 if (!bstr.isEmpty())
1394 u32UgaVertical = Utf8Str(bstr).toUInt32();
1395
1396 /*
1397 * EFI subtree.
1398 */
1399 InsertConfigNode(pDevices, "efi", &pDev);
1400 InsertConfigNode(pDev, "0", &pInst);
1401 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1402 InsertConfigNode(pInst, "Config", &pCfg);
1403 InsertConfigInteger(pCfg, "RamSize", cbRam);
1404 InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole);
1405 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1406 InsertConfigString(pCfg, "EfiRom", efiRomFile);
1407 InsertConfigString(pCfg, "BootArgs", bootArgs);
1408 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1409 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1410 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1411 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1412 InsertConfigInteger(pCfg, "GopMode", u32GopMode);
1413 InsertConfigInteger(pCfg, "UgaHorizontalResolution", u32UgaHorisontal);
1414 InsertConfigInteger(pCfg, "UgaVerticalResolution", u32UgaVertical);
1415
1416 /* For OS X guests we'll force passing host's DMI info to the guest */
1417 if (fOsXGuest)
1418 {
1419 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1420 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1421 }
1422 }
1423
1424 /*
1425 * Storage controllers.
1426 */
1427 com::SafeIfaceArray<IStorageController> ctrls;
1428 PCFGMNODE aCtrlNodes[StorageControllerType_LsiLogicSas + 1] = {};
1429 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
1430
1431 bool fFdcEnabled = false;
1432 for (size_t i = 0; i < ctrls.size(); ++i)
1433 {
1434 DeviceType_T *paLedDevType = NULL;
1435
1436 StorageControllerType_T enmCtrlType;
1437 rc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
1438 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes));
1439
1440 StorageBus_T enmBus;
1441 rc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
1442
1443 Bstr controllerName;
1444 rc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
1445
1446 ULONG ulInstance = 999;
1447 rc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
1448
1449 BOOL fUseHostIOCache;
1450 rc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
1451
1452 BOOL fBootable;
1453 rc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
1454
1455 /* /Devices/<ctrldev>/ */
1456 const char *pszCtrlDev = convertControllerTypeToDev(enmCtrlType);
1457 pDev = aCtrlNodes[enmCtrlType];
1458 if (!pDev)
1459 {
1460 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
1461 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
1462 }
1463
1464 /* /Devices/<ctrldev>/<instance>/ */
1465 PCFGMNODE pCtlInst = NULL;
1466 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
1467
1468 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
1469 InsertConfigInteger(pCtlInst, "Trusted", 1);
1470 InsertConfigNode(pCtlInst, "Config", &pCfg);
1471
1472 switch (enmCtrlType)
1473 {
1474 case StorageControllerType_LsiLogic:
1475 {
1476 hrc = BusMgr->assignPciDevice("lsilogic", pCtlInst); H();
1477
1478 InsertConfigInteger(pCfg, "Bootable", fBootable);
1479
1480 /* Attach the status driver */
1481 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
1482 InsertConfigString(pLunL0, "Driver", "MainStatus");
1483 InsertConfigNode(pLunL0, "Config", &pCfg);
1484 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapStorageLeds[iLedScsi]);
1485 InsertConfigInteger(pCfg, "First", 0);
1486 Assert(cLedScsi >= 16);
1487 InsertConfigInteger(pCfg, "Last", 15);
1488 paLedDevType = &maStorageDevType[iLedScsi];
1489 break;
1490 }
1491
1492 case StorageControllerType_BusLogic:
1493 {
1494 hrc = BusMgr->assignPciDevice("buslogic", pCtlInst); H();
1495
1496 InsertConfigInteger(pCfg, "Bootable", fBootable);
1497
1498 /* Attach the status driver */
1499 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
1500 InsertConfigString(pLunL0, "Driver", "MainStatus");
1501 InsertConfigNode(pLunL0, "Config", &pCfg);
1502 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapStorageLeds[iLedScsi]);
1503 InsertConfigInteger(pCfg, "First", 0);
1504 Assert(cLedScsi >= 16);
1505 InsertConfigInteger(pCfg, "Last", 15);
1506 paLedDevType = &maStorageDevType[iLedScsi];
1507 break;
1508 }
1509
1510 case StorageControllerType_IntelAhci:
1511 {
1512 hrc = BusMgr->assignPciDevice("ahci", pCtlInst); H();
1513
1514 ULONG cPorts = 0;
1515 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
1516 InsertConfigInteger(pCfg, "PortCount", cPorts);
1517 InsertConfigInteger(pCfg, "Bootable", fBootable);
1518
1519 /* Needed configuration values for the bios, only first controller. */
1520 if (!BusMgr->hasPciDevice("ahci", 1))
1521 {
1522 if (pBiosCfg)
1523 {
1524 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
1525 }
1526
1527 for (uint32_t j = 0; j < 4; ++j)
1528 {
1529 static const char * const s_apszConfig[4] =
1530 { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
1531 static const char * const s_apszBiosConfig[4] =
1532 { "SataPrimaryMasterLUN", "SataPrimarySlaveLUN", "SataSecondaryMasterLUN", "SataSecondarySlaveLUN" };
1533
1534 LONG lPortNumber = -1;
1535 hrc = ctrls[i]->GetIDEEmulationPort(j, &lPortNumber); H();
1536 InsertConfigInteger(pCfg, s_apszConfig[j], lPortNumber);
1537 if (pBiosCfg)
1538 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortNumber);
1539 }
1540 }
1541
1542 /* Attach the status driver */
1543 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
1544 InsertConfigString(pLunL0, "Driver", "MainStatus");
1545 InsertConfigNode(pLunL0, "Config", &pCfg);
1546 AssertRelease(cPorts <= cLedSata);
1547 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapStorageLeds[iLedSata]);
1548 InsertConfigInteger(pCfg, "First", 0);
1549 InsertConfigInteger(pCfg, "Last", cPorts - 1);
1550 paLedDevType = &maStorageDevType[iLedSata];
1551 break;
1552 }
1553
1554 case StorageControllerType_PIIX3:
1555 case StorageControllerType_PIIX4:
1556 case StorageControllerType_ICH6:
1557 {
1558 /*
1559 * IDE (update this when the main interface changes)
1560 */
1561 hrc = BusMgr->assignPciDevice("piix3ide", pCtlInst); H();
1562 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
1563
1564 /* Attach the status driver */
1565 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
1566 InsertConfigString(pLunL0, "Driver", "MainStatus");
1567 InsertConfigNode(pLunL0, "Config", &pCfg);
1568 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapStorageLeds[iLedIde]);
1569 InsertConfigInteger(pCfg, "First", 0);
1570 Assert(cLedIde >= 4);
1571 InsertConfigInteger(pCfg, "Last", 3);
1572 paLedDevType = &maStorageDevType[iLedIde];
1573
1574 /* IDE flavors */
1575 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
1576 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
1577 aCtrlNodes[StorageControllerType_ICH6] = pDev;
1578 break;
1579 }
1580
1581 case StorageControllerType_I82078:
1582 {
1583 /*
1584 * i82078 Floppy drive controller
1585 */
1586 fFdcEnabled = true;
1587 InsertConfigInteger(pCfg, "IRQ", 6);
1588 InsertConfigInteger(pCfg, "DMA", 2);
1589 InsertConfigInteger(pCfg, "MemMapped", 0 );
1590 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
1591
1592 /* Attach the status driver */
1593 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
1594 InsertConfigString(pLunL0, "Driver", "MainStatus");
1595 InsertConfigNode(pLunL0, "Config", &pCfg);
1596 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapStorageLeds[iLedFloppy]);
1597 InsertConfigInteger(pCfg, "First", 0);
1598 Assert(cLedFloppy >= 1);
1599 InsertConfigInteger(pCfg, "Last", 0);
1600 paLedDevType = &maStorageDevType[iLedFloppy];
1601 break;
1602 }
1603
1604 case StorageControllerType_LsiLogicSas:
1605 {
1606 hrc = BusMgr->assignPciDevice("lsilogicsas", pCtlInst); H();
1607
1608 InsertConfigString(pCfg, "ControllerType", "SAS1068");
1609 InsertConfigInteger(pCfg, "Bootable", fBootable);
1610
1611 /* Attach the status driver */
1612 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
1613 InsertConfigString(pLunL0, "Driver", "MainStatus");
1614 InsertConfigNode(pLunL0, "Config", &pCfg);
1615 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapStorageLeds[iLedSas]);
1616 InsertConfigInteger(pCfg, "First", 0);
1617 Assert(cLedSas >= 8);
1618 InsertConfigInteger(pCfg, "Last", 7);
1619 paLedDevType = &maStorageDevType[iLedSas];
1620 break;
1621 }
1622
1623 default:
1624 AssertMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_GENERAL_FAILURE);
1625 }
1626
1627 /* Attach the media to the storage controllers. */
1628 com::SafeIfaceArray<IMediumAttachment> atts;
1629 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
1630 ComSafeArrayAsOutParam(atts)); H();
1631
1632 /* Builtin I/O cache - per device setting. */
1633 BOOL fBuiltinIoCache = true;
1634 hrc = pMachine->COMGETTER(IoCacheEnabled)(&fBuiltinIoCache); H();
1635
1636
1637 for (size_t j = 0; j < atts.size(); ++j)
1638 {
1639 rc = configMediumAttachment(pCtlInst,
1640 pszCtrlDev,
1641 ulInstance,
1642 enmBus,
1643 !!fUseHostIOCache,
1644 !!fBuiltinIoCache,
1645 false /* fSetupMerge */,
1646 0 /* uMergeSource */,
1647 0 /* uMergeTarget */,
1648 atts[j],
1649 mMachineState,
1650 NULL /* phrc */,
1651 false /* fAttachDetach */,
1652 false /* fForceUnmount */,
1653 false /* fHotplug */,
1654 pVM,
1655 paLedDevType);
1656 if (RT_FAILURE(rc))
1657 return rc;
1658 }
1659 H();
1660 }
1661 H();
1662
1663 /*
1664 * Network adapters
1665 */
1666#ifdef VMWARE_NET_IN_SLOT_11
1667 bool fSwapSlots3and11 = false;
1668#endif
1669 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
1670 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
1671#ifdef VBOX_WITH_E1000
1672 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
1673 InsertConfigNode(pDevices, "e1000", &pDevE1000);
1674#endif
1675#ifdef VBOX_WITH_VIRTIO
1676 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
1677 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
1678#endif /* VBOX_WITH_VIRTIO */
1679 std::list<BootNic> llBootNics;
1680 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::NetworkAdapterCount; ++ulInstance)
1681 {
1682 ComPtr<INetworkAdapter> networkAdapter;
1683 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
1684 BOOL fEnabled = FALSE;
1685 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabled); H();
1686 if (!fEnabled)
1687 continue;
1688
1689 /*
1690 * The virtual hardware type. Create appropriate device first.
1691 */
1692 const char *pszAdapterName = "pcnet";
1693 NetworkAdapterType_T adapterType;
1694 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
1695 switch (adapterType)
1696 {
1697 case NetworkAdapterType_Am79C970A:
1698 case NetworkAdapterType_Am79C973:
1699 pDev = pDevPCNet;
1700 break;
1701#ifdef VBOX_WITH_E1000
1702 case NetworkAdapterType_I82540EM:
1703 case NetworkAdapterType_I82543GC:
1704 case NetworkAdapterType_I82545EM:
1705 pDev = pDevE1000;
1706 pszAdapterName = "e1000";
1707 break;
1708#endif
1709#ifdef VBOX_WITH_VIRTIO
1710 case NetworkAdapterType_Virtio:
1711 pDev = pDevVirtioNet;
1712 pszAdapterName = "virtio-net";
1713 break;
1714#endif /* VBOX_WITH_VIRTIO */
1715 default:
1716 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
1717 adapterType, ulInstance));
1718 return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1719 N_("Invalid network adapter type '%d' for slot '%d'"),
1720 adapterType, ulInstance);
1721 }
1722
1723 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1724 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1725 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
1726 * next 4 get 16..19. */
1727 int iPciDeviceNo;
1728 switch (ulInstance)
1729 {
1730 case 0:
1731 iPciDeviceNo = 3;
1732 break;
1733 case 1: case 2: case 3:
1734 iPciDeviceNo = ulInstance - 1 + 8;
1735 break;
1736 case 4: case 5: case 6: case 7:
1737 iPciDeviceNo = ulInstance - 4 + 16;
1738 break;
1739 default:
1740 /* auto assignment */
1741 iPciDeviceNo = -1;
1742 break;
1743 }
1744#ifdef VMWARE_NET_IN_SLOT_11
1745 /*
1746 * Dirty hack for PCI slot compatibility with VMWare,
1747 * it assigns slot 11 to the first network controller.
1748 */
1749 if (iPciDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
1750 {
1751 iPciDeviceNo = 0x11;
1752 fSwapSlots3and11 = true;
1753 }
1754 else if (iPciDeviceNo == 0x11 && fSwapSlots3and11)
1755 iPciDeviceNo = 3;
1756#endif
1757 PciBusAddress PciAddr = PciBusAddress(0, iPciDeviceNo, 0);
1758 hrc = BusMgr->assignPciDevice(pszAdapterName, pInst, PciAddr); H();
1759
1760 InsertConfigNode(pInst, "Config", &pCfg);
1761#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */
1762 if (pDev == pDevPCNet)
1763 {
1764 InsertConfigInteger(pCfg, "R0Enabled", false);
1765 }
1766#endif
1767 /*
1768 * Collect information needed for network booting and add it to the list.
1769 */
1770 BootNic nic;
1771
1772 nic.mInstance = ulInstance;
1773 /* Could be updated by reference, if auto assigned */
1774 nic.mPciAddress = PciAddr;
1775
1776 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
1777
1778 llBootNics.push_back(nic);
1779
1780 /*
1781 * The virtual hardware type. PCNet supports two types.
1782 */
1783 switch (adapterType)
1784 {
1785 case NetworkAdapterType_Am79C970A:
1786 InsertConfigInteger(pCfg, "Am79C973", 0);
1787 break;
1788 case NetworkAdapterType_Am79C973:
1789 InsertConfigInteger(pCfg, "Am79C973", 1);
1790 break;
1791 case NetworkAdapterType_I82540EM:
1792 InsertConfigInteger(pCfg, "AdapterType", 0);
1793 break;
1794 case NetworkAdapterType_I82543GC:
1795 InsertConfigInteger(pCfg, "AdapterType", 1);
1796 break;
1797 case NetworkAdapterType_I82545EM:
1798 InsertConfigInteger(pCfg, "AdapterType", 2);
1799 break;
1800 }
1801
1802 /*
1803 * Get the MAC address and convert it to binary representation
1804 */
1805 Bstr macAddr;
1806 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
1807 Assert(!macAddr.isEmpty());
1808 Utf8Str macAddrUtf8 = macAddr;
1809 char *macStr = (char*)macAddrUtf8.c_str();
1810 Assert(strlen(macStr) == 12);
1811 RTMAC Mac;
1812 memset(&Mac, 0, sizeof(Mac));
1813 char *pMac = (char*)&Mac;
1814 for (uint32_t i = 0; i < 6; ++i)
1815 {
1816 char c1 = *macStr++ - '0';
1817 if (c1 > 9)
1818 c1 -= 7;
1819 char c2 = *macStr++ - '0';
1820 if (c2 > 9)
1821 c2 -= 7;
1822 *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
1823 }
1824 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
1825
1826 /*
1827 * Check if the cable is supposed to be unplugged
1828 */
1829 BOOL fCableConnected;
1830 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
1831 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
1832
1833 /*
1834 * Line speed to report from custom drivers
1835 */
1836 ULONG ulLineSpeed;
1837 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
1838 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
1839
1840 /*
1841 * Attach the status driver.
1842 */
1843 InsertConfigNode(pInst, "LUN#999", &pLunL0);
1844 InsertConfigString(pLunL0, "Driver", "MainStatus");
1845 InsertConfigNode(pLunL0, "Config", &pCfg);
1846 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapNetworkLeds[ulInstance]);
1847
1848 /*
1849 * Configure the network card now
1850 */
1851 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
1852 rc = configNetwork(pszAdapterName,
1853 ulInstance,
1854 0,
1855 networkAdapter,
1856 pCfg,
1857 pLunL0,
1858 pInst,
1859 false /*fAttachDetach*/,
1860 fIgnoreConnectFailure);
1861 if (RT_FAILURE(rc))
1862 return rc;
1863 }
1864
1865 /*
1866 * Build network boot information and transfer it to the BIOS.
1867 */
1868 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
1869 {
1870 llBootNics.sort(); /* Sort the list by boot priority. */
1871
1872 char achBootIdx[] = "0";
1873 unsigned uBootIdx = 0;
1874
1875 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
1876 {
1877 /* A NIC with priority 0 is only used if it's first in the list. */
1878 if (it->mBootPrio == 0 && uBootIdx != 0)
1879 break;
1880
1881 PCFGMNODE pNetBtDevCfg;
1882 achBootIdx[0] = '0' + uBootIdx++; /* Boot device order. */
1883 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
1884 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
1885 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPciAddress.miBus);
1886 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPciAddress.miDevice);
1887 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPciAddress.miFn);
1888 }
1889 }
1890
1891 /*
1892 * Serial (UART) Ports
1893 */
1894 /* serial enabled mask to be passed to dev ACPI */
1895 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
1896 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
1897 InsertConfigNode(pDevices, "serial", &pDev);
1898 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
1899 {
1900 ComPtr<ISerialPort> serialPort;
1901 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
1902 BOOL fEnabled = FALSE;
1903 if (serialPort)
1904 hrc = serialPort->COMGETTER(Enabled)(&fEnabled); H();
1905 if (!fEnabled)
1906 continue;
1907
1908 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1909 InsertConfigNode(pInst, "Config", &pCfg);
1910
1911 ULONG ulIRQ;
1912 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
1913 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1914 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
1915
1916 ULONG ulIOBase;
1917 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
1918 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
1919 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
1920
1921 BOOL fServer;
1922 hrc = serialPort->COMGETTER(Server)(&fServer); H();
1923 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
1924 PortMode_T eHostMode;
1925 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
1926 if (eHostMode != PortMode_Disconnected)
1927 {
1928 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1929 if (eHostMode == PortMode_HostPipe)
1930 {
1931 InsertConfigString(pLunL0, "Driver", "Char");
1932 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1933 InsertConfigString(pLunL1, "Driver", "NamedPipe");
1934 InsertConfigNode(pLunL1, "Config", &pLunL2);
1935 InsertConfigString(pLunL2, "Location", bstr);
1936 InsertConfigInteger(pLunL2, "IsServer", fServer);
1937 }
1938 else if (eHostMode == PortMode_HostDevice)
1939 {
1940 InsertConfigString(pLunL0, "Driver", "Host Serial");
1941 InsertConfigNode(pLunL0, "Config", &pLunL1);
1942 InsertConfigString(pLunL1, "DevicePath", bstr);
1943 }
1944 else if (eHostMode == PortMode_RawFile)
1945 {
1946 InsertConfigString(pLunL0, "Driver", "Char");
1947 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1948 InsertConfigString(pLunL1, "Driver", "RawFile");
1949 InsertConfigNode(pLunL1, "Config", &pLunL2);
1950 InsertConfigString(pLunL2, "Location", bstr);
1951 }
1952 }
1953 }
1954
1955 /*
1956 * Parallel (LPT) Ports
1957 */
1958 InsertConfigNode(pDevices, "parallel", &pDev);
1959 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
1960 {
1961 ComPtr<IParallelPort> parallelPort;
1962 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
1963 BOOL fEnabled = FALSE;
1964 if (parallelPort)
1965 {
1966 hrc = parallelPort->COMGETTER(Enabled)(&fEnabled); H();
1967 }
1968 if (!fEnabled)
1969 continue;
1970
1971 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
1972 InsertConfigNode(pInst, "Config", &pCfg);
1973
1974 ULONG ulIRQ;
1975 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
1976 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
1977 ULONG ulIOBase;
1978 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
1979 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
1980 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1981 InsertConfigString(pLunL0, "Driver", "HostParallel");
1982 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1983 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
1984 InsertConfigString(pLunL1, "DevicePath", bstr);
1985 }
1986
1987 /*
1988 * VMM Device
1989 */
1990 InsertConfigNode(pDevices, "VMMDev", &pDev);
1991 InsertConfigNode(pDev, "0", &pInst);
1992 InsertConfigNode(pInst, "Config", &pCfg);
1993 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1994 hrc = BusMgr->assignPciDevice("VMMDev", pInst); H();
1995
1996 Bstr hwVersion;
1997 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
1998 InsertConfigInteger(pCfg, "RamSize", cbRam);
1999 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2000 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2001 Bstr snapshotFolder;
2002 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2003 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2004
2005 /* the VMM device's Main driver */
2006 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2007 InsertConfigString(pLunL0, "Driver", "HGCM");
2008 InsertConfigNode(pLunL0, "Config", &pCfg);
2009 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2010
2011 /*
2012 * Attach the status driver.
2013 */
2014 InsertConfigNode(pInst, "LUN#999", &pLunL0);
2015 InsertConfigString(pLunL0, "Driver", "MainStatus");
2016 InsertConfigNode(pLunL0, "Config", &pCfg);
2017 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapSharedFolderLed);
2018 InsertConfigInteger(pCfg, "First", 0);
2019 InsertConfigInteger(pCfg, "Last", 0);
2020
2021 /*
2022 * Audio Sniffer Device
2023 */
2024 InsertConfigNode(pDevices, "AudioSniffer", &pDev);
2025 InsertConfigNode(pDev, "0", &pInst);
2026 InsertConfigNode(pInst, "Config", &pCfg);
2027
2028 /* the Audio Sniffer device's Main driver */
2029 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2030 InsertConfigString(pLunL0, "Driver", "MainAudioSniffer");
2031 InsertConfigNode(pLunL0, "Config", &pCfg);
2032 AudioSniffer *pAudioSniffer = mAudioSniffer;
2033 InsertConfigInteger(pCfg, "Object", (uintptr_t)pAudioSniffer);
2034
2035 /*
2036 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio
2037 */
2038 BOOL fAudioEnabled = FALSE;
2039 ComPtr<IAudioAdapter> audioAdapter;
2040 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2041 if (audioAdapter)
2042 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2043
2044 if (fAudioEnabled)
2045 {
2046 AudioControllerType_T audioController;
2047 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2048 switch (audioController)
2049 {
2050 case AudioControllerType_AC97:
2051 {
2052 /* default: ICH AC97 */
2053 InsertConfigNode(pDevices, "ichac97", &pDev);
2054 InsertConfigNode(pDev, "0", &pInst);
2055 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2056 hrc = BusMgr->assignPciDevice("ichac97", pInst); H();
2057 InsertConfigNode(pInst, "Config", &pCfg);
2058 break;
2059 }
2060 case AudioControllerType_SB16:
2061 {
2062 /* legacy SoundBlaster16 */
2063 InsertConfigNode(pDevices, "sb16", &pDev);
2064 InsertConfigNode(pDev, "0", &pInst);
2065 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2066 InsertConfigNode(pInst, "Config", &pCfg);
2067 InsertConfigInteger(pCfg, "IRQ", 5);
2068 InsertConfigInteger(pCfg, "DMA", 1);
2069 InsertConfigInteger(pCfg, "DMA16", 5);
2070 InsertConfigInteger(pCfg, "Port", 0x220);
2071 InsertConfigInteger(pCfg, "Version", 0x0405);
2072 break;
2073 }
2074 case AudioControllerType_HDA:
2075 {
2076 /* Intel HD Audio */
2077 InsertConfigNode(pDevices, "hda", &pDev);
2078 InsertConfigNode(pDev, "0", &pInst);
2079 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2080 hrc = BusMgr->assignPciDevice("hda", pInst); H();
2081 InsertConfigNode(pInst, "Config", &pCfg);
2082 }
2083 }
2084
2085 /* the Audio driver */
2086 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2087 InsertConfigString(pLunL0, "Driver", "AUDIO");
2088 InsertConfigNode(pLunL0, "Config", &pCfg);
2089
2090 AudioDriverType_T audioDriver;
2091 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2092 switch (audioDriver)
2093 {
2094 case AudioDriverType_Null:
2095 {
2096 InsertConfigString(pCfg, "AudioDriver", "null");
2097 break;
2098 }
2099#ifdef RT_OS_WINDOWS
2100#ifdef VBOX_WITH_WINMM
2101 case AudioDriverType_WinMM:
2102 {
2103 InsertConfigString(pCfg, "AudioDriver", "winmm");
2104 break;
2105 }
2106#endif
2107 case AudioDriverType_DirectSound:
2108 {
2109 InsertConfigString(pCfg, "AudioDriver", "dsound");
2110 break;
2111 }
2112#endif /* RT_OS_WINDOWS */
2113#ifdef RT_OS_SOLARIS
2114 case AudioDriverType_SolAudio:
2115 {
2116 InsertConfigString(pCfg, "AudioDriver", "solaudio");
2117 break;
2118 }
2119#endif
2120#ifdef RT_OS_LINUX
2121# ifdef VBOX_WITH_ALSA
2122 case AudioDriverType_ALSA:
2123 {
2124 InsertConfigString(pCfg, "AudioDriver", "alsa");
2125 break;
2126 }
2127# endif
2128# ifdef VBOX_WITH_PULSE
2129 case AudioDriverType_Pulse:
2130 {
2131 InsertConfigString(pCfg, "AudioDriver", "pulse");
2132 break;
2133 }
2134# endif
2135#endif /* RT_OS_LINUX */
2136#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(VBOX_WITH_SOLARIS_OSS)
2137 case AudioDriverType_OSS:
2138 {
2139 InsertConfigString(pCfg, "AudioDriver", "oss");
2140 break;
2141 }
2142#endif
2143#ifdef RT_OS_FREEBSD
2144# ifdef VBOX_WITH_PULSE
2145 case AudioDriverType_Pulse:
2146 {
2147 InsertConfigString(pCfg, "AudioDriver", "pulse");
2148 break;
2149 }
2150# endif
2151#endif
2152#ifdef RT_OS_DARWIN
2153 case AudioDriverType_CoreAudio:
2154 {
2155 InsertConfigString(pCfg, "AudioDriver", "coreaudio");
2156 break;
2157 }
2158#endif
2159 }
2160 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2161 InsertConfigString(pCfg, "StreamName", bstr);
2162 }
2163
2164 /*
2165 * The USB Controller.
2166 */
2167 ComPtr<IUSBController> USBCtlPtr;
2168 hrc = pMachine->COMGETTER(USBController)(USBCtlPtr.asOutParam());
2169 if (USBCtlPtr)
2170 {
2171 BOOL fOhciEnabled;
2172 hrc = USBCtlPtr->COMGETTER(Enabled)(&fOhciEnabled); H();
2173 if (fOhciEnabled)
2174 {
2175 InsertConfigNode(pDevices, "usb-ohci", &pDev);
2176 InsertConfigNode(pDev, "0", &pInst);
2177 InsertConfigNode(pInst, "Config", &pCfg);
2178 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2179 hrc = BusMgr->assignPciDevice("usb-ohci", pInst); H();
2180 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2181 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2182 InsertConfigNode(pLunL0, "Config", &pCfg);
2183
2184 /*
2185 * Attach the status driver.
2186 */
2187 InsertConfigNode(pInst, "LUN#999", &pLunL0);
2188 InsertConfigString(pLunL0, "Driver", "MainStatus");
2189 InsertConfigNode(pLunL0, "Config", &pCfg);
2190 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapUSBLed[0]);
2191 InsertConfigInteger(pCfg, "First", 0);
2192 InsertConfigInteger(pCfg, "Last", 0);
2193
2194#ifdef VBOX_WITH_EHCI
2195 BOOL fEhciEnabled;
2196 hrc = USBCtlPtr->COMGETTER(EnabledEhci)(&fEhciEnabled); H();
2197 if (fEhciEnabled)
2198 {
2199 /*
2200 * USB 2.0 is only available if the proper ExtPack is installed.
2201 *
2202 * Note. Configuring EHCI here and providing messages about
2203 * the missing extpack isn't exactly clean, but it is a
2204 * necessary evil to patch over legacy compatability issues
2205 * introduced by the new distribution model.
2206 */
2207 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
2208# ifdef VBOX_WITH_EXTPACK
2209 if (mptrExtPackManager->isExtPackUsable(s_pszUsbExtPackName))
2210# endif
2211 {
2212 InsertConfigNode(pDevices, "usb-ehci", &pDev);
2213 InsertConfigNode(pDev, "0", &pInst);
2214 InsertConfigNode(pInst, "Config", &pCfg);
2215 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2216 hrc = BusMgr->assignPciDevice("usb-ehci", pInst); H();
2217
2218 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2219 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
2220 InsertConfigNode(pLunL0, "Config", &pCfg);
2221
2222 /*
2223 * Attach the status driver.
2224 */
2225 InsertConfigNode(pInst, "LUN#999", &pLunL0);
2226 InsertConfigString(pLunL0, "Driver", "MainStatus");
2227 InsertConfigNode(pLunL0, "Config", &pCfg);
2228 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)&mapUSBLed[1]);
2229 InsertConfigInteger(pCfg, "First", 0);
2230 InsertConfigInteger(pCfg, "Last", 0);
2231 }
2232# ifdef VBOX_WITH_EXTPACK
2233 else
2234 {
2235 /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
2236 * but this induced problems when the user saved + restored the VM! */
2237 return VMSetError(pVM, VERR_NOT_FOUND, RT_SRC_POS,
2238 N_("Implementation of the USB 2.0 controller not found!\n"
2239 "Because the USB 2.0 controller state is part of the saved "
2240 "VM state, the VM cannot be started. To fix "
2241 "this problem, either install the '%s' or disable USB 2.0 "
2242 "support in the VM settings"),
2243 s_pszUsbExtPackName);
2244 }
2245# endif
2246 }
2247#endif
2248
2249 /*
2250 * Virtual USB Devices.
2251 */
2252 PCFGMNODE pUsbDevices = NULL;
2253 InsertConfigNode(pRoot, "USB", &pUsbDevices);
2254
2255#ifdef VBOX_WITH_USB
2256 {
2257 /*
2258 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
2259 * on a per device level now.
2260 */
2261 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
2262 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
2263 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
2264 //InsertConfigInteger(pCfg, "Force11Device", true);
2265 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
2266 // that it's documented somewhere.) Users needing it can use:
2267 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
2268 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
2269 }
2270#endif
2271
2272# if 0 /* Virtual Web Cam */
2273
2274 InsertConfigNode(pUsbDevices, "WebCam", &pDev);
2275 InsertConfigNode(pDev, "0", &pInst);
2276 InsertConfigNode(pInst, "Config", &pCfg);
2277# if 0 /* Experiments with attaching */
2278 InsertConfigInteger(pCfg, "USBVER", RT_BIT(2));
2279# endif
2280 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2281# endif
2282# if 0 /* Virtual MSD*/
2283
2284 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2285 InsertConfigNode(pDev, "0", &pInst);
2286 InsertConfigNode(pInst, "Config", &pCfg);
2287 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2288
2289 InsertConfigString(pLunL0, "Driver", "SCSI");
2290 InsertConfigNode(pLunL0, "Config", &pCfg);
2291
2292 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2293 InsertConfigString(pLunL1, "Driver", "Block");
2294 InsertConfigNode(pLunL1, "Config", &pCfg);
2295 InsertConfigString(pCfg, "Type", "HardDisk");
2296 InsertConfigInteger(pCfg, "Mountable", 0);
2297
2298 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL2);
2299 InsertConfigString(pLunL2, "Driver", "VD");
2300 InsertConfigNode(pLunL2, "Config", &pCfg);
2301 InsertConfigString(pCfg, "Path", "/Volumes/DataHFS/bird/VDIs/linux.vdi");
2302 InsertConfigString(pCfg, "Format", "VDI");
2303# endif
2304
2305 /* Virtual USB Mouse/Tablet */
2306 PointingHidType_T aPointingHid;
2307 hrc = pMachine->COMGETTER(PointingHidType)(&aPointingHid); H();
2308 if (aPointingHid == PointingHidType_USBMouse || aPointingHid == PointingHidType_USBTablet)
2309 {
2310 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
2311 InsertConfigNode(pDev, "0", &pInst);
2312 InsertConfigNode(pInst, "Config", &pCfg);
2313
2314 if (aPointingHid == PointingHidType_USBTablet)
2315 {
2316 InsertConfigInteger(pCfg, "Absolute", 1);
2317 }
2318 else
2319 {
2320 InsertConfigInteger(pCfg, "Absolute", 0);
2321 }
2322 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2323 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2324 InsertConfigNode(pLunL0, "Config", &pCfg);
2325 InsertConfigInteger(pCfg, "QueueSize", 128);
2326
2327 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2328 InsertConfigString(pLunL1, "Driver", "MainMouse");
2329 InsertConfigNode(pLunL1, "Config", &pCfg);
2330 pMouse = mMouse;
2331 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2332 }
2333
2334 /* Virtual USB Keyboard */
2335 KeyboardHidType_T aKbdHid;
2336 hrc = pMachine->COMGETTER(KeyboardHidType)(&aKbdHid); H();
2337 if (aKbdHid == KeyboardHidType_USBKeyboard)
2338 {
2339 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
2340 InsertConfigNode(pDev, "0", &pInst);
2341 InsertConfigNode(pInst, "Config", &pCfg);
2342
2343 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2344 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
2345 InsertConfigNode(pLunL0, "Config", &pCfg);
2346 InsertConfigInteger(pCfg, "QueueSize", 64);
2347
2348 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2349 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
2350 InsertConfigNode(pLunL1, "Config", &pCfg);
2351 pKeyboard = mKeyboard;
2352 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
2353 }
2354 }
2355 }
2356
2357 /*
2358 * Clipboard
2359 */
2360 {
2361 ClipboardMode_T mode = ClipboardMode_Disabled;
2362 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
2363
2364 if (mode != ClipboardMode_Disabled)
2365 {
2366 /* Load the service */
2367 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
2368
2369 if (RT_FAILURE(rc))
2370 {
2371 LogRel(("VBoxSharedClipboard is not available. rc = %Rrc\n", rc));
2372 /* That is not a fatal failure. */
2373 rc = VINF_SUCCESS;
2374 }
2375 else
2376 {
2377 /* Setup the service. */
2378 VBOXHGCMSVCPARM parm;
2379
2380 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
2381
2382 switch (mode)
2383 {
2384 default:
2385 case ClipboardMode_Disabled:
2386 {
2387 LogRel(("VBoxSharedClipboard mode: Off\n"));
2388 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_OFF;
2389 break;
2390 }
2391 case ClipboardMode_GuestToHost:
2392 {
2393 LogRel(("VBoxSharedClipboard mode: Guest to Host\n"));
2394 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST;
2395 break;
2396 }
2397 case ClipboardMode_HostToGuest:
2398 {
2399 LogRel(("VBoxSharedClipboard mode: Host to Guest\n"));
2400 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST;
2401 break;
2402 }
2403 case ClipboardMode_Bidirectional:
2404 {
2405 LogRel(("VBoxSharedClipboard mode: Bidirectional\n"));
2406 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL;
2407 break;
2408 }
2409 }
2410
2411 pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE, 1, &parm);
2412
2413 Log(("Set VBoxSharedClipboard mode\n"));
2414 }
2415 }
2416 }
2417
2418#ifdef VBOX_WITH_CROGL
2419 /*
2420 * crOpenGL
2421 */
2422 {
2423 BOOL fEnabled = false;
2424 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled); H();
2425
2426 if (fEnabled)
2427 {
2428 /* Load the service */
2429 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
2430 if (RT_FAILURE(rc))
2431 {
2432 LogRel(("Failed to load Shared OpenGL service %Rrc\n", rc));
2433 /* That is not a fatal failure. */
2434 rc = VINF_SUCCESS;
2435 }
2436 else
2437 {
2438 LogRel(("Shared crOpenGL service loaded.\n"));
2439
2440 /* Setup the service. */
2441 VBOXHGCMSVCPARM parm;
2442 parm.type = VBOX_HGCM_SVC_PARM_PTR;
2443
2444 parm.u.pointer.addr = (IConsole *)(Console *)this;
2445 parm.u.pointer.size = sizeof(IConsole *);
2446
2447 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE, SHCRGL_CPARMS_SET_CONSOLE, &parm);
2448 if (!RT_SUCCESS(rc))
2449 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
2450
2451 parm.u.pointer.addr = pVM;
2452 parm.u.pointer.size = sizeof(pVM);
2453 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
2454 if (!RT_SUCCESS(rc))
2455 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
2456 }
2457
2458 }
2459 }
2460#endif
2461
2462#ifdef VBOX_WITH_GUEST_PROPS
2463 /*
2464 * Guest property service
2465 */
2466
2467 rc = configGuestProperties(this);
2468#endif /* VBOX_WITH_GUEST_PROPS defined */
2469
2470#ifdef VBOX_WITH_GUEST_CONTROL
2471 /*
2472 * Guest control service
2473 */
2474
2475 rc = configGuestControl(this);
2476#endif /* VBOX_WITH_GUEST_CONTROL defined */
2477
2478 /*
2479 * ACPI
2480 */
2481 BOOL fACPI;
2482 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
2483 if (fACPI)
2484 {
2485 BOOL fCpuHotPlug = false;
2486 BOOL fShowCpu = fOsXGuest;
2487 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
2488 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
2489 * intelppm driver refuses to register an idle state handler.
2490 */
2491 if ((cCpus > 1) || fIOAPIC)
2492 fShowCpu = true;
2493
2494 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
2495
2496 InsertConfigNode(pDevices, "acpi", &pDev);
2497 InsertConfigNode(pDev, "0", &pInst);
2498 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2499 InsertConfigNode(pInst, "Config", &pCfg);
2500 hrc = BusMgr->assignPciDevice("acpi", pInst); H();
2501
2502 InsertConfigInteger(pCfg, "RamSize", cbRam);
2503 InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole);
2504 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
2505
2506 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
2507 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
2508 InsertConfigInteger(pCfg, "HpetEnabled", fHpetEnabled);
2509 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
2510 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
2511 if (fOsXGuest && !llBootNics.empty())
2512 {
2513 BootNic aNic = llBootNics.front();
2514 uint32_t u32NicPciAddr = (aNic.mPciAddress.miDevice << 16) | aNic.mPciAddress.miFn;
2515 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPciAddr);
2516 }
2517 if (fOsXGuest && fAudioEnabled)
2518 {
2519 PciBusAddress Address;
2520 if (BusMgr->findPciAddress("hda", 0, Address))
2521 {
2522 uint32_t u32AudioPciAddr = (Address.miDevice << 16) | Address.miFn;
2523 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPciAddr);
2524 }
2525 }
2526 InsertConfigInteger(pCfg, "IocPciAddress", uIocPciAddress);
2527 if (chipsetType == ChipsetType_ICH9)
2528 {
2529 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
2530 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
2531 }
2532 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPciAddress);
2533 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
2534 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
2535
2536 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
2537 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
2538
2539 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
2540 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
2541
2542 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2543 InsertConfigString(pLunL0, "Driver", "ACPIHost");
2544 InsertConfigNode(pLunL0, "Config", &pCfg);
2545
2546 /* Attach the dummy CPU drivers */
2547 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
2548 {
2549 BOOL fCpuAttached = true;
2550
2551 if (fCpuHotPlug)
2552 {
2553 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
2554 }
2555
2556 if (fCpuAttached)
2557 {
2558 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
2559 InsertConfigString(pLunL0, "Driver", "ACPICpu");
2560 InsertConfigNode(pLunL0, "Config", &pCfg);
2561 }
2562 }
2563 }
2564 }
2565 catch (ConfigError &x)
2566 {
2567 // InsertConfig threw something:
2568 return x.m_vrc;
2569 }
2570
2571#ifdef VBOX_WITH_EXTPACK
2572 /*
2573 * Call the extension pack hooks if everything went well thus far.
2574 */
2575 if (RT_SUCCESS(rc))
2576 {
2577 pAlock->release();
2578 rc = mptrExtPackManager->callAllVmConfigureVmmHooks(this, pVM);
2579 pAlock->acquire();
2580 }
2581#endif
2582
2583 /*
2584 * Apply the CFGM overlay.
2585 */
2586 if (RT_SUCCESS(rc))
2587 rc = configCfgmOverlay(pVM, virtualBox, pMachine);
2588
2589#undef H
2590
2591 /*
2592 * Register VM state change handler.
2593 */
2594 int rc2 = VMR3AtStateRegister(pVM, Console::vmstateChangeCallback, this);
2595 AssertRC(rc2);
2596 if (RT_SUCCESS(rc))
2597 rc = rc2;
2598
2599 /*
2600 * Register VM runtime error handler.
2601 */
2602 rc2 = VMR3AtRuntimeErrorRegister(pVM, Console::setVMRuntimeErrorCallback, this);
2603 AssertRC(rc2);
2604 if (RT_SUCCESS(rc))
2605 rc = rc2;
2606
2607 LogFlowFunc(("vrc = %Rrc\n", rc));
2608 LogFlowFuncLeave();
2609
2610 return rc;
2611}
2612
2613/**
2614 * Applies the CFGM overlay as specified by /VBoxInternal/XXX extra data
2615 * values.
2616 *
2617 * @returns VBox status code.
2618 * @param pVM The VM handle.
2619 * @param pVirtualBox Pointer to the IVirtualBox interface.
2620 * @param pMachine Pointer to the IMachine interface.
2621 */
2622/* static */
2623int Console::configCfgmOverlay(PVM pVM, IVirtualBox *pVirtualBox, IMachine *pMachine)
2624{
2625 /*
2626 * CFGM overlay handling.
2627 *
2628 * Here we check the extra data entries for CFGM values
2629 * and create the nodes and insert the values on the fly. Existing
2630 * values will be removed and reinserted. CFGM is typed, so by default
2631 * we will guess whether it's a string or an integer (byte arrays are
2632 * not currently supported). It's possible to override this autodetection
2633 * by adding "string:", "integer:" or "bytes:" (future).
2634 *
2635 * We first perform a run on global extra data, then on the machine
2636 * extra data to support global settings with local overrides.
2637 */
2638 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
2639 int rc = VINF_SUCCESS;
2640 try
2641 {
2642 /** @todo add support for removing nodes and byte blobs. */
2643 /*
2644 * Get the next key
2645 */
2646 SafeArray<BSTR> aGlobalExtraDataKeys;
2647 SafeArray<BSTR> aMachineExtraDataKeys;
2648 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
2649 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
2650
2651 // remember the no. of global values so we can call the correct method below
2652 size_t cGlobalValues = aGlobalExtraDataKeys.size();
2653
2654 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
2655 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
2656
2657 // build a combined list from global keys...
2658 std::list<Utf8Str> llExtraDataKeys;
2659
2660 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
2661 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
2662 // ... and machine keys
2663 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
2664 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
2665
2666 size_t i2 = 0;
2667 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
2668 it != llExtraDataKeys.end();
2669 ++it, ++i2)
2670 {
2671 const Utf8Str &strKey = *it;
2672
2673 /*
2674 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
2675 */
2676 if (!strKey.startsWith("VBoxInternal/"))
2677 continue;
2678
2679 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
2680
2681 // get the value
2682 Bstr bstrExtraDataValue;
2683 if (i2 < cGlobalValues)
2684 // this is still one of the global values:
2685 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
2686 bstrExtraDataValue.asOutParam());
2687 else
2688 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
2689 bstrExtraDataValue.asOutParam());
2690 if (FAILED(hrc))
2691 LogRel(("Warning: Cannot get extra data key %s, rc = %Rrc\n", strKey.c_str(), hrc));
2692
2693 /*
2694 * The key will be in the format "Node1/Node2/Value" or simply "Value".
2695 * Split the two and get the node, delete the value and create the node
2696 * if necessary.
2697 */
2698 PCFGMNODE pNode;
2699 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
2700 if (pszCFGMValueName)
2701 {
2702 /* terminate the node and advance to the value (Utf8Str might not
2703 offically like this but wtf) */
2704 *(char*)pszCFGMValueName = '\0';
2705 ++pszCFGMValueName;
2706
2707 /* does the node already exist? */
2708 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
2709 if (pNode)
2710 CFGMR3RemoveValue(pNode, pszCFGMValueName);
2711 else
2712 {
2713 /* create the node */
2714 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
2715 if (RT_FAILURE(rc))
2716 {
2717 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
2718 continue;
2719 }
2720 Assert(pNode);
2721 }
2722 }
2723 else
2724 {
2725 /* root value (no node path). */
2726 pNode = pRoot;
2727 pszCFGMValueName = pszExtraDataKey;
2728 pszExtraDataKey--;
2729 CFGMR3RemoveValue(pNode, pszCFGMValueName);
2730 }
2731
2732 /*
2733 * Now let's have a look at the value.
2734 * Empty strings means that we should remove the value, which we've
2735 * already done above.
2736 */
2737 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
2738 if (!strCFGMValueUtf8.isEmpty())
2739 {
2740 uint64_t u64Value;
2741
2742 /* check for type prefix first. */
2743 if (!strncmp(strCFGMValueUtf8.c_str(), "string:", sizeof("string:") - 1))
2744 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
2745 else if (!strncmp(strCFGMValueUtf8.c_str(), "integer:", sizeof("integer:") - 1))
2746 {
2747 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
2748 if (RT_SUCCESS(rc))
2749 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
2750 }
2751 else if (!strncmp(strCFGMValueUtf8.c_str(), "bytes:", sizeof("bytes:") - 1))
2752 rc = VERR_NOT_IMPLEMENTED;
2753 /* auto detect type. */
2754 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
2755 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
2756 else
2757 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
2758 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n", strCFGMValueUtf8.c_str(), pszExtraDataKey));
2759 }
2760 }
2761 }
2762 catch (ConfigError &x)
2763 {
2764 // InsertConfig threw something:
2765 return x.m_vrc;
2766 }
2767 return rc;
2768}
2769
2770/**
2771 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
2772 */
2773/*static*/
2774void Console::setVMRuntimeErrorCallbackF(PVM pVM, void *pvConsole, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
2775{
2776 va_list va;
2777 va_start(va, pszFormat);
2778 setVMRuntimeErrorCallback(pVM, pvConsole, fFlags, pszErrorId, pszFormat, va);
2779 va_end(va);
2780}
2781
2782/* XXX introduce RT format specifier */
2783static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
2784{
2785 if (u64Size > INT64_C(5000)*_1G)
2786 {
2787 *pszUnit = "TB";
2788 return u64Size / _1T;
2789 }
2790 else if (u64Size > INT64_C(5000)*_1M)
2791 {
2792 *pszUnit = "GB";
2793 return u64Size / _1G;
2794 }
2795 else
2796 {
2797 *pszUnit = "MB";
2798 return u64Size / _1M;
2799 }
2800}
2801
2802int Console::configMediumAttachment(PCFGMNODE pCtlInst,
2803 const char *pcszDevice,
2804 unsigned uInstance,
2805 StorageBus_T enmBus,
2806 bool fUseHostIOCache,
2807 bool fBuiltinIoCache,
2808 bool fSetupMerge,
2809 unsigned uMergeSource,
2810 unsigned uMergeTarget,
2811 IMediumAttachment *pMediumAtt,
2812 MachineState_T aMachineState,
2813 HRESULT *phrc,
2814 bool fAttachDetach,
2815 bool fForceUnmount,
2816 bool fHotplug,
2817 PVM pVM,
2818 DeviceType_T *paLedDevType)
2819{
2820 // InsertConfig* throws
2821 try
2822 {
2823 int rc = VINF_SUCCESS;
2824 HRESULT hrc;
2825 Bstr bstr;
2826
2827// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
2828#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
2829
2830 LONG lDev;
2831 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
2832 LONG lPort;
2833 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
2834 DeviceType_T lType;
2835 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
2836
2837 unsigned uLUN;
2838 PCFGMNODE pLunL0 = NULL;
2839 PCFGMNODE pCfg = NULL;
2840 hrc = Console::convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
2841
2842 /* First check if the LUN already exists. */
2843 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
2844 if (pLunL0)
2845 {
2846 if (fAttachDetach)
2847 {
2848 if (lType != DeviceType_HardDisk)
2849 {
2850 /* Unmount existing media only for floppy and DVD drives. */
2851 PPDMIBASE pBase;
2852 rc = PDMR3QueryLun(pVM, pcszDevice, uInstance, uLUN, &pBase);
2853 if (RT_FAILURE(rc))
2854 {
2855 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
2856 rc = VINF_SUCCESS;
2857 AssertRC(rc);
2858 }
2859 else
2860 {
2861 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
2862 AssertReturn(pIMount, VERR_INVALID_POINTER);
2863
2864 /* Unmount the media (but do not eject the medium!) */
2865 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
2866 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
2867 rc = VINF_SUCCESS;
2868 /* for example if the medium is locked */
2869 else if (RT_FAILURE(rc))
2870 return rc;
2871 }
2872 }
2873
2874 rc = PDMR3DeviceDetach(pVM, pcszDevice, uInstance, uLUN, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
2875 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
2876 rc = VINF_SUCCESS;
2877 AssertRCReturn(rc, rc);
2878
2879 CFGMR3RemoveNode(pLunL0);
2880 }
2881 else
2882 AssertFailedReturn(VERR_INTERNAL_ERROR);
2883 }
2884
2885 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
2886
2887 /* SCSI has a another driver between device and block. */
2888 if (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS)
2889 {
2890 InsertConfigString(pLunL0, "Driver", "SCSI");
2891 InsertConfigNode(pLunL0, "Config", &pCfg);
2892
2893 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
2894 }
2895
2896 ComPtr<IMedium> pMedium;
2897 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
2898
2899 /*
2900 * 1. Only check this for hard disk images.
2901 * 2. Only check during VM creation and not later, especially not during
2902 * taking an online snapshot!
2903 */
2904 if ( lType == DeviceType_HardDisk
2905 && ( aMachineState == MachineState_Starting
2906 || aMachineState == MachineState_Restoring))
2907 {
2908 /*
2909 * Some sanity checks.
2910 */
2911 ComPtr<IMediumFormat> pMediumFormat;
2912 hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
2913 ULONG uCaps;
2914 hrc = pMediumFormat->COMGETTER(Capabilities)(&uCaps); H();
2915 if (uCaps & MediumFormatCapabilities_File)
2916 {
2917 Bstr strFile;
2918 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
2919 Utf8Str utfFile = Utf8Str(strFile);
2920 Bstr strSnap;
2921 ComPtr<IMachine> pMachine = machine();
2922 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
2923 Utf8Str utfSnap = Utf8Str(strSnap);
2924 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
2925 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
2926 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
2927 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
2928 /* Ignore the error code. On error, the file system type is still 'unknown' so
2929 * none of the following paths are taken. This can happen for new VMs which
2930 * still don't have a snapshot folder. */
2931 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
2932 if (!mfSnapshotFolderDiskTypeShown)
2933 {
2934 LogRel(("File system of '%s' (snapshots) is %s\n", utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
2935 mfSnapshotFolderDiskTypeShown = true;
2936 }
2937 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
2938 LONG64 i64Size;
2939 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
2940#ifdef RT_OS_WINDOWS
2941 if ( enmFsTypeFile == RTFSTYPE_FAT
2942 && i64Size >= _4G)
2943 {
2944 const char *pszUnit;
2945 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
2946 setVMRuntimeErrorCallbackF(pVM, this, 0,
2947 "FatPartitionDetected",
2948 N_("The medium '%ls' has a logical size of %RU64%s "
2949 "but the file system the medium is located on seems "
2950 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
2951 "We strongly recommend to put all your virtual disk images and "
2952 "the snapshot folder onto an NTFS partition"),
2953 strFile.raw(), u64Print, pszUnit);
2954 }
2955#else /* !RT_OS_WINDOWS */
2956 if ( enmFsTypeFile == RTFSTYPE_FAT
2957 || enmFsTypeFile == RTFSTYPE_EXT
2958 || enmFsTypeFile == RTFSTYPE_EXT2
2959 || enmFsTypeFile == RTFSTYPE_EXT3
2960 || enmFsTypeFile == RTFSTYPE_EXT4)
2961 {
2962 RTFILE file;
2963 rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
2964 if (RT_SUCCESS(rc))
2965 {
2966 RTFOFF maxSize;
2967 /* Careful: This function will work only on selected local file systems! */
2968 rc = RTFileGetMaxSizeEx(file, &maxSize);
2969 RTFileClose(file);
2970 if ( RT_SUCCESS(rc)
2971 && maxSize > 0
2972 && i64Size > (LONG64)maxSize)
2973 {
2974 const char *pszUnitSiz;
2975 const char *pszUnitMax;
2976 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
2977 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
2978 setVMRuntimeErrorCallbackF(pVM, this, 0,
2979 "FatPartitionDetected", /* <= not exact but ... */
2980 N_("The medium '%ls' has a logical size of %RU64%s "
2981 "but the file system the medium is located on can "
2982 "only handle files up to %RU64%s in theory.\n"
2983 "We strongly recommend to put all your virtual disk "
2984 "images and the snapshot folder onto a proper "
2985 "file system (e.g. ext3) with a sufficient size"),
2986 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
2987 }
2988 }
2989 }
2990#endif /* !RT_OS_WINDOWS */
2991
2992 /*
2993 * Snapshot folder:
2994 * Here we test only for a FAT partition as we had to create a dummy file otherwise
2995 */
2996 if ( enmFsTypeSnap == RTFSTYPE_FAT
2997 && i64Size >= _4G
2998 && !mfSnapshotFolderSizeWarningShown)
2999 {
3000 const char *pszUnit;
3001 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3002 setVMRuntimeErrorCallbackF(pVM, this, 0,
3003 "FatPartitionDetected",
3004#ifdef RT_OS_WINDOWS
3005 N_("The snapshot folder of this VM '%ls' seems to be located on "
3006 "a FAT(32) file system. The logical size of the medium '%ls' "
3007 "(%RU64%s) is bigger than the maximum file size this file "
3008 "system can handle (4GB).\n"
3009 "We strongly recommend to put all your virtual disk images and "
3010 "the snapshot folder onto an NTFS partition"),
3011#else
3012 N_("The snapshot folder of this VM '%ls' seems to be located on "
3013 "a FAT(32) file system. The logical size of the medium '%ls' "
3014 "(%RU64%s) is bigger than the maximum file size this file "
3015 "system can handle (4GB).\n"
3016 "We strongly recommend to put all your virtual disk images and "
3017 "the snapshot folder onto a proper file system (e.g. ext3)"),
3018#endif
3019 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3020 /* Show this particular warning only once */
3021 mfSnapshotFolderSizeWarningShown = true;
3022 }
3023
3024#ifdef RT_OS_LINUX
3025 /*
3026 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3027 * on an ext4 partition. Later we have to check the Linux kernel version!
3028 * This bug apparently applies to the XFS file system as well.
3029 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3030 */
3031
3032 char szOsRelease[128];
3033 rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3034 bool fKernelHasODirectBug = RT_FAILURE(rc)
3035 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3036
3037 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3038 && !fUseHostIOCache
3039 && fKernelHasODirectBug)
3040 {
3041 if ( enmFsTypeFile == RTFSTYPE_EXT4
3042 || enmFsTypeFile == RTFSTYPE_XFS)
3043 {
3044 setVMRuntimeErrorCallbackF(pVM, this, 0,
3045 "Ext4PartitionDetected",
3046 N_("The host I/O cache for at least one controller is disabled "
3047 "and the medium '%ls' for this VM "
3048 "is located on an %s partition. There is a known Linux "
3049 "kernel bug which can lead to the corruption of the virtual "
3050 "disk image under these conditions.\n"
3051 "Either enable the host I/O cache permanently in the VM "
3052 "settings or put the disk image and the snapshot folder "
3053 "onto a different file system.\n"
3054 "The host I/O cache will now be enabled for this medium"),
3055 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3056 fUseHostIOCache = true;
3057 }
3058 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
3059 || enmFsTypeSnap == RTFSTYPE_XFS)
3060 && !mfSnapshotFolderExt4WarningShown)
3061 {
3062 setVMRuntimeErrorCallbackF(pVM, this, 0,
3063 "Ext4PartitionDetected",
3064 N_("The host I/O cache for at least one controller is disabled "
3065 "and the snapshot folder for this VM "
3066 "is located on an %s partition. There is a known Linux "
3067 "kernel bug which can lead to the corruption of the virtual "
3068 "disk image under these conditions.\n"
3069 "Either enable the host I/O cache permanently in the VM "
3070 "settings or put the disk image and the snapshot folder "
3071 "onto a different file system.\n"
3072 "The host I/O cache will now be enabled for this medium"),
3073 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3074 fUseHostIOCache = true;
3075 mfSnapshotFolderExt4WarningShown = true;
3076 }
3077 }
3078#endif
3079 }
3080 }
3081
3082 BOOL fPassthrough;
3083 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
3084
3085 ComObjPtr<IBandwidthGroup> pBwGroup;
3086 Bstr strBwGroup;
3087 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
3088
3089 if (!pBwGroup.isNull())
3090 {
3091 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
3092 }
3093
3094 rc = configMedium(pLunL0,
3095 !!fPassthrough,
3096 lType,
3097 fUseHostIOCache,
3098 fBuiltinIoCache,
3099 fSetupMerge,
3100 uMergeSource,
3101 uMergeTarget,
3102 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
3103 pMedium,
3104 aMachineState,
3105 phrc);
3106 if (RT_FAILURE(rc))
3107 return rc;
3108
3109 if (fAttachDetach)
3110 {
3111 /* Attach the new driver. */
3112 rc = PDMR3DeviceAttach(pVM, pcszDevice, uInstance, uLUN,
3113 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
3114 AssertRCReturn(rc, rc);
3115
3116 /* There is no need to handle removable medium mounting, as we
3117 * unconditionally replace everthing including the block driver level.
3118 * This means the new medium will be picked up automatically. */
3119 }
3120
3121 if (paLedDevType)
3122 paLedDevType[uLUN] = lType;
3123 }
3124 catch (ConfigError &x)
3125 {
3126 // InsertConfig threw something:
3127 return x.m_vrc;
3128 }
3129
3130#undef H
3131
3132 return VINF_SUCCESS;;
3133}
3134
3135int Console::configMedium(PCFGMNODE pLunL0,
3136 bool fPassthrough,
3137 DeviceType_T enmType,
3138 bool fUseHostIOCache,
3139 bool fBuiltinIoCache,
3140 bool fSetupMerge,
3141 unsigned uMergeSource,
3142 unsigned uMergeTarget,
3143 const char *pcszBwGroup,
3144 IMedium *pMedium,
3145 MachineState_T aMachineState,
3146 HRESULT *phrc)
3147{
3148 // InsertConfig* throws
3149 try
3150 {
3151 int rc = VINF_SUCCESS;
3152 HRESULT hrc;
3153 Bstr bstr;
3154 PCFGMNODE pLunL1 = NULL;
3155 PCFGMNODE pCfg = NULL;
3156
3157#define H() \
3158 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
3159
3160
3161 BOOL fHostDrive = FALSE;
3162 MediumType_T mediumType = MediumType_Normal;
3163 if (pMedium)
3164 {
3165 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
3166 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
3167 }
3168
3169 if (fHostDrive)
3170 {
3171 Assert(pMedium);
3172 if (enmType == DeviceType_DVD)
3173 {
3174 InsertConfigString(pLunL0, "Driver", "HostDVD");
3175 InsertConfigNode(pLunL0, "Config", &pCfg);
3176
3177 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
3178 InsertConfigString(pCfg, "Path", bstr);
3179
3180 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
3181 }
3182 else if (enmType == DeviceType_Floppy)
3183 {
3184 InsertConfigString(pLunL0, "Driver", "HostFloppy");
3185 InsertConfigNode(pLunL0, "Config", &pCfg);
3186
3187 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
3188 InsertConfigString(pCfg, "Path", bstr);
3189 }
3190 }
3191 else
3192 {
3193 InsertConfigString(pLunL0, "Driver", "Block");
3194 InsertConfigNode(pLunL0, "Config", &pCfg);
3195 switch (enmType)
3196 {
3197 case DeviceType_DVD:
3198 InsertConfigString(pCfg, "Type", "DVD");
3199 InsertConfigInteger(pCfg, "Mountable", 1);
3200 break;
3201 case DeviceType_Floppy:
3202 InsertConfigString(pCfg, "Type", "Floppy 1.44");
3203 InsertConfigInteger(pCfg, "Mountable", 1);
3204 break;
3205 case DeviceType_HardDisk:
3206 default:
3207 InsertConfigString(pCfg, "Type", "HardDisk");
3208 InsertConfigInteger(pCfg, "Mountable", 0);
3209 }
3210
3211 if ( pMedium
3212 && ( enmType == DeviceType_DVD
3213 || enmType == DeviceType_Floppy)
3214 )
3215 {
3216 // if this medium represents an ISO image and this image is inaccessible,
3217 // the ignore it instead of causing a failure; this can happen when we
3218 // restore a VM state and the ISO has disappeared, e.g. because the Guest
3219 // Additions were mounted and the user upgraded VirtualBox. Previously
3220 // we failed on startup, but that's not good because the only way out then
3221 // would be to discard the VM state...
3222 MediumState_T mediumState;
3223 hrc = pMedium->RefreshState(&mediumState); H();
3224 if (mediumState == MediumState_Inaccessible)
3225 {
3226 Bstr loc;
3227 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
3228 setVMRuntimeErrorCallbackF(VMR3GetVM(mpUVM),
3229 this,
3230 0,
3231 "DvdOrFloppyImageInaccessible",
3232 "The image file '%ls' is inaccessible and is being ignored. Please select a different image file for the virtual %s drive.",
3233 loc.raw(),
3234 enmType == DeviceType_DVD ? "DVD" : "floppy");
3235 pMedium = NULL;
3236 }
3237 }
3238
3239 if (pMedium)
3240 {
3241 /* Start with length of parent chain, as the list is reversed */
3242 unsigned uImage = 0;
3243 IMedium *pTmp = pMedium;
3244 while (pTmp)
3245 {
3246 uImage++;
3247 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
3248 }
3249 /* Index of last image */
3250 uImage--;
3251
3252#if 0 /* Enable for I/O debugging */
3253 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
3254 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
3255 InsertConfigNode(pLunL0, "Config", &pCfg);
3256 InsertConfigInteger(pCfg, "CheckConsistency", 0);
3257 InsertConfigInteger(pCfg, "CheckDoubleCompletions", 1);
3258#endif
3259
3260 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3261 InsertConfigString(pLunL1, "Driver", "VD");
3262 InsertConfigNode(pLunL1, "Config", &pCfg);
3263
3264 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
3265 InsertConfigString(pCfg, "Path", bstr);
3266
3267 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
3268 InsertConfigString(pCfg, "Format", bstr);
3269
3270 if (mediumType == MediumType_Readonly)
3271 InsertConfigInteger(pCfg, "ReadOnly", 1);
3272 else if (enmType == DeviceType_Floppy)
3273 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
3274
3275 /* Start without exclusive write access to the images. */
3276 /** @todo Live Migration: I don't quite like this, we risk screwing up when
3277 * we're resuming the VM if some 3rd dude have any of the VDIs open
3278 * with write sharing denied. However, if the two VMs are sharing a
3279 * image it really is necessary....
3280 *
3281 * So, on the "lock-media" command, the target teleporter should also
3282 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
3283 * that. Grumble. */
3284 if ( enmType == DeviceType_HardDisk
3285 && ( aMachineState == MachineState_TeleportingIn
3286 || aMachineState == MachineState_FaultTolerantSyncing))
3287 InsertConfigInteger(pCfg, "TempReadOnly", 1);
3288
3289 /* Flag for opening the medium for sharing between VMs. This
3290 * is done at the moment only for the first (and only) medium
3291 * in the chain, as shared media can have no diffs. */
3292 if (mediumType == MediumType_Shareable)
3293 InsertConfigInteger(pCfg, "Shareable", 1);
3294
3295 if (!fUseHostIOCache)
3296 {
3297 InsertConfigInteger(pCfg, "UseNewIo", 1);
3298 /*
3299 * Activate the builtin I/O cache for harddisks only.
3300 * It caches writes only which doesn't make sense for DVD drives
3301 * and just increases the overhead.
3302 */
3303 if ( fBuiltinIoCache
3304 && (enmType == DeviceType_HardDisk))
3305 InsertConfigInteger(pCfg, "BlockCache", 1);
3306 }
3307
3308 if (fSetupMerge)
3309 {
3310 InsertConfigInteger(pCfg, "SetupMerge", 1);
3311 if (uImage == uMergeSource)
3312 InsertConfigInteger(pCfg, "MergeSource", 1);
3313 else if (uImage == uMergeTarget)
3314 InsertConfigInteger(pCfg, "MergeTarget", 1);
3315 }
3316
3317 switch (enmType)
3318 {
3319 case DeviceType_DVD:
3320 InsertConfigString(pCfg, "Type", "DVD");
3321 break;
3322 case DeviceType_Floppy:
3323 InsertConfigString(pCfg, "Type", "Floppy");
3324 break;
3325 case DeviceType_HardDisk:
3326 default:
3327 InsertConfigString(pCfg, "Type", "HardDisk");
3328 }
3329
3330 if (pcszBwGroup)
3331 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
3332
3333 /* Pass all custom parameters. */
3334 bool fHostIP = true;
3335 SafeArray<BSTR> names;
3336 SafeArray<BSTR> values;
3337 hrc = pMedium->GetProperties((CBSTR)L"",
3338 ComSafeArrayAsOutParam(names),
3339 ComSafeArrayAsOutParam(values)); H();
3340
3341 if (names.size() != 0)
3342 {
3343 PCFGMNODE pVDC;
3344 InsertConfigNode(pCfg, "VDConfig", &pVDC);
3345 for (size_t ii = 0; ii < names.size(); ++ii)
3346 {
3347 if (values[ii] && *values[ii])
3348 {
3349 Utf8Str name = names[ii];
3350 Utf8Str value = values[ii];
3351 InsertConfigString(pVDC, name.c_str(), value);
3352 if ( name.compare("HostIPStack") == 0
3353 && value.compare("0") == 0)
3354 fHostIP = false;
3355 }
3356 }
3357 }
3358
3359 /* Create an inverted list of parents. */
3360 uImage--;
3361 IMedium *pParentMedium = pMedium;
3362 for (PCFGMNODE pParent = pCfg;; uImage--)
3363 {
3364 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
3365 if (!pMedium)
3366 break;
3367
3368 PCFGMNODE pCur;
3369 InsertConfigNode(pParent, "Parent", &pCur);
3370 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
3371 InsertConfigString(pCur, "Path", bstr);
3372
3373 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
3374 InsertConfigString(pCur, "Format", bstr);
3375
3376 if (fSetupMerge)
3377 {
3378 if (uImage == uMergeSource)
3379 InsertConfigInteger(pCur, "MergeSource", 1);
3380 else if (uImage == uMergeTarget)
3381 InsertConfigInteger(pCur, "MergeTarget", 1);
3382 }
3383
3384 /* Pass all custom parameters. */
3385 SafeArray<BSTR> aNames;
3386 SafeArray<BSTR> aValues;
3387 hrc = pMedium->GetProperties(NULL,
3388 ComSafeArrayAsOutParam(aNames),
3389 ComSafeArrayAsOutParam(aValues)); H();
3390
3391 if (aNames.size() != 0)
3392 {
3393 PCFGMNODE pVDC;
3394 InsertConfigNode(pCur, "VDConfig", &pVDC);
3395 for (size_t ii = 0; ii < aNames.size(); ++ii)
3396 {
3397 if (aValues[ii] && *aValues[ii])
3398 {
3399 Utf8Str name = aNames[ii];
3400 Utf8Str value = aValues[ii];
3401 InsertConfigString(pVDC, name.c_str(), value);
3402 if ( name.compare("HostIPStack") == 0
3403 && value.compare("0") == 0)
3404 fHostIP = false;
3405 }
3406 }
3407 }
3408
3409 /* next */
3410 pParent = pCur;
3411 pParentMedium = pMedium;
3412 }
3413
3414 /* Custom code: put marker to not use host IP stack to driver
3415 * configuration node. Simplifies life of DrvVD a bit. */
3416 if (!fHostIP)
3417 InsertConfigInteger(pCfg, "HostIPStack", 0);
3418 }
3419 }
3420#undef H
3421 }
3422 catch (ConfigError &x)
3423 {
3424 // InsertConfig threw something:
3425 return x.m_vrc;
3426 }
3427
3428 return VINF_SUCCESS;
3429}
3430
3431/**
3432 * Construct the Network configuration tree
3433 *
3434 * @returns VBox status code.
3435 *
3436 * @param pszDevice The PDM device name.
3437 * @param uInstance The PDM device instance.
3438 * @param uLun The PDM LUN number of the drive.
3439 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
3440 * @param pCfg Configuration node for the device
3441 * @param pLunL0 To store the pointer to the LUN#0.
3442 * @param pInst The instance CFGM node
3443 * @param fAttachDetach To determine if the network attachment should
3444 * be attached/detached after/before
3445 * configuration.
3446 * @param fIgnoreConnectFailure
3447 * True if connection failures should be ignored
3448 * (makes only sense for bridged/host-only networks).
3449 *
3450 * @note Locks this object for writing.
3451 * @thread EMT
3452 */
3453int Console::configNetwork(const char *pszDevice,
3454 unsigned uInstance,
3455 unsigned uLun,
3456 INetworkAdapter *aNetworkAdapter,
3457 PCFGMNODE pCfg,
3458 PCFGMNODE pLunL0,
3459 PCFGMNODE pInst,
3460 bool fAttachDetach,
3461 bool fIgnoreConnectFailure)
3462{
3463 AutoCaller autoCaller(this);
3464 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
3465
3466 // InsertConfig* throws
3467 try
3468 {
3469 int rc = VINF_SUCCESS;
3470 HRESULT hrc;
3471 Bstr bstr;
3472
3473#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
3474
3475 /*
3476 * Locking the object before doing VMR3* calls is quite safe here, since
3477 * we're on EMT. Write lock is necessary because we indirectly modify the
3478 * meAttachmentType member.
3479 */
3480 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3481
3482 PVM pVM = VMR3GetVM(mpUVM); /* We're on an EMT, so this is safe. */
3483
3484 ComPtr<IMachine> pMachine = machine();
3485
3486 ComPtr<IVirtualBox> virtualBox;
3487 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
3488
3489 ComPtr<IHost> host;
3490 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
3491
3492 BOOL fSniffer;
3493 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
3494
3495 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
3496 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
3497 const char *pszPromiscuousGuestPolicy;
3498 switch (enmPromiscModePolicy)
3499 {
3500 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
3501 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
3502 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
3503 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
3504 }
3505
3506 Utf8Str strNetDriver;
3507 if (fAttachDetach && fSniffer)
3508 {
3509 const char *pszNetDriver = "IntNet";
3510 if (meAttachmentType[uInstance] == NetworkAttachmentType_NAT)
3511 pszNetDriver = "NAT";
3512#if !defined(VBOX_WITH_NETFLT) && defined(RT_OS_LINUX)
3513 if (meAttachmentType[uInstance] == NetworkAttachmentType_Bridged)
3514 pszNetDriver = "HostInterface";
3515#endif
3516 if (meAttachmentType[uInstance] == NetworkAttachmentType_Generic)
3517 {
3518 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
3519 strNetDriver = bstr;
3520 pszNetDriver = strNetDriver.c_str();
3521 }
3522
3523 rc = PDMR3DriverDetach(pVM, pszDevice, uInstance, uLun, pszNetDriver, 0, 0 /*fFlags*/);
3524 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
3525 rc = VINF_SUCCESS;
3526 AssertLogRelRCReturn(rc, rc);
3527
3528 pLunL0 = CFGMR3GetChildF(pInst, "LUN#%u", uLun);
3529 PCFGMNODE pLunAD = CFGMR3GetChildF(pLunL0, "AttachedDriver");
3530 if (pLunAD)
3531 {
3532 CFGMR3RemoveNode(pLunAD);
3533 }
3534 else
3535 {
3536 CFGMR3RemoveNode(pLunL0);
3537 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3538 InsertConfigString(pLunL0, "Driver", "NetSniffer");
3539 InsertConfigNode(pLunL0, "Config", &pCfg);
3540 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
3541 if (!bstr.isEmpty()) /* check convention for indicating default file. */
3542 InsertConfigString(pCfg, "File", bstr);
3543 }
3544 }
3545 else if (fAttachDetach && !fSniffer)
3546 {
3547 rc = PDMR3DeviceDetach(pVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
3548 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
3549 rc = VINF_SUCCESS;
3550 AssertLogRelRCReturn(rc, rc);
3551
3552 /* nuke anything which might have been left behind. */
3553 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
3554 }
3555 else if (!fAttachDetach && fSniffer)
3556 {
3557 /* insert the sniffer filter driver. */
3558 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3559 InsertConfigString(pLunL0, "Driver", "NetSniffer");
3560 InsertConfigNode(pLunL0, "Config", &pCfg);
3561 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
3562 if (!bstr.isEmpty()) /* check convention for indicating default file. */
3563 InsertConfigString(pCfg, "File", bstr);
3564 }
3565
3566 Bstr networkName, trunkName, trunkType;
3567 NetworkAttachmentType_T eAttachmentType;
3568 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
3569 switch (eAttachmentType)
3570 {
3571 case NetworkAttachmentType_Null:
3572 break;
3573
3574 case NetworkAttachmentType_NAT:
3575 {
3576 ComPtr<INATEngine> natDriver;
3577 hrc = aNetworkAdapter->COMGETTER(NatDriver)(natDriver.asOutParam()); H();
3578 if (fSniffer)
3579 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
3580 else
3581 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3582 InsertConfigString(pLunL0, "Driver", "NAT");
3583 InsertConfigNode(pLunL0, "Config", &pCfg);
3584
3585 /* Configure TFTP prefix and boot filename. */
3586 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3587 if (!bstr.isEmpty())
3588 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
3589 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
3590 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
3591
3592 hrc = natDriver->COMGETTER(Network)(bstr.asOutParam()); H();
3593 if (!bstr.isEmpty())
3594 InsertConfigString(pCfg, "Network", bstr);
3595 else
3596 {
3597 ULONG uSlot;
3598 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
3599 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
3600 }
3601 hrc = natDriver->COMGETTER(HostIP)(bstr.asOutParam()); H();
3602 if (!bstr.isEmpty())
3603 InsertConfigString(pCfg, "BindIP", bstr);
3604 ULONG mtu = 0;
3605 ULONG sockSnd = 0;
3606 ULONG sockRcv = 0;
3607 ULONG tcpSnd = 0;
3608 ULONG tcpRcv = 0;
3609 hrc = natDriver->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
3610 if (mtu)
3611 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
3612 if (sockRcv)
3613 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
3614 if (sockSnd)
3615 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
3616 if (tcpRcv)
3617 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
3618 if (tcpSnd)
3619 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
3620 hrc = natDriver->COMGETTER(TftpPrefix)(bstr.asOutParam()); H();
3621 if (!bstr.isEmpty())
3622 {
3623 RemoveConfigValue(pCfg, "TFTPPrefix");
3624 InsertConfigString(pCfg, "TFTPPrefix", bstr);
3625 }
3626 hrc = natDriver->COMGETTER(TftpBootFile)(bstr.asOutParam()); H();
3627 if (!bstr.isEmpty())
3628 {
3629 RemoveConfigValue(pCfg, "BootFile");
3630 InsertConfigString(pCfg, "BootFile", bstr);
3631 }
3632 hrc = natDriver->COMGETTER(TftpNextServer)(bstr.asOutParam()); H();
3633 if (!bstr.isEmpty())
3634 InsertConfigString(pCfg, "NextServer", bstr);
3635 BOOL fDnsFlag;
3636 hrc = natDriver->COMGETTER(DnsPassDomain)(&fDnsFlag); H();
3637 InsertConfigInteger(pCfg, "PassDomain", fDnsFlag);
3638 hrc = natDriver->COMGETTER(DnsProxy)(&fDnsFlag); H();
3639 InsertConfigInteger(pCfg, "DNSProxy", fDnsFlag);
3640 hrc = natDriver->COMGETTER(DnsUseHostResolver)(&fDnsFlag); H();
3641 InsertConfigInteger(pCfg, "UseHostResolver", fDnsFlag);
3642
3643 ULONG aliasMode;
3644 hrc = natDriver->COMGETTER(AliasMode)(&aliasMode); H();
3645 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
3646
3647 /* port-forwarding */
3648 SafeArray<BSTR> pfs;
3649 hrc = natDriver->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
3650 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PF#0/ */
3651 for (unsigned int i = 0; i < pfs.size(); ++i)
3652 {
3653 uint16_t port = 0;
3654 BSTR r = pfs[i];
3655 Utf8Str utf = Utf8Str(r);
3656 Utf8Str strName;
3657 Utf8Str strProto;
3658 Utf8Str strHostPort;
3659 Utf8Str strHostIP;
3660 Utf8Str strGuestPort;
3661 Utf8Str strGuestIP;
3662 size_t pos, ppos;
3663 pos = ppos = 0;
3664#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
3665 do { \
3666 pos = str.find(",", ppos); \
3667 if (pos == Utf8Str::npos) \
3668 { \
3669 Log(( #res " extracting from %s is failed\n", str.c_str())); \
3670 continue; \
3671 } \
3672 res = str.substr(ppos, pos - ppos); \
3673 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
3674 ppos = pos + 1; \
3675 } while (0)
3676 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
3677 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
3678 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
3679 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
3680 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
3681 strGuestPort = utf.substr(ppos, utf.length() - ppos);
3682#undef ITERATE_TO_NEXT_TERM
3683
3684 uint32_t proto = strProto.toUInt32();
3685 bool fValid = true;
3686 switch (proto)
3687 {
3688 case NATProtocol_UDP:
3689 strProto = "UDP";
3690 break;
3691 case NATProtocol_TCP:
3692 strProto = "TCP";
3693 break;
3694 default:
3695 fValid = false;
3696 }
3697 /* continue with next rule if no valid proto was passed */
3698 if (!fValid)
3699 continue;
3700
3701 InsertConfigNode(pCfg, strName.c_str(), &pPF);
3702 InsertConfigString(pPF, "Protocol", strProto);
3703
3704 if (!strHostIP.isEmpty())
3705 InsertConfigString(pPF, "BindIP", strHostIP);
3706
3707 if (!strGuestIP.isEmpty())
3708 InsertConfigString(pPF, "GuestIP", strGuestIP);
3709
3710 port = RTStrToUInt16(strHostPort.c_str());
3711 if (port)
3712 InsertConfigInteger(pPF, "HostPort", port);
3713
3714 port = RTStrToUInt16(strGuestPort.c_str());
3715 if (port)
3716 InsertConfigInteger(pPF, "GuestPort", port);
3717 }
3718 break;
3719 }
3720
3721 case NetworkAttachmentType_Bridged:
3722 {
3723#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
3724 hrc = attachToTapInterface(aNetworkAdapter);
3725 if (FAILED(hrc))
3726 {
3727 switch (hrc)
3728 {
3729 case VERR_ACCESS_DENIED:
3730 return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
3731 "Failed to open '/dev/net/tun' for read/write access. Please check the "
3732 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
3733 "change the group of that node and make yourself a member of that group. Make "
3734 "sure that these changes are permanent, especially if you are "
3735 "using udev"));
3736 default:
3737 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
3738 return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
3739 "Failed to initialize Host Interface Networking"));
3740 }
3741 }
3742
3743 Assert((int)maTapFD[uInstance] >= 0);
3744 if ((int)maTapFD[uInstance] >= 0)
3745 {
3746 if (fSniffer)
3747 {
3748 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
3749 }
3750 else
3751 {
3752 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3753 }
3754 InsertConfigString(pLunL0, "Driver", "HostInterface");
3755 InsertConfigNode(pLunL0, "Config", &pCfg);
3756 InsertConfigInteger(pCfg, "FileHandle", maTapFD[uInstance]);
3757 }
3758
3759#elif defined(VBOX_WITH_NETFLT)
3760 /*
3761 * This is the new VBoxNetFlt+IntNet stuff.
3762 */
3763 if (fSniffer)
3764 {
3765 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
3766 }
3767 else
3768 {
3769 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3770 }
3771
3772 Bstr BridgedIfName;
3773 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
3774 if (FAILED(hrc))
3775 {
3776 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)", hrc));
3777 H();
3778 }
3779
3780 Utf8Str BridgedIfNameUtf8(BridgedIfName);
3781 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
3782
3783# if defined(RT_OS_DARWIN)
3784 /* The name is on the form 'ifX: long name', chop it off at the colon. */
3785 char szTrunk[8];
3786 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
3787 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
3788// Quick fix for #5633
3789// if (!pszColon)
3790// {
3791// /*
3792// * Dynamic changing of attachment causes an attempt to configure
3793// * network with invalid host adapter (as it is must be changed before
3794// * the attachment), calling Detach here will cause a deadlock.
3795// * See #4750.
3796// * hrc = aNetworkAdapter->Detach(); H();
3797// */
3798// return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3799// N_("Malformed host interface networking name '%ls'"),
3800// BridgedIfName.raw());
3801// }
3802 if (pszColon)
3803 *pszColon = '\0';
3804 const char *pszTrunk = szTrunk;
3805
3806# elif defined(RT_OS_SOLARIS)
3807 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
3808 char szTrunk[256];
3809 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
3810 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
3811
3812 /*
3813 * Currently don't bother about malformed names here for the sake of people using
3814 * VBoxManage and setting only the NIC name from there. If there is a space we
3815 * chop it off and proceed, otherwise just use whatever we've got.
3816 */
3817 if (pszSpace)
3818 *pszSpace = '\0';
3819
3820 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
3821 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
3822 if (pszColon)
3823 *pszColon = '\0';
3824
3825 const char *pszTrunk = szTrunk;
3826
3827# elif defined(RT_OS_WINDOWS)
3828 ComPtr<IHostNetworkInterface> hostInterface;
3829 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
3830 hostInterface.asOutParam());
3831 if (!SUCCEEDED(hrc))
3832 {
3833 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
3834 return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3835 N_("Nonexistent host networking interface, name '%ls'"),
3836 BridgedIfName.raw());
3837 }
3838
3839 HostNetworkInterfaceType_T eIfType;
3840 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
3841 if (FAILED(hrc))
3842 {
3843 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)", hrc));
3844 H();
3845 }
3846
3847 if (eIfType != HostNetworkInterfaceType_Bridged)
3848 {
3849 return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3850 N_("Interface ('%ls') is not a Bridged Adapter interface"),
3851 BridgedIfName.raw());
3852 }
3853
3854 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
3855 if (FAILED(hrc))
3856 {
3857 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)", hrc));
3858 H();
3859 }
3860 Guid hostIFGuid(bstr);
3861
3862 INetCfg *pNc;
3863 ComPtr<INetCfgComponent> pAdaptorComponent;
3864 LPWSTR pszApp;
3865
3866 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
3867 Assert(hrc == S_OK);
3868 if (hrc != S_OK)
3869 {
3870 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
3871 H();
3872 }
3873
3874 /* get the adapter's INetCfgComponent*/
3875 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(), pAdaptorComponent.asOutParam());
3876 if (hrc != S_OK)
3877 {
3878 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3879 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)", hrc));
3880 H();
3881 }
3882#define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
3883 char szTrunkName[INTNET_MAX_TRUNK_NAME];
3884 char *pszTrunkName = szTrunkName;
3885 wchar_t * pswzBindName;
3886 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
3887 Assert(hrc == S_OK);
3888 if (hrc == S_OK)
3889 {
3890 int cwBindName = (int)wcslen(pswzBindName) + 1;
3891 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
3892 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
3893 {
3894 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
3895 pszTrunkName += cbFullBindNamePrefix-1;
3896 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
3897 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
3898 {
3899 DWORD err = GetLastError();
3900 hrc = HRESULT_FROM_WIN32(err);
3901 AssertMsgFailed(("%hrc=%Rhrc %#x\n", hrc, hrc));
3902 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n", hrc, hrc, err));
3903 }
3904 }
3905 else
3906 {
3907 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
3908 /** @todo set appropriate error code */
3909 hrc = E_FAIL;
3910 }
3911
3912 if (hrc != S_OK)
3913 {
3914 AssertFailed();
3915 CoTaskMemFree(pswzBindName);
3916 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3917 H();
3918 }
3919
3920 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
3921 }
3922 else
3923 {
3924 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3925 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)", hrc));
3926 H();
3927 }
3928
3929 const char *pszTrunk = szTrunkName;
3930 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
3931
3932# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
3933# if defined(RT_OS_FREEBSD)
3934 /*
3935 * If we bridge to a tap interface open it the `old' direct way.
3936 * This works and performs better than bridging a physical
3937 * interface via the current FreeBSD vboxnetflt implementation.
3938 */
3939 if (!strncmp(pszBridgedIfName, "tap", sizeof "tap" - 1)) {
3940 hrc = attachToTapInterface(aNetworkAdapter);
3941 if (FAILED(hrc))
3942 {
3943 switch (hrc)
3944 {
3945 case VERR_ACCESS_DENIED:
3946 return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
3947 "Failed to open '/dev/%s' for read/write access. Please check the "
3948 "permissions of that node, and that the net.link.tap.user_open "
3949 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
3950 "change the group of that node to vboxusers and make yourself "
3951 "a member of that group. Make sure that these changes are permanent."), pszBridgedIfName, pszBridgedIfName);
3952 default:
3953 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
3954 return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
3955 "Failed to initialize Host Interface Networking"));
3956 }
3957 }
3958
3959 Assert((int)maTapFD[uInstance] >= 0);
3960 if ((int)maTapFD[uInstance] >= 0)
3961 {
3962 InsertConfigString(pLunL0, "Driver", "HostInterface");
3963 InsertConfigNode(pLunL0, "Config", &pCfg);
3964 InsertConfigInteger(pCfg, "FileHandle", maTapFD[uInstance]);
3965 }
3966 break;
3967 }
3968# endif
3969 /** @todo Check for malformed names. */
3970 const char *pszTrunk = pszBridgedIfName;
3971
3972 /* Issue a warning if the interface is down */
3973 {
3974 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
3975 if (iSock >= 0)
3976 {
3977 struct ifreq Req;
3978 RT_ZERO(Req);
3979 strncpy(Req.ifr_name, pszBridgedIfName, sizeof(Req.ifr_name) - 1);
3980 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
3981 if ((Req.ifr_flags & IFF_UP) == 0)
3982 setVMRuntimeErrorCallbackF(pVM, this, 0, "BridgedInterfaceDown",
3983 "Bridged interface %s is down. Guest will not be able to use this interface",
3984 pszBridgedIfName);
3985
3986 close(iSock);
3987 }
3988 }
3989
3990# else
3991# error "PORTME (VBOX_WITH_NETFLT)"
3992# endif
3993
3994 InsertConfigString(pLunL0, "Driver", "IntNet");
3995 InsertConfigNode(pLunL0, "Config", &pCfg);
3996 InsertConfigString(pCfg, "Trunk", pszTrunk);
3997 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
3998 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
3999 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
4000 char szNetwork[INTNET_MAX_NETWORK_NAME];
4001 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
4002 InsertConfigString(pCfg, "Network", szNetwork);
4003 networkName = Bstr(szNetwork);
4004 trunkName = Bstr(pszTrunk);
4005 trunkType = Bstr(TRUNKTYPE_NETFLT);
4006
4007# if defined(RT_OS_DARWIN)
4008 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
4009 if ( strstr(pszBridgedIfName, "Wireless")
4010 || strstr(pszBridgedIfName, "AirPort" ))
4011 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
4012# elif defined(RT_OS_LINUX)
4013 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
4014 if (iSock >= 0)
4015 {
4016 struct iwreq WRq;
4017
4018 memset(&WRq, 0, sizeof(WRq));
4019 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
4020 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
4021 close(iSock);
4022 if (fSharedMacOnWire)
4023 {
4024 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
4025 Log(("Set SharedMacOnWire\n"));
4026 }
4027 else
4028 Log(("Failed to get wireless name\n"));
4029 }
4030 else
4031 Log(("Failed to open wireless socket\n"));
4032# elif defined(RT_OS_FREEBSD)
4033 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
4034 if (iSock >= 0)
4035 {
4036 struct ieee80211req WReq;
4037 uint8_t abData[32];
4038
4039 memset(&WReq, 0, sizeof(WReq));
4040 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
4041 WReq.i_type = IEEE80211_IOC_SSID;
4042 WReq.i_val = -1;
4043 WReq.i_data = abData;
4044 WReq.i_len = sizeof(abData);
4045
4046 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
4047 close(iSock);
4048 if (fSharedMacOnWire)
4049 {
4050 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
4051 Log(("Set SharedMacOnWire\n"));
4052 }
4053 else
4054 Log(("Failed to get wireless name\n"));
4055 }
4056 else
4057 Log(("Failed to open wireless socket\n"));
4058# elif defined(RT_OS_WINDOWS)
4059# define DEVNAME_PREFIX L"\\\\.\\"
4060 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
4061 * there is a pretty long way till there though since we need to obtain the symbolic link name
4062 * for the adapter device we are going to query given the device Guid */
4063
4064
4065 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
4066
4067 wchar_t FileName[MAX_PATH];
4068 wcscpy(FileName, DEVNAME_PREFIX);
4069 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
4070
4071 /* open the device */
4072 HANDLE hDevice = CreateFile(FileName,
4073 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
4074 NULL,
4075 OPEN_EXISTING,
4076 FILE_ATTRIBUTE_NORMAL,
4077 NULL);
4078
4079 if (hDevice != INVALID_HANDLE_VALUE)
4080 {
4081 bool fSharedMacOnWire = false;
4082
4083 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
4084 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
4085 NDIS_PHYSICAL_MEDIUM PhMedium;
4086 DWORD cbResult;
4087 if (DeviceIoControl(hDevice,
4088 IOCTL_NDIS_QUERY_GLOBAL_STATS,
4089 &Oid,
4090 sizeof(Oid),
4091 &PhMedium,
4092 sizeof(PhMedium),
4093 &cbResult,
4094 NULL))
4095 {
4096 /* that was simple, now examine PhMedium */
4097 if ( PhMedium == NdisPhysicalMediumWirelessWan
4098 || PhMedium == NdisPhysicalMediumWirelessLan
4099 || PhMedium == NdisPhysicalMediumNative802_11
4100 || PhMedium == NdisPhysicalMediumBluetooth)
4101 fSharedMacOnWire = true;
4102 }
4103 else
4104 {
4105 int winEr = GetLastError();
4106 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
4107 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
4108 }
4109 CloseHandle(hDevice);
4110
4111 if (fSharedMacOnWire)
4112 {
4113 Log(("this is a wireless adapter"));
4114 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
4115 Log(("Set SharedMacOnWire\n"));
4116 }
4117 else
4118 Log(("this is NOT a wireless adapter"));
4119 }
4120 else
4121 {
4122 int winEr = GetLastError();
4123 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
4124 }
4125
4126 CoTaskMemFree(pswzBindName);
4127
4128 pAdaptorComponent.setNull();
4129 /* release the pNc finally */
4130 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4131# else
4132 /** @todo PORTME: wireless detection */
4133# endif
4134
4135# if defined(RT_OS_SOLARIS)
4136# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
4137 /* Zone access restriction, don't allow snooping the global zone. */
4138 zoneid_t ZoneId = getzoneid();
4139 if (ZoneId != GLOBAL_ZONEID)
4140 {
4141 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
4142 }
4143# endif
4144# endif
4145
4146#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
4147 /* NOTHING TO DO HERE */
4148#elif defined(RT_OS_LINUX)
4149/// @todo aleksey: is there anything to be done here?
4150#elif defined(RT_OS_FREEBSD)
4151/** @todo FreeBSD: Check out this later (HIF networking). */
4152#else
4153# error "Port me"
4154#endif
4155 break;
4156 }
4157
4158 case NetworkAttachmentType_Internal:
4159 {
4160 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
4161 if (!bstr.isEmpty())
4162 {
4163 if (fSniffer)
4164 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4165 else
4166 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4167 InsertConfigString(pLunL0, "Driver", "IntNet");
4168 InsertConfigNode(pLunL0, "Config", &pCfg);
4169 InsertConfigString(pCfg, "Network", bstr);
4170 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
4171 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
4172 networkName = bstr;
4173 trunkType = Bstr(TRUNKTYPE_WHATEVER);
4174 }
4175 break;
4176 }
4177
4178 case NetworkAttachmentType_HostOnly:
4179 {
4180 if (fSniffer)
4181 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4182 else
4183 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4184
4185 InsertConfigString(pLunL0, "Driver", "IntNet");
4186 InsertConfigNode(pLunL0, "Config", &pCfg);
4187
4188 Bstr HostOnlyName;
4189 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
4190 if (FAILED(hrc))
4191 {
4192 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
4193 H();
4194 }
4195
4196 Utf8Str HostOnlyNameUtf8(HostOnlyName);
4197 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
4198 ComPtr<IHostNetworkInterface> hostInterface;
4199 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
4200 hostInterface.asOutParam());
4201 if (!SUCCEEDED(rc))
4202 {
4203 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
4204 return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
4205 N_("Nonexistent host networking interface, name '%ls'"),
4206 HostOnlyName.raw());
4207 }
4208
4209 char szNetwork[INTNET_MAX_NETWORK_NAME];
4210 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
4211
4212#if defined(RT_OS_WINDOWS)
4213# ifndef VBOX_WITH_NETFLT
4214 hrc = E_NOTIMPL;
4215 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
4216 H();
4217# else /* defined VBOX_WITH_NETFLT*/
4218 /** @todo r=bird: Put this in a function. */
4219
4220 HostNetworkInterfaceType_T eIfType;
4221 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
4222 if (FAILED(hrc))
4223 {
4224 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
4225 H();
4226 }
4227
4228 if (eIfType != HostNetworkInterfaceType_HostOnly)
4229 return VMSetError(pVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
4230 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
4231 HostOnlyName.raw());
4232
4233 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
4234 if (FAILED(hrc))
4235 {
4236 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
4237 H();
4238 }
4239 Guid hostIFGuid(bstr);
4240
4241 INetCfg *pNc;
4242 ComPtr<INetCfgComponent> pAdaptorComponent;
4243 LPWSTR pszApp;
4244 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
4245 Assert(hrc == S_OK);
4246 if (hrc != S_OK)
4247 {
4248 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
4249 H();
4250 }
4251
4252 /* get the adapter's INetCfgComponent*/
4253 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(), pAdaptorComponent.asOutParam());
4254 if (hrc != S_OK)
4255 {
4256 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4257 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
4258 H();
4259 }
4260# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
4261 char szTrunkName[INTNET_MAX_TRUNK_NAME];
4262 char *pszTrunkName = szTrunkName;
4263 wchar_t * pswzBindName;
4264 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
4265 Assert(hrc == S_OK);
4266 if (hrc == S_OK)
4267 {
4268 int cwBindName = (int)wcslen(pswzBindName) + 1;
4269 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
4270 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
4271 {
4272 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
4273 pszTrunkName += cbFullBindNamePrefix-1;
4274 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
4275 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
4276 {
4277 DWORD err = GetLastError();
4278 hrc = HRESULT_FROM_WIN32(err);
4279 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n", hrc, hrc, err));
4280 }
4281 }
4282 else
4283 {
4284 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
4285 /** @todo set appropriate error code */
4286 hrc = E_FAIL;
4287 }
4288
4289 if (hrc != S_OK)
4290 {
4291 AssertFailed();
4292 CoTaskMemFree(pswzBindName);
4293 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4294 H();
4295 }
4296 }
4297 else
4298 {
4299 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4300 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
4301 H();
4302 }
4303
4304
4305 CoTaskMemFree(pswzBindName);
4306
4307 pAdaptorComponent.setNull();
4308 /* release the pNc finally */
4309 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
4310
4311 const char *pszTrunk = szTrunkName;
4312
4313 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
4314 InsertConfigString(pCfg, "Trunk", pszTrunk);
4315 InsertConfigString(pCfg, "Network", szNetwork);
4316 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this windows only?? */
4317 networkName = Bstr(szNetwork);
4318 trunkName = Bstr(pszTrunk);
4319 trunkType = TRUNKTYPE_NETADP;
4320# endif /* defined VBOX_WITH_NETFLT*/
4321#elif defined(RT_OS_DARWIN)
4322 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
4323 InsertConfigString(pCfg, "Network", szNetwork);
4324 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
4325 networkName = Bstr(szNetwork);
4326 trunkName = Bstr(pszHostOnlyName);
4327 trunkType = TRUNKTYPE_NETADP;
4328#else
4329 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
4330 InsertConfigString(pCfg, "Network", szNetwork);
4331 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
4332 networkName = Bstr(szNetwork);
4333 trunkName = Bstr(pszHostOnlyName);
4334 trunkType = TRUNKTYPE_NETFLT;
4335#endif
4336 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
4337
4338#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
4339
4340 Bstr tmpAddr, tmpMask;
4341
4342 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
4343 pszHostOnlyName).raw(),
4344 tmpAddr.asOutParam());
4345 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
4346 {
4347 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
4348 pszHostOnlyName).raw(),
4349 tmpMask.asOutParam());
4350 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
4351 hrc = hostInterface->EnableStaticIpConfig(tmpAddr.raw(),
4352 tmpMask.raw());
4353 else
4354 hrc = hostInterface->EnableStaticIpConfig(tmpAddr.raw(),
4355 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
4356 }
4357 else
4358 {
4359 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
4360 hrc = hostInterface->EnableStaticIpConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
4361 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
4362 }
4363
4364 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
4365
4366 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
4367 pszHostOnlyName).raw(),
4368 tmpAddr.asOutParam());
4369 if (SUCCEEDED(hrc))
4370 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
4371 tmpMask.asOutParam());
4372 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
4373 {
4374 hrc = hostInterface->EnableStaticIpConfigV6(tmpAddr.raw(),
4375 Utf8Str(tmpMask).toUInt32());
4376 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
4377 }
4378#endif
4379 break;
4380 }
4381
4382 case NetworkAttachmentType_Generic:
4383 {
4384 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
4385 SafeArray<BSTR> names;
4386 SafeArray<BSTR> values;
4387 hrc = aNetworkAdapter->GetProperties((CBSTR)L"",
4388 ComSafeArrayAsOutParam(names),
4389 ComSafeArrayAsOutParam(values)); H();
4390
4391 if (fSniffer)
4392 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4393 else
4394 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4395 InsertConfigString(pLunL0, "Driver", bstr);
4396 InsertConfigNode(pLunL0, "Config", &pCfg);
4397 for (size_t ii = 0; ii < names.size(); ++ii)
4398 {
4399 if (values[ii] && *values[ii])
4400 {
4401 Utf8Str name = names[ii];
4402 Utf8Str value = values[ii];
4403 InsertConfigString(pCfg, name.c_str(), value);
4404 }
4405 }
4406 break;
4407 }
4408
4409 default:
4410 AssertMsgFailed(("should not get here!\n"));
4411 break;
4412 }
4413
4414 /*
4415 * Attempt to attach the driver.
4416 */
4417 switch (eAttachmentType)
4418 {
4419 case NetworkAttachmentType_Null:
4420 break;
4421
4422 case NetworkAttachmentType_Bridged:
4423 case NetworkAttachmentType_Internal:
4424 case NetworkAttachmentType_HostOnly:
4425 case NetworkAttachmentType_NAT:
4426 case NetworkAttachmentType_Generic:
4427 {
4428 if (SUCCEEDED(hrc) && SUCCEEDED(rc))
4429 {
4430 if (fAttachDetach)
4431 {
4432 rc = PDMR3DriverAttach(pVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
4433 //AssertRC(rc);
4434 }
4435
4436 {
4437 /** @todo pritesh: get the dhcp server name from the
4438 * previous network configuration and then stop the server
4439 * else it may conflict with the dhcp server running with
4440 * the current attachment type
4441 */
4442 /* Stop the hostonly DHCP Server */
4443 }
4444
4445 if (!networkName.isEmpty())
4446 {
4447 /*
4448 * Until we implement service reference counters DHCP Server will be stopped
4449 * by DHCPServerRunner destructor.
4450 */
4451 ComPtr<IDHCPServer> dhcpServer;
4452 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
4453 dhcpServer.asOutParam());
4454 if (SUCCEEDED(hrc))
4455 {
4456 /* there is a DHCP server available for this network */
4457 BOOL fEnabled;
4458 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabled);
4459 if (FAILED(hrc))
4460 {
4461 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)", hrc));
4462 H();
4463 }
4464
4465 if (fEnabled)
4466 hrc = dhcpServer->Start(networkName.raw(),
4467 trunkName.raw(),
4468 trunkType.raw());
4469 }
4470 else
4471 hrc = S_OK;
4472 }
4473 }
4474
4475 break;
4476 }
4477
4478 default:
4479 AssertMsgFailed(("should not get here!\n"));
4480 break;
4481 }
4482
4483 meAttachmentType[uInstance] = eAttachmentType;
4484 }
4485 catch (ConfigError &x)
4486 {
4487 // InsertConfig threw something:
4488 return x.m_vrc;
4489 }
4490
4491#undef H
4492
4493 return VINF_SUCCESS;
4494}
4495
4496#ifdef VBOX_WITH_GUEST_PROPS
4497/**
4498 * Set an array of guest properties
4499 */
4500static void configSetProperties(VMMDev * const pVMMDev,
4501 void *names,
4502 void *values,
4503 void *timestamps,
4504 void *flags)
4505{
4506 VBOXHGCMSVCPARM parms[4];
4507
4508 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
4509 parms[0].u.pointer.addr = names;
4510 parms[0].u.pointer.size = 0; /* We don't actually care. */
4511 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
4512 parms[1].u.pointer.addr = values;
4513 parms[1].u.pointer.size = 0; /* We don't actually care. */
4514 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
4515 parms[2].u.pointer.addr = timestamps;
4516 parms[2].u.pointer.size = 0; /* We don't actually care. */
4517 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
4518 parms[3].u.pointer.addr = flags;
4519 parms[3].u.pointer.size = 0; /* We don't actually care. */
4520
4521 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
4522 guestProp::SET_PROPS_HOST,
4523 4,
4524 &parms[0]);
4525}
4526
4527/**
4528 * Set a single guest property
4529 */
4530static void configSetProperty(VMMDev * const pVMMDev,
4531 const char *pszName,
4532 const char *pszValue,
4533 const char *pszFlags)
4534{
4535 VBOXHGCMSVCPARM parms[4];
4536
4537 AssertPtrReturnVoid(pszName);
4538 AssertPtrReturnVoid(pszValue);
4539 AssertPtrReturnVoid(pszFlags);
4540 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
4541 parms[0].u.pointer.addr = (void *)pszName;
4542 parms[0].u.pointer.size = strlen(pszName) + 1;
4543 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
4544 parms[1].u.pointer.addr = (void *)pszValue;
4545 parms[1].u.pointer.size = strlen(pszValue) + 1;
4546 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
4547 parms[2].u.pointer.addr = (void *)pszFlags;
4548 parms[2].u.pointer.size = strlen(pszFlags) + 1;
4549 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
4550 &parms[0]);
4551}
4552
4553/**
4554 * Set the global flags value by calling the service
4555 * @returns the status returned by the call to the service
4556 *
4557 * @param pTable the service instance handle
4558 * @param eFlags the flags to set
4559 */
4560int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
4561 guestProp::ePropFlags eFlags)
4562{
4563 VBOXHGCMSVCPARM paParm;
4564 paParm.setUInt32(eFlags);
4565 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
4566 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
4567 &paParm);
4568 if (RT_FAILURE(rc))
4569 {
4570 char szFlags[guestProp::MAX_FLAGS_LEN];
4571 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
4572 Log(("Failed to set the global flags.\n"));
4573 else
4574 Log(("Failed to set the global flags \"%s\".\n", szFlags));
4575 }
4576 return rc;
4577}
4578#endif /* VBOX_WITH_GUEST_PROPS */
4579
4580/**
4581 * Set up the Guest Property service, populate it with properties read from
4582 * the machine XML and set a couple of initial properties.
4583 */
4584/* static */ int Console::configGuestProperties(void *pvConsole)
4585{
4586#ifdef VBOX_WITH_GUEST_PROPS
4587 AssertReturn(pvConsole, VERR_GENERAL_FAILURE);
4588 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
4589 AssertReturn(pConsole->m_pVMMDev, VERR_GENERAL_FAILURE);
4590
4591 /* Load the service */
4592 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
4593
4594 if (RT_FAILURE(rc))
4595 {
4596 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
4597 /* That is not a fatal failure. */
4598 rc = VINF_SUCCESS;
4599 }
4600 else
4601 {
4602 /*
4603 * Initialize built-in properties that can be changed and saved.
4604 *
4605 * These are typically transient properties that the guest cannot
4606 * change.
4607 */
4608
4609 /* Sysprep execution by VBoxService. */
4610 configSetProperty(pConsole->m_pVMMDev,
4611 "/VirtualBox/HostGuest/SysprepExec", "",
4612 "TRANSIENT, RDONLYGUEST");
4613 configSetProperty(pConsole->m_pVMMDev,
4614 "/VirtualBox/HostGuest/SysprepArgs", "",
4615 "TRANSIENT, RDONLYGUEST");
4616
4617 /*
4618 * Pull over the properties from the server.
4619 */
4620 SafeArray<BSTR> namesOut;
4621 SafeArray<BSTR> valuesOut;
4622 SafeArray<LONG64> timestampsOut;
4623 SafeArray<BSTR> flagsOut;
4624 HRESULT hrc;
4625 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
4626 ComSafeArrayAsOutParam(valuesOut),
4627 ComSafeArrayAsOutParam(timestampsOut),
4628 ComSafeArrayAsOutParam(flagsOut));
4629 AssertMsgReturn(SUCCEEDED(hrc), ("hrc=%Rrc\n", hrc), VERR_GENERAL_FAILURE);
4630 size_t cProps = namesOut.size();
4631 size_t cAlloc = cProps + 1;
4632 if ( valuesOut.size() != cProps
4633 || timestampsOut.size() != cProps
4634 || flagsOut.size() != cProps
4635 )
4636 AssertFailedReturn(VERR_INVALID_PARAMETER);
4637
4638 char **papszNames, **papszValues, **papszFlags;
4639 char szEmpty[] = "";
4640 LONG64 *pai64Timestamps;
4641 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
4642 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
4643 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
4644 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
4645 if (papszNames && papszValues && pai64Timestamps && papszFlags)
4646 {
4647 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
4648 {
4649 AssertPtrReturn(namesOut[i], VERR_INVALID_PARAMETER);
4650 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
4651 if (RT_FAILURE(rc))
4652 break;
4653 if (valuesOut[i])
4654 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
4655 else
4656 papszValues[i] = szEmpty;
4657 if (RT_FAILURE(rc))
4658 break;
4659 pai64Timestamps[i] = timestampsOut[i];
4660 if (flagsOut[i])
4661 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
4662 else
4663 papszFlags[i] = szEmpty;
4664 }
4665 if (RT_SUCCESS(rc))
4666 configSetProperties(pConsole->m_pVMMDev,
4667 (void *)papszNames,
4668 (void *)papszValues,
4669 (void *)pai64Timestamps,
4670 (void *)papszFlags);
4671 for (unsigned i = 0; i < cProps; ++i)
4672 {
4673 RTStrFree(papszNames[i]);
4674 if (valuesOut[i])
4675 RTStrFree(papszValues[i]);
4676 if (flagsOut[i])
4677 RTStrFree(papszFlags[i]);
4678 }
4679 }
4680 else
4681 rc = VERR_NO_MEMORY;
4682 RTMemTmpFree(papszNames);
4683 RTMemTmpFree(papszValues);
4684 RTMemTmpFree(pai64Timestamps);
4685 RTMemTmpFree(papszFlags);
4686 AssertRCReturn(rc, rc);
4687
4688 /*
4689 * These properties have to be set before pulling over the properties
4690 * from the machine XML, to ensure that properties saved in the XML
4691 * will override them.
4692 */
4693 /* Set the raw VBox version string as a guest property. Used for host/guest
4694 * version comparison. */
4695 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
4696 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
4697 /* Set the full VBox version string as a guest property. Can contain vendor-specific
4698 * information/branding and/or pre-release tags. */
4699 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
4700 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
4701 /* Set the VBox SVN revision as a guest property */
4702 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
4703 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
4704
4705 /*
4706 * Register the host notification callback
4707 */
4708 HGCMSVCEXTHANDLE hDummy;
4709 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
4710 Console::doGuestPropNotification,
4711 pvConsole);
4712
4713#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
4714 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
4715 guestProp::RDONLYGUEST);
4716 AssertRCReturn(rc, rc);
4717#endif
4718
4719 Log(("Set VBoxGuestPropSvc property store\n"));
4720 }
4721 return VINF_SUCCESS;
4722#else /* !VBOX_WITH_GUEST_PROPS */
4723 return VERR_NOT_SUPPORTED;
4724#endif /* !VBOX_WITH_GUEST_PROPS */
4725}
4726
4727/**
4728 * Set up the Guest Control service.
4729 */
4730/* static */ int Console::configGuestControl(void *pvConsole)
4731{
4732#ifdef VBOX_WITH_GUEST_CONTROL
4733 AssertReturn(pvConsole, VERR_GENERAL_FAILURE);
4734 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
4735
4736 /* Load the service */
4737 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
4738
4739 if (RT_FAILURE(rc))
4740 {
4741 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
4742 /* That is not a fatal failure. */
4743 rc = VINF_SUCCESS;
4744 }
4745 else
4746 {
4747 HGCMSVCEXTHANDLE hDummy;
4748 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
4749 &Guest::doGuestCtrlNotification,
4750 pConsole->getGuest());
4751 if (RT_FAILURE(rc))
4752 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
4753 else
4754 Log(("VBoxGuestControlSvc loaded\n"));
4755 }
4756
4757 return rc;
4758#else /* !VBOX_WITH_GUEST_CONTROL */
4759 return VERR_NOT_SUPPORTED;
4760#endif /* !VBOX_WITH_GUEST_CONTROL */
4761}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use