VirtualBox

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

Last change on this file since 34645 was 34587, checked in by vboxsync, 14 years ago

Main: Bandwidth groups for disks (and later network)

This introduces two new interfaces. The first one named IBandwidthGroup
represents one I/O limit and can be assigned to several mediums which
share this limit (which works only for harddisk images with the disabled
host cache).
The second one IBandwdithControl manages the groups and can create new ones
and destroy them if not required anymore.

VBoxManage: commands to access the bandwidth groups

Syntax:
VBoxManage storageattach <uuid|vmname>

...
--bandwidthgroup <name>

--bandwidthgroup assigns the specified device to the given group.

VBoxManage bandwidthctl <uuid|vmname>

--name <name>
--add disk|network
--limit <megabytes per second>
--delete

The --name parameter gives the name of the bandwidth group.
--add creates a new group of the given type (only disk is implemented so far)

with the given name.

--limit sets the limit to the given amount of MB/s

Note that limit can be changed while the VM is running. The VM
will immediately pick up the new limit for the given group name.

--delete deletes the group with the given name if it isn't used anymore.

Trying to delete a still used group will result in an error.

Example:

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 20
Creates a group named Test having a 20 MB/s limit.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup Limit
Adds a new disk to the SATA controller and assigns the bandwidth group Limit to it.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup none
Removes the bandwidth limit from the disk.

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 10
Changes the limit of bandwidth group Limit to 10 MB/s. If the VM is running the limit will be picked up
immediately.

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