VirtualBox

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

Last change on this file since 31164 was 31128, checked in by vboxsync, 14 years ago

Main/Console,Storage/DrvVD+fdc: Allow readonly floppy images (suppress runtime error on VM start for readonly media), and take this as the signal to make the floppy medium readonly. Never attempt to write to such images, and signal the appropriate error.

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