VirtualBox

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

Last change on this file since 72343 was 72343, checked in by vboxsync, 6 years ago

VMM,ConsoleImpl2: NEM and 64-bit guests. Sync NXE state with PGM. bugref:9044

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

© 2023 Oracle
ContactPrivacy policyTerms of Use