VirtualBox

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

Last change on this file since 65410 was 65410, checked in by vboxsync, 8 years ago

VideoRec: Interface work, added container / codec configuration stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 253.7 KB
Line 
1/* $Id: ConsoleImpl2.cpp 65410 2017-01-24 10:06:12Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - VM Configuration Bits.
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-2017 Oracle Corporation
13 *
14 * This file is part of VirtualBox Open Source Edition (OSE), as
15 * available from http://www.215389.xyz. 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/*********************************************************************************************************************************
25* Header Files *
26*********************************************************************************************************************************/
27
28// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
29// header file includes Windows.h.
30#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
31# include <VBox/VBoxNetCfg-win.h>
32#endif
33
34#include "ConsoleImpl.h"
35#include "DisplayImpl.h"
36#ifdef VBOX_WITH_GUEST_CONTROL
37# include "GuestImpl.h"
38#endif
39#ifdef VBOX_WITH_DRAG_AND_DROP
40# include "GuestDnDPrivate.h"
41#endif
42#include "VMMDev.h"
43#include "Global.h"
44#ifdef VBOX_WITH_PCI_PASSTHROUGH
45# include "PCIRawDevImpl.h"
46#endif
47
48// generated header
49#include "SchemaDefs.h"
50
51#include "AutoCaller.h"
52#include "Logging.h"
53
54#include <iprt/base64.h>
55#include <iprt/buildconfig.h>
56#include <iprt/ctype.h>
57#include <iprt/dir.h>
58#include <iprt/file.h>
59#include <iprt/param.h>
60#include <iprt/path.h>
61#include <iprt/string.h>
62#include <iprt/system.h>
63#include <iprt/cpp/exception.h>
64#if 0 /* enable to play with lots of memory. */
65# include <iprt/env.h>
66#endif
67#include <iprt/stream.h>
68
69#include <VBox/vmm/vmapi.h>
70#include <VBox/err.h>
71#include <VBox/param.h>
72#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
73#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
74#include <VBox/vmm/apic.h> /* For APICMODE enum. */
75#include <VBox/vmm/pdmstorageifs.h>
76#include <VBox/version.h>
77#include <VBox/HostServices/VBoxClipboardSvc.h>
78#ifdef VBOX_WITH_CROGL
79# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
80#include <VBox/VBoxOGL.h>
81#endif
82#ifdef VBOX_WITH_GUEST_PROPS
83# include <VBox/HostServices/GuestPropertySvc.h>
84# include <VBox/com/defs.h>
85# include <VBox/com/array.h>
86# include "HGCM.h" /** @todo It should be possible to register a service
87 * extension using a VMMDev callback. */
88# include <vector>
89#endif /* VBOX_WITH_GUEST_PROPS */
90#include <VBox/intnet.h>
91
92#include <VBox/com/com.h>
93#include <VBox/com/string.h>
94#include <VBox/com/array.h>
95
96#ifdef VBOX_WITH_NETFLT
97# if defined(RT_OS_SOLARIS)
98# include <zone.h>
99# elif defined(RT_OS_LINUX)
100# include <unistd.h>
101# include <sys/ioctl.h>
102# include <sys/socket.h>
103# include <linux/types.h>
104# include <linux/if.h>
105# include <linux/wireless.h>
106# elif defined(RT_OS_FREEBSD)
107# include <unistd.h>
108# include <sys/types.h>
109# include <sys/ioctl.h>
110# include <sys/socket.h>
111# include <net/if.h>
112# include <net80211/ieee80211_ioctl.h>
113# endif
114# if defined(RT_OS_WINDOWS)
115# include <iprt/win/ntddndis.h>
116# include <devguid.h>
117# else
118# include <HostNetworkInterfaceImpl.h>
119# include <netif.h>
120# include <stdlib.h>
121# endif
122#endif /* VBOX_WITH_NETFLT */
123
124#include "NetworkServiceRunner.h"
125#include "BusAssignmentManager.h"
126#ifdef VBOX_WITH_EXTPACK
127# include "ExtPackManagerImpl.h"
128#endif
129
130
131/*********************************************************************************************************************************
132* Internal Functions *
133*********************************************************************************************************************************/
134static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);
135
136
137/* Darwin compile kludge */
138#undef PVM
139
140/* Comment out the following line to remove VMWare compatibility hack. */
141#define VMWARE_NET_IN_SLOT_11
142
143/**
144 * Translate IDE StorageControllerType_T to string representation.
145 */
146const char* controllerString(StorageControllerType_T enmType)
147{
148 switch (enmType)
149 {
150 case StorageControllerType_PIIX3:
151 return "PIIX3";
152 case StorageControllerType_PIIX4:
153 return "PIIX4";
154 case StorageControllerType_ICH6:
155 return "ICH6";
156 default:
157 return "Unknown";
158 }
159}
160
161/**
162 * Simple class for storing network boot information.
163 */
164struct BootNic
165{
166 ULONG mInstance;
167 PCIBusAddress mPCIAddress;
168
169 ULONG mBootPrio;
170 bool operator < (const BootNic &rhs) const
171 {
172 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */
173 ULONG rval = rhs.mBootPrio - 1;
174 return lval < rval; /* Zero compares as highest number (lowest prio). */
175 }
176};
177
178static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
179{
180 Bstr aFilePath, empty;
181 BOOL fPresent = FALSE;
182 HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),
183 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
184 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
185
186 if (!fPresent)
187 {
188 LogRel(("Failed to find an EFI ROM file.\n"));
189 return VERR_FILE_NOT_FOUND;
190 }
191
192 *pEfiRomFile = Utf8Str(aFilePath);
193
194 return VINF_SUCCESS;
195}
196
197/**
198 * @throws HRESULT on extra data retrival error.
199 */
200static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)
201{
202 *pfGetKeyFromRealSMC = false;
203
204 /*
205 * The extra data takes precedence (if non-zero).
206 */
207 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);
208 if (pStrKey->isNotEmpty())
209 return VINF_SUCCESS;
210
211#ifdef RT_OS_DARWIN
212
213 /*
214 * Work done in EFI/DevSmc
215 */
216 *pfGetKeyFromRealSMC = true;
217 int rc = VINF_SUCCESS;
218
219#else
220 /*
221 * Is it apple hardware in bootcamp?
222 */
223 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.
224 * Currently falling back on the product name. */
225 char szManufacturer[256];
226 szManufacturer[0] = '\0';
227 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));
228 if (szManufacturer[0] != '\0')
229 {
230 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")
231 || !strcmp(szManufacturer, "Apple Inc.")
232 )
233 *pfGetKeyFromRealSMC = true;
234 }
235 else
236 {
237 char szProdName[256];
238 szProdName[0] = '\0';
239 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));
240 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))
241 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
242 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))
243 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))
244 )
245 && !strchr(szProdName, ' ') /* no spaces */
246 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */
247 )
248 *pfGetKeyFromRealSMC = true;
249 }
250
251 int rc = VINF_SUCCESS;
252#endif
253
254 return rc;
255}
256
257
258/*
259 * VC++ 8 / amd64 has some serious trouble with the next functions.
260 * As a temporary measure, we'll drop global optimizations.
261 */
262#if defined(_MSC_VER) && defined(RT_ARCH_AMD64)
263# if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100
264# pragma optimize("g", off)
265# endif
266#endif
267
268class ConfigError : public RTCError
269{
270public:
271
272 ConfigError(const char *pcszFunction,
273 int vrc,
274 const char *pcszName)
275 : RTCError(Utf8StrFmt("%s failed: rc=%Rrc, pcszName=%s", pcszFunction, vrc, pcszName)),
276 m_vrc(vrc)
277 {
278 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here
279 }
280
281 int m_vrc;
282};
283
284
285/**
286 * Helper that calls CFGMR3InsertString and throws an RTCError if that
287 * fails (C-string variant).
288 * @param pNode See CFGMR3InsertStringN.
289 * @param pcszName See CFGMR3InsertStringN.
290 * @param pcszValue The string value.
291 */
292static void InsertConfigString(PCFGMNODE pNode,
293 const char *pcszName,
294 const char *pcszValue)
295{
296 int vrc = CFGMR3InsertString(pNode,
297 pcszName,
298 pcszValue);
299 if (RT_FAILURE(vrc))
300 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
301}
302
303/**
304 * Helper that calls CFGMR3InsertString and throws an RTCError if that
305 * fails (Utf8Str variant).
306 * @param pNode See CFGMR3InsertStringN.
307 * @param pcszName See CFGMR3InsertStringN.
308 * @param rStrValue The string value.
309 */
310static void InsertConfigString(PCFGMNODE pNode,
311 const char *pcszName,
312 const Utf8Str &rStrValue)
313{
314 int vrc = CFGMR3InsertStringN(pNode,
315 pcszName,
316 rStrValue.c_str(),
317 rStrValue.length());
318 if (RT_FAILURE(vrc))
319 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
320}
321
322/**
323 * Helper that calls CFGMR3InsertString and throws an RTCError if that
324 * fails (Bstr variant).
325 *
326 * @param pNode See CFGMR3InsertStringN.
327 * @param pcszName See CFGMR3InsertStringN.
328 * @param rBstrValue The string value.
329 */
330static void InsertConfigString(PCFGMNODE pNode,
331 const char *pcszName,
332 const Bstr &rBstrValue)
333{
334 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
335}
336
337/**
338 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
339 *
340 * @param pNode See CFGMR3InsertBytes.
341 * @param pcszName See CFGMR3InsertBytes.
342 * @param pvBytes See CFGMR3InsertBytes.
343 * @param cbBytes See CFGMR3InsertBytes.
344 */
345static void InsertConfigBytes(PCFGMNODE pNode,
346 const char *pcszName,
347 const void *pvBytes,
348 size_t cbBytes)
349{
350 int vrc = CFGMR3InsertBytes(pNode,
351 pcszName,
352 pvBytes,
353 cbBytes);
354 if (RT_FAILURE(vrc))
355 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
356}
357
358/**
359 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
360 * fails.
361 *
362 * @param pNode See CFGMR3InsertInteger.
363 * @param pcszName See CFGMR3InsertInteger.
364 * @param u64Integer See CFGMR3InsertInteger.
365 */
366static void InsertConfigInteger(PCFGMNODE pNode,
367 const char *pcszName,
368 uint64_t u64Integer)
369{
370 int vrc = CFGMR3InsertInteger(pNode,
371 pcszName,
372 u64Integer);
373 if (RT_FAILURE(vrc))
374 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
375}
376
377/**
378 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
379 *
380 * @param pNode See CFGMR3InsertNode.
381 * @param pcszName See CFGMR3InsertNode.
382 * @param ppChild See CFGMR3InsertNode.
383 */
384static void InsertConfigNode(PCFGMNODE pNode,
385 const char *pcszName,
386 PCFGMNODE *ppChild)
387{
388 int vrc = CFGMR3InsertNode(pNode, pcszName, ppChild);
389 if (RT_FAILURE(vrc))
390 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
391}
392
393/**
394 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
395 *
396 * @param pNode See CFGMR3RemoveValue.
397 * @param pcszName See CFGMR3RemoveValue.
398 */
399static void RemoveConfigValue(PCFGMNODE pNode,
400 const char *pcszName)
401{
402 int vrc = CFGMR3RemoveValue(pNode, pcszName);
403 if (RT_FAILURE(vrc))
404 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
405}
406
407/**
408 * Gets an extra data value, consulting both machine and global extra data.
409 *
410 * @throws HRESULT on failure
411 * @returns pStrValue for the callers convenience.
412 * @param pVirtualBox Pointer to the IVirtualBox interface.
413 * @param pMachine Pointer to the IMachine interface.
414 * @param pszName The value to get.
415 * @param pStrValue Where to return it's value (empty string if not
416 * found).
417 */
418static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
419{
420 pStrValue->setNull();
421
422 Bstr bstrName(pszName);
423 Bstr bstrValue;
424 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
425 if (FAILED(hrc))
426 throw hrc;
427 if (bstrValue.isEmpty())
428 {
429 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
430 if (FAILED(hrc))
431 throw hrc;
432 }
433
434 if (bstrValue.isNotEmpty())
435 *pStrValue = bstrValue;
436 return pStrValue;
437}
438
439
440/** Helper that finds out the next HBA port used
441 */
442static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)
443{
444 LONG lNextPortUsed = 30;
445 for (size_t j = 0; j < u32Size; ++j)
446 {
447 if ( aPortUsed[j] > lBaseVal
448 && aPortUsed[j] <= lNextPortUsed)
449 lNextPortUsed = aPortUsed[j];
450 }
451 return lNextPortUsed;
452}
453
454#define MAX_BIOS_LUN_COUNT 4
455
456static int SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,
457 Bstr controllerName, const char * const s_apszBiosConfig[4])
458{
459 RT_NOREF(pCfg);
460 HRESULT hrc;
461#define MAX_DEVICES 30
462#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
463
464 LONG lPortLUN[MAX_BIOS_LUN_COUNT];
465 LONG lPortUsed[MAX_DEVICES];
466 uint32_t u32HDCount = 0;
467
468 /* init to max value */
469 lPortLUN[0] = MAX_DEVICES;
470
471 com::SafeIfaceArray<IMediumAttachment> atts;
472 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
473 ComSafeArrayAsOutParam(atts)); H();
474 size_t uNumAttachments = atts.size();
475 if (uNumAttachments > MAX_DEVICES)
476 {
477 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));
478 uNumAttachments = MAX_DEVICES;
479 }
480
481 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */
482 for (size_t j = 0; j < uNumAttachments; ++j)
483 {
484 IMediumAttachment *pMediumAtt = atts[j];
485 LONG lPortNum = 0;
486 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
487 if (SUCCEEDED(hrc))
488 {
489 DeviceType_T lType;
490 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
491 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)
492 {
493 /* find min port number used for HD */
494 if (lPortNum < lPortLUN[0])
495 lPortLUN[0] = lPortNum;
496 lPortUsed[u32HDCount++] = lPortNum;
497 LogFlowFunc(("HD port Count=%d\n", u32HDCount));
498 }
499 }
500 }
501
502
503 /* Pick only the top 4 used HD Ports as CMOS doesn't have space
504 * to save details for all 30 ports
505 */
506 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;
507 if (u32HDCount < MAX_BIOS_LUN_COUNT)
508 u32MaxPortCount = u32HDCount;
509 for (size_t j = 1; j < u32MaxPortCount; j++)
510 lPortLUN[j] = GetNextUsedPort(lPortUsed,
511 lPortLUN[j-1],
512 u32HDCount);
513 if (pBiosCfg)
514 {
515 for (size_t j = 0; j < u32MaxPortCount; j++)
516 {
517 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);
518 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));
519 }
520 }
521 return VINF_SUCCESS;
522}
523
524#ifdef VBOX_WITH_PCI_PASSTHROUGH
525HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)
526{
527# ifndef VBOX_WITH_EXTPACK
528 RT_NOREF(pUVM);
529# endif
530 HRESULT hrc = S_OK;
531 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;
532
533 SafeIfaceArray<IPCIDeviceAttachment> assignments;
534 ComPtr<IMachine> aMachine = i_machine();
535
536 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));
537 if ( hrc != S_OK
538 || assignments.size() < 1)
539 return hrc;
540
541 /*
542 * PCI passthrough is only available if the proper ExtPack is installed.
543 *
544 * Note. Configuring PCI passthrough here and providing messages about
545 * the missing extpack isn't exactly clean, but it is a necessary evil
546 * to patch over legacy compatability issues introduced by the new
547 * distribution model.
548 */
549# ifdef VBOX_WITH_EXTPACK
550 static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";
551 if (!mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName))
552 /* Always fatal! */
553 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
554 N_("Implementation of the PCI passthrough framework not found!\n"
555 "The VM cannot be started. To fix this problem, either "
556 "install the '%s' or disable PCI passthrough via VBoxManage"),
557 s_pszPCIRawExtPackName);
558# endif
559
560 PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
561 Assert(pBridges);
562
563 /* Find required bridges, and add missing ones */
564 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
565 {
566 ComPtr<IPCIDeviceAttachment> assignment = assignments[iDev];
567 LONG guest = 0;
568 PCIBusAddress GuestPCIAddress;
569
570 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
571 GuestPCIAddress.fromLong(guest);
572 Assert(GuestPCIAddress.valid());
573
574 if (GuestPCIAddress.miBus > 0)
575 {
576 int iBridgesMissed = 0;
577 int iBase = GuestPCIAddress.miBus - 1;
578
579 while (!pBusMgr->hasPCIDevice("ich9pcibridge", iBase) && iBase > 0)
580 {
581 iBridgesMissed++; iBase--;
582 }
583 iBase++;
584
585 for (int iBridge = 0; iBridge < iBridgesMissed; iBridge++)
586 {
587 InsertConfigNode(pBridges, Utf8StrFmt("%d", iBase + iBridge).c_str(), &pInst);
588 InsertConfigInteger(pInst, "Trusted", 1);
589 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);
590 }
591 }
592 }
593
594 /* Now actually add devices */
595 PCFGMNODE pPCIDevs = NULL;
596
597 if (assignments.size() > 0)
598 {
599 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);
600
601 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);
602
603 /* Tell PGM to tell GPCIRaw about guest mappings. */
604 CFGMR3InsertNode(pRoot, "PGM", NULL);
605 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);
606
607 /*
608 * Currently, using IOMMU needed for PCI passthrough
609 * requires RAM preallocation.
610 */
611 /** @todo check if we can lift this requirement */
612 CFGMR3RemoveValue(pRoot, "RamPreAlloc");
613 InsertConfigInteger(pRoot, "RamPreAlloc", 1);
614 }
615
616 for (size_t iDev = 0; iDev < assignments.size(); iDev++)
617 {
618 PCIBusAddress HostPCIAddress, GuestPCIAddress;
619 ComPtr<IPCIDeviceAttachment> assignment = assignments[iDev];
620 LONG host, guest;
621 Bstr aDevName;
622
623 hrc = assignment->COMGETTER(HostAddress)(&host); H();
624 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();
625 hrc = assignment->COMGETTER(Name)(aDevName.asOutParam()); H();
626
627 InsertConfigNode(pPCIDevs, Utf8StrFmt("%d", iDev).c_str(), &pInst);
628 InsertConfigInteger(pInst, "Trusted", 1);
629
630 HostPCIAddress.fromLong(host);
631 Assert(HostPCIAddress.valid());
632 InsertConfigNode(pInst, "Config", &pCfg);
633 InsertConfigString(pCfg, "DeviceName", aDevName);
634
635 InsertConfigInteger(pCfg, "DetachHostDriver", 1);
636 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);
637 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);
638 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);
639
640 GuestPCIAddress.fromLong(guest);
641 Assert(GuestPCIAddress.valid());
642 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);
643 if (hrc != S_OK)
644 return hrc;
645
646 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);
647 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);
648 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);
649
650 /* the driver */
651 InsertConfigNode(pInst, "LUN#0", &pLunL0);
652 InsertConfigString(pLunL0, "Driver", "pciraw");
653 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
654
655 /* the Main driver */
656 InsertConfigString(pLunL1, "Driver", "MainPciRaw");
657 InsertConfigNode(pLunL1, "Config", &pCfg);
658 PCIRawDev* pMainDev = new PCIRawDev(this);
659 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);
660 }
661
662 return hrc;
663}
664#endif
665
666
667void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, PPDMLED *papLeds,
668 uint64_t uFirst, uint64_t uLast,
669 Console::MediumAttachmentMap *pmapMediumAttachments,
670 const char *pcszDevice, unsigned uInstance)
671{
672 PCFGMNODE pLunL0, pCfg;
673 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
674 InsertConfigString(pLunL0, "Driver", "MainStatus");
675 InsertConfigNode(pLunL0, "Config", &pCfg);
676 InsertConfigInteger(pCfg, "papLeds", (uintptr_t)papLeds);
677 if (pmapMediumAttachments)
678 {
679 InsertConfigInteger(pCfg, "pmapMediumAttachments", (uintptr_t)pmapMediumAttachments);
680 InsertConfigInteger(pCfg, "pConsole", (uintptr_t)this);
681 AssertPtr(pcszDevice);
682 Utf8Str deviceInstance = Utf8StrFmt("%s/%u", pcszDevice, uInstance);
683 InsertConfigString(pCfg, "DeviceInstance", deviceInstance.c_str());
684 }
685 InsertConfigInteger(pCfg, "First", uFirst);
686 InsertConfigInteger(pCfg, "Last", uLast);
687}
688
689
690/**
691 * Construct the VM configuration tree (CFGM).
692 *
693 * This is a callback for VMR3Create() call. It is called from CFGMR3Init()
694 * in the emulation thread (EMT). Any per thread COM/XPCOM initialization
695 * is done here.
696 *
697 * @param pUVM The user mode VM handle.
698 * @param pVM The cross context VM handle.
699 * @param pvConsole Pointer to the VMPowerUpTask object.
700 * @return VBox status code.
701 *
702 * @note Locks the Console object for writing.
703 */
704DECLCALLBACK(int) Console::i_configConstructor(PUVM pUVM, PVM pVM, void *pvConsole)
705{
706 LogFlowFuncEnter();
707
708 AssertReturn(pvConsole, VERR_INVALID_POINTER);
709 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
710
711 AutoCaller autoCaller(pConsole);
712 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
713
714 /* lock the console because we widely use internal fields and methods */
715 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
716
717 /*
718 * Set the VM handle and do the rest of the job in an worker method so we
719 * can easily reset the VM handle on failure.
720 */
721 pConsole->mpUVM = pUVM;
722 VMR3RetainUVM(pUVM);
723 int vrc;
724 try
725 {
726 vrc = pConsole->i_configConstructorInner(pUVM, pVM, &alock);
727 }
728 catch (...)
729 {
730 vrc = VERR_UNEXPECTED_EXCEPTION;
731 }
732 if (RT_FAILURE(vrc))
733 {
734 pConsole->mpUVM = NULL;
735 VMR3ReleaseUVM(pUVM);
736 }
737
738 return vrc;
739}
740
741
742/**
743 * Worker for configConstructor.
744 *
745 * @return VBox status code.
746 * @param pUVM The user mode VM handle.
747 * @param pVM The cross context VM handle.
748 * @param pAlock The automatic lock instance. This is for when we have
749 * to leave it in order to avoid deadlocks (ext packs and
750 * more).
751 */
752int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
753{
754 RT_NOREF(pVM /* when everything is disabled */);
755 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
756 ComPtr<IMachine> pMachine = i_machine();
757
758 int rc;
759 HRESULT hrc;
760 Utf8Str strTmp;
761 Bstr bstr;
762
763#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
764
765 /*
766 * Get necessary objects and frequently used parameters.
767 */
768 ComPtr<IVirtualBox> virtualBox;
769 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
770
771 ComPtr<IHost> host;
772 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
773
774 ComPtr<ISystemProperties> systemProperties;
775 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
776
777 ComPtr<IBIOSSettings> biosSettings;
778 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();
779
780 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();
781 RTUUID HardwareUuid;
782 rc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());
783 AssertRCReturn(rc, rc);
784
785 ULONG cRamMBs;
786 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
787#if 0 /* enable to play with lots of memory. */
788 if (RTEnvExist("VBOX_RAM_SIZE"))
789 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));
790#endif
791 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;
792 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;
793 uint64_t uMcfgBase = 0;
794 uint32_t cbMcfgLength = 0;
795
796 ParavirtProvider_T paravirtProvider;
797 hrc = pMachine->GetEffectiveParavirtProvider(&paravirtProvider); H();
798
799 Bstr strParavirtDebug;
800 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();
801
802 ChipsetType_T chipsetType;
803 hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType); H();
804 if (chipsetType == ChipsetType_ICH9)
805 {
806 /* We'd better have 0x10000000 region, to cover 256 buses
807 but this put too much load on hypervisor heap */
808 cbMcfgLength = 0x4000000; //0x10000000;
809 cbRamHole += cbMcfgLength;
810 uMcfgBase = _4G - cbRamHole;
811 }
812
813 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(chipsetType);
814
815 ULONG cCpus = 1;
816 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();
817
818 ULONG ulCpuExecutionCap = 100;
819 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();
820
821 Bstr osTypeId;
822 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();
823 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));
824
825 BOOL fIOAPIC;
826 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
827
828 APICMode_T apicMode;
829 hrc = biosSettings->COMGETTER(APICMode)(&apicMode); H();
830 uint32_t uFwAPIC;
831 switch (apicMode)
832 {
833 case APICMode_Disabled:
834 uFwAPIC = 0;
835 break;
836 case APICMode_APIC:
837 uFwAPIC = 1;
838 break;
839 case APICMode_X2APIC:
840 uFwAPIC = 2;
841 break;
842 default:
843 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));
844 uFwAPIC = 1;
845 break;
846 }
847
848 ComPtr<IGuestOSType> guestOSType;
849 hrc = virtualBox->GetGuestOSType(osTypeId.raw(), guestOSType.asOutParam()); H();
850
851 Bstr guestTypeFamilyId;
852 hrc = guestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
853 BOOL fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
854
855 ULONG maxNetworkAdapters;
856 hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
857
858 /*
859 * Get root node first.
860 * This is the only node in the tree.
861 */
862 PCFGMNODE pRoot = CFGMR3GetRootU(pUVM);
863 Assert(pRoot);
864
865 // InsertConfigString throws
866 try
867 {
868
869 /*
870 * Set the root (and VMM) level values.
871 */
872 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
873 InsertConfigString(pRoot, "Name", bstr);
874 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
875 InsertConfigInteger(pRoot, "RamSize", cbRam);
876 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
877 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
878 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
879 InsertConfigInteger(pRoot, "TimerMillies", 10);
880#ifdef VBOX_WITH_RAW_MODE
881 InsertConfigInteger(pRoot, "RawR3Enabled", 1); /* boolean */
882 InsertConfigInteger(pRoot, "RawR0Enabled", 1); /* boolean */
883 /** @todo Config: RawR0, PATMEnabled and CSAMEnabled needs attention later. */
884 InsertConfigInteger(pRoot, "PATMEnabled", 1); /* boolean */
885 InsertConfigInteger(pRoot, "CSAMEnabled", 1); /* boolean */
886#endif
887
888#ifdef VBOX_WITH_RAW_RING1
889 if (osTypeId == "QNX")
890 {
891 /* QNX needs special treatment in raw mode due to its use of ring-1. */
892 InsertConfigInteger(pRoot, "RawR1Enabled", 1); /* boolean */
893 }
894#endif
895
896 BOOL fPageFusion = FALSE;
897 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
898 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
899
900 /* Not necessary, but makes sure this setting ends up in the release log. */
901 ULONG ulBalloonSize = 0;
902 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
903 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
904
905 /*
906 * EM values (before CPUM as it may need to set IemExecutesAll).
907 */
908 PCFGMNODE pEM;
909 InsertConfigNode(pRoot, "EM", &pEM);
910
911 /* Triple fault behavior. */
912 BOOL fTripleFaultReset = false;
913 hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();
914 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
915
916 /*
917 * CPUM values.
918 */
919 PCFGMNODE pCPUM;
920 InsertConfigNode(pRoot, "CPUM", &pCPUM);
921
922 /* cpuid leaf overrides. */
923 static uint32_t const s_auCpuIdRanges[] =
924 {
925 UINT32_C(0x00000000), UINT32_C(0x0000000a),
926 UINT32_C(0x80000000), UINT32_C(0x8000000a)
927 };
928 for (unsigned i = 0; i < RT_ELEMENTS(s_auCpuIdRanges); i += 2)
929 for (uint32_t uLeaf = s_auCpuIdRanges[i]; uLeaf < s_auCpuIdRanges[i + 1]; uLeaf++)
930 {
931 ULONG ulEax, ulEbx, ulEcx, ulEdx;
932 hrc = pMachine->GetCPUIDLeaf(uLeaf, &ulEax, &ulEbx, &ulEcx, &ulEdx);
933 if (SUCCEEDED(hrc))
934 {
935 PCFGMNODE pLeaf;
936 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
937
938 InsertConfigInteger(pLeaf, "eax", ulEax);
939 InsertConfigInteger(pLeaf, "ebx", ulEbx);
940 InsertConfigInteger(pLeaf, "ecx", ulEcx);
941 InsertConfigInteger(pLeaf, "edx", ulEdx);
942 }
943 else if (hrc != E_INVALIDARG) H();
944 }
945
946 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
947 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
948 if (osTypeId == "WindowsNT4")
949 {
950 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
951 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
952 }
953
954 /* Expose CMPXCHG16B. Currently a hack. */
955 if ( osTypeId == "Windows81_64"
956 || osTypeId == "Windows2012_64"
957 || osTypeId == "Windows10_64")
958 {
959 LogRel(("Enabling CMPXCHG16B for Windows 8.1 / 2k12 or newer guests\n"));
960 InsertConfigInteger(pCPUM, "CMPXCHG16B", true);
961 }
962
963 if (fOsXGuest)
964 {
965 /* Expose extended MWAIT features to Mac OS X guests. */
966 LogRel(("Using MWAIT extensions\n"));
967 InsertConfigInteger(pCPUM, "MWaitExtensions", true);
968
969 /* Fake the CPU family/model so the guest works. This is partly
970 because older mac releases really doesn't work on newer cpus,
971 and partly because mac os x expects more from systems with newer
972 cpus (MSRs, power features, whatever). */
973 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
974 if ( osTypeId == "MacOS"
975 || osTypeId == "MacOS_64")
976 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
977 else if ( osTypeId == "MacOS106"
978 || osTypeId == "MacOS106_64")
979 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
980 else if ( osTypeId == "MacOS107"
981 || osTypeId == "MacOS107_64")
982 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
983 what is required here. */
984 else if ( osTypeId == "MacOS108"
985 || osTypeId == "MacOS108_64")
986 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
987 what is required here. */
988 else if ( osTypeId == "MacOS109"
989 || osTypeId == "MacOS109_64")
990 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
991 out what is required here. */
992 if (uMaxIntelFamilyModelStep != UINT32_MAX)
993 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
994 }
995
996 /* CPU Portability level, */
997 ULONG uCpuIdPortabilityLevel = 0;
998 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
999 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
1000
1001 /* Physical Address Extension (PAE) */
1002 BOOL fEnablePAE = false;
1003 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();
1004 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
1005
1006 /* APIC/X2APIC configuration */
1007 BOOL fEnableAPIC = true;
1008 BOOL fEnableX2APIC = true;
1009 hrc = pMachine->GetCPUProperty(CPUPropertyType_APIC, &fEnableAPIC); H();
1010 hrc = pMachine->GetCPUProperty(CPUPropertyType_X2APIC, &fEnableX2APIC); H();
1011 if (fEnableX2APIC)
1012 Assert(fEnableAPIC);
1013
1014 /* CPUM profile name. */
1015 hrc = pMachine->COMGETTER(CPUProfile)(bstr.asOutParam()); H();
1016 InsertConfigString(pCPUM, "GuestCpuName", bstr);
1017
1018 /*
1019 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
1020 * correctly. There are way too many #UDs we'll miss using VT-x,
1021 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
1022 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
1023 */
1024 if ( bstr.equals("Intel 80386") /* just for now */
1025 || bstr.equals("Intel 80286")
1026 || bstr.equals("Intel 80186")
1027 || bstr.equals("Nec V20")
1028 || bstr.equals("Intel 8086") )
1029 {
1030 InsertConfigInteger(pEM, "IemExecutesAll", true);
1031 if (!bstr.equals("Intel 80386"))
1032 {
1033 fEnableAPIC = false;
1034 fIOAPIC = false;
1035 }
1036 fEnableX2APIC = false;
1037 }
1038
1039 /* Adjust firmware APIC handling to stay within the VCPU limits. */
1040 if (uFwAPIC == 2 && !fEnableX2APIC)
1041 {
1042 if (fEnableAPIC)
1043 uFwAPIC = 1;
1044 else
1045 uFwAPIC = 0;
1046 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
1047 }
1048 else if (uFwAPIC == 1 && !fEnableAPIC)
1049 {
1050 uFwAPIC = 0;
1051 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
1052 }
1053
1054 /*
1055 * Hardware virtualization extensions.
1056 */
1057 BOOL fSupportsHwVirtEx;
1058 hrc = host->GetProcessorFeature(ProcessorFeature_HWVirtEx, &fSupportsHwVirtEx); H();
1059
1060 BOOL fIsGuest64Bit;
1061 hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H();
1062 if (fIsGuest64Bit)
1063 {
1064 BOOL fSupportsLongMode;
1065 hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, &fSupportsLongMode); H();
1066 if (!fSupportsLongMode)
1067 {
1068 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support 64-bit.\n"));
1069 fIsGuest64Bit = FALSE;
1070 }
1071 if (!fSupportsHwVirtEx)
1072 {
1073 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support HW virtualization.\n"));
1074 fIsGuest64Bit = FALSE;
1075 }
1076 }
1077
1078 BOOL fHMEnabled;
1079 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
1080 if (cCpus > 1 && !fHMEnabled)
1081 {
1082 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
1083 fHMEnabled = TRUE;
1084 }
1085
1086 BOOL fHMForced;
1087#ifdef VBOX_WITH_RAW_MODE
1088 /* - With more than 4GB PGM will use different RAMRANGE sizes for raw
1089 mode and hv mode to optimize lookup times.
1090 - With more than one virtual CPU, raw-mode isn't a fallback option.
1091 - With a 64-bit guest, raw-mode isn't a fallback option either. */
1092 fHMForced = fHMEnabled
1093 && ( cbRam + cbRamHole > _4G
1094 || cCpus > 1
1095 || fIsGuest64Bit);
1096# ifdef RT_OS_DARWIN
1097 fHMForced = fHMEnabled;
1098# endif
1099 if (fHMForced)
1100 {
1101 if (cbRam + cbRamHole > _4G)
1102 LogRel(("fHMForced=true - Lots of RAM\n"));
1103 if (cCpus > 1)
1104 LogRel(("fHMForced=true - SMP\n"));
1105 if (fIsGuest64Bit)
1106 LogRel(("fHMForced=true - 64-bit guest\n"));
1107# ifdef RT_OS_DARWIN
1108 LogRel(("fHMForced=true - Darwin host\n"));
1109# endif
1110 }
1111#else /* !VBOX_WITH_RAW_MODE */
1112 fHMEnabled = fHMForced = TRUE;
1113 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
1114#endif /* !VBOX_WITH_RAW_MODE */
1115 if (!fHMForced) /* No need to query if already forced above. */
1116 {
1117 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
1118 if (fHMForced)
1119 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
1120 }
1121 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
1122
1123 /* /HM/xzy */
1124 PCFGMNODE pHM;
1125 InsertConfigNode(pRoot, "HM", &pHM);
1126 InsertConfigInteger(pHM, "HMForced", fHMForced);
1127 if (fHMEnabled)
1128 {
1129 /* Indicate whether 64-bit guests are supported or not. */
1130 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
1131#if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */
1132 PCFGMNODE pREM;
1133 InsertConfigNode(pRoot, "REM", &pREM);
1134 InsertConfigInteger(pREM, "64bitEnabled", 1);
1135#endif
1136
1137 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
1138 but that requires quite a bit of API change in Main. */
1139 if ( fIOAPIC
1140 && ( osTypeId == "WindowsNT4"
1141 || osTypeId == "Windows2000"
1142 || osTypeId == "WindowsXP"
1143 || osTypeId == "Windows2003"))
1144 {
1145 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
1146 * We may want to consider adding more guest OSes (Solaris) later on.
1147 */
1148 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
1149 }
1150 }
1151
1152 /* HWVirtEx exclusive mode */
1153 BOOL fHMExclusive = true;
1154 hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
1155 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
1156
1157 /* Nested paging (VT-x/AMD-V) */
1158 BOOL fEnableNestedPaging = false;
1159 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
1160 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
1161
1162 /* Large pages; requires nested paging */
1163 BOOL fEnableLargePages = false;
1164 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
1165 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
1166
1167 /* VPID (VT-x) */
1168 BOOL fEnableVPID = false;
1169 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
1170 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
1171
1172 /* Unrestricted execution aka UX (VT-x) */
1173 BOOL fEnableUX = false;
1174 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
1175 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
1176
1177 /* Reset overwrite. */
1178 if (i_isResetTurnedIntoPowerOff())
1179 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
1180
1181 /*
1182 * Paravirt. provider.
1183 */
1184 PCFGMNODE pParavirtNode;
1185 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1186 const char *pcszParavirtProvider;
1187 bool fGimDeviceNeeded = true;
1188 switch (paravirtProvider)
1189 {
1190 case ParavirtProvider_None:
1191 pcszParavirtProvider = "None";
1192 fGimDeviceNeeded = false;
1193 break;
1194
1195 case ParavirtProvider_Minimal:
1196 pcszParavirtProvider = "Minimal";
1197 break;
1198
1199 case ParavirtProvider_HyperV:
1200 pcszParavirtProvider = "HyperV";
1201 break;
1202
1203 case ParavirtProvider_KVM:
1204 pcszParavirtProvider = "KVM";
1205 break;
1206
1207 default:
1208 AssertMsgFailed(("Invalid paravirtProvider=%d\n", paravirtProvider));
1209 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1210 paravirtProvider);
1211 }
1212 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1213
1214 /*
1215 * Parse paravirt. debug options.
1216 */
1217 bool fGimDebug = false;
1218 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1219 uint32_t uGimDebugPort = 50000;
1220 if (strParavirtDebug.isNotEmpty())
1221 {
1222 /* Hyper-V debug options. */
1223 if (paravirtProvider == ParavirtProvider_HyperV)
1224 {
1225 bool fGimHvDebug = false;
1226 com::Utf8Str strGimHvVendor;
1227 bool fGimHvVsIf = false;
1228 bool fGimHvHypercallIf = false;
1229
1230 size_t uPos = 0;
1231 com::Utf8Str strDebugOptions = strParavirtDebug;
1232 do
1233 {
1234 com::Utf8Str strKey;
1235 com::Utf8Str strVal;
1236 uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos);
1237 if (strKey == "enabled")
1238 {
1239 if (strVal.toUInt32() == 1)
1240 {
1241 /* Apply defaults.
1242 The defaults are documented in the user manual,
1243 changes need to be reflected accordingly. */
1244 fGimHvDebug = true;
1245 strGimHvVendor = "Microsoft Hv";
1246 fGimHvVsIf = true;
1247 fGimHvHypercallIf = false;
1248 }
1249 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1250 }
1251 else if (strKey == "address")
1252 strGimDebugAddress = strVal;
1253 else if (strKey == "port")
1254 uGimDebugPort = strVal.toUInt32();
1255 else if (strKey == "vendor")
1256 strGimHvVendor = strVal;
1257 else if (strKey == "vsinterface")
1258 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1259 else if (strKey == "hypercallinterface")
1260 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1261 else
1262 {
1263 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1264 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1265 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1266 strDebugOptions.c_str());
1267 }
1268 } while (uPos != com::Utf8Str::npos);
1269
1270 /* Update HyperV CFGM node with active debug options. */
1271 if (fGimHvDebug)
1272 {
1273 PCFGMNODE pHvNode;
1274 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1275 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1276 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1277 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1278 fGimDebug = true;
1279 }
1280 }
1281 }
1282
1283 /*
1284 * MM values.
1285 */
1286 PCFGMNODE pMM;
1287 InsertConfigNode(pRoot, "MM", &pMM);
1288 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1289
1290 /*
1291 * PDM config.
1292 * Load drivers in VBoxC.[so|dll]
1293 */
1294 PCFGMNODE pPDM;
1295 PCFGMNODE pNode;
1296 PCFGMNODE pMod;
1297 InsertConfigNode(pRoot, "PDM", &pPDM);
1298 InsertConfigNode(pPDM, "Devices", &pNode);
1299 InsertConfigNode(pPDM, "Drivers", &pNode);
1300 InsertConfigNode(pNode, "VBoxC", &pMod);
1301#ifdef VBOX_WITH_XPCOM
1302 // VBoxC is located in the components subdirectory
1303 char szPathVBoxC[RTPATH_MAX];
1304 rc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(rc);
1305 strcat(szPathVBoxC, "/components/VBoxC");
1306 InsertConfigString(pMod, "Path", szPathVBoxC);
1307#else
1308 InsertConfigString(pMod, "Path", "VBoxC");
1309#endif
1310
1311
1312 /*
1313 * Block cache settings.
1314 */
1315 PCFGMNODE pPDMBlkCache;
1316 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
1317
1318 /* I/O cache size */
1319 ULONG ioCacheSize = 5;
1320 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
1321 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
1322
1323 /*
1324 * Bandwidth groups.
1325 */
1326 PCFGMNODE pAc;
1327 PCFGMNODE pAcFile;
1328 PCFGMNODE pAcFileBwGroups;
1329 ComPtr<IBandwidthControl> bwCtrl;
1330 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
1331
1332 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
1333
1334 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
1335
1336 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
1337 InsertConfigNode(pAc, "File", &pAcFile);
1338 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
1339#ifdef VBOX_WITH_NETSHAPER
1340 PCFGMNODE pNetworkShaper;
1341 PCFGMNODE pNetworkBwGroups;
1342
1343 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
1344 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
1345#endif /* VBOX_WITH_NETSHAPER */
1346
1347 for (size_t i = 0; i < bwGroups.size(); i++)
1348 {
1349 Bstr strName;
1350 LONG64 cMaxBytesPerSec;
1351 BandwidthGroupType_T enmType;
1352
1353 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
1354 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
1355 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
1356
1357 if (strName.isEmpty())
1358 return VMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS,
1359 N_("No bandwidth group name specified"));
1360
1361 if (enmType == BandwidthGroupType_Disk)
1362 {
1363 PCFGMNODE pBwGroup;
1364 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1365 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1366 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
1367 InsertConfigInteger(pBwGroup, "Step", 0);
1368 }
1369#ifdef VBOX_WITH_NETSHAPER
1370 else if (enmType == BandwidthGroupType_Network)
1371 {
1372 /* Network bandwidth groups. */
1373 PCFGMNODE pBwGroup;
1374 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1375 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1376 }
1377#endif /* VBOX_WITH_NETSHAPER */
1378 }
1379
1380 /*
1381 * Devices
1382 */
1383 PCFGMNODE pDevices = NULL; /* /Devices */
1384 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1385 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1386 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1387 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1388 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1389 PCFGMNODE pLunL2 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config/ */
1390 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1391 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1392
1393 InsertConfigNode(pRoot, "Devices", &pDevices);
1394
1395 /*
1396 * GIM Device
1397 */
1398 if (fGimDeviceNeeded)
1399 {
1400 InsertConfigNode(pDevices, "GIMDev", &pDev);
1401 InsertConfigNode(pDev, "0", &pInst);
1402 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1403 //InsertConfigNode(pInst, "Config", &pCfg);
1404
1405 if (fGimDebug)
1406 {
1407 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1408 InsertConfigString(pLunL0, "Driver", "UDP");
1409 InsertConfigNode(pLunL0, "Config", &pLunL1);
1410 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1411 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1412 }
1413 }
1414
1415 /*
1416 * PC Arch.
1417 */
1418 InsertConfigNode(pDevices, "pcarch", &pDev);
1419 InsertConfigNode(pDev, "0", &pInst);
1420 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1421 InsertConfigNode(pInst, "Config", &pCfg);
1422
1423 /*
1424 * The time offset
1425 */
1426 LONG64 timeOffset;
1427 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1428 PCFGMNODE pTMNode;
1429 InsertConfigNode(pRoot, "TM", &pTMNode);
1430 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1431
1432 /*
1433 * DMA
1434 */
1435 InsertConfigNode(pDevices, "8237A", &pDev);
1436 InsertConfigNode(pDev, "0", &pInst);
1437 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1438
1439 /*
1440 * PCI buses.
1441 */
1442 uint32_t uIocPCIAddress, uHbcPCIAddress;
1443 switch (chipsetType)
1444 {
1445 default:
1446 Assert(false);
1447 case ChipsetType_PIIX3:
1448 InsertConfigNode(pDevices, "pci", &pDev);
1449 uHbcPCIAddress = (0x0 << 16) | 0;
1450 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1451 break;
1452 case ChipsetType_ICH9:
1453 InsertConfigNode(pDevices, "ich9pci", &pDev);
1454 uHbcPCIAddress = (0x1e << 16) | 0;
1455 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1456 break;
1457 }
1458 InsertConfigNode(pDev, "0", &pInst);
1459 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1460 InsertConfigNode(pInst, "Config", &pCfg);
1461 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1462 if (chipsetType == ChipsetType_ICH9)
1463 {
1464 /* Provide MCFG info */
1465 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1466 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1467
1468
1469 /* And register 2 bridges */
1470 InsertConfigNode(pDevices, "ich9pcibridge", &pDev);
1471 InsertConfigNode(pDev, "0", &pInst);
1472 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1473 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H();
1474
1475 InsertConfigNode(pDev, "1", &pInst);
1476 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1477 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst); H();
1478
1479#ifdef VBOX_WITH_PCI_PASSTHROUGH
1480 /* Add PCI passthrough devices */
1481 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1482#endif
1483 }
1484
1485 /*
1486 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1487 */
1488
1489 /*
1490 * High Precision Event Timer (HPET)
1491 */
1492 BOOL fHPETEnabled;
1493 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1494 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1495 /* so always enable HPET in extended profile */
1496 fHPETEnabled |= fOsXGuest;
1497 /* HPET is always present on ICH9 */
1498 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1499 if (fHPETEnabled)
1500 {
1501 InsertConfigNode(pDevices, "hpet", &pDev);
1502 InsertConfigNode(pDev, "0", &pInst);
1503 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1504 InsertConfigNode(pInst, "Config", &pCfg);
1505 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1506 }
1507
1508 /*
1509 * System Management Controller (SMC)
1510 */
1511 BOOL fSmcEnabled;
1512 fSmcEnabled = fOsXGuest;
1513 if (fSmcEnabled)
1514 {
1515 InsertConfigNode(pDevices, "smc", &pDev);
1516 InsertConfigNode(pDev, "0", &pInst);
1517 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1518 InsertConfigNode(pInst, "Config", &pCfg);
1519
1520 bool fGetKeyFromRealSMC;
1521 Utf8Str strKey;
1522 rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1523 AssertRCReturn(rc, rc);
1524
1525 if (!fGetKeyFromRealSMC)
1526 InsertConfigString(pCfg, "DeviceKey", strKey);
1527 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1528 }
1529
1530 /*
1531 * Low Pin Count (LPC) bus
1532 */
1533 BOOL fLpcEnabled;
1534 /** @todo implement appropriate getter */
1535 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1536 if (fLpcEnabled)
1537 {
1538 InsertConfigNode(pDevices, "lpc", &pDev);
1539 InsertConfigNode(pDev, "0", &pInst);
1540 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1541 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1542 }
1543
1544 BOOL fShowRtc;
1545 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1546
1547 /*
1548 * PS/2 keyboard & mouse.
1549 */
1550 InsertConfigNode(pDevices, "pckbd", &pDev);
1551 InsertConfigNode(pDev, "0", &pInst);
1552 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1553 InsertConfigNode(pInst, "Config", &pCfg);
1554
1555 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1556 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1557 InsertConfigNode(pLunL0, "Config", &pCfg);
1558 InsertConfigInteger(pCfg, "QueueSize", 64);
1559
1560 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1561 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1562 InsertConfigNode(pLunL1, "Config", &pCfg);
1563 Keyboard *pKeyboard = mKeyboard;
1564 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
1565
1566 Mouse *pMouse = mMouse;
1567 PointingHIDType_T aPointingHID;
1568 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1569 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1570 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1571 InsertConfigNode(pLunL0, "Config", &pCfg);
1572 InsertConfigInteger(pCfg, "QueueSize", 128);
1573
1574 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1575 InsertConfigString(pLunL1, "Driver", "MainMouse");
1576 InsertConfigNode(pLunL1, "Config", &pCfg);
1577 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
1578
1579 /*
1580 * i8254 Programmable Interval Timer And Dummy Speaker
1581 */
1582 InsertConfigNode(pDevices, "i8254", &pDev);
1583 InsertConfigNode(pDev, "0", &pInst);
1584 InsertConfigNode(pInst, "Config", &pCfg);
1585#ifdef DEBUG
1586 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1587#endif
1588
1589 /*
1590 * i8259 Programmable Interrupt Controller.
1591 */
1592 InsertConfigNode(pDevices, "i8259", &pDev);
1593 InsertConfigNode(pDev, "0", &pInst);
1594 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1595 InsertConfigNode(pInst, "Config", &pCfg);
1596
1597 /*
1598 * Advanced Programmable Interrupt Controller.
1599 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1600 * thus only single insert
1601 */
1602 if (fEnableAPIC)
1603 {
1604 InsertConfigNode(pDevices, "apic", &pDev);
1605 InsertConfigNode(pDev, "0", &pInst);
1606 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1607 InsertConfigNode(pInst, "Config", &pCfg);
1608 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1609 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1610 if (fEnableX2APIC)
1611 enmAPICMode = PDMAPICMODE_X2APIC;
1612 else if (!fEnableAPIC)
1613 enmAPICMode = PDMAPICMODE_NONE;
1614 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1615 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1616
1617 if (fIOAPIC)
1618 {
1619 /*
1620 * I/O Advanced Programmable Interrupt Controller.
1621 */
1622 InsertConfigNode(pDevices, "ioapic", &pDev);
1623 InsertConfigNode(pDev, "0", &pInst);
1624 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1625 InsertConfigNode(pInst, "Config", &pCfg);
1626 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1627 }
1628 }
1629
1630 /*
1631 * RTC MC146818.
1632 */
1633 InsertConfigNode(pDevices, "mc146818", &pDev);
1634 InsertConfigNode(pDev, "0", &pInst);
1635 InsertConfigNode(pInst, "Config", &pCfg);
1636 BOOL fRTCUseUTC;
1637 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1638 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1639
1640 /*
1641 * VGA.
1642 */
1643 GraphicsControllerType_T enmGraphicsController;
1644 hrc = pMachine->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1645 switch (enmGraphicsController)
1646 {
1647 case GraphicsControllerType_Null:
1648 break;
1649 case GraphicsControllerType_VBoxVGA:
1650#ifdef VBOX_WITH_VMSVGA
1651 case GraphicsControllerType_VMSVGA:
1652#endif
1653 rc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, biosSettings,
1654 RT_BOOL(fHMEnabled));
1655 if (FAILED(rc))
1656 return rc;
1657 break;
1658 default:
1659 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1660 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1661 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1662 }
1663
1664 /*
1665 * Firmware.
1666 */
1667 FirmwareType_T eFwType = FirmwareType_BIOS;
1668 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1669
1670#ifdef VBOX_WITH_EFI
1671 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1672#else
1673 BOOL fEfiEnabled = false;
1674#endif
1675 if (!fEfiEnabled)
1676 {
1677 /*
1678 * PC Bios.
1679 */
1680 InsertConfigNode(pDevices, "pcbios", &pDev);
1681 InsertConfigNode(pDev, "0", &pInst);
1682 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1683 InsertConfigNode(pInst, "Config", &pBiosCfg);
1684 InsertConfigInteger(pBiosCfg, "RamSize", cbRam);
1685 InsertConfigInteger(pBiosCfg, "RamHoleSize", cbRamHole);
1686 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1687 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1688 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1689 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1690 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1691 BOOL fPXEDebug;
1692 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1693 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1694 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1695 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1696 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1697 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1698
1699 DeviceType_T bootDevice;
1700 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1701 VERR_INVALID_PARAMETER);
1702
1703 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1704 {
1705 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
1706
1707 char szParamName[] = "BootDeviceX";
1708 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1709
1710 const char *pszBootDevice;
1711 switch (bootDevice)
1712 {
1713 case DeviceType_Null:
1714 pszBootDevice = "NONE";
1715 break;
1716 case DeviceType_HardDisk:
1717 pszBootDevice = "IDE";
1718 break;
1719 case DeviceType_DVD:
1720 pszBootDevice = "DVD";
1721 break;
1722 case DeviceType_Floppy:
1723 pszBootDevice = "FLOPPY";
1724 break;
1725 case DeviceType_Network:
1726 pszBootDevice = "LAN";
1727 break;
1728 default:
1729 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
1730 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1731 N_("Invalid boot device '%d'"), bootDevice);
1732 }
1733 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1734 }
1735
1736 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1737 * this is required for Windows 2012 guests. */
1738 if (osTypeId == "Windows2012_64")
1739 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1740 }
1741 else
1742 {
1743 /* Autodetect firmware type, basing on guest type */
1744 if (eFwType == FirmwareType_EFI)
1745 {
1746 eFwType = fIsGuest64Bit
1747 ? (FirmwareType_T)FirmwareType_EFI64
1748 : (FirmwareType_T)FirmwareType_EFI32;
1749 }
1750 bool const f64BitEntry = eFwType == FirmwareType_EFI64;
1751
1752 Utf8Str efiRomFile;
1753 rc = findEfiRom(virtualBox, eFwType, &efiRomFile);
1754 AssertRCReturn(rc, rc);
1755
1756 /* Get boot args */
1757 Utf8Str bootArgs;
1758 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);
1759
1760 /* Get device props */
1761 Utf8Str deviceProps;
1762 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);
1763
1764 /* Get GOP mode settings */
1765 uint32_t u32GopMode = UINT32_MAX;
1766 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);
1767 if (!strTmp.isEmpty())
1768 u32GopMode = strTmp.toUInt32();
1769
1770 /* UGA mode settings */
1771 uint32_t u32UgaHorizontal = 0;
1772 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);
1773 if (!strTmp.isEmpty())
1774 u32UgaHorizontal = strTmp.toUInt32();
1775
1776 uint32_t u32UgaVertical = 0;
1777 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);
1778 if (!strTmp.isEmpty())
1779 u32UgaVertical = strTmp.toUInt32();
1780
1781 /*
1782 * EFI subtree.
1783 */
1784 InsertConfigNode(pDevices, "efi", &pDev);
1785 InsertConfigNode(pDev, "0", &pInst);
1786 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1787 InsertConfigNode(pInst, "Config", &pCfg);
1788 InsertConfigInteger(pCfg, "RamSize", cbRam);
1789 InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole);
1790 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1791 InsertConfigString(pCfg, "EfiRom", efiRomFile);
1792 InsertConfigString(pCfg, "BootArgs", bootArgs);
1793 InsertConfigString(pCfg, "DeviceProps", deviceProps);
1794 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1795 InsertConfigInteger(pCfg, "APIC", uFwAPIC);
1796 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1797 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */
1798 InsertConfigInteger(pCfg, "GopMode", u32GopMode);
1799 InsertConfigInteger(pCfg, "UgaHorizontalResolution", u32UgaHorizontal);
1800 InsertConfigInteger(pCfg, "UgaVerticalResolution", u32UgaVertical);
1801
1802 /* For OS X guests we'll force passing host's DMI info to the guest */
1803 if (fOsXGuest)
1804 {
1805 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);
1806 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);
1807 }
1808 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1809 InsertConfigString(pLunL0, "Driver", "NvramStorage");
1810 InsertConfigNode(pLunL0, "Config", &pCfg);
1811 InsertConfigInteger(pCfg, "Object", (uintptr_t)mNvram);
1812#ifdef DEBUG_vvl
1813 InsertConfigInteger(pCfg, "PermanentSave", 1);
1814#endif
1815 }
1816
1817 /*
1818 * The USB Controllers.
1819 */
1820 com::SafeIfaceArray<IUSBController> usbCtrls;
1821 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
1822 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
1823 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
1824
1825 if (SUCCEEDED(hrc))
1826 {
1827 for (size_t i = 0; i < usbCtrls.size(); ++i)
1828 {
1829 USBControllerType_T enmCtrlType;
1830 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1831 if (enmCtrlType == USBControllerType_OHCI)
1832 {
1833 fOhciPresent = true;
1834 break;
1835 }
1836 else if (enmCtrlType == USBControllerType_XHCI)
1837 {
1838 fXhciPresent = true;
1839 break;
1840 }
1841 }
1842 }
1843 else if (hrc != E_NOTIMPL)
1844 {
1845 H();
1846 }
1847
1848 /*
1849 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
1850 */
1851 if (fOhciPresent || fXhciPresent)
1852 mfVMHasUsbController = true;
1853
1854 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */
1855 if (mfVMHasUsbController)
1856 {
1857 for (size_t i = 0; i < usbCtrls.size(); ++i)
1858 {
1859 USBControllerType_T enmCtrlType;
1860 rc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
1861
1862 if (enmCtrlType == USBControllerType_OHCI)
1863 {
1864 InsertConfigNode(pDevices, "usb-ohci", &pDev);
1865 InsertConfigNode(pDev, "0", &pInst);
1866 InsertConfigNode(pInst, "Config", &pCfg);
1867 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1868 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
1869 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1870 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1871 InsertConfigNode(pLunL0, "Config", &pCfg);
1872
1873 /*
1874 * Attach the status driver.
1875 */
1876 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 0, NULL, NULL, 0);
1877 }
1878#ifdef VBOX_WITH_EHCI
1879 else if (enmCtrlType == USBControllerType_EHCI)
1880 {
1881 /*
1882 * USB 2.0 is only available if the proper ExtPack is installed.
1883 *
1884 * Note. Configuring EHCI here and providing messages about
1885 * the missing extpack isn't exactly clean, but it is a
1886 * necessary evil to patch over legacy compatability issues
1887 * introduced by the new distribution model.
1888 */
1889# ifdef VBOX_WITH_EXTPACK
1890 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1891 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1892# endif
1893 {
1894 InsertConfigNode(pDevices, "usb-ehci", &pDev);
1895 InsertConfigNode(pDev, "0", &pInst);
1896 InsertConfigNode(pInst, "Config", &pCfg);
1897 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1898 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
1899
1900 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1901 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1902 InsertConfigNode(pLunL0, "Config", &pCfg);
1903
1904 /*
1905 * Attach the status driver.
1906 */
1907 i_attachStatusDriver(pInst, &mapUSBLed[1], 0, 0, NULL, NULL, 0);
1908 }
1909# ifdef VBOX_WITH_EXTPACK
1910 else
1911 {
1912 /* Always fatal! Up to VBox 4.0.4 we allowed to start the VM anyway
1913 * but this induced problems when the user saved + restored the VM! */
1914 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1915 N_("Implementation of the USB 2.0 controller not found!\n"
1916 "Because the USB 2.0 controller state is part of the saved "
1917 "VM state, the VM cannot be started. To fix "
1918 "this problem, either install the '%s' or disable USB 2.0 "
1919 "support in the VM settings.\n"
1920 "Note! This error could also mean that an incompatible version of "
1921 "the '%s' is installed"),
1922 s_pszUsbExtPackName, s_pszUsbExtPackName);
1923 }
1924# endif
1925 }
1926#endif
1927 else if (enmCtrlType == USBControllerType_XHCI)
1928 {
1929 /*
1930 * USB 3.0 is only available if the proper ExtPack is installed.
1931 *
1932 * Note. Configuring EHCI here and providing messages about
1933 * the missing extpack isn't exactly clean, but it is a
1934 * necessary evil to patch over legacy compatability issues
1935 * introduced by the new distribution model.
1936 */
1937# ifdef VBOX_WITH_EXTPACK
1938 static const char *s_pszUsbExtPackName = "Oracle VM VirtualBox Extension Pack";
1939 if (mptrExtPackManager->i_isExtPackUsable(s_pszUsbExtPackName))
1940# endif
1941 {
1942 InsertConfigNode(pDevices, "usb-xhci", &pDev);
1943 InsertConfigNode(pDev, "0", &pInst);
1944 InsertConfigNode(pInst, "Config", &pCfg);
1945 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1946 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
1947
1948 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1949 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
1950 InsertConfigNode(pLunL0, "Config", &pCfg);
1951
1952 InsertConfigNode(pInst, "LUN#1", &pLunL1);
1953 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
1954 InsertConfigNode(pLunL1, "Config", &pCfg);
1955
1956 /*
1957 * Attach the status driver.
1958 */
1959 i_attachStatusDriver(pInst, &mapUSBLed[0], 0, 1, NULL, NULL, 0);
1960 }
1961# ifdef VBOX_WITH_EXTPACK
1962 else
1963 {
1964 /* Always fatal. */
1965 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
1966 N_("Implementation of the USB 3.0 controller not found!\n"
1967 "Because the USB 3.0 controller state is part of the saved "
1968 "VM state, the VM cannot be started. To fix "
1969 "this problem, either install the '%s' or disable USB 3.0 "
1970 "support in the VM settings"),
1971 s_pszUsbExtPackName);
1972 }
1973# endif
1974 }
1975 } /* for every USB controller. */
1976
1977
1978 /*
1979 * Virtual USB Devices.
1980 */
1981 InsertConfigNode(pRoot, "USB", &pUsbDevices);
1982
1983#ifdef VBOX_WITH_USB
1984 {
1985 /*
1986 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
1987 * on a per device level now.
1988 */
1989 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
1990 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
1991 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
1992 //InsertConfigInteger(pCfg, "Force11Device", true);
1993 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
1994 // that it's documented somewhere.) Users needing it can use:
1995 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
1996 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
1997 }
1998#endif
1999
2000#ifdef VBOX_WITH_USB_CARDREADER
2001 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
2002 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
2003 if (aEmulatedUSBCardReaderEnabled)
2004 {
2005 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
2006 InsertConfigNode(pDev, "0", &pInst);
2007 InsertConfigNode(pInst, "Config", &pCfg);
2008
2009 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2010# ifdef VBOX_WITH_USB_CARDREADER_TEST
2011 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
2012 InsertConfigNode(pLunL0, "Config", &pCfg);
2013# else
2014 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
2015 InsertConfigNode(pLunL0, "Config", &pCfg);
2016 InsertConfigInteger(pCfg, "Object", (uintptr_t)mUsbCardReader);
2017# endif
2018 }
2019#endif
2020
2021 /* Virtual USB Mouse/Tablet */
2022 if ( aPointingHID == PointingHIDType_USBMouse
2023 || aPointingHID == PointingHIDType_USBTablet
2024 || aPointingHID == PointingHIDType_USBMultiTouch)
2025 {
2026 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
2027 InsertConfigNode(pDev, "0", &pInst);
2028 InsertConfigNode(pInst, "Config", &pCfg);
2029
2030 if (aPointingHID == PointingHIDType_USBMouse)
2031 InsertConfigString(pCfg, "Mode", "relative");
2032 else
2033 InsertConfigString(pCfg, "Mode", "absolute");
2034 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2035 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2036 InsertConfigNode(pLunL0, "Config", &pCfg);
2037 InsertConfigInteger(pCfg, "QueueSize", 128);
2038
2039 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2040 InsertConfigString(pLunL1, "Driver", "MainMouse");
2041 InsertConfigNode(pLunL1, "Config", &pCfg);
2042 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2043 }
2044 if (aPointingHID == PointingHIDType_USBMultiTouch)
2045 {
2046 InsertConfigNode(pDev, "1", &pInst);
2047 InsertConfigNode(pInst, "Config", &pCfg);
2048
2049 InsertConfigString(pCfg, "Mode", "multitouch");
2050 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2051 InsertConfigString(pLunL0, "Driver", "MouseQueue");
2052 InsertConfigNode(pLunL0, "Config", &pCfg);
2053 InsertConfigInteger(pCfg, "QueueSize", 128);
2054
2055 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2056 InsertConfigString(pLunL1, "Driver", "MainMouse");
2057 InsertConfigNode(pLunL1, "Config", &pCfg);
2058 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
2059 }
2060
2061 /* Virtual USB Keyboard */
2062 KeyboardHIDType_T aKbdHID;
2063 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();
2064 if (aKbdHID == KeyboardHIDType_USBKeyboard)
2065 {
2066 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
2067 InsertConfigNode(pDev, "0", &pInst);
2068 InsertConfigNode(pInst, "Config", &pCfg);
2069
2070 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2071 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
2072 InsertConfigNode(pLunL0, "Config", &pCfg);
2073 InsertConfigInteger(pCfg, "QueueSize", 64);
2074
2075 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2076 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
2077 InsertConfigNode(pLunL1, "Config", &pCfg);
2078 pKeyboard = mKeyboard;
2079 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
2080 }
2081 }
2082
2083 /*
2084 * Storage controllers.
2085 */
2086 com::SafeIfaceArray<IStorageController> ctrls;
2087 PCFGMNODE aCtrlNodes[StorageControllerType_NVMe + 1] = {};
2088 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
2089
2090 bool fFdcEnabled = false;
2091 for (size_t i = 0; i < ctrls.size(); ++i)
2092 {
2093 DeviceType_T *paLedDevType = NULL;
2094
2095 StorageControllerType_T enmCtrlType;
2096 rc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
2097 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
2098 || enmCtrlType == StorageControllerType_USB);
2099
2100 StorageBus_T enmBus;
2101 rc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
2102
2103 Bstr controllerName;
2104 rc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
2105
2106 ULONG ulInstance = 999;
2107 rc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
2108
2109 BOOL fUseHostIOCache;
2110 rc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
2111
2112 BOOL fBootable;
2113 rc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
2114
2115 PCFGMNODE pCtlInst = NULL;
2116 const char *pszCtrlDev = i_convertControllerTypeToDev(enmCtrlType);
2117 if (enmCtrlType != StorageControllerType_USB)
2118 {
2119 /* /Devices/<ctrldev>/ */
2120 pDev = aCtrlNodes[enmCtrlType];
2121 if (!pDev)
2122 {
2123 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
2124 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
2125 }
2126
2127 /* /Devices/<ctrldev>/<instance>/ */
2128 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
2129
2130 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
2131 InsertConfigInteger(pCtlInst, "Trusted", 1);
2132 InsertConfigNode(pCtlInst, "Config", &pCfg);
2133 }
2134
2135 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
2136 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
2137
2138 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
2139 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
2140
2141 switch (enmCtrlType)
2142 {
2143 case StorageControllerType_LsiLogic:
2144 {
2145 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
2146
2147 InsertConfigInteger(pCfg, "Bootable", fBootable);
2148
2149 /* BIOS configuration values, first SCSI controller only. */
2150 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
2151 && !pBusMgr->hasPCIDevice("buslogic", 0)
2152 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2153 && pBiosCfg)
2154 {
2155 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
2156 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2157 }
2158
2159 /* Attach the status driver */
2160 Assert(cLedScsi >= 16);
2161 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2162 &mapMediumAttachments, pszCtrlDev, ulInstance);
2163 paLedDevType = &maStorageDevType[iLedScsi];
2164 break;
2165 }
2166
2167 case StorageControllerType_BusLogic:
2168 {
2169 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
2170
2171 InsertConfigInteger(pCfg, "Bootable", fBootable);
2172
2173 /* BIOS configuration values, first SCSI controller only. */
2174 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2175 && !pBusMgr->hasPCIDevice("buslogic", 1)
2176 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
2177 && pBiosCfg)
2178 {
2179 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
2180 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2181 }
2182
2183 /* Attach the status driver */
2184 Assert(cLedScsi >= 16);
2185 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedScsi], 0, 15,
2186 &mapMediumAttachments, pszCtrlDev, ulInstance);
2187 paLedDevType = &maStorageDevType[iLedScsi];
2188 break;
2189 }
2190
2191 case StorageControllerType_IntelAhci:
2192 {
2193 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
2194
2195 ULONG cPorts = 0;
2196 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2197 InsertConfigInteger(pCfg, "PortCount", cPorts);
2198 InsertConfigInteger(pCfg, "Bootable", fBootable);
2199
2200 com::SafeIfaceArray<IMediumAttachment> atts;
2201 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2202 ComSafeArrayAsOutParam(atts)); H();
2203
2204 /* Configure the hotpluggable flag for the port. */
2205 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
2206 {
2207 IMediumAttachment *pMediumAtt = atts[idxAtt];
2208
2209 LONG lPortNum = 0;
2210 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
2211
2212 BOOL fHotPluggable = FALSE;
2213 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
2214 if (SUCCEEDED(hrc))
2215 {
2216 PCFGMNODE pPortCfg;
2217 char szName[24];
2218 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
2219
2220 InsertConfigNode(pCfg, szName, &pPortCfg);
2221 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
2222 }
2223 }
2224
2225 /* BIOS configuration values, first AHCI controller only. */
2226 if ( !pBusMgr->hasPCIDevice("ahci", 1)
2227 && pBiosCfg)
2228 {
2229 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
2230 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
2231 }
2232
2233 /* Attach the status driver */
2234 AssertRelease(cPorts <= cLedSata);
2235 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSata], 0, cPorts - 1,
2236 &mapMediumAttachments, pszCtrlDev, ulInstance);
2237 paLedDevType = &maStorageDevType[iLedSata];
2238 break;
2239 }
2240
2241 case StorageControllerType_PIIX3:
2242 case StorageControllerType_PIIX4:
2243 case StorageControllerType_ICH6:
2244 {
2245 /*
2246 * IDE (update this when the main interface changes)
2247 */
2248 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
2249 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
2250 /* Attach the status driver */
2251 Assert(cLedIde >= 4);
2252 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedIde], 0, 3,
2253 &mapMediumAttachments, pszCtrlDev, ulInstance);
2254 paLedDevType = &maStorageDevType[iLedIde];
2255
2256 /* IDE flavors */
2257 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
2258 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
2259 aCtrlNodes[StorageControllerType_ICH6] = pDev;
2260 break;
2261 }
2262
2263 case StorageControllerType_I82078:
2264 {
2265 /*
2266 * i82078 Floppy drive controller
2267 */
2268 fFdcEnabled = true;
2269 InsertConfigInteger(pCfg, "IRQ", 6);
2270 InsertConfigInteger(pCfg, "DMA", 2);
2271 InsertConfigInteger(pCfg, "MemMapped", 0 );
2272 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
2273
2274 /* Attach the status driver */
2275 Assert(cLedFloppy >= 2);
2276 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedFloppy], 0, 1,
2277 &mapMediumAttachments, pszCtrlDev, ulInstance);
2278 paLedDevType = &maStorageDevType[iLedFloppy];
2279 break;
2280 }
2281
2282 case StorageControllerType_LsiLogicSas:
2283 {
2284 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
2285
2286 InsertConfigString(pCfg, "ControllerType", "SAS1068");
2287 InsertConfigInteger(pCfg, "Bootable", fBootable);
2288
2289 /* BIOS configuration values, first SCSI controller only. */
2290 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
2291 && !pBusMgr->hasPCIDevice("buslogic", 0)
2292 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
2293 && pBiosCfg)
2294 {
2295 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
2296 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
2297 }
2298
2299 ULONG cPorts = 0;
2300 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2301 InsertConfigInteger(pCfg, "NumPorts", cPorts);
2302
2303 /* Attach the status driver */
2304 Assert(cLedSas >= 8);
2305 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedSas], 0, 7,
2306 &mapMediumAttachments, pszCtrlDev, ulInstance);
2307 paLedDevType = &maStorageDevType[iLedSas];
2308 break;
2309 }
2310
2311 case StorageControllerType_USB:
2312 {
2313 if (pUsbDevices)
2314 {
2315 /*
2316 * USB MSDs are handled a bit different as the device instance
2317 * doesn't match the storage controller instance but the port.
2318 */
2319 InsertConfigNode(pUsbDevices, "Msd", &pDev);
2320 pCtlInst = pDev;
2321 }
2322 else
2323 return VMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2324 N_("There is no USB controller enabled but there\n"
2325 "is at least one USB storage device configured for this VM.\n"
2326 "To fix this problem either enable the USB controller or remove\n"
2327 "the storage device from the VM"));
2328 break;
2329 }
2330
2331 case StorageControllerType_NVMe:
2332 {
2333 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
2334
2335 ULONG cPorts = 0;
2336 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
2337 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
2338
2339 /* For ICH9 we need to create a new PCI bridge if there is more than one NVMe instance. */
2340 if ( ulInstance > 0
2341 && chipsetType == ChipsetType_ICH9
2342 && !pBusMgr->hasPCIDevice("ich9pcibridge", 2))
2343 {
2344 PCFGMNODE pBridges = CFGMR3GetChild(pDevices, "ich9pcibridge");
2345 Assert(pBridges);
2346
2347 InsertConfigNode(pBridges, "2", &pInst);
2348 InsertConfigInteger(pInst, "Trusted", 1);
2349 hrc = pBusMgr->assignPCIDevice("ich9pcibridge", pInst);
2350 }
2351
2352 /* Attach the status driver */
2353 AssertRelease(cPorts <= cLedSata);
2354 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedNvme], 0, cPorts - 1,
2355 &mapMediumAttachments, pszCtrlDev, ulInstance);
2356 paLedDevType = &maStorageDevType[iLedNvme];
2357 break;
2358 }
2359
2360 default:
2361 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
2362 }
2363
2364 /* Attach the media to the storage controllers. */
2365 com::SafeIfaceArray<IMediumAttachment> atts;
2366 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
2367 ComSafeArrayAsOutParam(atts)); H();
2368
2369 /* Builtin I/O cache - per device setting. */
2370 BOOL fBuiltinIOCache = true;
2371 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
2372
2373
2374 for (size_t j = 0; j < atts.size(); ++j)
2375 {
2376 IMediumAttachment *pMediumAtt = atts[j];
2377 rc = i_configMediumAttachment(pszCtrlDev,
2378 ulInstance,
2379 enmBus,
2380 !!fUseHostIOCache,
2381 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
2382 false /* fSetupMerge */,
2383 0 /* uMergeSource */,
2384 0 /* uMergeTarget */,
2385 pMediumAtt,
2386 mMachineState,
2387 NULL /* phrc */,
2388 false /* fAttachDetach */,
2389 false /* fForceUnmount */,
2390 false /* fHotplug */,
2391 pUVM,
2392 paLedDevType,
2393 NULL /* ppLunL0 */);
2394 if (RT_FAILURE(rc))
2395 return rc;
2396 }
2397 H();
2398 }
2399 H();
2400
2401 /*
2402 * Network adapters
2403 */
2404#ifdef VMWARE_NET_IN_SLOT_11
2405 bool fSwapSlots3and11 = false;
2406#endif
2407 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
2408 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
2409#ifdef VBOX_WITH_E1000
2410 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
2411 InsertConfigNode(pDevices, "e1000", &pDevE1000);
2412#endif
2413#ifdef VBOX_WITH_VIRTIO
2414 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
2415 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
2416#endif /* VBOX_WITH_VIRTIO */
2417 std::list<BootNic> llBootNics;
2418 for (ULONG ulInstance = 0; ulInstance < maxNetworkAdapters; ++ulInstance)
2419 {
2420 ComPtr<INetworkAdapter> networkAdapter;
2421 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
2422 BOOL fEnabledNetAdapter = FALSE;
2423 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
2424 if (!fEnabledNetAdapter)
2425 continue;
2426
2427 /*
2428 * The virtual hardware type. Create appropriate device first.
2429 */
2430 const char *pszAdapterName = "pcnet";
2431 NetworkAdapterType_T adapterType;
2432 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
2433 switch (adapterType)
2434 {
2435 case NetworkAdapterType_Am79C970A:
2436 case NetworkAdapterType_Am79C973:
2437 pDev = pDevPCNet;
2438 break;
2439#ifdef VBOX_WITH_E1000
2440 case NetworkAdapterType_I82540EM:
2441 case NetworkAdapterType_I82543GC:
2442 case NetworkAdapterType_I82545EM:
2443 pDev = pDevE1000;
2444 pszAdapterName = "e1000";
2445 break;
2446#endif
2447#ifdef VBOX_WITH_VIRTIO
2448 case NetworkAdapterType_Virtio:
2449 pDev = pDevVirtioNet;
2450 pszAdapterName = "virtio-net";
2451 break;
2452#endif /* VBOX_WITH_VIRTIO */
2453 default:
2454 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
2455 adapterType, ulInstance));
2456 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
2457 N_("Invalid network adapter type '%d' for slot '%d'"),
2458 adapterType, ulInstance);
2459 }
2460
2461 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2462 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2463 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
2464 * next 4 get 16..19. */
2465 int iPCIDeviceNo;
2466 switch (ulInstance)
2467 {
2468 case 0:
2469 iPCIDeviceNo = 3;
2470 break;
2471 case 1: case 2: case 3:
2472 iPCIDeviceNo = ulInstance - 1 + 8;
2473 break;
2474 case 4: case 5: case 6: case 7:
2475 iPCIDeviceNo = ulInstance - 4 + 16;
2476 break;
2477 default:
2478 /* auto assignment */
2479 iPCIDeviceNo = -1;
2480 break;
2481 }
2482#ifdef VMWARE_NET_IN_SLOT_11
2483 /*
2484 * Dirty hack for PCI slot compatibility with VMWare,
2485 * it assigns slot 0x11 to the first network controller.
2486 */
2487 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
2488 {
2489 iPCIDeviceNo = 0x11;
2490 fSwapSlots3and11 = true;
2491 }
2492 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
2493 iPCIDeviceNo = 3;
2494#endif
2495 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
2496 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
2497
2498 InsertConfigNode(pInst, "Config", &pCfg);
2499#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
2500 if (pDev == pDevPCNet)
2501 {
2502 InsertConfigInteger(pCfg, "R0Enabled", false);
2503 }
2504#endif
2505 /*
2506 * Collect information needed for network booting and add it to the list.
2507 */
2508 BootNic nic;
2509
2510 nic.mInstance = ulInstance;
2511 /* Could be updated by reference, if auto assigned */
2512 nic.mPCIAddress = PCIAddr;
2513
2514 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
2515
2516 llBootNics.push_back(nic);
2517
2518 /*
2519 * The virtual hardware type. PCNet supports two types, E1000 three,
2520 * but VirtIO only one.
2521 */
2522 switch (adapterType)
2523 {
2524 case NetworkAdapterType_Am79C970A:
2525 InsertConfigInteger(pCfg, "Am79C973", 0);
2526 break;
2527 case NetworkAdapterType_Am79C973:
2528 InsertConfigInteger(pCfg, "Am79C973", 1);
2529 break;
2530 case NetworkAdapterType_I82540EM:
2531 InsertConfigInteger(pCfg, "AdapterType", 0);
2532 break;
2533 case NetworkAdapterType_I82543GC:
2534 InsertConfigInteger(pCfg, "AdapterType", 1);
2535 break;
2536 case NetworkAdapterType_I82545EM:
2537 InsertConfigInteger(pCfg, "AdapterType", 2);
2538 break;
2539 case NetworkAdapterType_Virtio:
2540 break;
2541 case NetworkAdapterType_Null: AssertFailedBreak(); /* Shut up MSC */
2542 }
2543
2544 /*
2545 * Get the MAC address and convert it to binary representation
2546 */
2547 Bstr macAddr;
2548 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2549 Assert(!macAddr.isEmpty());
2550 Utf8Str macAddrUtf8 = macAddr;
2551 char *macStr = (char*)macAddrUtf8.c_str();
2552 Assert(strlen(macStr) == 12);
2553 RTMAC Mac;
2554 RT_ZERO(Mac);
2555 char *pMac = (char*)&Mac;
2556 for (uint32_t i = 0; i < 6; ++i)
2557 {
2558 int c1 = *macStr++ - '0';
2559 if (c1 > 9)
2560 c1 -= 7;
2561 int c2 = *macStr++ - '0';
2562 if (c2 > 9)
2563 c2 -= 7;
2564 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2565 }
2566 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2567
2568 /*
2569 * Check if the cable is supposed to be unplugged
2570 */
2571 BOOL fCableConnected;
2572 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2573 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2574
2575 /*
2576 * Line speed to report from custom drivers
2577 */
2578 ULONG ulLineSpeed;
2579 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2580 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2581
2582 /*
2583 * Attach the status driver.
2584 */
2585 i_attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
2586
2587 /*
2588 * Configure the network card now
2589 */
2590 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2591 rc = i_configNetwork(pszAdapterName,
2592 ulInstance,
2593 0,
2594 networkAdapter,
2595 pCfg,
2596 pLunL0,
2597 pInst,
2598 false /*fAttachDetach*/,
2599 fIgnoreConnectFailure);
2600 if (RT_FAILURE(rc))
2601 return rc;
2602 }
2603
2604 /*
2605 * Build network boot information and transfer it to the BIOS.
2606 */
2607 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2608 {
2609 llBootNics.sort(); /* Sort the list by boot priority. */
2610
2611 char achBootIdx[] = "0";
2612 unsigned uBootIdx = 0;
2613
2614 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2615 {
2616 /* A NIC with priority 0 is only used if it's first in the list. */
2617 if (it->mBootPrio == 0 && uBootIdx != 0)
2618 break;
2619
2620 PCFGMNODE pNetBtDevCfg;
2621 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2622 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2623 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2624 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2625 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2626 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2627 }
2628 }
2629
2630 /*
2631 * Serial (UART) Ports
2632 */
2633 /* serial enabled mask to be passed to dev ACPI */
2634 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2635 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2636 InsertConfigNode(pDevices, "serial", &pDev);
2637 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2638 {
2639 ComPtr<ISerialPort> serialPort;
2640 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2641 BOOL fEnabledSerPort = FALSE;
2642 if (serialPort)
2643 {
2644 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2645 }
2646 if (!fEnabledSerPort)
2647 continue;
2648
2649 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2650 InsertConfigNode(pInst, "Config", &pCfg);
2651
2652 ULONG ulIRQ;
2653 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2654 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2655 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2656
2657 ULONG ulIOBase;
2658 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2659 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2660 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2661
2662 BOOL fServer;
2663 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2664 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2665 PortMode_T eHostMode;
2666 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2667 if (eHostMode != PortMode_Disconnected)
2668 {
2669 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2670 if (eHostMode == PortMode_HostPipe)
2671 {
2672 InsertConfigString(pLunL0, "Driver", "Char");
2673 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2674 InsertConfigString(pLunL1, "Driver", "NamedPipe");
2675 InsertConfigNode(pLunL1, "Config", &pLunL2);
2676 InsertConfigString(pLunL2, "Location", bstr);
2677 InsertConfigInteger(pLunL2, "IsServer", fServer);
2678 }
2679 else if (eHostMode == PortMode_HostDevice)
2680 {
2681 InsertConfigString(pLunL0, "Driver", "Host Serial");
2682 InsertConfigNode(pLunL0, "Config", &pLunL1);
2683 InsertConfigString(pLunL1, "DevicePath", bstr);
2684 }
2685 else if (eHostMode == PortMode_TCP)
2686 {
2687 InsertConfigString(pLunL0, "Driver", "Char");
2688 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2689 InsertConfigString(pLunL1, "Driver", "TCP");
2690 InsertConfigNode(pLunL1, "Config", &pLunL2);
2691 InsertConfigString(pLunL2, "Location", bstr);
2692 InsertConfigInteger(pLunL2, "IsServer", fServer);
2693 }
2694 else if (eHostMode == PortMode_RawFile)
2695 {
2696 InsertConfigString(pLunL0, "Driver", "Char");
2697 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2698 InsertConfigString(pLunL1, "Driver", "RawFile");
2699 InsertConfigNode(pLunL1, "Config", &pLunL2);
2700 InsertConfigString(pLunL2, "Location", bstr);
2701 }
2702 }
2703 }
2704
2705 /*
2706 * Parallel (LPT) Ports
2707 */
2708 /* parallel enabled mask to be passed to dev ACPI */
2709 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2710 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2711 InsertConfigNode(pDevices, "parallel", &pDev);
2712 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2713 {
2714 ComPtr<IParallelPort> parallelPort;
2715 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2716 BOOL fEnabledParPort = FALSE;
2717 if (parallelPort)
2718 {
2719 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2720 }
2721 if (!fEnabledParPort)
2722 continue;
2723
2724 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2725 InsertConfigNode(pInst, "Config", &pCfg);
2726
2727 ULONG ulIRQ;
2728 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2729 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2730 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2731 ULONG ulIOBase;
2732 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2733 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2734 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2735
2736 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2737 if (!bstr.isEmpty())
2738 {
2739 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2740 InsertConfigString(pLunL0, "Driver", "HostParallel");
2741 InsertConfigNode(pLunL0, "Config", &pLunL1);
2742 InsertConfigString(pLunL1, "DevicePath", bstr);
2743 }
2744 }
2745
2746 /*
2747 * VMM Device
2748 */
2749 InsertConfigNode(pDevices, "VMMDev", &pDev);
2750 InsertConfigNode(pDev, "0", &pInst);
2751 InsertConfigNode(pInst, "Config", &pCfg);
2752 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2753 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
2754
2755 Bstr hwVersion;
2756 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
2757 InsertConfigInteger(pCfg, "RamSize", cbRam);
2758 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2759 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2760 Bstr snapshotFolder;
2761 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2762 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2763
2764 /* the VMM device's Main driver */
2765 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2766 InsertConfigString(pLunL0, "Driver", "HGCM");
2767 InsertConfigNode(pLunL0, "Config", &pCfg);
2768 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2769
2770 /*
2771 * Attach the status driver.
2772 */
2773 i_attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
2774
2775 /*
2776 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2777 */
2778 BOOL fAudioEnabled = FALSE;
2779 ComPtr<IAudioAdapter> audioAdapter;
2780 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2781 if (audioAdapter)
2782 {
2783 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2784 }
2785
2786 if (fAudioEnabled)
2787 {
2788 AudioControllerType_T audioController;
2789 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2790 AudioCodecType_T audioCodec;
2791 hrc = audioAdapter->COMGETTER(AudioCodec)(&audioCodec); H();
2792 switch (audioController)
2793 {
2794 case AudioControllerType_AC97:
2795 {
2796 /* Default: ICH AC97. */
2797 InsertConfigNode(pDevices, "ichac97", &pDev);
2798 InsertConfigNode(pDev, "0", &pInst);
2799 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2800 hrc = pBusMgr->assignPCIDevice("ichac97", pInst); H();
2801 InsertConfigNode(pInst, "Config", &pCfg);
2802 switch (audioCodec)
2803 {
2804 case AudioCodecType_STAC9700:
2805 InsertConfigString(pCfg, "Codec", "STAC9700");
2806 break;
2807 case AudioCodecType_AD1980:
2808 InsertConfigString(pCfg, "Codec", "AD1980");
2809 break;
2810 default: AssertFailedBreak();
2811 }
2812 break;
2813 }
2814 case AudioControllerType_SB16:
2815 {
2816 /* Legacy SoundBlaster16. */
2817 InsertConfigNode(pDevices, "sb16", &pDev);
2818 InsertConfigNode(pDev, "0", &pInst);
2819 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2820 InsertConfigNode(pInst, "Config", &pCfg);
2821 InsertConfigInteger(pCfg, "IRQ", 5);
2822 InsertConfigInteger(pCfg, "DMA", 1);
2823 InsertConfigInteger(pCfg, "DMA16", 5);
2824 InsertConfigInteger(pCfg, "Port", 0x220);
2825 InsertConfigInteger(pCfg, "Version", 0x0405);
2826 break;
2827 }
2828 case AudioControllerType_HDA:
2829 {
2830 /* Intel HD Audio. */
2831 InsertConfigNode(pDevices, "hda", &pDev);
2832 InsertConfigNode(pDev, "0", &pInst);
2833 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2834 hrc = pBusMgr->assignPCIDevice("hda", pInst); H();
2835 InsertConfigNode(pInst, "Config", &pCfg);
2836 }
2837 }
2838
2839 PCFGMNODE pCfgAudioSettings = NULL;
2840 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioSettings);
2841 SafeArray<BSTR> audioProps;
2842 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2843
2844 std::list<Utf8Str> audioPropertyNamesList;
2845 for (size_t i = 0; i < audioProps.size(); ++i)
2846 {
2847 Bstr bstrValue;
2848 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2849 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2850 Utf8Str strKey(audioProps[i]);
2851 InsertConfigString(pCfgAudioSettings, strKey.c_str(), bstrValue);
2852 }
2853
2854 /*
2855 * The audio driver.
2856 */
2857 uint8_t u8AudioLUN = 0;
2858
2859 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", u8AudioLUN++);
2860 InsertConfigString(pLunL0, "Driver", "AUDIO");
2861 InsertConfigNode(pLunL0, "Config", &pCfg);
2862
2863 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
2864 InsertConfigNode(pLunL1, "Config", &pCfg);
2865
2866 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2867 InsertConfigString(pCfg, "StreamName", bstr);
2868
2869 AudioDriverType_T audioDriver;
2870 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2871 switch (audioDriver)
2872 {
2873 case AudioDriverType_Null:
2874 {
2875 InsertConfigString(pLunL1, "Driver", "NullAudio");
2876 break;
2877 }
2878#ifdef RT_OS_WINDOWS
2879# ifdef VBOX_WITH_WINMM
2880 case AudioDriverType_WinMM:
2881 {
2882 #error "Port WinMM audio backend!" /** @todo Still needed? */
2883 break;
2884 }
2885# endif
2886 case AudioDriverType_DirectSound:
2887 {
2888 InsertConfigString(pLunL1, "Driver", "DSoundAudio");
2889 break;
2890 }
2891#endif /* RT_OS_WINDOWS */
2892#ifdef RT_OS_SOLARIS
2893 case AudioDriverType_SolAudio:
2894 {
2895 /* Should not happen, as the Solaris Audio backend is not around anymore.
2896 * Remove this sometime later. */
2897 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2898 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2899
2900 /* Manually set backend to OSS for now. */
2901 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2902 break;
2903 }
2904#endif
2905#ifdef VBOX_WITH_AUDIO_OSS
2906 case AudioDriverType_OSS:
2907 {
2908 InsertConfigString(pLunL1, "Driver", "OSSAudio");
2909 break;
2910 }
2911#endif
2912#ifdef VBOX_WITH_AUDIO_ALSA
2913 case AudioDriverType_ALSA:
2914 {
2915 InsertConfigString(pLunL1, "Driver", "ALSAAudio");
2916 break;
2917 }
2918#endif
2919#ifdef VBOX_WITH_AUDIO_PULSE
2920 case AudioDriverType_Pulse:
2921 {
2922 InsertConfigString(pLunL1, "Driver", "PulseAudio");
2923 break;
2924 }
2925#endif
2926#ifdef RT_OS_DARWIN
2927 case AudioDriverType_CoreAudio:
2928 {
2929 InsertConfigString(pLunL1, "Driver", "CoreAudio");
2930 break;
2931 }
2932#endif
2933 default: AssertFailedBreak();
2934 }
2935
2936 /** @todo Implement a prioritizing feature here, e.g. which driver to insert in which order? */
2937
2938#ifdef VBOX_WITH_VRDE_AUDIO
2939 /*
2940 * The VRDE audio backend driver.
2941 */
2942 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2943 InsertConfigString(pLunL1, "Driver", "AUDIO");
2944
2945 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2946 InsertConfigString(pLunL1, "Driver", "AudioVRDE");
2947
2948 InsertConfigNode(pLunL1, "Config", &pCfg);
2949 InsertConfigString(pCfg, "AudioDriver", "AudioVRDE");
2950 InsertConfigString(pCfg, "StreamName", bstr);
2951 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVRDE);
2952 InsertConfigInteger(pCfg, "ObjectVRDPServer", (uintptr_t)mConsoleVRDPServer);
2953#endif /* VBOX_WITH_VRDE_AUDIO */
2954
2955#ifdef VBOX_WITH_AUDIO_VIDEOREC
2956 /*
2957 * The video recording audio backend driver.
2958 * Currently being used with VPX video recording only.
2959 */
2960 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2961 InsertConfigString(pLunL1, "Driver", "AUDIO");
2962
2963 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2964 InsertConfigString(pLunL1, "Driver", "AudioVideoRec");
2965
2966 InsertConfigNode(pLunL1, "Config", &pCfg);
2967 InsertConfigString(pCfg, "AudioDriver", "AudioVideoRec");
2968 InsertConfigString(pCfg, "StreamName", bstr);
2969 InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVideoRec);
2970 InsertConfigInteger(pCfg, "ObjectConsole", (uintptr_t)this /* Console */);
2971#endif /* VBOX_WITH_AUDIO_VIDEOREC */
2972
2973#ifdef VBOX_WITH_AUDIO_DEBUG
2974 /*
2975 * The audio debug backend. Only can be used in debug builds.
2976 */
2977 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2978 InsertConfigString(pLunL1, "Driver", "AUDIO");
2979
2980 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2981 InsertConfigString(pLunL1, "Driver", "DebugAudio");
2982
2983 InsertConfigNode(pLunL1, "Config", &pCfg);
2984 InsertConfigString(pCfg, "AudioDriver", "DebugAudio");
2985 InsertConfigString(pCfg, "StreamName", bstr);
2986#endif /* VBOX_WITH_AUDIO_DEBUG */
2987
2988#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
2989 /** @todo Make this a runtime-configurable entry! */
2990
2991 /*
2992 * The ValidationKit backend.
2993 */
2994 CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
2995 InsertConfigString(pLunL1, "Driver", "AUDIO");
2996
2997 InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
2998 InsertConfigString(pLunL1, "Driver", "ValidationKitAudio");
2999
3000 InsertConfigNode(pLunL1, "Config", &pCfg);
3001 InsertConfigString(pCfg, "AudioDriver", "ValidationKitAudio");
3002 InsertConfigString(pCfg, "StreamName", bstr);
3003#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3004
3005 /** @todo Add audio video recording driver here. */
3006 }
3007
3008 /*
3009 * Shared Clipboard.
3010 */
3011 {
3012 ClipboardMode_T mode = ClipboardMode_Disabled;
3013 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3014
3015 if (/* mode != ClipboardMode_Disabled */ true)
3016 {
3017 /* Load the service */
3018 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3019 if (RT_FAILURE(rc))
3020 {
3021 LogRel(("Shared clipboard is not available, rc=%Rrc\n", rc));
3022 /* That is not a fatal failure. */
3023 rc = VINF_SUCCESS;
3024 }
3025 else
3026 {
3027 LogRel(("Shared clipboard service loaded\n"));
3028
3029 i_changeClipboardMode(mode);
3030
3031 /* Setup the service. */
3032 VBOXHGCMSVCPARM parm;
3033 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
3034 parm.setUInt32(!i_useHostClipboard());
3035 pVMMDev->hgcmHostCall("VBoxSharedClipboard",
3036 VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3037 }
3038 }
3039 }
3040
3041 /*
3042 * HGCM HostChannel.
3043 */
3044 {
3045 Bstr value;
3046 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3047 value.asOutParam());
3048
3049 if ( hrc == S_OK
3050 && value == "1")
3051 {
3052 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3053 if (RT_FAILURE(rc))
3054 {
3055 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3056 /* That is not a fatal failure. */
3057 rc = VINF_SUCCESS;
3058 }
3059 }
3060 }
3061
3062#ifdef VBOX_WITH_DRAG_AND_DROP
3063 /*
3064 * Drag and Drop.
3065 */
3066 {
3067 DnDMode_T enmMode = DnDMode_Disabled;
3068 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3069
3070 /* Load the service */
3071 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3072 if (RT_FAILURE(rc))
3073 {
3074 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3075 /* That is not a fatal failure. */
3076 rc = VINF_SUCCESS;
3077 }
3078 else
3079 {
3080 HGCMSVCEXTHANDLE hDummy;
3081 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
3082 &GuestDnD::notifyDnDDispatcher,
3083 GuestDnDInst());
3084 if (RT_FAILURE(rc))
3085 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3086 else
3087 {
3088 LogRel(("Drag and drop service loaded\n"));
3089 rc = i_changeDnDMode(enmMode);
3090 }
3091 }
3092 }
3093#endif /* VBOX_WITH_DRAG_AND_DROP */
3094
3095#ifdef VBOX_WITH_CROGL
3096 /*
3097 * crOpenGL.
3098 */
3099 {
3100 BOOL fEnabled3D = false;
3101 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3102
3103 if ( fEnabled3D
3104# ifdef VBOX_WITH_VMSVGA3D
3105 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3106# endif
3107 )
3108 {
3109 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3110 if (!fSupports3D)
3111 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3112 N_("This VM was configured to use 3D acceleration. However, the "
3113 "3D support of the host is not working properly and the "
3114 "VM cannot be started. To fix this problem, either "
3115 "fix the host 3D support (update the host graphics driver?) "
3116 "or disable 3D acceleration in the VM settings"));
3117
3118 /* Load the service. */
3119 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3120 if (RT_FAILURE(rc))
3121 {
3122 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3123 /* That is not a fatal failure. */
3124 rc = VINF_SUCCESS;
3125 }
3126 else
3127 {
3128 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3129
3130 /* Setup the service. */
3131 VBOXHGCMSVCPARM parm;
3132 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3133
3134 parm.u.pointer.addr = (IConsole *)(Console *)this;
3135 parm.u.pointer.size = sizeof(IConsole *);
3136
3137 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3138 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3139 if (!RT_SUCCESS(rc))
3140 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3141
3142 parm.u.pointer.addr = pVM;
3143 parm.u.pointer.size = sizeof(pVM);
3144 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3145 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3146 if (!RT_SUCCESS(rc))
3147 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3148 }
3149 }
3150 }
3151#endif
3152
3153#ifdef VBOX_WITH_GUEST_PROPS
3154 /*
3155 * Guest property service.
3156 */
3157 rc = i_configGuestProperties(this, pUVM);
3158#endif /* VBOX_WITH_GUEST_PROPS defined */
3159
3160#ifdef VBOX_WITH_GUEST_CONTROL
3161 /*
3162 * Guest control service.
3163 */
3164 rc = i_configGuestControl(this);
3165#endif /* VBOX_WITH_GUEST_CONTROL defined */
3166
3167 /*
3168 * ACPI
3169 */
3170 BOOL fACPI;
3171 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3172 if (fACPI)
3173 {
3174 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3175 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3176 * intelppm driver refuses to register an idle state handler.
3177 * Always show CPU leafs for OS X guests. */
3178 BOOL fShowCpu = fOsXGuest;
3179 if (cCpus > 1 || fIOAPIC)
3180 fShowCpu = true;
3181
3182 BOOL fCpuHotPlug;
3183 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3184
3185 InsertConfigNode(pDevices, "acpi", &pDev);
3186 InsertConfigNode(pDev, "0", &pInst);
3187 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3188 InsertConfigNode(pInst, "Config", &pCfg);
3189 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3190
3191 InsertConfigInteger(pCfg, "RamSize", cbRam);
3192 InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole);
3193 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3194
3195 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3196 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3197 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3198 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3199 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3200 if (fOsXGuest && !llBootNics.empty())
3201 {
3202 BootNic aNic = llBootNics.front();
3203 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3204 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3205 }
3206 if (fOsXGuest && fAudioEnabled)
3207 {
3208 PCIBusAddress Address;
3209 if (pBusMgr->findPCIAddress("hda", 0, Address))
3210 {
3211 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3212 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3213 }
3214 }
3215 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3216 if (chipsetType == ChipsetType_ICH9)
3217 {
3218 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3219 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3220 }
3221 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3222 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3223 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3224
3225 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3226 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3227
3228 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3229 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3230
3231 if (auSerialIoPortBase[2])
3232 {
3233 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3234 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3235 }
3236
3237 if (auSerialIoPortBase[3])
3238 {
3239 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3240 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3241 }
3242
3243 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3244 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3245
3246 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3247 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3248
3249 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3250 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3251 InsertConfigNode(pLunL0, "Config", &pCfg);
3252
3253 /* Attach the dummy CPU drivers */
3254 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3255 {
3256 BOOL fCpuAttached = true;
3257
3258 if (fCpuHotPlug)
3259 {
3260 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3261 }
3262
3263 if (fCpuAttached)
3264 {
3265 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3266 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3267 InsertConfigNode(pLunL0, "Config", &pCfg);
3268 }
3269 }
3270 }
3271
3272 /*
3273 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3274 */
3275 {
3276 PCFGMNODE pDbgf;
3277 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3278
3279 /* Paths to search for debug info and such things. */
3280 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3281 Utf8Str strSettingsPath(bstr);
3282 bstr.setNull();
3283 strSettingsPath.stripFilename();
3284 strSettingsPath.append("/");
3285
3286 char szHomeDir[RTPATH_MAX + 1];
3287 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3288 if (RT_FAILURE(rc2))
3289 szHomeDir[0] = '\0';
3290 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3291
3292
3293 Utf8Str strPath;
3294 strPath.append(strSettingsPath).append("debug/;");
3295 strPath.append(strSettingsPath).append(";");
3296 strPath.append(szHomeDir);
3297
3298 InsertConfigString(pDbgf, "Path", strPath.c_str());
3299
3300 /* Tracing configuration. */
3301 BOOL fTracingEnabled;
3302 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3303 if (fTracingEnabled)
3304 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3305
3306 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3307 if (fTracingEnabled)
3308 InsertConfigString(pDbgf, "TracingConfig", bstr);
3309
3310 BOOL fAllowTracingToAccessVM;
3311 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3312 if (fAllowTracingToAccessVM)
3313 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3314
3315 /* Debugger console config. */
3316 PCFGMNODE pDbgc;
3317 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3318
3319 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3320 Utf8Str strVBoxHome = bstr;
3321 bstr.setNull();
3322 if (strVBoxHome.isNotEmpty())
3323 strVBoxHome.append("/");
3324 else
3325 {
3326 strVBoxHome = szHomeDir;
3327 strVBoxHome.append("/.vbox");
3328 }
3329
3330 Utf8Str strFile(strVBoxHome);
3331 strFile.append("dbgc-history");
3332 InsertConfigString(pDbgc, "HistoryFile", strFile);
3333
3334 strFile = strSettingsPath;
3335 strFile.append("dbgc-init");
3336 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3337
3338 strFile = strVBoxHome;
3339 strFile.append("dbgc-init");
3340 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3341 }
3342 }
3343 catch (ConfigError &x)
3344 {
3345 // InsertConfig threw something:
3346 return x.m_vrc;
3347 }
3348 catch (HRESULT hrcXcpt)
3349 {
3350 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3351 }
3352
3353#ifdef VBOX_WITH_EXTPACK
3354 /*
3355 * Call the extension pack hooks if everything went well thus far.
3356 */
3357 if (RT_SUCCESS(rc))
3358 {
3359 pAlock->release();
3360 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3361 pAlock->acquire();
3362 }
3363#endif
3364
3365 /*
3366 * Apply the CFGM overlay.
3367 */
3368 if (RT_SUCCESS(rc))
3369 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3370
3371 /*
3372 * Dump all extradata API settings tweaks, both global and per VM.
3373 */
3374 if (RT_SUCCESS(rc))
3375 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3376
3377#undef H
3378
3379 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3380
3381 /*
3382 * Register VM state change handler.
3383 */
3384 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3385 AssertRC(rc2);
3386 if (RT_SUCCESS(rc))
3387 rc = rc2;
3388
3389 /*
3390 * Register VM runtime error handler.
3391 */
3392 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3393 AssertRC(rc2);
3394 if (RT_SUCCESS(rc))
3395 rc = rc2;
3396
3397 pAlock->acquire();
3398
3399 LogFlowFunc(("vrc = %Rrc\n", rc));
3400 LogFlowFuncLeave();
3401
3402 return rc;
3403}
3404
3405/**
3406 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3407 * values.
3408 *
3409 * @returns VBox status code.
3410 * @param pRoot The root of the configuration tree.
3411 * @param pVirtualBox Pointer to the IVirtualBox interface.
3412 * @param pMachine Pointer to the IMachine interface.
3413 */
3414/* static */
3415int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3416{
3417 /*
3418 * CFGM overlay handling.
3419 *
3420 * Here we check the extra data entries for CFGM values
3421 * and create the nodes and insert the values on the fly. Existing
3422 * values will be removed and reinserted. CFGM is typed, so by default
3423 * we will guess whether it's a string or an integer (byte arrays are
3424 * not currently supported). It's possible to override this autodetection
3425 * by adding "string:", "integer:" or "bytes:" (future).
3426 *
3427 * We first perform a run on global extra data, then on the machine
3428 * extra data to support global settings with local overrides.
3429 */
3430 int rc = VINF_SUCCESS;
3431 try
3432 {
3433 /** @todo add support for removing nodes and byte blobs. */
3434 /*
3435 * Get the next key
3436 */
3437 SafeArray<BSTR> aGlobalExtraDataKeys;
3438 SafeArray<BSTR> aMachineExtraDataKeys;
3439 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3440 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3441
3442 // remember the no. of global values so we can call the correct method below
3443 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3444
3445 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3446 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3447
3448 // build a combined list from global keys...
3449 std::list<Utf8Str> llExtraDataKeys;
3450
3451 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3452 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3453 // ... and machine keys
3454 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3455 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3456
3457 size_t i2 = 0;
3458 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3459 it != llExtraDataKeys.end();
3460 ++it, ++i2)
3461 {
3462 const Utf8Str &strKey = *it;
3463
3464 /*
3465 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3466 */
3467 if (!strKey.startsWith("VBoxInternal/"))
3468 continue;
3469
3470 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3471
3472 // get the value
3473 Bstr bstrExtraDataValue;
3474 if (i2 < cGlobalValues)
3475 // this is still one of the global values:
3476 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3477 bstrExtraDataValue.asOutParam());
3478 else
3479 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3480 bstrExtraDataValue.asOutParam());
3481 if (FAILED(hrc))
3482 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3483
3484 /*
3485 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3486 * Split the two and get the node, delete the value and create the node
3487 * if necessary.
3488 */
3489 PCFGMNODE pNode;
3490 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3491 if (pszCFGMValueName)
3492 {
3493 /* terminate the node and advance to the value (Utf8Str might not
3494 offically like this but wtf) */
3495 *(char*)pszCFGMValueName = '\0';
3496 ++pszCFGMValueName;
3497
3498 /* does the node already exist? */
3499 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3500 if (pNode)
3501 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3502 else
3503 {
3504 /* create the node */
3505 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3506 if (RT_FAILURE(rc))
3507 {
3508 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3509 continue;
3510 }
3511 Assert(pNode);
3512 }
3513 }
3514 else
3515 {
3516 /* root value (no node path). */
3517 pNode = pRoot;
3518 pszCFGMValueName = pszExtraDataKey;
3519 pszExtraDataKey--;
3520 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3521 }
3522
3523 /*
3524 * Now let's have a look at the value.
3525 * Empty strings means that we should remove the value, which we've
3526 * already done above.
3527 */
3528 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3529 if (!strCFGMValueUtf8.isEmpty())
3530 {
3531 uint64_t u64Value;
3532
3533 /* check for type prefix first. */
3534 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3535 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3536 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3537 {
3538 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3539 if (RT_SUCCESS(rc))
3540 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3541 }
3542 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3543 {
3544 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3545 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3546 if (cbValue > 0)
3547 {
3548 void *pvBytes = RTMemTmpAlloc(cbValue);
3549 if (pvBytes)
3550 {
3551 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3552 if (RT_SUCCESS(rc))
3553 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3554 RTMemTmpFree(pvBytes);
3555 }
3556 else
3557 rc = VERR_NO_TMP_MEMORY;
3558 }
3559 else if (cbValue == 0)
3560 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3561 else
3562 rc = VERR_INVALID_BASE64_ENCODING;
3563 }
3564 /* auto detect type. */
3565 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3566 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3567 else
3568 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3569 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3570 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3571 }
3572 }
3573 }
3574 catch (ConfigError &x)
3575 {
3576 // InsertConfig threw something:
3577 return x.m_vrc;
3578 }
3579 return rc;
3580}
3581
3582/**
3583 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3584 * values.
3585 *
3586 * @returns VBox status code.
3587 * @param pVirtualBox Pointer to the IVirtualBox interface.
3588 * @param pMachine Pointer to the IMachine interface.
3589 */
3590/* static */
3591int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3592{
3593 {
3594 SafeArray<BSTR> aGlobalExtraDataKeys;
3595 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3596 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3597 bool hasKey = false;
3598 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3599 {
3600 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3601 if (!strKey.startsWith("VBoxInternal2/"))
3602 continue;
3603
3604 Bstr bstrValue;
3605 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3606 bstrValue.asOutParam());
3607 if (FAILED(hrc))
3608 continue;
3609 if (!hasKey)
3610 LogRel(("Global extradata API settings:\n"));
3611 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3612 hasKey = true;
3613 }
3614 }
3615
3616 {
3617 SafeArray<BSTR> aMachineExtraDataKeys;
3618 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3619 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3620 bool hasKey = false;
3621 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3622 {
3623 Utf8Str strKey(aMachineExtraDataKeys[i]);
3624 if (!strKey.startsWith("VBoxInternal2/"))
3625 continue;
3626
3627 Bstr bstrValue;
3628 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3629 bstrValue.asOutParam());
3630 if (FAILED(hrc))
3631 continue;
3632 if (!hasKey)
3633 LogRel(("Per-VM extradata API settings:\n"));
3634 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3635 hasKey = true;
3636 }
3637 }
3638
3639 return VINF_SUCCESS;
3640}
3641
3642int Console::i_configGraphicsController(PCFGMNODE pDevices,
3643 const GraphicsControllerType_T enmGraphicsController,
3644 BusAssignmentManager *pBusMgr,
3645 const ComPtr<IMachine> &ptrMachine,
3646 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3647 bool fHMEnabled)
3648{
3649 // InsertConfig* throws
3650 try
3651 {
3652 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3653 HRESULT hrc;
3654 Bstr bstr;
3655 const char *pcszDevice = "vga";
3656
3657#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3658 InsertConfigNode(pDevices, pcszDevice, &pDev);
3659 InsertConfigNode(pDev, "0", &pInst);
3660 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3661
3662 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3663 InsertConfigNode(pInst, "Config", &pCfg);
3664 ULONG cVRamMBs;
3665 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3666 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3667 ULONG cMonitorCount;
3668 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3669 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3670#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3671 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3672#else
3673 NOREF(fHMEnabled);
3674#endif
3675
3676 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3677
3678#ifdef VBOX_WITH_VMSVGA
3679 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3680 {
3681 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3682#ifdef VBOX_WITH_VMSVGA3D
3683 IFramebuffer *pFramebuffer = NULL;
3684 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3685 if (SUCCEEDED(hrc) && pFramebuffer)
3686 {
3687 LONG64 winId = 0;
3688 /** @todo deal with multimonitor setup */
3689 Assert(cMonitorCount == 1);
3690 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3691 InsertConfigInteger(pCfg, "HostWindowId", winId);
3692 pFramebuffer->Release();
3693 }
3694 BOOL f3DEnabled;
3695 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3696 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3697#else
3698 LogRel(("VMSVGA3d not available in this build!\n"));
3699#endif
3700 }
3701#endif
3702
3703 /* Custom VESA mode list */
3704 unsigned cModes = 0;
3705 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3706 {
3707 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3708 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3709 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3710 if (bstr.isEmpty())
3711 break;
3712 InsertConfigString(pCfg, szExtraDataKey, bstr);
3713 ++cModes;
3714 }
3715 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3716
3717 /* VESA height reduction */
3718 ULONG ulHeightReduction;
3719 IFramebuffer *pFramebuffer = NULL;
3720 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3721 if (SUCCEEDED(hrc) && pFramebuffer)
3722 {
3723 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3724 pFramebuffer->Release();
3725 pFramebuffer = NULL;
3726 }
3727 else
3728 {
3729 /* If framebuffer is not available, there is no height reduction. */
3730 ulHeightReduction = 0;
3731 }
3732 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3733
3734 /*
3735 * BIOS logo
3736 */
3737 BOOL fFadeIn;
3738 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3739 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3740 BOOL fFadeOut;
3741 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3742 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3743 ULONG logoDisplayTime;
3744 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3745 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3746 Bstr logoImagePath;
3747 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3748 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3749
3750 /*
3751 * Boot menu
3752 */
3753 BIOSBootMenuMode_T eBootMenuMode;
3754 int iShowBootMenu;
3755 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3756 switch (eBootMenuMode)
3757 {
3758 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3759 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3760 default: iShowBootMenu = 2; break;
3761 }
3762 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3763
3764 /* Attach the display. */
3765 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3766 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3767 InsertConfigNode(pLunL0, "Config", &pCfg);
3768 Display *pDisplay = mDisplay;
3769 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3770 }
3771 catch (ConfigError &x)
3772 {
3773 // InsertConfig threw something:
3774 return x.m_vrc;
3775 }
3776
3777#undef H
3778
3779 return VINF_SUCCESS;
3780}
3781
3782
3783/**
3784 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3785 */
3786void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3787{
3788 va_list va;
3789 va_start(va, pszFormat);
3790 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3791 va_end(va);
3792}
3793
3794/* XXX introduce RT format specifier */
3795static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3796{
3797 if (u64Size > INT64_C(5000)*_1G)
3798 {
3799 *pszUnit = "TB";
3800 return u64Size / _1T;
3801 }
3802 else if (u64Size > INT64_C(5000)*_1M)
3803 {
3804 *pszUnit = "GB";
3805 return u64Size / _1G;
3806 }
3807 else
3808 {
3809 *pszUnit = "MB";
3810 return u64Size / _1M;
3811 }
3812}
3813
3814/**
3815 * Checks the location of the given medium for known bugs affecting the usage
3816 * of the host I/O cache setting.
3817 *
3818 * @returns VBox status code.
3819 * @param pMedium The medium to check.
3820 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3821 */
3822int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3823{
3824#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3825 /*
3826 * Some sanity checks.
3827 */
3828 RT_NOREF(pfUseHostIOCache);
3829 ComPtr<IMediumFormat> pMediumFormat;
3830 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3831 ULONG uCaps = 0;
3832 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3833 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3834
3835 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3836 uCaps |= mediumFormatCap[j];
3837
3838 if (uCaps & MediumFormatCapabilities_File)
3839 {
3840 Bstr strFile;
3841 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3842 Utf8Str utfFile = Utf8Str(strFile);
3843 Bstr strSnap;
3844 ComPtr<IMachine> pMachine = i_machine();
3845 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3846 Utf8Str utfSnap = Utf8Str(strSnap);
3847 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3848 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3849 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3850 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3851 /* Ignore the error code. On error, the file system type is still 'unknown' so
3852 * none of the following paths are taken. This can happen for new VMs which
3853 * still don't have a snapshot folder. */
3854 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
3855 if (!mfSnapshotFolderDiskTypeShown)
3856 {
3857 LogRel(("File system of '%s' (snapshots) is %s\n",
3858 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
3859 mfSnapshotFolderDiskTypeShown = true;
3860 }
3861 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
3862 LONG64 i64Size;
3863 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
3864#ifdef RT_OS_WINDOWS
3865 if ( enmFsTypeFile == RTFSTYPE_FAT
3866 && i64Size >= _4G)
3867 {
3868 const char *pszUnit;
3869 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
3870 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3871 N_("The medium '%ls' has a logical size of %RU64%s "
3872 "but the file system the medium is located on seems "
3873 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
3874 "We strongly recommend to put all your virtual disk images and "
3875 "the snapshot folder onto an NTFS partition"),
3876 strFile.raw(), u64Print, pszUnit);
3877 }
3878#else /* !RT_OS_WINDOWS */
3879 if ( enmFsTypeFile == RTFSTYPE_FAT
3880 || enmFsTypeFile == RTFSTYPE_EXT
3881 || enmFsTypeFile == RTFSTYPE_EXT2
3882 || enmFsTypeFile == RTFSTYPE_EXT3
3883 || enmFsTypeFile == RTFSTYPE_EXT4)
3884 {
3885 RTFILE file;
3886 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3887 if (RT_SUCCESS(rc))
3888 {
3889 RTFOFF maxSize;
3890 /* Careful: This function will work only on selected local file systems! */
3891 rc = RTFileGetMaxSizeEx(file, &maxSize);
3892 RTFileClose(file);
3893 if ( RT_SUCCESS(rc)
3894 && maxSize > 0
3895 && i64Size > (LONG64)maxSize)
3896 {
3897 const char *pszUnitSiz;
3898 const char *pszUnitMax;
3899 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
3900 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
3901 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
3902 N_("The medium '%ls' has a logical size of %RU64%s "
3903 "but the file system the medium is located on can "
3904 "only handle files up to %RU64%s in theory.\n"
3905 "We strongly recommend to put all your virtual disk "
3906 "images and the snapshot folder onto a proper "
3907 "file system (e.g. ext3) with a sufficient size"),
3908 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
3909 }
3910 }
3911 }
3912#endif /* !RT_OS_WINDOWS */
3913
3914 /*
3915 * Snapshot folder:
3916 * Here we test only for a FAT partition as we had to create a dummy file otherwise
3917 */
3918 if ( enmFsTypeSnap == RTFSTYPE_FAT
3919 && i64Size >= _4G
3920 && !mfSnapshotFolderSizeWarningShown)
3921 {
3922 const char *pszUnit;
3923 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
3924 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
3925#ifdef RT_OS_WINDOWS
3926 N_("The snapshot folder of this VM '%ls' seems to be located on "
3927 "a FAT(32) file system. The logical size of the medium '%ls' "
3928 "(%RU64%s) is bigger than the maximum file size this file "
3929 "system can handle (4GB).\n"
3930 "We strongly recommend to put all your virtual disk images and "
3931 "the snapshot folder onto an NTFS partition"),
3932#else
3933 N_("The snapshot folder of this VM '%ls' seems to be located on "
3934 "a FAT(32) file system. The logical size of the medium '%ls' "
3935 "(%RU64%s) is bigger than the maximum file size this file "
3936 "system can handle (4GB).\n"
3937 "We strongly recommend to put all your virtual disk images and "
3938 "the snapshot folder onto a proper file system (e.g. ext3)"),
3939#endif
3940 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
3941 /* Show this particular warning only once */
3942 mfSnapshotFolderSizeWarningShown = true;
3943 }
3944
3945#ifdef RT_OS_LINUX
3946 /*
3947 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
3948 * on an ext4 partition.
3949 * This bug apparently applies to the XFS file system as well.
3950 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
3951 */
3952
3953 char szOsRelease[128];
3954 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
3955 bool fKernelHasODirectBug = RT_FAILURE(rc)
3956 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
3957
3958 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
3959 && !*pfUseHostIOCache
3960 && fKernelHasODirectBug)
3961 {
3962 if ( enmFsTypeFile == RTFSTYPE_EXT4
3963 || enmFsTypeFile == RTFSTYPE_XFS)
3964 {
3965 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3966 N_("The host I/O cache for at least one controller is disabled "
3967 "and the medium '%ls' for this VM "
3968 "is located on an %s partition. There is a known Linux "
3969 "kernel bug which can lead to the corruption of the virtual "
3970 "disk image under these conditions.\n"
3971 "Either enable the host I/O cache permanently in the VM "
3972 "settings or put the disk image and the snapshot folder "
3973 "onto a different file system.\n"
3974 "The host I/O cache will now be enabled for this medium"),
3975 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3976 *pfUseHostIOCache = true;
3977 }
3978 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
3979 || enmFsTypeSnap == RTFSTYPE_XFS)
3980 && !mfSnapshotFolderExt4WarningShown)
3981 {
3982 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
3983 N_("The host I/O cache for at least one controller is disabled "
3984 "and the snapshot folder for this VM "
3985 "is located on an %s partition. There is a known Linux "
3986 "kernel bug which can lead to the corruption of the virtual "
3987 "disk image under these conditions.\n"
3988 "Either enable the host I/O cache permanently in the VM "
3989 "settings or put the disk image and the snapshot folder "
3990 "onto a different file system.\n"
3991 "The host I/O cache will now be enabled for this medium"),
3992 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
3993 *pfUseHostIOCache = true;
3994 mfSnapshotFolderExt4WarningShown = true;
3995 }
3996 }
3997
3998 /*
3999 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4000 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4001 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4002 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4003 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4004 */
4005 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4006 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4007 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4008 && !*pfUseHostIOCache
4009 && fKernelAsyncUnreliable)
4010 {
4011 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4012 N_("The host I/O cache for at least one controller is disabled. "
4013 "There is a known Linux kernel bug which can lead to kernel "
4014 "oopses under heavy load. To our knowledge this bug affects "
4015 "all 2.6.18 kernels.\n"
4016 "Either enable the host I/O cache permanently in the VM "
4017 "settings or switch to a newer host kernel.\n"
4018 "The host I/O cache will now be enabled for this medium"));
4019 *pfUseHostIOCache = true;
4020 }
4021#endif
4022 }
4023#undef H
4024
4025 return VINF_SUCCESS;
4026}
4027
4028/**
4029 * Unmounts the specified medium from the specified device.
4030 *
4031 * @returns VBox status code.
4032 * @param pUVM The usermode VM handle.
4033 * @param enmBus The storage bus.
4034 * @param enmDevType The device type.
4035 * @param pcszDevice The device emulation.
4036 * @param uInstance Instance of the device.
4037 * @param uLUN The LUN on the device.
4038 * @param fForceUnmount Whether to force unmounting.
4039 */
4040int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4041 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4042 bool fForceUnmount)
4043{
4044 /* Unmount existing media only for floppy and DVD drives. */
4045 int rc = VINF_SUCCESS;
4046 PPDMIBASE pBase;
4047 if (enmBus == StorageBus_USB)
4048 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4049 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4050 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4051 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4052 else /* IDE or Floppy */
4053 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4054
4055 if (RT_FAILURE(rc))
4056 {
4057 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4058 rc = VINF_SUCCESS;
4059 AssertRC(rc);
4060 }
4061 else
4062 {
4063 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4064 AssertReturn(pIMount, VERR_INVALID_POINTER);
4065
4066 /* Unmount the media (but do not eject the medium!) */
4067 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4068 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4069 rc = VINF_SUCCESS;
4070 /* for example if the medium is locked */
4071 else if (RT_FAILURE(rc))
4072 return rc;
4073 }
4074
4075 return rc;
4076}
4077
4078/**
4079 * Removes the currently attached medium driver form the specified device
4080 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4081 *
4082 * @returns VBox status code.
4083 * @param pCtlInst The controler instance node in the CFGM tree.
4084 * @param pcszDevice The device name.
4085 * @param uInstance The device instance.
4086 * @param uLUN The device LUN.
4087 * @param enmBus The storage bus.
4088 * @param fAttachDetach Flag whether this is a change while the VM is running
4089 * @param fHotplug Flag whether the guest should be notified about the device change.
4090 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4091 * @param pUVM The usermode VM handle.
4092 * @param enmDevType The device type.
4093 * @param ppLunL0 Where to store the node to attach the new config to on success.
4094 */
4095int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4096 const char *pcszDevice,
4097 unsigned uInstance,
4098 unsigned uLUN,
4099 StorageBus_T enmBus,
4100 bool fAttachDetach,
4101 bool fHotplug,
4102 bool fForceUnmount,
4103 PUVM pUVM,
4104 DeviceType_T enmDevType,
4105 PCFGMNODE *ppLunL0)
4106{
4107 int rc = VINF_SUCCESS;
4108 bool fAddLun = false;
4109
4110 /* First check if the LUN already exists. */
4111 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4112 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4113
4114 if (pLunL0)
4115 {
4116 /*
4117 * Unmount the currently mounted medium if we don't just hot remove the
4118 * complete device (SATA) and it supports unmounting (DVD).
4119 */
4120 if ( (enmDevType != DeviceType_HardDisk)
4121 && !fHotplug)
4122 {
4123 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4124 uInstance, uLUN, fForceUnmount);
4125 if (RT_FAILURE(rc))
4126 return rc;
4127 }
4128
4129 /*
4130 * Don't detach the SCSI driver when unmounting the current medium
4131 * (we are not ripping out the device but only eject the medium).
4132 */
4133 char *pszDriverDetach = NULL;
4134 if ( !fHotplug
4135 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4136 || enmBus == StorageBus_SAS
4137 || enmBus == StorageBus_SCSI
4138 || enmBus == StorageBus_USB))
4139 {
4140 /* Get the current attached driver we have to detach. */
4141 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4142 if (pDrvLun)
4143 {
4144 char szDriver[128];
4145 RT_ZERO(szDriver);
4146 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4147 if (RT_SUCCESS(rc))
4148 pszDriverDetach = RTStrDup(&szDriver[0]);
4149
4150 pLunL0 = pDrvLun;
4151 }
4152 }
4153
4154 if (enmBus == StorageBus_USB)
4155 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4156 pszDriverDetach, 0 /* iOccurence */,
4157 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4158 else
4159 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4160 pszDriverDetach, 0 /* iOccurence */,
4161 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4162
4163 if (pszDriverDetach)
4164 {
4165 RTStrFree(pszDriverDetach);
4166 /* Remove the complete node and create new for the new config. */
4167 CFGMR3RemoveNode(pLunL0);
4168 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4169 if (pLunL0)
4170 {
4171 try
4172 {
4173 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4174 }
4175 catch (ConfigError &x)
4176 {
4177 // InsertConfig threw something:
4178 return x.m_vrc;
4179 }
4180 }
4181 }
4182 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4183 rc = VINF_SUCCESS;
4184 AssertRCReturn(rc, rc);
4185
4186 /*
4187 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4188 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4189 */
4190 if ( fHotplug
4191 || enmBus == StorageBus_IDE
4192 || enmBus == StorageBus_Floppy
4193 || enmBus == StorageBus_PCIe
4194 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4195 {
4196 fAddLun = true;
4197 CFGMR3RemoveNode(pLunL0);
4198 }
4199 }
4200 else
4201 fAddLun = true;
4202
4203 try
4204 {
4205 if (fAddLun)
4206 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4207 }
4208 catch (ConfigError &x)
4209 {
4210 // InsertConfig threw something:
4211 return x.m_vrc;
4212 }
4213
4214 if (ppLunL0)
4215 *ppLunL0 = pLunL0;
4216
4217 return rc;
4218}
4219
4220int Console::i_configMediumAttachment(const char *pcszDevice,
4221 unsigned uInstance,
4222 StorageBus_T enmBus,
4223 bool fUseHostIOCache,
4224 bool fBuiltinIOCache,
4225 bool fSetupMerge,
4226 unsigned uMergeSource,
4227 unsigned uMergeTarget,
4228 IMediumAttachment *pMediumAtt,
4229 MachineState_T aMachineState,
4230 HRESULT *phrc,
4231 bool fAttachDetach,
4232 bool fForceUnmount,
4233 bool fHotplug,
4234 PUVM pUVM,
4235 DeviceType_T *paLedDevType,
4236 PCFGMNODE *ppLunL0)
4237{
4238 // InsertConfig* throws
4239 try
4240 {
4241 int rc = VINF_SUCCESS;
4242 HRESULT hrc;
4243 Bstr bstr;
4244 PCFGMNODE pCtlInst = NULL;
4245
4246// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4247#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4248
4249 LONG lDev;
4250 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4251 LONG lPort;
4252 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4253 DeviceType_T lType;
4254 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4255 BOOL fNonRotational;
4256 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4257 BOOL fDiscard;
4258 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4259
4260 unsigned uLUN;
4261 PCFGMNODE pLunL0 = NULL;
4262 hrc = Console::i_convertBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4263
4264 /* Determine the base path for the device instance. */
4265 if (enmBus != StorageBus_USB)
4266 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4267 else
4268 {
4269 /* If we hotplug a USB device create a new CFGM tree. */
4270 if (!fHotplug)
4271 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4272 else
4273 pCtlInst = CFGMR3CreateTree(pUVM);
4274 }
4275 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4276
4277 if (enmBus == StorageBus_USB)
4278 {
4279 PCFGMNODE pCfg = NULL;
4280
4281 /* Create correct instance. */
4282 if (!fHotplug)
4283 {
4284 if (!fAttachDetach)
4285 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4286 else
4287 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4288 }
4289
4290 if (!fAttachDetach)
4291 InsertConfigNode(pCtlInst, "Config", &pCfg);
4292
4293 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4294
4295 if (!fHotplug && !fAttachDetach)
4296 {
4297 char aszUuid[RTUUID_STR_LENGTH + 1];
4298 USBStorageDevice UsbMsd = USBStorageDevice();
4299
4300 memset(aszUuid, 0, sizeof(aszUuid));
4301 rc = RTUuidCreate(&UsbMsd.mUuid);
4302 AssertRCReturn(rc, rc);
4303 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4304 AssertRCReturn(rc, rc);
4305
4306 UsbMsd.iPort = uInstance;
4307
4308 InsertConfigString(pCtlInst, "UUID", aszUuid);
4309 mUSBStorageDevices.push_back(UsbMsd);
4310
4311 /** @todo No LED after hotplugging. */
4312 /* Attach the status driver */
4313 Assert(cLedUsb >= 8);
4314 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4315 &mapMediumAttachments, pcszDevice, 0);
4316 paLedDevType = &maStorageDevType[iLedUsb];
4317 }
4318 }
4319
4320 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4321 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4322 if (RT_FAILURE(rc))
4323 return rc;
4324 if (ppLunL0)
4325 *ppLunL0 = pLunL0;
4326
4327 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4328 mapMediumAttachments[devicePath] = pMediumAtt;
4329
4330 ComPtr<IMedium> pMedium;
4331 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4332
4333 /*
4334 * 1. Only check this for hard disk images.
4335 * 2. Only check during VM creation and not later, especially not during
4336 * taking an online snapshot!
4337 */
4338 if ( lType == DeviceType_HardDisk
4339 && ( aMachineState == MachineState_Starting
4340 || aMachineState == MachineState_Restoring))
4341 {
4342 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4343 if (RT_FAILURE(rc))
4344 return rc;
4345 }
4346
4347 if (pMedium)
4348 {
4349 BOOL fHostDrive;
4350 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4351 if ( ( lType == DeviceType_DVD
4352 || lType == DeviceType_Floppy)
4353 && !fHostDrive)
4354 {
4355 /*
4356 * Informative logging.
4357 */
4358 Bstr strFile;
4359 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4360 Utf8Str utfFile = Utf8Str(strFile);
4361 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4362 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4363 LogRel(("File system of '%s' (%s) is %s\n",
4364 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4365 RTFsTypeName(enmFsTypeFile)));
4366 }
4367 }
4368
4369 BOOL fPassthrough;
4370 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4371
4372 ComObjPtr<IBandwidthGroup> pBwGroup;
4373 Bstr strBwGroup;
4374 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4375
4376 if (!pBwGroup.isNull())
4377 {
4378 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4379 }
4380
4381 /*
4382 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4383 * or for SATA if the new device is a CD/DVD drive.
4384 */
4385 if ( (fHotplug || !fAttachDetach)
4386 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4387 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4388 {
4389 InsertConfigString(pLunL0, "Driver", "SCSI");
4390 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4391 }
4392
4393 rc = i_configMedium(pLunL0,
4394 !!fPassthrough,
4395 lType,
4396 fUseHostIOCache,
4397 fBuiltinIOCache,
4398 fSetupMerge,
4399 uMergeSource,
4400 uMergeTarget,
4401 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4402 !!fDiscard,
4403 !!fNonRotational,
4404 pMedium,
4405 aMachineState,
4406 phrc);
4407 if (RT_FAILURE(rc))
4408 return rc;
4409
4410 if (fAttachDetach)
4411 {
4412 /* Attach the new driver. */
4413 if (enmBus == StorageBus_USB)
4414 {
4415 if (fHotplug)
4416 {
4417 USBStorageDevice UsbMsd = USBStorageDevice();
4418 RTUuidCreate(&UsbMsd.mUuid);
4419 UsbMsd.iPort = uInstance;
4420 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4421 if (RT_SUCCESS(rc))
4422 mUSBStorageDevices.push_back(UsbMsd);
4423 }
4424 else
4425 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4426 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4427 }
4428 else if ( !fHotplug
4429 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4430 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4431 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4432 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4433 else
4434 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4435 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4436 AssertRCReturn(rc, rc);
4437
4438 /*
4439 * Make the secret key helper interface known to the VD driver if it is attached,
4440 * so we can get notified about missing keys.
4441 */
4442 PPDMIBASE pIBase = NULL;
4443 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4444 if (RT_SUCCESS(rc) && pIBase)
4445 {
4446 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4447 if (pIMedium)
4448 {
4449 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4450 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4451 }
4452 }
4453
4454 /* There is no need to handle removable medium mounting, as we
4455 * unconditionally replace everthing including the block driver level.
4456 * This means the new medium will be picked up automatically. */
4457 }
4458
4459 if (paLedDevType)
4460 paLedDevType[uLUN] = lType;
4461
4462 /* Dump the changed LUN if possible, dump the complete device otherwise */
4463 if ( aMachineState != MachineState_Starting
4464 && aMachineState != MachineState_Restoring)
4465 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4466 }
4467 catch (ConfigError &x)
4468 {
4469 // InsertConfig threw something:
4470 return x.m_vrc;
4471 }
4472
4473#undef H
4474
4475 return VINF_SUCCESS;
4476}
4477
4478int Console::i_configMedium(PCFGMNODE pLunL0,
4479 bool fPassthrough,
4480 DeviceType_T enmType,
4481 bool fUseHostIOCache,
4482 bool fBuiltinIOCache,
4483 bool fSetupMerge,
4484 unsigned uMergeSource,
4485 unsigned uMergeTarget,
4486 const char *pcszBwGroup,
4487 bool fDiscard,
4488 bool fNonRotational,
4489 IMedium *pMedium,
4490 MachineState_T aMachineState,
4491 HRESULT *phrc)
4492{
4493 // InsertConfig* throws
4494 try
4495 {
4496 HRESULT hrc;
4497 Bstr bstr;
4498 PCFGMNODE pCfg = NULL;
4499
4500#define H() \
4501 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4502
4503
4504 BOOL fHostDrive = FALSE;
4505 MediumType_T mediumType = MediumType_Normal;
4506 if (pMedium)
4507 {
4508 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4509 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4510 }
4511
4512 if (fHostDrive)
4513 {
4514 Assert(pMedium);
4515 if (enmType == DeviceType_DVD)
4516 {
4517 InsertConfigString(pLunL0, "Driver", "HostDVD");
4518 InsertConfigNode(pLunL0, "Config", &pCfg);
4519
4520 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4521 InsertConfigString(pCfg, "Path", bstr);
4522
4523 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4524 }
4525 else if (enmType == DeviceType_Floppy)
4526 {
4527 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4528 InsertConfigNode(pLunL0, "Config", &pCfg);
4529
4530 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4531 InsertConfigString(pCfg, "Path", bstr);
4532 }
4533 }
4534 else
4535 {
4536#if 0 /* Enable for I/O debugging */
4537 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4538 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4539 InsertConfigNode(pLunL0, "Config", &pCfg);
4540 InsertConfigInteger(pCfg, "CheckConsistency", 0);
4541 InsertConfigInteger(pCfg, "CheckDoubleCompletions", 1);
4542#endif
4543
4544 InsertConfigString(pLunL0, "Driver", "VD");
4545 InsertConfigNode(pLunL0, "Config", &pCfg);
4546 switch (enmType)
4547 {
4548 case DeviceType_DVD:
4549 InsertConfigString(pCfg, "Type", "DVD");
4550 InsertConfigInteger(pCfg, "Mountable", 1);
4551 break;
4552 case DeviceType_Floppy:
4553 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4554 InsertConfigInteger(pCfg, "Mountable", 1);
4555 break;
4556 case DeviceType_HardDisk:
4557 default:
4558 InsertConfigString(pCfg, "Type", "HardDisk");
4559 InsertConfigInteger(pCfg, "Mountable", 0);
4560 }
4561
4562 if ( pMedium
4563 && ( enmType == DeviceType_DVD
4564 || enmType == DeviceType_Floppy)
4565 )
4566 {
4567 // if this medium represents an ISO image and this image is inaccessible,
4568 // the ignore it instead of causing a failure; this can happen when we
4569 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4570 // Additions were mounted and the user upgraded VirtualBox. Previously
4571 // we failed on startup, but that's not good because the only way out then
4572 // would be to discard the VM state...
4573 MediumState_T mediumState;
4574 hrc = pMedium->RefreshState(&mediumState); H();
4575 if (mediumState == MediumState_Inaccessible)
4576 {
4577 Bstr loc;
4578 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4579 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4580 "The image file '%ls' is inaccessible and is being ignored. "
4581 "Please select a different image file for the virtual %s drive.",
4582 loc.raw(),
4583 enmType == DeviceType_DVD ? "DVD" : "floppy");
4584 pMedium = NULL;
4585 }
4586 }
4587
4588 if (pMedium)
4589 {
4590 /* Start with length of parent chain, as the list is reversed */
4591 unsigned uImage = 0;
4592 IMedium *pTmp = pMedium;
4593 while (pTmp)
4594 {
4595 uImage++;
4596 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4597 }
4598 /* Index of last image */
4599 uImage--;
4600
4601# ifdef VBOX_WITH_EXTPACK
4602 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4603 {
4604 /* Configure loading the VDPlugin. */
4605 static const char s_szVDPlugin[] = "VDPluginCrypt";
4606 PCFGMNODE pCfgPlugins = NULL;
4607 PCFGMNODE pCfgPlugin = NULL;
4608 Utf8Str strPlugin;
4609 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4610 // Don't fail, this is optional!
4611 if (SUCCEEDED(hrc))
4612 {
4613 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4614 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4615 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4616 }
4617 }
4618# endif
4619
4620 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4621 InsertConfigString(pCfg, "Path", bstr);
4622
4623 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4624 InsertConfigString(pCfg, "Format", bstr);
4625
4626 if (mediumType == MediumType_Readonly)
4627 InsertConfigInteger(pCfg, "ReadOnly", 1);
4628 else if (enmType == DeviceType_Floppy)
4629 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4630
4631 /* Start without exclusive write access to the images. */
4632 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4633 * we're resuming the VM if some 3rd dude have any of the VDIs open
4634 * with write sharing denied. However, if the two VMs are sharing a
4635 * image it really is necessary....
4636 *
4637 * So, on the "lock-media" command, the target teleporter should also
4638 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4639 * that. Grumble. */
4640 if ( enmType == DeviceType_HardDisk
4641 && ( aMachineState == MachineState_TeleportingIn
4642 || aMachineState == MachineState_FaultTolerantSyncing))
4643 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4644
4645 /* Flag for opening the medium for sharing between VMs. This
4646 * is done at the moment only for the first (and only) medium
4647 * in the chain, as shared media can have no diffs. */
4648 if (mediumType == MediumType_Shareable)
4649 InsertConfigInteger(pCfg, "Shareable", 1);
4650
4651 if (!fUseHostIOCache)
4652 {
4653 InsertConfigInteger(pCfg, "UseNewIo", 1);
4654 /*
4655 * Activate the builtin I/O cache for harddisks only.
4656 * It caches writes only which doesn't make sense for DVD drives
4657 * and just increases the overhead.
4658 */
4659 if ( fBuiltinIOCache
4660 && (enmType == DeviceType_HardDisk))
4661 InsertConfigInteger(pCfg, "BlockCache", 1);
4662 }
4663
4664 if (fSetupMerge)
4665 {
4666 InsertConfigInteger(pCfg, "SetupMerge", 1);
4667 if (uImage == uMergeSource)
4668 InsertConfigInteger(pCfg, "MergeSource", 1);
4669 else if (uImage == uMergeTarget)
4670 InsertConfigInteger(pCfg, "MergeTarget", 1);
4671 }
4672
4673 if (pcszBwGroup)
4674 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4675
4676 if (fDiscard)
4677 InsertConfigInteger(pCfg, "Discard", 1);
4678
4679 if (fNonRotational)
4680 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4681
4682 /* Pass all custom parameters. */
4683 bool fHostIP = true;
4684 bool fEncrypted = false;
4685 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4686
4687 /* Create an inverted list of parents. */
4688 uImage--;
4689 IMedium *pParentMedium = pMedium;
4690 for (PCFGMNODE pParent = pCfg;; uImage--)
4691 {
4692 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4693 if (!pMedium)
4694 break;
4695
4696 PCFGMNODE pCur;
4697 InsertConfigNode(pParent, "Parent", &pCur);
4698 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4699 InsertConfigString(pCur, "Path", bstr);
4700
4701 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4702 InsertConfigString(pCur, "Format", bstr);
4703
4704 if (fSetupMerge)
4705 {
4706 if (uImage == uMergeSource)
4707 InsertConfigInteger(pCur, "MergeSource", 1);
4708 else if (uImage == uMergeTarget)
4709 InsertConfigInteger(pCur, "MergeTarget", 1);
4710 }
4711
4712 /* Configure medium properties. */
4713 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4714
4715 /* next */
4716 pParent = pCur;
4717 pParentMedium = pMedium;
4718 }
4719
4720 /* Custom code: put marker to not use host IP stack to driver
4721 * configuration node. Simplifies life of DrvVD a bit. */
4722 if (!fHostIP)
4723 InsertConfigInteger(pCfg, "HostIPStack", 0);
4724
4725 if (fEncrypted)
4726 m_cDisksEncrypted++;
4727 }
4728 else
4729 {
4730 /* Set empty drive flag for DVD or floppy without media. */
4731 if ( enmType == DeviceType_DVD
4732 || enmType == DeviceType_Floppy)
4733 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4734 }
4735 }
4736#undef H
4737 }
4738 catch (ConfigError &x)
4739 {
4740 // InsertConfig threw something:
4741 return x.m_vrc;
4742 }
4743
4744 return VINF_SUCCESS;
4745}
4746
4747/**
4748 * Adds the medium properties to the CFGM tree.
4749 *
4750 * @returns VBox status code.
4751 * @param pCur The current CFGM node.
4752 * @param pMedium The medium object to configure.
4753 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4754 * @param pfEncrypted Where to return whether the medium is encrypted.
4755 */
4756int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4757{
4758 /* Pass all custom parameters. */
4759 SafeArray<BSTR> aNames;
4760 SafeArray<BSTR> aValues;
4761 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4762 ComSafeArrayAsOutParam(aValues));
4763
4764 if ( SUCCEEDED(hrc)
4765 && aNames.size() != 0)
4766 {
4767 PCFGMNODE pVDC;
4768 InsertConfigNode(pCur, "VDConfig", &pVDC);
4769 for (size_t ii = 0; ii < aNames.size(); ++ii)
4770 {
4771 if (aValues[ii] && *aValues[ii])
4772 {
4773 Utf8Str name = aNames[ii];
4774 Utf8Str value = aValues[ii];
4775 size_t offSlash = name.find("/", 0);
4776 if ( offSlash != name.npos
4777 && !name.startsWith("Special/"))
4778 {
4779 com::Utf8Str strFilter;
4780 com::Utf8Str strKey;
4781
4782 hrc = strFilter.assignEx(name, 0, offSlash);
4783 if (FAILED(hrc))
4784 break;
4785
4786 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4787 if (FAILED(hrc))
4788 break;
4789
4790 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4791 if (!pCfgFilterConfig)
4792 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4793
4794 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4795 }
4796 else
4797 {
4798 InsertConfigString(pVDC, name.c_str(), value);
4799 if ( name.compare("HostIPStack") == 0
4800 && value.compare("0") == 0)
4801 *pfHostIP = false;
4802 }
4803
4804 if ( name.compare("CRYPT/KeyId") == 0
4805 && pfEncrypted)
4806 *pfEncrypted = true;
4807 }
4808 }
4809 }
4810
4811 return hrc;
4812}
4813
4814
4815#ifdef RT_OS_WINDOWS
4816DECLINLINE(bool) IsNdis6(void)
4817{
4818 LogFlowFunc(("entry\n"));
4819 HANDLE hFile = CreateFile(L"\\\\.\\VBoxNetLwf",
4820 0,
4821 FILE_SHARE_READ | FILE_SHARE_WRITE,
4822 NULL,
4823 OPEN_EXISTING,
4824 0,
4825 NULL);
4826 bool fNdis6 = hFile != INVALID_HANDLE_VALUE;
4827 if (fNdis6)
4828 CloseHandle(hFile);
4829 else
4830 LogFunc(("CreateFile failed with 0x%x\n", GetLastError()));
4831 LogFlowFunc(("return %s\n", fNdis6 ? "true" : "false"));
4832 return fNdis6;
4833}
4834#endif /* RT_OS_WINDOWS */
4835
4836
4837/**
4838 * Construct the Network configuration tree
4839 *
4840 * @returns VBox status code.
4841 *
4842 * @param pszDevice The PDM device name.
4843 * @param uInstance The PDM device instance.
4844 * @param uLun The PDM LUN number of the drive.
4845 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4846 * @param pCfg Configuration node for the device
4847 * @param pLunL0 To store the pointer to the LUN#0.
4848 * @param pInst The instance CFGM node
4849 * @param fAttachDetach To determine if the network attachment should
4850 * be attached/detached after/before
4851 * configuration.
4852 * @param fIgnoreConnectFailure
4853 * True if connection failures should be ignored
4854 * (makes only sense for bridged/host-only networks).
4855 *
4856 * @note Locks this object for writing.
4857 * @thread EMT
4858 */
4859int Console::i_configNetwork(const char *pszDevice,
4860 unsigned uInstance,
4861 unsigned uLun,
4862 INetworkAdapter *aNetworkAdapter,
4863 PCFGMNODE pCfg,
4864 PCFGMNODE pLunL0,
4865 PCFGMNODE pInst,
4866 bool fAttachDetach,
4867 bool fIgnoreConnectFailure)
4868{
4869 RT_NOREF(fIgnoreConnectFailure);
4870 AutoCaller autoCaller(this);
4871 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
4872
4873 // InsertConfig* throws
4874 try
4875 {
4876 int rc = VINF_SUCCESS;
4877 HRESULT hrc;
4878 Bstr bstr;
4879
4880#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4881
4882 /*
4883 * Locking the object before doing VMR3* calls is quite safe here, since
4884 * we're on EMT. Write lock is necessary because we indirectly modify the
4885 * meAttachmentType member.
4886 */
4887 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4888
4889 ComPtr<IMachine> pMachine = i_machine();
4890
4891 ComPtr<IVirtualBox> virtualBox;
4892 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4893
4894 ComPtr<IHost> host;
4895 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4896
4897 BOOL fSniffer;
4898 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4899
4900 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
4901 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
4902 const char *pszPromiscuousGuestPolicy;
4903 switch (enmPromiscModePolicy)
4904 {
4905 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
4906 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
4907 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
4908 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
4909 }
4910
4911 if (fAttachDetach)
4912 {
4913 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
4914 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4915 rc = VINF_SUCCESS;
4916 AssertLogRelRCReturn(rc, rc);
4917
4918 /* nuke anything which might have been left behind. */
4919 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
4920 }
4921
4922#ifdef VBOX_WITH_NETSHAPER
4923 ComObjPtr<IBandwidthGroup> pBwGroup;
4924 Bstr strBwGroup;
4925 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4926
4927 if (!pBwGroup.isNull())
4928 {
4929 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4930 }
4931#endif /* VBOX_WITH_NETSHAPER */
4932
4933 Utf8Str strNetDriver;
4934
4935
4936 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4937
4938#ifdef VBOX_WITH_NETSHAPER
4939 if (!strBwGroup.isEmpty())
4940 {
4941 InsertConfigString(pLunL0, "Driver", "NetShaper");
4942 InsertConfigNode(pLunL0, "Config", &pCfg);
4943 InsertConfigString(pCfg, "BwGroup", strBwGroup);
4944 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4945 }
4946#endif /* VBOX_WITH_NETSHAPER */
4947
4948 if (fSniffer)
4949 {
4950 InsertConfigString(pLunL0, "Driver", "NetSniffer");
4951 InsertConfigNode(pLunL0, "Config", &pCfg);
4952 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
4953 if (!bstr.isEmpty()) /* check convention for indicating default file. */
4954 InsertConfigString(pCfg, "File", bstr);
4955 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4956 }
4957
4958
4959 Bstr networkName, trunkName, trunkType;
4960 NetworkAttachmentType_T eAttachmentType;
4961 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4962 switch (eAttachmentType)
4963 {
4964 case NetworkAttachmentType_Null:
4965 break;
4966
4967 case NetworkAttachmentType_NAT:
4968 {
4969 ComPtr<INATEngine> natEngine;
4970 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
4971 InsertConfigString(pLunL0, "Driver", "NAT");
4972 InsertConfigNode(pLunL0, "Config", &pCfg);
4973
4974 /* Configure TFTP prefix and boot filename. */
4975 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4976 if (!bstr.isEmpty())
4977 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
4978 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
4979 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
4980
4981 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
4982 if (!bstr.isEmpty())
4983 InsertConfigString(pCfg, "Network", bstr);
4984 else
4985 {
4986 ULONG uSlot;
4987 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
4988 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
4989 }
4990 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
4991 if (!bstr.isEmpty())
4992 InsertConfigString(pCfg, "BindIP", bstr);
4993 ULONG mtu = 0;
4994 ULONG sockSnd = 0;
4995 ULONG sockRcv = 0;
4996 ULONG tcpSnd = 0;
4997 ULONG tcpRcv = 0;
4998 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
4999 if (mtu)
5000 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5001 if (sockRcv)
5002 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5003 if (sockSnd)
5004 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5005 if (tcpRcv)
5006 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5007 if (tcpSnd)
5008 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5009 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5010 if (!bstr.isEmpty())
5011 {
5012 RemoveConfigValue(pCfg, "TFTPPrefix");
5013 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5014 }
5015 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5016 if (!bstr.isEmpty())
5017 {
5018 RemoveConfigValue(pCfg, "BootFile");
5019 InsertConfigString(pCfg, "BootFile", bstr);
5020 }
5021 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5022 if (!bstr.isEmpty())
5023 InsertConfigString(pCfg, "NextServer", bstr);
5024 BOOL fDNSFlag;
5025 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5026 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5027 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5028 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5029 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5030 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5031
5032 ULONG aliasMode;
5033 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5034 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5035
5036 /* port-forwarding */
5037 SafeArray<BSTR> pfs;
5038 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5039
5040 PCFGMNODE pPFTree = NULL;
5041 if (pfs.size() > 0)
5042 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5043
5044 for (unsigned int i = 0; i < pfs.size(); ++i)
5045 {
5046 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5047
5048 uint16_t port = 0;
5049 BSTR r = pfs[i];
5050 Utf8Str utf = Utf8Str(r);
5051 Utf8Str strName;
5052 Utf8Str strProto;
5053 Utf8Str strHostPort;
5054 Utf8Str strHostIP;
5055 Utf8Str strGuestPort;
5056 Utf8Str strGuestIP;
5057 size_t pos, ppos;
5058 pos = ppos = 0;
5059#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5060 { \
5061 pos = str.find(",", ppos); \
5062 if (pos == Utf8Str::npos) \
5063 { \
5064 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5065 continue; \
5066 } \
5067 res = str.substr(ppos, pos - ppos); \
5068 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5069 ppos = pos + 1; \
5070 } /* no do { ... } while because of 'continue' */
5071 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5072 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5073 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5074 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5075 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5076 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5077#undef ITERATE_TO_NEXT_TERM
5078
5079 uint32_t proto = strProto.toUInt32();
5080 bool fValid = true;
5081 switch (proto)
5082 {
5083 case NATProtocol_UDP:
5084 strProto = "UDP";
5085 break;
5086 case NATProtocol_TCP:
5087 strProto = "TCP";
5088 break;
5089 default:
5090 fValid = false;
5091 }
5092 /* continue with next rule if no valid proto was passed */
5093 if (!fValid)
5094 continue;
5095
5096 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5097
5098 if (!strName.isEmpty())
5099 InsertConfigString(pPF, "Name", strName);
5100
5101 InsertConfigString(pPF, "Protocol", strProto);
5102
5103 if (!strHostIP.isEmpty())
5104 InsertConfigString(pPF, "BindIP", strHostIP);
5105
5106 if (!strGuestIP.isEmpty())
5107 InsertConfigString(pPF, "GuestIP", strGuestIP);
5108
5109 port = RTStrToUInt16(strHostPort.c_str());
5110 if (port)
5111 InsertConfigInteger(pPF, "HostPort", port);
5112
5113 port = RTStrToUInt16(strGuestPort.c_str());
5114 if (port)
5115 InsertConfigInteger(pPF, "GuestPort", port);
5116 }
5117 break;
5118 }
5119
5120 case NetworkAttachmentType_Bridged:
5121 {
5122#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5123 hrc = i_attachToTapInterface(aNetworkAdapter);
5124 if (FAILED(hrc))
5125 {
5126 switch (hrc)
5127 {
5128 case VERR_ACCESS_DENIED:
5129 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5130 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5131 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5132 "change the group of that node and make yourself a member of that group. Make "
5133 "sure that these changes are permanent, especially if you are "
5134 "using udev"));
5135 default:
5136 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5137 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5138 "Failed to initialize Host Interface Networking"));
5139 }
5140 }
5141
5142 Assert((intptr_t)maTapFD[uInstance] >= 0);
5143 if ((intptr_t)maTapFD[uInstance] >= 0)
5144 {
5145 InsertConfigString(pLunL0, "Driver", "HostInterface");
5146 InsertConfigNode(pLunL0, "Config", &pCfg);
5147 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5148 }
5149
5150#elif defined(VBOX_WITH_NETFLT)
5151 /*
5152 * This is the new VBoxNetFlt+IntNet stuff.
5153 */
5154 Bstr BridgedIfName;
5155 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5156 if (FAILED(hrc))
5157 {
5158 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5159 H();
5160 }
5161
5162 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5163 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5164
5165# if defined(RT_OS_DARWIN)
5166 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5167 char szTrunk[8];
5168 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5169 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5170// Quick fix for @bugref{5633}
5171// if (!pszColon)
5172// {
5173// /*
5174// * Dynamic changing of attachment causes an attempt to configure
5175// * network with invalid host adapter (as it is must be changed before
5176// * the attachment), calling Detach here will cause a deadlock.
5177// * See @bugref{4750}.
5178// * hrc = aNetworkAdapter->Detach(); H();
5179// */
5180// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5181// N_("Malformed host interface networking name '%ls'"),
5182// BridgedIfName.raw());
5183// }
5184 if (pszColon)
5185 *pszColon = '\0';
5186 const char *pszTrunk = szTrunk;
5187
5188# elif defined(RT_OS_SOLARIS)
5189 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5190 char szTrunk[256];
5191 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5192 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5193
5194 /*
5195 * Currently don't bother about malformed names here for the sake of people using
5196 * VBoxManage and setting only the NIC name from there. If there is a space we
5197 * chop it off and proceed, otherwise just use whatever we've got.
5198 */
5199 if (pszSpace)
5200 *pszSpace = '\0';
5201
5202 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5203 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5204 if (pszColon)
5205 *pszColon = '\0';
5206
5207 const char *pszTrunk = szTrunk;
5208
5209# elif defined(RT_OS_WINDOWS)
5210 ComPtr<IHostNetworkInterface> hostInterface;
5211 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5212 hostInterface.asOutParam());
5213 if (!SUCCEEDED(hrc))
5214 {
5215 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5216 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5217 N_("Nonexistent host networking interface, name '%ls'"),
5218 BridgedIfName.raw());
5219 }
5220
5221 HostNetworkInterfaceType_T eIfType;
5222 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5223 if (FAILED(hrc))
5224 {
5225 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5226 H();
5227 }
5228
5229 if (eIfType != HostNetworkInterfaceType_Bridged)
5230 {
5231 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5232 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5233 BridgedIfName.raw());
5234 }
5235
5236 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5237 if (FAILED(hrc))
5238 {
5239 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5240 H();
5241 }
5242 Guid hostIFGuid(bstr);
5243
5244 INetCfg *pNc;
5245 ComPtr<INetCfgComponent> pAdaptorComponent;
5246 LPWSTR pszApp;
5247
5248 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5249 Assert(hrc == S_OK);
5250 if (hrc != S_OK)
5251 {
5252 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5253 H();
5254 }
5255
5256 /* get the adapter's INetCfgComponent*/
5257 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5258 pAdaptorComponent.asOutParam());
5259 if (hrc != S_OK)
5260 {
5261 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5262 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5263 H();
5264 }
5265# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5266 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5267 char *pszTrunkName = szTrunkName;
5268 wchar_t * pswzBindName;
5269 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5270 Assert(hrc == S_OK);
5271 if (hrc == S_OK)
5272 {
5273 int cwBindName = (int)wcslen(pswzBindName) + 1;
5274 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5275 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5276 {
5277 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5278 pszTrunkName += cbFullBindNamePrefix-1;
5279 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5280 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5281 {
5282 DWORD err = GetLastError();
5283 hrc = HRESULT_FROM_WIN32(err);
5284 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5285 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5286 hrc, hrc, err));
5287 }
5288 }
5289 else
5290 {
5291 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5292 /** @todo set appropriate error code */
5293 hrc = E_FAIL;
5294 }
5295
5296 if (hrc != S_OK)
5297 {
5298 AssertFailed();
5299 CoTaskMemFree(pswzBindName);
5300 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5301 H();
5302 }
5303
5304 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5305 }
5306 else
5307 {
5308 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5309 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5310 hrc));
5311 H();
5312 }
5313
5314 const char *pszTrunk = szTrunkName;
5315 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5316
5317# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5318# if defined(RT_OS_FREEBSD)
5319 /*
5320 * If we bridge to a tap interface open it the `old' direct way.
5321 * This works and performs better than bridging a physical
5322 * interface via the current FreeBSD vboxnetflt implementation.
5323 */
5324 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5325 hrc = i_attachToTapInterface(aNetworkAdapter);
5326 if (FAILED(hrc))
5327 {
5328 switch (hrc)
5329 {
5330 case VERR_ACCESS_DENIED:
5331 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5332 "Failed to open '/dev/%s' for read/write access. Please check the "
5333 "permissions of that node, and that the net.link.tap.user_open "
5334 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5335 "change the group of that node to vboxusers and make yourself "
5336 "a member of that group. Make sure that these changes are permanent."),
5337 pszBridgedIfName, pszBridgedIfName);
5338 default:
5339 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5340 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5341 "Failed to initialize Host Interface Networking"));
5342 }
5343 }
5344
5345 Assert((intptr_t)maTapFD[uInstance] >= 0);
5346 if ((intptr_t)maTapFD[uInstance] >= 0)
5347 {
5348 InsertConfigString(pLunL0, "Driver", "HostInterface");
5349 InsertConfigNode(pLunL0, "Config", &pCfg);
5350 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5351 }
5352 break;
5353 }
5354# endif
5355 /** @todo Check for malformed names. */
5356 const char *pszTrunk = pszBridgedIfName;
5357
5358 /* Issue a warning if the interface is down */
5359 {
5360 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5361 if (iSock >= 0)
5362 {
5363 struct ifreq Req;
5364 RT_ZERO(Req);
5365 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5366 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5367 if ((Req.ifr_flags & IFF_UP) == 0)
5368 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5369 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5370 pszBridgedIfName);
5371
5372 close(iSock);
5373 }
5374 }
5375
5376# else
5377# error "PORTME (VBOX_WITH_NETFLT)"
5378# endif
5379
5380 InsertConfigString(pLunL0, "Driver", "IntNet");
5381 InsertConfigNode(pLunL0, "Config", &pCfg);
5382 InsertConfigString(pCfg, "Trunk", pszTrunk);
5383 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5384 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5385 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5386 char szNetwork[INTNET_MAX_NETWORK_NAME];
5387
5388# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5389 /*
5390 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5391 * interface name + optional description. We must not pass any description to the VM as it can differ
5392 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5393 */
5394 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5395# else
5396 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5397# endif
5398 InsertConfigString(pCfg, "Network", szNetwork);
5399 networkName = Bstr(szNetwork);
5400 trunkName = Bstr(pszTrunk);
5401 trunkType = Bstr(TRUNKTYPE_NETFLT);
5402
5403# if defined(RT_OS_DARWIN)
5404 /** @todo Come up with a better deal here. Problem is that IHostNetworkInterface is completely useless here. */
5405 if ( strstr(pszBridgedIfName, "Wireless")
5406 || strstr(pszBridgedIfName, "AirPort" ))
5407 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5408# elif defined(RT_OS_LINUX)
5409 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5410 if (iSock >= 0)
5411 {
5412 struct iwreq WRq;
5413
5414 RT_ZERO(WRq);
5415 strncpy(WRq.ifr_name, pszBridgedIfName, IFNAMSIZ);
5416 bool fSharedMacOnWire = ioctl(iSock, SIOCGIWNAME, &WRq) >= 0;
5417 close(iSock);
5418 if (fSharedMacOnWire)
5419 {
5420 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5421 Log(("Set SharedMacOnWire\n"));
5422 }
5423 else
5424 Log(("Failed to get wireless name\n"));
5425 }
5426 else
5427 Log(("Failed to open wireless socket\n"));
5428# elif defined(RT_OS_FREEBSD)
5429 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5430 if (iSock >= 0)
5431 {
5432 struct ieee80211req WReq;
5433 uint8_t abData[32];
5434
5435 RT_ZERO(WReq);
5436 strncpy(WReq.i_name, pszBridgedIfName, sizeof(WReq.i_name));
5437 WReq.i_type = IEEE80211_IOC_SSID;
5438 WReq.i_val = -1;
5439 WReq.i_data = abData;
5440 WReq.i_len = sizeof(abData);
5441
5442 bool fSharedMacOnWire = ioctl(iSock, SIOCG80211, &WReq) >= 0;
5443 close(iSock);
5444 if (fSharedMacOnWire)
5445 {
5446 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5447 Log(("Set SharedMacOnWire\n"));
5448 }
5449 else
5450 Log(("Failed to get wireless name\n"));
5451 }
5452 else
5453 Log(("Failed to open wireless socket\n"));
5454# elif defined(RT_OS_WINDOWS)
5455# define DEVNAME_PREFIX L"\\\\.\\"
5456 /* we are getting the medium type via IOCTL_NDIS_QUERY_GLOBAL_STATS Io Control
5457 * there is a pretty long way till there though since we need to obtain the symbolic link name
5458 * for the adapter device we are going to query given the device Guid */
5459
5460
5461 /* prepend the "\\\\.\\" to the bind name to obtain the link name */
5462
5463 wchar_t FileName[MAX_PATH];
5464 wcscpy(FileName, DEVNAME_PREFIX);
5465 wcscpy((wchar_t*)(((char*)FileName) + sizeof(DEVNAME_PREFIX) - sizeof(FileName[0])), pswzBindName);
5466
5467 /* open the device */
5468 HANDLE hDevice = CreateFile(FileName,
5469 GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5470 NULL,
5471 OPEN_EXISTING,
5472 FILE_ATTRIBUTE_NORMAL,
5473 NULL);
5474
5475 if (hDevice != INVALID_HANDLE_VALUE)
5476 {
5477 bool fSharedMacOnWire = false;
5478
5479 /* now issue the OID_GEN_PHYSICAL_MEDIUM query */
5480 DWORD Oid = OID_GEN_PHYSICAL_MEDIUM;
5481 NDIS_PHYSICAL_MEDIUM PhMedium;
5482 DWORD cbResult;
5483 if (DeviceIoControl(hDevice,
5484 IOCTL_NDIS_QUERY_GLOBAL_STATS,
5485 &Oid,
5486 sizeof(Oid),
5487 &PhMedium,
5488 sizeof(PhMedium),
5489 &cbResult,
5490 NULL))
5491 {
5492 /* that was simple, now examine PhMedium */
5493 if ( PhMedium == NdisPhysicalMediumWirelessWan
5494 || PhMedium == NdisPhysicalMediumWirelessLan
5495 || PhMedium == NdisPhysicalMediumNative802_11
5496 || PhMedium == NdisPhysicalMediumBluetooth)
5497 fSharedMacOnWire = true;
5498 }
5499 else
5500 {
5501 int winEr = GetLastError();
5502 LogRel(("Console::configNetwork: DeviceIoControl failed, err (0x%x), ignoring\n", winEr));
5503 Assert(winEr == ERROR_INVALID_PARAMETER || winEr == ERROR_NOT_SUPPORTED || winEr == ERROR_BAD_COMMAND);
5504 }
5505 CloseHandle(hDevice);
5506
5507 if (fSharedMacOnWire)
5508 {
5509 Log(("this is a wireless adapter"));
5510 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5511 Log(("Set SharedMacOnWire\n"));
5512 }
5513 else
5514 Log(("this is NOT a wireless adapter"));
5515 }
5516 else
5517 {
5518 int winEr = GetLastError();
5519 AssertLogRelMsgFailed(("Console::configNetwork: CreateFile failed, err (0x%x), ignoring\n", winEr));
5520 }
5521
5522 CoTaskMemFree(pswzBindName);
5523
5524 pAdaptorComponent.setNull();
5525 /* release the pNc finally */
5526 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5527# else
5528 /** @todo PORTME: wireless detection */
5529# endif
5530
5531# if defined(RT_OS_SOLARIS)
5532# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5533 /* Zone access restriction, don't allow snooping the global zone. */
5534 zoneid_t ZoneId = getzoneid();
5535 if (ZoneId != GLOBAL_ZONEID)
5536 {
5537 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5538 }
5539# endif
5540# endif
5541
5542#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5543 /* NOTHING TO DO HERE */
5544#elif defined(RT_OS_LINUX)
5545/// @todo aleksey: is there anything to be done here?
5546#elif defined(RT_OS_FREEBSD)
5547/** @todo FreeBSD: Check out this later (HIF networking). */
5548#else
5549# error "Port me"
5550#endif
5551 break;
5552 }
5553
5554 case NetworkAttachmentType_Internal:
5555 {
5556 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5557 if (!bstr.isEmpty())
5558 {
5559 InsertConfigString(pLunL0, "Driver", "IntNet");
5560 InsertConfigNode(pLunL0, "Config", &pCfg);
5561 InsertConfigString(pCfg, "Network", bstr);
5562 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5563 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5564 networkName = bstr;
5565 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5566 }
5567 break;
5568 }
5569
5570 case NetworkAttachmentType_HostOnly:
5571 {
5572 InsertConfigString(pLunL0, "Driver", "IntNet");
5573 InsertConfigNode(pLunL0, "Config", &pCfg);
5574
5575 Bstr HostOnlyName;
5576 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5577 if (FAILED(hrc))
5578 {
5579 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5580 H();
5581 }
5582
5583 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5584 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5585 ComPtr<IHostNetworkInterface> hostInterface;
5586 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5587 hostInterface.asOutParam());
5588 if (!SUCCEEDED(rc))
5589 {
5590 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5591 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5592 N_("Nonexistent host networking interface, name '%ls'"),
5593 HostOnlyName.raw());
5594 }
5595
5596 char szNetwork[INTNET_MAX_NETWORK_NAME];
5597 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5598
5599#if defined(RT_OS_WINDOWS)
5600# ifndef VBOX_WITH_NETFLT
5601 hrc = E_NOTIMPL;
5602 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5603 H();
5604# else /* defined VBOX_WITH_NETFLT*/
5605 /** @todo r=bird: Put this in a function. */
5606
5607 HostNetworkInterfaceType_T eIfType;
5608 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5609 if (FAILED(hrc))
5610 {
5611 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5612 H();
5613 }
5614
5615 if (eIfType != HostNetworkInterfaceType_HostOnly)
5616 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5617 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5618 HostOnlyName.raw());
5619
5620 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5621 if (FAILED(hrc))
5622 {
5623 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5624 H();
5625 }
5626 Guid hostIFGuid(bstr);
5627
5628 INetCfg *pNc;
5629 ComPtr<INetCfgComponent> pAdaptorComponent;
5630 LPWSTR pszApp;
5631 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5632 Assert(hrc == S_OK);
5633 if (hrc != S_OK)
5634 {
5635 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5636 H();
5637 }
5638
5639 /* get the adapter's INetCfgComponent*/
5640 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5641 pAdaptorComponent.asOutParam());
5642 if (hrc != S_OK)
5643 {
5644 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5645 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5646 H();
5647 }
5648# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5649 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5650 char *pszTrunkName = szTrunkName;
5651 wchar_t * pswzBindName;
5652 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5653 Assert(hrc == S_OK);
5654 if (hrc == S_OK)
5655 {
5656 int cwBindName = (int)wcslen(pswzBindName) + 1;
5657 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5658 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5659 {
5660 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5661 pszTrunkName += cbFullBindNamePrefix-1;
5662 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5663 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5664 {
5665 DWORD err = GetLastError();
5666 hrc = HRESULT_FROM_WIN32(err);
5667 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5668 hrc, hrc, err));
5669 }
5670 }
5671 else
5672 {
5673 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5674 /** @todo set appropriate error code */
5675 hrc = E_FAIL;
5676 }
5677
5678 if (hrc != S_OK)
5679 {
5680 AssertFailed();
5681 CoTaskMemFree(pswzBindName);
5682 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5683 H();
5684 }
5685 }
5686 else
5687 {
5688 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5689 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5690 hrc, hrc));
5691 H();
5692 }
5693
5694
5695 CoTaskMemFree(pswzBindName);
5696
5697 /* The old NDIS5.1 version of driver uses TRUNKTYPE_NETADP */
5698 trunkType = IsNdis6() ? TRUNKTYPE_NETFLT : TRUNKTYPE_NETADP;
5699 InsertConfigInteger(pCfg, "TrunkType", trunkType == TRUNKTYPE_NETFLT ? kIntNetTrunkType_NetFlt : kIntNetTrunkType_NetAdp);
5700
5701 pAdaptorComponent.setNull();
5702 /* release the pNc finally */
5703 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5704
5705 const char *pszTrunk = szTrunkName;
5706
5707 InsertConfigString(pCfg, "Trunk", pszTrunk);
5708 InsertConfigString(pCfg, "Network", szNetwork);
5709 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5710 windows only?? */
5711 networkName = Bstr(szNetwork);
5712 trunkName = Bstr(pszTrunk);
5713# endif /* defined VBOX_WITH_NETFLT*/
5714#elif defined(RT_OS_DARWIN)
5715 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5716 InsertConfigString(pCfg, "Network", szNetwork);
5717 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5718 networkName = Bstr(szNetwork);
5719 trunkName = Bstr(pszHostOnlyName);
5720 trunkType = TRUNKTYPE_NETADP;
5721#else
5722 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5723 InsertConfigString(pCfg, "Network", szNetwork);
5724 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5725 networkName = Bstr(szNetwork);
5726 trunkName = Bstr(pszHostOnlyName);
5727 trunkType = TRUNKTYPE_NETFLT;
5728#endif
5729 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5730
5731#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5732
5733 Bstr tmpAddr, tmpMask;
5734
5735 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5736 pszHostOnlyName).raw(),
5737 tmpAddr.asOutParam());
5738 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5739 {
5740 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5741 pszHostOnlyName).raw(),
5742 tmpMask.asOutParam());
5743 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5744 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5745 tmpMask.raw());
5746 else
5747 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5748 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5749 }
5750 else
5751 {
5752 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5753 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5754 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5755 }
5756
5757 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5758
5759 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5760 pszHostOnlyName).raw(),
5761 tmpAddr.asOutParam());
5762 if (SUCCEEDED(hrc))
5763 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5764 tmpMask.asOutParam());
5765 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5766 {
5767 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5768 Utf8Str(tmpMask).toUInt32());
5769 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5770 }
5771#endif
5772 break;
5773 }
5774
5775 case NetworkAttachmentType_Generic:
5776 {
5777 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5778 SafeArray<BSTR> names;
5779 SafeArray<BSTR> values;
5780 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5781 ComSafeArrayAsOutParam(names),
5782 ComSafeArrayAsOutParam(values)); H();
5783
5784 InsertConfigString(pLunL0, "Driver", bstr);
5785 InsertConfigNode(pLunL0, "Config", &pCfg);
5786 for (size_t ii = 0; ii < names.size(); ++ii)
5787 {
5788 if (values[ii] && *values[ii])
5789 {
5790 Utf8Str name = names[ii];
5791 Utf8Str value = values[ii];
5792 InsertConfigString(pCfg, name.c_str(), value);
5793 }
5794 }
5795 break;
5796 }
5797
5798 case NetworkAttachmentType_NATNetwork:
5799 {
5800 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5801 if (!bstr.isEmpty())
5802 {
5803 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5804 InsertConfigString(pLunL0, "Driver", "IntNet");
5805 InsertConfigNode(pLunL0, "Config", &pCfg);
5806 InsertConfigString(pCfg, "Network", bstr);
5807 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5808 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5809 networkName = bstr;
5810 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5811 }
5812 break;
5813 }
5814
5815 default:
5816 AssertMsgFailed(("should not get here!\n"));
5817 break;
5818 }
5819
5820 /*
5821 * Attempt to attach the driver.
5822 */
5823 switch (eAttachmentType)
5824 {
5825 case NetworkAttachmentType_Null:
5826 break;
5827
5828 case NetworkAttachmentType_Bridged:
5829 case NetworkAttachmentType_Internal:
5830 case NetworkAttachmentType_HostOnly:
5831 case NetworkAttachmentType_NAT:
5832 case NetworkAttachmentType_Generic:
5833 case NetworkAttachmentType_NATNetwork:
5834 {
5835 if (SUCCEEDED(hrc) && SUCCEEDED(rc))
5836 {
5837 if (fAttachDetach)
5838 {
5839 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5840 //AssertRC(rc);
5841 }
5842
5843 {
5844 /** @todo pritesh: get the dhcp server name from the
5845 * previous network configuration and then stop the server
5846 * else it may conflict with the dhcp server running with
5847 * the current attachment type
5848 */
5849 /* Stop the hostonly DHCP Server */
5850 }
5851
5852 /*
5853 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5854 */
5855 if ( !networkName.isEmpty()
5856 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5857 {
5858 /*
5859 * Until we implement service reference counters DHCP Server will be stopped
5860 * by DHCPServerRunner destructor.
5861 */
5862 ComPtr<IDHCPServer> dhcpServer;
5863 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5864 dhcpServer.asOutParam());
5865 if (SUCCEEDED(hrc))
5866 {
5867 /* there is a DHCP server available for this network */
5868 BOOL fEnabledDhcp;
5869 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5870 if (FAILED(hrc))
5871 {
5872 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5873 H();
5874 }
5875
5876 if (fEnabledDhcp)
5877 hrc = dhcpServer->Start(networkName.raw(),
5878 trunkName.raw(),
5879 trunkType.raw());
5880 }
5881 else
5882 hrc = S_OK;
5883 }
5884 }
5885
5886 break;
5887 }
5888
5889 default:
5890 AssertMsgFailed(("should not get here!\n"));
5891 break;
5892 }
5893
5894 meAttachmentType[uInstance] = eAttachmentType;
5895 }
5896 catch (ConfigError &x)
5897 {
5898 // InsertConfig threw something:
5899 return x.m_vrc;
5900 }
5901
5902#undef H
5903
5904 return VINF_SUCCESS;
5905}
5906
5907#ifdef VBOX_WITH_GUEST_PROPS
5908/**
5909 * Set an array of guest properties
5910 */
5911static void configSetProperties(VMMDev * const pVMMDev,
5912 void *names,
5913 void *values,
5914 void *timestamps,
5915 void *flags)
5916{
5917 VBOXHGCMSVCPARM parms[4];
5918
5919 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5920 parms[0].u.pointer.addr = names;
5921 parms[0].u.pointer.size = 0; /* We don't actually care. */
5922 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5923 parms[1].u.pointer.addr = values;
5924 parms[1].u.pointer.size = 0; /* We don't actually care. */
5925 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5926 parms[2].u.pointer.addr = timestamps;
5927 parms[2].u.pointer.size = 0; /* We don't actually care. */
5928 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
5929 parms[3].u.pointer.addr = flags;
5930 parms[3].u.pointer.size = 0; /* We don't actually care. */
5931
5932 pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5933 guestProp::SET_PROPS_HOST,
5934 4,
5935 &parms[0]);
5936}
5937
5938/**
5939 * Set a single guest property
5940 */
5941static void configSetProperty(VMMDev * const pVMMDev,
5942 const char *pszName,
5943 const char *pszValue,
5944 const char *pszFlags)
5945{
5946 VBOXHGCMSVCPARM parms[4];
5947
5948 AssertPtrReturnVoid(pszName);
5949 AssertPtrReturnVoid(pszValue);
5950 AssertPtrReturnVoid(pszFlags);
5951 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
5952 parms[0].u.pointer.addr = (void *)pszName;
5953 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
5954 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
5955 parms[1].u.pointer.addr = (void *)pszValue;
5956 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
5957 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
5958 parms[2].u.pointer.addr = (void *)pszFlags;
5959 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
5960 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::SET_PROP_HOST, 3,
5961 &parms[0]);
5962}
5963
5964/**
5965 * Set the global flags value by calling the service
5966 * @returns the status returned by the call to the service
5967 *
5968 * @param pTable the service instance handle
5969 * @param eFlags the flags to set
5970 */
5971int configSetGlobalPropertyFlags(VMMDev * const pVMMDev,
5972 guestProp::ePropFlags eFlags)
5973{
5974 VBOXHGCMSVCPARM paParm;
5975 paParm.setUInt32(eFlags);
5976 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc",
5977 guestProp::SET_GLOBAL_FLAGS_HOST, 1,
5978 &paParm);
5979 if (RT_FAILURE(rc))
5980 {
5981 char szFlags[guestProp::MAX_FLAGS_LEN];
5982 if (RT_FAILURE(writeFlags(eFlags, szFlags)))
5983 Log(("Failed to set the global flags.\n"));
5984 else
5985 Log(("Failed to set the global flags \"%s\".\n", szFlags));
5986 }
5987 return rc;
5988}
5989#endif /* VBOX_WITH_GUEST_PROPS */
5990
5991/**
5992 * Set up the Guest Property service, populate it with properties read from
5993 * the machine XML and set a couple of initial properties.
5994 */
5995/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
5996{
5997#ifdef VBOX_WITH_GUEST_PROPS
5998 AssertReturn(pvConsole, VERR_INVALID_POINTER);
5999 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6000 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
6001
6002 /* Load the service */
6003 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
6004
6005 if (RT_FAILURE(rc))
6006 {
6007 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
6008 /* That is not a fatal failure. */
6009 rc = VINF_SUCCESS;
6010 }
6011 else
6012 {
6013 /*
6014 * Initialize built-in properties that can be changed and saved.
6015 *
6016 * These are typically transient properties that the guest cannot
6017 * change.
6018 */
6019
6020 {
6021 VBOXHGCMSVCPARM Params[2];
6022 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", guestProp::GET_DBGF_INFO_FN, 2, &Params[0]);
6023 if (RT_SUCCESS(rc2))
6024 {
6025 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
6026 void *pService = (void*)Params[1].u.pointer.addr;
6027 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pService);
6028 }
6029 }
6030
6031 /* Sysprep execution by VBoxService. */
6032 configSetProperty(pConsole->m_pVMMDev,
6033 "/VirtualBox/HostGuest/SysprepExec", "",
6034 "TRANSIENT, RDONLYGUEST");
6035 configSetProperty(pConsole->m_pVMMDev,
6036 "/VirtualBox/HostGuest/SysprepArgs", "",
6037 "TRANSIENT, RDONLYGUEST");
6038
6039 /*
6040 * Pull over the properties from the server.
6041 */
6042 SafeArray<BSTR> namesOut;
6043 SafeArray<BSTR> valuesOut;
6044 SafeArray<LONG64> timestampsOut;
6045 SafeArray<BSTR> flagsOut;
6046 HRESULT hrc;
6047 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
6048 ComSafeArrayAsOutParam(valuesOut),
6049 ComSafeArrayAsOutParam(timestampsOut),
6050 ComSafeArrayAsOutParam(flagsOut));
6051 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6052 size_t cProps = namesOut.size();
6053 size_t cAlloc = cProps + 1;
6054 if ( valuesOut.size() != cProps
6055 || timestampsOut.size() != cProps
6056 || flagsOut.size() != cProps
6057 )
6058 AssertFailedReturn(VERR_INVALID_PARAMETER);
6059
6060 char **papszNames, **papszValues, **papszFlags;
6061 char szEmpty[] = "";
6062 LONG64 *pai64Timestamps;
6063 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6064 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6065 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
6066 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6067 if (papszNames && papszValues && pai64Timestamps && papszFlags)
6068 {
6069 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
6070 {
6071 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
6072 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
6073 if (RT_FAILURE(rc))
6074 break;
6075 if (valuesOut[i])
6076 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6077 else
6078 papszValues[i] = szEmpty;
6079 if (RT_FAILURE(rc))
6080 break;
6081 pai64Timestamps[i] = timestampsOut[i];
6082 if (flagsOut[i])
6083 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6084 else
6085 papszFlags[i] = szEmpty;
6086 }
6087 if (RT_SUCCESS(rc))
6088 configSetProperties(pConsole->m_pVMMDev,
6089 (void *)papszNames,
6090 (void *)papszValues,
6091 (void *)pai64Timestamps,
6092 (void *)papszFlags);
6093 for (unsigned i = 0; i < cProps; ++i)
6094 {
6095 RTStrFree(papszNames[i]);
6096 if (valuesOut[i])
6097 RTStrFree(papszValues[i]);
6098 if (flagsOut[i])
6099 RTStrFree(papszFlags[i]);
6100 }
6101 }
6102 else
6103 rc = VERR_NO_MEMORY;
6104 RTMemTmpFree(papszNames);
6105 RTMemTmpFree(papszValues);
6106 RTMemTmpFree(pai64Timestamps);
6107 RTMemTmpFree(papszFlags);
6108 AssertRCReturn(rc, rc);
6109
6110 /*
6111 * These properties have to be set before pulling over the properties
6112 * from the machine XML, to ensure that properties saved in the XML
6113 * will override them.
6114 */
6115 /* Set the raw VBox version string as a guest property. Used for host/guest
6116 * version comparison. */
6117 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6118 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6119 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6120 * information/branding and/or pre-release tags. */
6121 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6122 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6123 /* Set the VBox SVN revision as a guest property */
6124 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6125 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6126
6127 /*
6128 * Register the host notification callback
6129 */
6130 HGCMSVCEXTHANDLE hDummy;
6131 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6132 Console::i_doGuestPropNotification,
6133 pvConsole);
6134
6135#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6136 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev,
6137 guestProp::RDONLYGUEST);
6138 AssertRCReturn(rc, rc);
6139#endif
6140
6141 Log(("Set VBoxGuestPropSvc property store\n"));
6142 }
6143 return VINF_SUCCESS;
6144#else /* !VBOX_WITH_GUEST_PROPS */
6145 return VERR_NOT_SUPPORTED;
6146#endif /* !VBOX_WITH_GUEST_PROPS */
6147}
6148
6149/**
6150 * Set up the Guest Control service.
6151 */
6152/* static */ int Console::i_configGuestControl(void *pvConsole)
6153{
6154#ifdef VBOX_WITH_GUEST_CONTROL
6155 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6156 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6157
6158 /* Load the service */
6159 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6160
6161 if (RT_FAILURE(rc))
6162 {
6163 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6164 /* That is not a fatal failure. */
6165 rc = VINF_SUCCESS;
6166 }
6167 else
6168 {
6169 HGCMSVCEXTHANDLE hDummy;
6170 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6171 &Guest::i_notifyCtrlDispatcher,
6172 pConsole->i_getGuest());
6173 if (RT_FAILURE(rc))
6174 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6175 else
6176 LogRel(("Guest Control service loaded\n"));
6177 }
6178
6179 return rc;
6180#else /* !VBOX_WITH_GUEST_CONTROL */
6181 return VERR_NOT_SUPPORTED;
6182#endif /* !VBOX_WITH_GUEST_CONTROL */
6183}
Note: See TracBrowser for help on using the repository browser.

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