VirtualBox

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

Last change on this file since 36200 was 36130, checked in by vboxsync, 14 years ago

Main: don't allow to start a VM if USB2.0 was enabled but no extension pack is available

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

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