VirtualBox

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

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

Runtime: new guest OS type for Solaris 11
Frontends/VirtualBox: add new patterns for Solaris 11 guest OS type, reuse the icon
Frontends/VBoxManage: more details for "list ostypes"
Main/xml: make guest OS type in config file an arbitrary string (still validated/mapped in the old way in the settings code), remove hardcoded limit of 8 network adapters
Main/Global: move list of valid guest OS types into a single place, add function to get the network adapter limit for each chipset type
Main/Console+Machine+Snapshot+NetworkAdapter+Appliance+VirtualBox+Guest+SystemProperties: consistently use the appropriate network adapter limit so that ICH9 chipset can use 36 network adapters, adapt to cleaned up guest OS type handling, remove leftover rendundant guest OS mapping, whitespace
Network/NAT: release log message cosmetics, allow unlimited number of instances, fix maxconn clamping
Network/PCNet+VirtioNet+E1000: allow unlimited number of instances

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

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