VirtualBox

source: vbox/trunk/src/VBox/Main/ConsoleImpl2.cpp@ 30951

Last change on this file since 30951 was 30951, checked in by vboxsync, 15 years ago

ConsoleImpl2.cpp: ConfigError need not be exported I think.

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