VirtualBox

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

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

Main,FE/VBoxManage: Allow changing the UART type of the serial ports through the API

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 257.8 KB
Line 
1/* $Id: ConsoleImpl2.cpp 73768 2018-08-19 19:07:19Z 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> pGuestOSType;
823 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());
824
825 BOOL fOsXGuest = FALSE;
826 if (!pGuestOSType.isNull())
827 {
828 Bstr guestTypeFamilyId;
829 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();
830 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");
831 }
832
833 ULONG maxNetworkAdapters;
834 hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();
835
836 /*
837 * Get root node first.
838 * This is the only node in the tree.
839 */
840 PCFGMNODE pRoot = CFGMR3GetRootU(pUVM);
841 Assert(pRoot);
842
843 // InsertConfigString throws
844 try
845 {
846
847 /*
848 * Set the root (and VMM) level values.
849 */
850 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
851 InsertConfigString(pRoot, "Name", bstr);
852 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));
853 InsertConfigInteger(pRoot, "RamSize", cbRam);
854 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);
855 InsertConfigInteger(pRoot, "NumCPUs", cCpus);
856 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);
857 InsertConfigInteger(pRoot, "TimerMillies", 10);
858#ifdef VBOX_WITH_RAW_MODE
859 InsertConfigInteger(pRoot, "RawR3Enabled", 1); /* boolean */
860 InsertConfigInteger(pRoot, "RawR0Enabled", 1); /* boolean */
861 /** @todo Config: RawR0, PATMEnabled and CSAMEnabled needs attention later. */
862 InsertConfigInteger(pRoot, "PATMEnabled", 1); /* boolean */
863 InsertConfigInteger(pRoot, "CSAMEnabled", 1); /* boolean */
864#endif
865
866#ifdef VBOX_WITH_RAW_RING1
867 if (osTypeId == "QNX")
868 {
869 /* QNX needs special treatment in raw mode due to its use of ring-1. */
870 InsertConfigInteger(pRoot, "RawR1Enabled", 1); /* boolean */
871 }
872#endif
873
874 BOOL fPageFusion = FALSE;
875 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();
876 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */
877
878 /* Not necessary, but makes sure this setting ends up in the release log. */
879 ULONG ulBalloonSize = 0;
880 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();
881 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);
882
883 /*
884 * EM values (before CPUM as it may need to set IemExecutesAll).
885 */
886 PCFGMNODE pEM;
887 InsertConfigNode(pRoot, "EM", &pEM);
888
889 /* Triple fault behavior. */
890 BOOL fTripleFaultReset = false;
891 hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();
892 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);
893
894 /*
895 * CPUM values.
896 */
897 PCFGMNODE pCPUM;
898 InsertConfigNode(pRoot, "CPUM", &pCPUM);
899 PCFGMNODE pIsaExts;
900 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);
901
902 /* Host CPUID leaf overrides. */
903 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)
904 {
905 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;
906 hrc = pMachine->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);
907 if (hrc == E_INVALIDARG)
908 break;
909 H();
910 PCFGMNODE pLeaf;
911 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);
912 /** @todo Figure out how to tell the VMM about uSubLeaf */
913 InsertConfigInteger(pLeaf, "eax", uEax);
914 InsertConfigInteger(pLeaf, "ebx", uEbx);
915 InsertConfigInteger(pLeaf, "ecx", uEcx);
916 InsertConfigInteger(pLeaf, "edx", uEdx);
917 }
918
919 /* We must limit CPUID count for Windows NT 4, as otherwise it stops
920 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */
921 if (osTypeId == "WindowsNT4")
922 {
923 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));
924 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);
925 }
926
927 /* Expose CMPXCHG16B. Currently a hack. */
928 if ( osTypeId == "Windows81_64"
929 || osTypeId == "Windows2012_64"
930 || osTypeId == "Windows10_64"
931 || osTypeId == "Windows2016_64")
932 {
933 LogRel(("Enabling CMPXCHG16B for Windows 8.1 / 2k12 or newer guests\n"));
934 InsertConfigInteger(pIsaExts, "CMPXCHG16B", true);
935 }
936
937 if (fOsXGuest)
938 {
939 /* Expose extended MWAIT features to Mac OS X guests. */
940 LogRel(("Using MWAIT extensions\n"));
941 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);
942
943 /* Fake the CPU family/model so the guest works. This is partly
944 because older mac releases really doesn't work on newer cpus,
945 and partly because mac os x expects more from systems with newer
946 cpus (MSRs, power features, whatever). */
947 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;
948 if ( osTypeId == "MacOS"
949 || osTypeId == "MacOS_64")
950 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */
951 else if ( osTypeId == "MacOS106"
952 || osTypeId == "MacOS106_64")
953 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */
954 else if ( osTypeId == "MacOS107"
955 || osTypeId == "MacOS107_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 == "MacOS108"
959 || osTypeId == "MacOS108_64")
960 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out
961 what is required here. */
962 else if ( osTypeId == "MacOS109"
963 || osTypeId == "MacOS109_64")
964 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure
965 out what is required here. */
966 if (uMaxIntelFamilyModelStep != UINT32_MAX)
967 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);
968 }
969
970 /* CPU Portability level, */
971 ULONG uCpuIdPortabilityLevel = 0;
972 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();
973 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);
974
975 /* Physical Address Extension (PAE) */
976 BOOL fEnablePAE = false;
977 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();
978 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);
979
980 /* APIC/X2APIC configuration */
981 BOOL fEnableAPIC = true;
982 BOOL fEnableX2APIC = true;
983 hrc = pMachine->GetCPUProperty(CPUPropertyType_APIC, &fEnableAPIC); H();
984 hrc = pMachine->GetCPUProperty(CPUPropertyType_X2APIC, &fEnableX2APIC); H();
985 if (fEnableX2APIC)
986 Assert(fEnableAPIC);
987
988 /* CPUM profile name. */
989 hrc = pMachine->COMGETTER(CPUProfile)(bstr.asOutParam()); H();
990 InsertConfigString(pCPUM, "GuestCpuName", bstr);
991
992 /*
993 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs
994 * correctly. There are way too many #UDs we'll miss using VT-x,
995 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes
996 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).
997 */
998 if ( bstr.equals("Intel 80386") /* just for now */
999 || bstr.equals("Intel 80286")
1000 || bstr.equals("Intel 80186")
1001 || bstr.equals("Nec V20")
1002 || bstr.equals("Intel 8086") )
1003 {
1004 InsertConfigInteger(pEM, "IemExecutesAll", true);
1005 if (!bstr.equals("Intel 80386"))
1006 {
1007 fEnableAPIC = false;
1008 fIOAPIC = false;
1009 }
1010 fEnableX2APIC = false;
1011 }
1012
1013 /* Adjust firmware APIC handling to stay within the VCPU limits. */
1014 if (uFwAPIC == 2 && !fEnableX2APIC)
1015 {
1016 if (fEnableAPIC)
1017 uFwAPIC = 1;
1018 else
1019 uFwAPIC = 0;
1020 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));
1021 }
1022 else if (uFwAPIC == 1 && !fEnableAPIC)
1023 {
1024 uFwAPIC = 0;
1025 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));
1026 }
1027
1028 /* Speculation Control. */
1029 BOOL fSpecCtrl = FALSE;
1030 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrl, &fSpecCtrl); H();
1031 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);
1032
1033 /* Nested VT-x / AMD-V. */
1034 BOOL fNestedHWVirt = FALSE;
1035 hrc = pMachine->GetCPUProperty(CPUPropertyType_HWVirt, &fNestedHWVirt); H();
1036 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);
1037
1038 /*
1039 * Hardware virtualization extensions.
1040 */
1041 BOOL fSupportsHwVirtEx;
1042 hrc = host->GetProcessorFeature(ProcessorFeature_HWVirtEx, &fSupportsHwVirtEx); H();
1043
1044 BOOL fIsGuest64Bit;
1045 hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H();
1046 if (fIsGuest64Bit)
1047 {
1048 BOOL fSupportsLongMode;
1049 hrc = host->GetProcessorFeature(ProcessorFeature_LongMode, &fSupportsLongMode); H();
1050 if (!fSupportsLongMode)
1051 {
1052 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support 64-bit.\n"));
1053 fIsGuest64Bit = FALSE;
1054 }
1055 if (!fSupportsHwVirtEx)
1056 {
1057 LogRel(("WARNING! 64-bit guest type selected but the host CPU does NOT support HW virtualization.\n"));
1058 fIsGuest64Bit = FALSE;
1059 }
1060 }
1061
1062 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */
1063 if (!fEnableAPIC)
1064 {
1065 if (fIsGuest64Bit)
1066 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Cannot disable the APIC for a 64-bit guest."));
1067 if (cCpus > 1)
1068 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Cannot disable the APIC for an SMP guest."));
1069 if (fIOAPIC)
1070 {
1071 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1072 N_("Cannot disable the APIC when the I/O APIC is present."));
1073 }
1074 }
1075
1076 BOOL fHMEnabled;
1077 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();
1078 if (cCpus > 1 && !fHMEnabled)
1079 {
1080 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));
1081 fHMEnabled = TRUE;
1082 }
1083
1084 BOOL fHMForced;
1085#ifdef VBOX_WITH_RAW_MODE
1086 /* - With more than 4GB PGM will use different RAMRANGE sizes for raw
1087 mode and hv mode to optimize lookup times.
1088 - With more than one virtual CPU, raw-mode isn't a fallback option.
1089 - With a 64-bit guest, raw-mode isn't a fallback option either. */
1090 fHMForced = fHMEnabled
1091 && ( cbRam + cbRamHole > _4G
1092 || cCpus > 1
1093 || fIsGuest64Bit);
1094# ifdef RT_OS_DARWIN
1095 fHMForced = fHMEnabled;
1096# endif
1097 if (fHMForced)
1098 {
1099 if (cbRam + cbRamHole > _4G)
1100 LogRel(("fHMForced=true - Lots of RAM\n"));
1101 if (cCpus > 1)
1102 LogRel(("fHMForced=true - SMP\n"));
1103 if (fIsGuest64Bit)
1104 LogRel(("fHMForced=true - 64-bit guest\n"));
1105# ifdef RT_OS_DARWIN
1106 LogRel(("fHMForced=true - Darwin host\n"));
1107# endif
1108 }
1109#else /* !VBOX_WITH_RAW_MODE */
1110 fHMEnabled = fHMForced = TRUE;
1111 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));
1112#endif /* !VBOX_WITH_RAW_MODE */
1113 if (!fHMForced) /* No need to query if already forced above. */
1114 {
1115 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();
1116 if (fHMForced)
1117 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));
1118 }
1119 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);
1120
1121 /* /HM/xyz */
1122 PCFGMNODE pHM;
1123 InsertConfigNode(pRoot, "HM", &pHM);
1124 InsertConfigInteger(pHM, "HMForced", fHMForced);
1125 if (fHMEnabled)
1126 {
1127 /* Indicate whether 64-bit guests are supported or not. */
1128 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);
1129#if ARCH_BITS == 32 /* The recompiler must use VBoxREM64 (32-bit host only). */
1130 PCFGMNODE pREM;
1131 InsertConfigNode(pRoot, "REM", &pREM);
1132 InsertConfigInteger(pREM, "64bitEnabled", 1);
1133#endif
1134
1135 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,
1136 but that requires quite a bit of API change in Main. */
1137 if ( fIOAPIC
1138 && ( osTypeId == "WindowsNT4"
1139 || osTypeId == "Windows2000"
1140 || osTypeId == "WindowsXP"
1141 || osTypeId == "Windows2003"))
1142 {
1143 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)
1144 * We may want to consider adding more guest OSes (Solaris) later on.
1145 */
1146 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);
1147 }
1148 }
1149
1150 /* HWVirtEx exclusive mode */
1151 BOOL fHMExclusive = true;
1152 hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();
1153 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);
1154
1155 /* Nested paging (VT-x/AMD-V) */
1156 BOOL fEnableNestedPaging = false;
1157 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();
1158 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);
1159
1160 /* Large pages; requires nested paging */
1161 BOOL fEnableLargePages = false;
1162 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();
1163 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);
1164
1165 /* VPID (VT-x) */
1166 BOOL fEnableVPID = false;
1167 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();
1168 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);
1169
1170 /* Unrestricted execution aka UX (VT-x) */
1171 BOOL fEnableUX = false;
1172 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();
1173 InsertConfigInteger(pHM, "EnableUX", fEnableUX);
1174
1175 /* Indirect branch prediction boundraries. */
1176 BOOL fIBPBOnVMExit = false;
1177 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMExit, &fIBPBOnVMExit); H();
1178 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);
1179
1180 BOOL fIBPBOnVMEntry = false;
1181 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMEntry, &fIBPBOnVMEntry); H();
1182 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);
1183
1184 BOOL fSpecCtrlByHost = false;
1185 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrlByHost, &fSpecCtrlByHost); H();
1186 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);
1187
1188 /* Reset overwrite. */
1189 if (i_isResetTurnedIntoPowerOff())
1190 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);
1191
1192 /* Use NEM rather than HM. */
1193 BOOL fUseNativeApi = false;
1194 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();
1195 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);
1196
1197 /*
1198 * NEM
1199 */
1200 PCFGMNODE pNEM;
1201 InsertConfigNode(pRoot, "NEM", &pNEM);
1202 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);
1203
1204 /*
1205 * Paravirt. provider.
1206 */
1207 PCFGMNODE pParavirtNode;
1208 InsertConfigNode(pRoot, "GIM", &pParavirtNode);
1209 const char *pcszParavirtProvider;
1210 bool fGimDeviceNeeded = true;
1211 switch (paravirtProvider)
1212 {
1213 case ParavirtProvider_None:
1214 pcszParavirtProvider = "None";
1215 fGimDeviceNeeded = false;
1216 break;
1217
1218 case ParavirtProvider_Minimal:
1219 pcszParavirtProvider = "Minimal";
1220 break;
1221
1222 case ParavirtProvider_HyperV:
1223 pcszParavirtProvider = "HyperV";
1224 break;
1225
1226 case ParavirtProvider_KVM:
1227 pcszParavirtProvider = "KVM";
1228 break;
1229
1230 default:
1231 AssertMsgFailed(("Invalid paravirtProvider=%d\n", paravirtProvider));
1232 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),
1233 paravirtProvider);
1234 }
1235 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);
1236
1237 /*
1238 * Parse paravirt. debug options.
1239 */
1240 bool fGimDebug = false;
1241 com::Utf8Str strGimDebugAddress = "127.0.0.1";
1242 uint32_t uGimDebugPort = 50000;
1243 if (strParavirtDebug.isNotEmpty())
1244 {
1245 /* Hyper-V debug options. */
1246 if (paravirtProvider == ParavirtProvider_HyperV)
1247 {
1248 bool fGimHvDebug = false;
1249 com::Utf8Str strGimHvVendor;
1250 bool fGimHvVsIf = false;
1251 bool fGimHvHypercallIf = false;
1252
1253 size_t uPos = 0;
1254 com::Utf8Str strDebugOptions = strParavirtDebug;
1255 com::Utf8Str strKey;
1256 com::Utf8Str strVal;
1257 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)
1258 {
1259 if (strKey == "enabled")
1260 {
1261 if (strVal.toUInt32() == 1)
1262 {
1263 /* Apply defaults.
1264 The defaults are documented in the user manual,
1265 changes need to be reflected accordingly. */
1266 fGimHvDebug = true;
1267 strGimHvVendor = "Microsoft Hv";
1268 fGimHvVsIf = true;
1269 fGimHvHypercallIf = false;
1270 }
1271 /* else: ignore, i.e. don't assert below with 'enabled=0'. */
1272 }
1273 else if (strKey == "address")
1274 strGimDebugAddress = strVal;
1275 else if (strKey == "port")
1276 uGimDebugPort = strVal.toUInt32();
1277 else if (strKey == "vendor")
1278 strGimHvVendor = strVal;
1279 else if (strKey == "vsinterface")
1280 fGimHvVsIf = RT_BOOL(strVal.toUInt32());
1281 else if (strKey == "hypercallinterface")
1282 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());
1283 else
1284 {
1285 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));
1286 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1287 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),
1288 strDebugOptions.c_str());
1289 }
1290 }
1291
1292 /* Update HyperV CFGM node with active debug options. */
1293 if (fGimHvDebug)
1294 {
1295 PCFGMNODE pHvNode;
1296 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);
1297 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);
1298 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);
1299 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);
1300 fGimDebug = true;
1301 }
1302 }
1303 }
1304
1305 /*
1306 * MM values.
1307 */
1308 PCFGMNODE pMM;
1309 InsertConfigNode(pRoot, "MM", &pMM);
1310 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);
1311
1312 /*
1313 * PDM config.
1314 * Load drivers in VBoxC.[so|dll]
1315 */
1316 PCFGMNODE pPDM;
1317 PCFGMNODE pNode;
1318 PCFGMNODE pMod;
1319 InsertConfigNode(pRoot, "PDM", &pPDM);
1320 InsertConfigNode(pPDM, "Devices", &pNode);
1321 InsertConfigNode(pPDM, "Drivers", &pNode);
1322 InsertConfigNode(pNode, "VBoxC", &pMod);
1323#ifdef VBOX_WITH_XPCOM
1324 // VBoxC is located in the components subdirectory
1325 char szPathVBoxC[RTPATH_MAX];
1326 rc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(rc);
1327 strcat(szPathVBoxC, "/components/VBoxC");
1328 InsertConfigString(pMod, "Path", szPathVBoxC);
1329#else
1330 InsertConfigString(pMod, "Path", "VBoxC");
1331#endif
1332
1333
1334 /*
1335 * Block cache settings.
1336 */
1337 PCFGMNODE pPDMBlkCache;
1338 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
1339
1340 /* I/O cache size */
1341 ULONG ioCacheSize = 5;
1342 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
1343 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
1344
1345 /*
1346 * Bandwidth groups.
1347 */
1348 PCFGMNODE pAc;
1349 PCFGMNODE pAcFile;
1350 PCFGMNODE pAcFileBwGroups;
1351 ComPtr<IBandwidthControl> bwCtrl;
1352 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
1353
1354 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
1355
1356 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
1357
1358 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
1359 InsertConfigNode(pAc, "File", &pAcFile);
1360 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
1361#ifdef VBOX_WITH_NETSHAPER
1362 PCFGMNODE pNetworkShaper;
1363 PCFGMNODE pNetworkBwGroups;
1364
1365 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
1366 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
1367#endif /* VBOX_WITH_NETSHAPER */
1368
1369 for (size_t i = 0; i < bwGroups.size(); i++)
1370 {
1371 Bstr strName;
1372 LONG64 cMaxBytesPerSec;
1373 BandwidthGroupType_T enmType;
1374
1375 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
1376 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
1377 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
1378
1379 if (strName.isEmpty())
1380 return VMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS,
1381 N_("No bandwidth group name specified"));
1382
1383 if (enmType == BandwidthGroupType_Disk)
1384 {
1385 PCFGMNODE pBwGroup;
1386 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1387 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1388 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
1389 InsertConfigInteger(pBwGroup, "Step", 0);
1390 }
1391#ifdef VBOX_WITH_NETSHAPER
1392 else if (enmType == BandwidthGroupType_Network)
1393 {
1394 /* Network bandwidth groups. */
1395 PCFGMNODE pBwGroup;
1396 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
1397 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
1398 }
1399#endif /* VBOX_WITH_NETSHAPER */
1400 }
1401
1402 /*
1403 * Devices
1404 */
1405 PCFGMNODE pDevices = NULL; /* /Devices */
1406 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
1407 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
1408 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
1409 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
1410 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
1411 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */
1412 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */
1413
1414 InsertConfigNode(pRoot, "Devices", &pDevices);
1415
1416 /*
1417 * GIM Device
1418 */
1419 if (fGimDeviceNeeded)
1420 {
1421 InsertConfigNode(pDevices, "GIMDev", &pDev);
1422 InsertConfigNode(pDev, "0", &pInst);
1423 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1424 //InsertConfigNode(pInst, "Config", &pCfg);
1425
1426 if (fGimDebug)
1427 {
1428 InsertConfigNode(pInst, "LUN#998", &pLunL0);
1429 InsertConfigString(pLunL0, "Driver", "UDP");
1430 InsertConfigNode(pLunL0, "Config", &pLunL1);
1431 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);
1432 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);
1433 }
1434 }
1435
1436 /*
1437 * PC Arch.
1438 */
1439 InsertConfigNode(pDevices, "pcarch", &pDev);
1440 InsertConfigNode(pDev, "0", &pInst);
1441 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1442 InsertConfigNode(pInst, "Config", &pCfg);
1443
1444 /*
1445 * The time offset
1446 */
1447 LONG64 timeOffset;
1448 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();
1449 PCFGMNODE pTMNode;
1450 InsertConfigNode(pRoot, "TM", &pTMNode);
1451 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);
1452
1453 /*
1454 * DMA
1455 */
1456 InsertConfigNode(pDevices, "8237A", &pDev);
1457 InsertConfigNode(pDev, "0", &pInst);
1458 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1459
1460 /*
1461 * PCI buses.
1462 */
1463 uint32_t uIocPCIAddress, uHbcPCIAddress;
1464 switch (chipsetType)
1465 {
1466 default:
1467 AssertFailed();
1468 RT_FALL_THRU();
1469 case ChipsetType_PIIX3:
1470 /* Create the base for adding bridges on demand */
1471 InsertConfigNode(pDevices, "pcibridge", NULL);
1472
1473 InsertConfigNode(pDevices, "pci", &pDev);
1474 uHbcPCIAddress = (0x0 << 16) | 0;
1475 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller
1476 break;
1477 case ChipsetType_ICH9:
1478 /* Create the base for adding bridges on demand */
1479 InsertConfigNode(pDevices, "ich9pcibridge", NULL);
1480
1481 InsertConfigNode(pDevices, "ich9pci", &pDev);
1482 uHbcPCIAddress = (0x1e << 16) | 0;
1483 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller
1484 break;
1485 }
1486 InsertConfigNode(pDev, "0", &pInst);
1487 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1488 InsertConfigNode(pInst, "Config", &pCfg);
1489 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1490 if (chipsetType == ChipsetType_ICH9)
1491 {
1492 /* Provide MCFG info */
1493 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
1494 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
1495
1496#ifdef VBOX_WITH_PCI_PASSTHROUGH
1497 /* Add PCI passthrough devices */
1498 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();
1499#endif
1500 }
1501
1502 /*
1503 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset
1504 */
1505
1506 /*
1507 * High Precision Event Timer (HPET)
1508 */
1509 BOOL fHPETEnabled;
1510 /* Other guests may wish to use HPET too, but MacOS X not functional without it */
1511 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();
1512 /* so always enable HPET in extended profile */
1513 fHPETEnabled |= fOsXGuest;
1514 /* HPET is always present on ICH9 */
1515 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);
1516 if (fHPETEnabled)
1517 {
1518 InsertConfigNode(pDevices, "hpet", &pDev);
1519 InsertConfigNode(pDev, "0", &pInst);
1520 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1521 InsertConfigNode(pInst, "Config", &pCfg);
1522 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */
1523 }
1524
1525 /*
1526 * System Management Controller (SMC)
1527 */
1528 BOOL fSmcEnabled;
1529 fSmcEnabled = fOsXGuest;
1530 if (fSmcEnabled)
1531 {
1532 InsertConfigNode(pDevices, "smc", &pDev);
1533 InsertConfigNode(pDev, "0", &pInst);
1534 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1535 InsertConfigNode(pInst, "Config", &pCfg);
1536
1537 bool fGetKeyFromRealSMC;
1538 Utf8Str strKey;
1539 rc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);
1540 AssertRCReturn(rc, rc);
1541
1542 if (!fGetKeyFromRealSMC)
1543 InsertConfigString(pCfg, "DeviceKey", strKey);
1544 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);
1545 }
1546
1547 /*
1548 * Low Pin Count (LPC) bus
1549 */
1550 BOOL fLpcEnabled;
1551 /** @todo implement appropriate getter */
1552 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1553 if (fLpcEnabled)
1554 {
1555 InsertConfigNode(pDevices, "lpc", &pDev);
1556 InsertConfigNode(pDev, "0", &pInst);
1557 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();
1558 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1559 }
1560
1561 BOOL fShowRtc;
1562 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);
1563
1564 /*
1565 * PS/2 keyboard & mouse.
1566 */
1567 InsertConfigNode(pDevices, "pckbd", &pDev);
1568 InsertConfigNode(pDev, "0", &pInst);
1569 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1570 InsertConfigNode(pInst, "Config", &pCfg);
1571
1572 InsertConfigNode(pInst, "LUN#0", &pLunL0);
1573 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
1574 InsertConfigNode(pLunL0, "Config", &pCfg);
1575 InsertConfigInteger(pCfg, "QueueSize", 64);
1576
1577 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1578 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
1579 InsertConfigNode(pLunL1, "Config", &pCfg);
1580 Keyboard *pKeyboard = mKeyboard;
1581 InsertConfigInteger(pCfg, "Object", (uintptr_t)pKeyboard);
1582
1583 Mouse *pMouse = mMouse;
1584 PointingHIDType_T aPointingHID;
1585 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();
1586 InsertConfigNode(pInst, "LUN#1", &pLunL0);
1587 InsertConfigString(pLunL0, "Driver", "MouseQueue");
1588 InsertConfigNode(pLunL0, "Config", &pCfg);
1589 InsertConfigInteger(pCfg, "QueueSize", 128);
1590
1591 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
1592 InsertConfigString(pLunL1, "Driver", "MainMouse");
1593 InsertConfigNode(pLunL1, "Config", &pCfg);
1594 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMouse);
1595
1596 /*
1597 * i8254 Programmable Interval Timer And Dummy Speaker
1598 */
1599 InsertConfigNode(pDevices, "i8254", &pDev);
1600 InsertConfigNode(pDev, "0", &pInst);
1601 InsertConfigNode(pInst, "Config", &pCfg);
1602#ifdef DEBUG
1603 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1604#endif
1605
1606 /*
1607 * i8259 Programmable Interrupt Controller.
1608 */
1609 InsertConfigNode(pDevices, "i8259", &pDev);
1610 InsertConfigNode(pDev, "0", &pInst);
1611 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1612 InsertConfigNode(pInst, "Config", &pCfg);
1613
1614 /*
1615 * Advanced Programmable Interrupt Controller.
1616 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,
1617 * thus only single insert
1618 */
1619 if (fEnableAPIC)
1620 {
1621 InsertConfigNode(pDevices, "apic", &pDev);
1622 InsertConfigNode(pDev, "0", &pInst);
1623 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1624 InsertConfigNode(pInst, "Config", &pCfg);
1625 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
1626 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;
1627 if (fEnableX2APIC)
1628 enmAPICMode = PDMAPICMODE_X2APIC;
1629 else if (!fEnableAPIC)
1630 enmAPICMode = PDMAPICMODE_NONE;
1631 InsertConfigInteger(pCfg, "Mode", enmAPICMode);
1632 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1633
1634 if (fIOAPIC)
1635 {
1636 /*
1637 * I/O Advanced Programmable Interrupt Controller.
1638 */
1639 InsertConfigNode(pDevices, "ioapic", &pDev);
1640 InsertConfigNode(pDev, "0", &pInst);
1641 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1642 InsertConfigNode(pInst, "Config", &pCfg);
1643 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
1644 }
1645 }
1646
1647 /*
1648 * RTC MC146818.
1649 */
1650 InsertConfigNode(pDevices, "mc146818", &pDev);
1651 InsertConfigNode(pDev, "0", &pInst);
1652 InsertConfigNode(pInst, "Config", &pCfg);
1653 BOOL fRTCUseUTC;
1654 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();
1655 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);
1656
1657 /*
1658 * VGA.
1659 */
1660 GraphicsControllerType_T enmGraphicsController;
1661 hrc = pMachine->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();
1662 switch (enmGraphicsController)
1663 {
1664 case GraphicsControllerType_Null:
1665 break;
1666 case GraphicsControllerType_VBoxVGA:
1667#ifdef VBOX_WITH_VMSVGA
1668 case GraphicsControllerType_VMSVGA:
1669#endif
1670 rc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, biosSettings,
1671 RT_BOOL(fHMEnabled));
1672 if (FAILED(rc))
1673 return rc;
1674 break;
1675 default:
1676 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));
1677 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1678 N_("Invalid graphics controller type '%d'"), enmGraphicsController);
1679 }
1680
1681 /*
1682 * Firmware.
1683 */
1684 FirmwareType_T eFwType = FirmwareType_BIOS;
1685 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();
1686
1687#ifdef VBOX_WITH_EFI
1688 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);
1689#else
1690 BOOL fEfiEnabled = false;
1691#endif
1692 if (!fEfiEnabled)
1693 {
1694 /*
1695 * PC Bios.
1696 */
1697 InsertConfigNode(pDevices, "pcbios", &pDev);
1698 InsertConfigNode(pDev, "0", &pInst);
1699 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
1700 InsertConfigNode(pInst, "Config", &pBiosCfg);
1701 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
1702 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
1703 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
1704 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);
1705 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);
1706 BOOL fPXEDebug;
1707 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();
1708 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);
1709 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));
1710 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);
1711 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);
1712 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);
1713
1714 DeviceType_T bootDevice;
1715 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),
1716 VERR_INVALID_PARAMETER);
1717
1718 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)
1719 {
1720 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
1721
1722 char szParamName[] = "BootDeviceX";
1723 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');
1724
1725 const char *pszBootDevice;
1726 switch (bootDevice)
1727 {
1728 case DeviceType_Null:
1729 pszBootDevice = "NONE";
1730 break;
1731 case DeviceType_HardDisk:
1732 pszBootDevice = "IDE";
1733 break;
1734 case DeviceType_DVD:
1735 pszBootDevice = "DVD";
1736 break;
1737 case DeviceType_Floppy:
1738 pszBootDevice = "FLOPPY";
1739 break;
1740 case DeviceType_Network:
1741 pszBootDevice = "LAN";
1742 break;
1743 default:
1744 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
1745 return VMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
1746 N_("Invalid boot device '%d'"), bootDevice);
1747 }
1748 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);
1749 }
1750
1751 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,
1752 * this is required for Windows 2012 guests. */
1753 if (osTypeId == "Windows2012_64")
1754 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */
1755 }
1756 else
1757 {
1758 /* Autodetect firmware type, basing on guest type */
1759 if (eFwType == FirmwareType_EFI)
1760 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;
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(); /* (compiler warnings) */
2578#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
2579 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
2580#endif
2581 }
2582
2583 /*
2584 * Get the MAC address and convert it to binary representation
2585 */
2586 Bstr macAddr;
2587 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
2588 Assert(!macAddr.isEmpty());
2589 Utf8Str macAddrUtf8 = macAddr;
2590 char *macStr = (char*)macAddrUtf8.c_str();
2591 Assert(strlen(macStr) == 12);
2592 RTMAC Mac;
2593 RT_ZERO(Mac);
2594 char *pMac = (char*)&Mac;
2595 for (uint32_t i = 0; i < 6; ++i)
2596 {
2597 int c1 = *macStr++ - '0';
2598 if (c1 > 9)
2599 c1 -= 7;
2600 int c2 = *macStr++ - '0';
2601 if (c2 > 9)
2602 c2 -= 7;
2603 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
2604 }
2605 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
2606
2607 /*
2608 * Check if the cable is supposed to be unplugged
2609 */
2610 BOOL fCableConnected;
2611 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
2612 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
2613
2614 /*
2615 * Line speed to report from custom drivers
2616 */
2617 ULONG ulLineSpeed;
2618 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
2619 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
2620
2621 /*
2622 * Attach the status driver.
2623 */
2624 i_attachStatusDriver(pInst, &mapNetworkLeds[ulInstance], 0, 0, NULL, NULL, 0);
2625
2626 /*
2627 * Configure the network card now
2628 */
2629 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
2630 rc = i_configNetwork(pszAdapterName,
2631 ulInstance,
2632 0,
2633 networkAdapter,
2634 pCfg,
2635 pLunL0,
2636 pInst,
2637 false /*fAttachDetach*/,
2638 fIgnoreConnectFailure);
2639 if (RT_FAILURE(rc))
2640 return rc;
2641 }
2642
2643 /*
2644 * Build network boot information and transfer it to the BIOS.
2645 */
2646 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */
2647 {
2648 llBootNics.sort(); /* Sort the list by boot priority. */
2649
2650 char achBootIdx[] = "0";
2651 unsigned uBootIdx = 0;
2652
2653 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)
2654 {
2655 /* A NIC with priority 0 is only used if it's first in the list. */
2656 if (it->mBootPrio == 0 && uBootIdx != 0)
2657 break;
2658
2659 PCFGMNODE pNetBtDevCfg;
2660 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */
2661 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);
2662 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);
2663 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);
2664 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);
2665 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);
2666 }
2667 }
2668
2669 /*
2670 * Serial (UART) Ports
2671 */
2672 /* serial enabled mask to be passed to dev ACPI */
2673 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};
2674 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};
2675 InsertConfigNode(pDevices, "serial", &pDev);
2676 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)
2677 {
2678 ComPtr<ISerialPort> serialPort;
2679 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();
2680 BOOL fEnabledSerPort = FALSE;
2681 if (serialPort)
2682 {
2683 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();
2684 }
2685 if (!fEnabledSerPort)
2686 {
2687 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;
2688 continue;
2689 }
2690
2691 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2692 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2693 InsertConfigNode(pInst, "Config", &pCfg);
2694
2695 ULONG ulIRQ;
2696 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();
2697 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2698 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;
2699
2700 ULONG ulIOBase;
2701 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();
2702 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2703 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2704
2705 BOOL fServer;
2706 hrc = serialPort->COMGETTER(Server)(&fServer); H();
2707 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();
2708 UartType_T eUartType;
2709 const char *pszUartType;
2710 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();
2711 switch (eUartType)
2712 {
2713 case UartType_U16450: pszUartType = "16450"; break;
2714 case UartType_U16750: pszUartType = "16750"; break;
2715 default: AssertFailed(); RT_FALL_THRU();
2716 case UartType_U16550A: pszUartType = "16550A"; break;
2717 }
2718 InsertConfigString(pCfg, "UartType", pszUartType);
2719
2720 PortMode_T eHostMode;
2721 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();
2722
2723 m_aeSerialPortMode[ulInstance] = eHostMode;
2724 if (eHostMode != PortMode_Disconnected)
2725 {
2726 rc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));
2727 if (RT_FAILURE(rc))
2728 return rc;
2729 }
2730 }
2731
2732 /*
2733 * Parallel (LPT) Ports
2734 */
2735 /* parallel enabled mask to be passed to dev ACPI */
2736 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};
2737 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};
2738 InsertConfigNode(pDevices, "parallel", &pDev);
2739 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)
2740 {
2741 ComPtr<IParallelPort> parallelPort;
2742 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();
2743 BOOL fEnabledParPort = FALSE;
2744 if (parallelPort)
2745 {
2746 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();
2747 }
2748 if (!fEnabledParPort)
2749 continue;
2750
2751 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);
2752 InsertConfigNode(pInst, "Config", &pCfg);
2753
2754 ULONG ulIRQ;
2755 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();
2756 InsertConfigInteger(pCfg, "IRQ", ulIRQ);
2757 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;
2758 ULONG ulIOBase;
2759 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();
2760 InsertConfigInteger(pCfg, "IOBase", ulIOBase);
2761 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;
2762
2763 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();
2764 if (!bstr.isEmpty())
2765 {
2766 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2767 InsertConfigString(pLunL0, "Driver", "HostParallel");
2768 InsertConfigNode(pLunL0, "Config", &pLunL1);
2769 InsertConfigString(pLunL1, "DevicePath", bstr);
2770 }
2771 }
2772
2773 /*
2774 * VMM Device
2775 */
2776 InsertConfigNode(pDevices, "VMMDev", &pDev);
2777 InsertConfigNode(pDev, "0", &pInst);
2778 InsertConfigNode(pInst, "Config", &pCfg);
2779 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2780 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
2781
2782 Bstr hwVersion;
2783 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
2784 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
2785 InsertConfigInteger(pCfg, "HeapEnabled", 0);
2786 Bstr snapshotFolder;
2787 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
2788 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
2789
2790 /* the VMM device's Main driver */
2791 InsertConfigNode(pInst, "LUN#0", &pLunL0);
2792 InsertConfigString(pLunL0, "Driver", "HGCM");
2793 InsertConfigNode(pLunL0, "Config", &pCfg);
2794 InsertConfigInteger(pCfg, "Object", (uintptr_t)pVMMDev);
2795
2796 /*
2797 * Attach the status driver.
2798 */
2799 i_attachStatusDriver(pInst, &mapSharedFolderLed, 0, 0, NULL, NULL, 0);
2800
2801 /*
2802 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
2803 */
2804 BOOL fAudioEnabled = FALSE;
2805 ComPtr<IAudioAdapter> audioAdapter;
2806 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
2807 if (audioAdapter)
2808 {
2809 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
2810 }
2811
2812 if (fAudioEnabled)
2813 {
2814 Utf8Str strAudioDevice;
2815
2816 AudioControllerType_T audioController;
2817 hrc = audioAdapter->COMGETTER(AudioController)(&audioController); H();
2818 AudioCodecType_T audioCodec;
2819 hrc = audioAdapter->COMGETTER(AudioCodec)(&audioCodec); H();
2820
2821 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
2822 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
2823
2824 Utf8Str strDebugPathOut;
2825 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
2826
2827 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
2828 * without duplicating (more) code. */
2829
2830 switch (audioController)
2831 {
2832 case AudioControllerType_AC97:
2833 {
2834 /* ICH AC'97. */
2835 strAudioDevice = "ichac97";
2836
2837 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2838 InsertConfigNode (pDev, "0", &pInst);
2839 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2840 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2841 InsertConfigNode (pInst, "Config", &pCfg);
2842 switch (audioCodec)
2843 {
2844 case AudioCodecType_STAC9700:
2845 InsertConfigString(pCfg, "Codec", "STAC9700");
2846 break;
2847 case AudioCodecType_AD1980:
2848 InsertConfigString(pCfg, "Codec", "AD1980");
2849 break;
2850 default: AssertFailedBreak();
2851 }
2852 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2853 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2854 break;
2855 }
2856 case AudioControllerType_SB16:
2857 {
2858 /* Legacy SoundBlaster16. */
2859 strAudioDevice = "sb16";
2860
2861 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2862 InsertConfigNode (pDev, "0", &pInst);
2863 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2864 InsertConfigNode (pInst, "Config", &pCfg);
2865 InsertConfigInteger(pCfg, "IRQ", 5);
2866 InsertConfigInteger(pCfg, "DMA", 1);
2867 InsertConfigInteger(pCfg, "DMA16", 5);
2868 InsertConfigInteger(pCfg, "Port", 0x220);
2869 InsertConfigInteger(pCfg, "Version", 0x0405);
2870 break;
2871 }
2872 case AudioControllerType_HDA:
2873 {
2874 /* Intel HD Audio. */
2875 strAudioDevice = "hda";
2876
2877 InsertConfigNode (pDevices, strAudioDevice.c_str(), &pDev);
2878 InsertConfigNode (pDev, "0", &pInst);
2879 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
2880 hrc = pBusMgr->assignPCIDevice(strAudioDevice.c_str(), pInst); H();
2881 InsertConfigNode (pInst, "Config", &pCfg);
2882 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
2883 InsertConfigString (pCfg, "DebugPathOut", strDebugPathOut);
2884 break;
2885 }
2886 default: AssertFailedBreak();
2887 }
2888
2889 PCFGMNODE pCfgAudioAdapter = NULL;
2890 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
2891 SafeArray<BSTR> audioProps;
2892 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
2893
2894 std::list<Utf8Str> audioPropertyNamesList;
2895 for (size_t i = 0; i < audioProps.size(); ++i)
2896 {
2897 Bstr bstrValue;
2898 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
2899 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
2900 Utf8Str strKey(audioProps[i]);
2901 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
2902 }
2903
2904 /*
2905 * The audio driver.
2906 */
2907 Utf8Str strAudioDriver;
2908
2909 AudioDriverType_T audioDriver;
2910 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
2911 switch (audioDriver)
2912 {
2913 case AudioDriverType_Null:
2914 {
2915 strAudioDriver = "NullAudio";
2916 break;
2917 }
2918#ifdef RT_OS_WINDOWS
2919# ifdef VBOX_WITH_WINMM
2920 case AudioDriverType_WinMM:
2921 {
2922 #error "Port WinMM audio backend!" /** @todo Still needed? */
2923 break;
2924 }
2925# endif
2926 case AudioDriverType_DirectSound:
2927 {
2928 strAudioDriver = "DSoundAudio";
2929 break;
2930 }
2931#endif /* RT_OS_WINDOWS */
2932#ifdef RT_OS_SOLARIS
2933 case AudioDriverType_SolAudio:
2934 {
2935 /* Should not happen, as the Solaris Audio backend is not around anymore.
2936 * Remove this sometime later. */
2937 LogRel(("Audio: WARNING: Solaris Audio is deprecated, please switch to OSS!\n"));
2938 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
2939
2940 /* Manually set backend to OSS for now. */
2941 strAudioDriver = "OSSAudio";
2942 break;
2943 }
2944#endif
2945#ifdef VBOX_WITH_AUDIO_OSS
2946 case AudioDriverType_OSS:
2947 {
2948 strAudioDriver = "OSSAudio";
2949 break;
2950 }
2951#endif
2952#ifdef VBOX_WITH_AUDIO_ALSA
2953 case AudioDriverType_ALSA:
2954 {
2955 strAudioDriver = "ALSAAudio";
2956 break;
2957 }
2958#endif
2959#ifdef VBOX_WITH_AUDIO_PULSE
2960 case AudioDriverType_Pulse:
2961 {
2962 strAudioDriver = "PulseAudio";
2963 break;
2964 }
2965#endif
2966#ifdef RT_OS_DARWIN
2967 case AudioDriverType_CoreAudio:
2968 {
2969 strAudioDriver = "CoreAudio";
2970 break;
2971 }
2972#endif
2973 default: AssertFailedBreak();
2974 }
2975
2976 unsigned uAudioLUN = 0;
2977
2978 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2979 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
2980 strAudioDriver.c_str());
2981 if (RT_SUCCESS(rc))
2982 uAudioLUN++;
2983
2984#ifdef VBOX_WITH_AUDIO_VRDE
2985 /* Insert dummy audio driver to have the LUN configured. */
2986 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2987 InsertConfigString(pLunL0, "Driver", "AUDIO");
2988 AudioDriverCfg DrvCfgVRDE(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVRDE");
2989 rc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
2990 if (RT_SUCCESS(rc))
2991 uAudioLUN++;
2992#endif /* VBOX_WITH_AUDIO_VRDE */
2993
2994#ifdef VBOX_WITH_AUDIO_VIDEOREC
2995 /* Insert dummy audio driver to have the LUN configured. */
2996 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
2997 InsertConfigString(pLunL0, "Driver", "AUDIO");
2998 AudioDriverCfg DrvCfgVideoRec(strAudioDevice, 0 /* Instance */, uAudioLUN, "AudioVideoRec");
2999 rc = mAudioVideoRec->InitializeConfig(&DrvCfgVideoRec);
3000 if (RT_SUCCESS(rc))
3001 uAudioLUN++;
3002#endif /* VBOX_WITH_AUDIO_VIDEOREC */
3003
3004 if (fDebugEnabled)
3005 {
3006#ifdef VBOX_WITH_AUDIO_DEBUG
3007 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3008 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3009 "DebugAudio");
3010 if (RT_SUCCESS(rc))
3011 uAudioLUN++;
3012#endif /* VBOX_WITH_AUDIO_DEBUG */
3013
3014 /*
3015 * Tweak the logging groups.
3016 */
3017 Utf8Str strLogGroups = "drv_host_audio.e.l.l2.l3.f+" \
3018 "drv_audio.e.l.l2.l3.f+" \
3019 "audio_mixer.e.l.l2.l3.f+" \
3020 "dev_hda_codec.e.l.l2.l3.f+" \
3021 "dev_hda.e.l.l2.l3.f+" \
3022 "dev_ac97.e.l.l2.l3.f+" \
3023 "dev_sb16.e.l.l2.l3.f";
3024
3025 rc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strLogGroups.c_str());
3026 if (RT_FAILURE(rc))
3027 LogRel(("Audio: Setting debug logging failed, rc=%Rrc\n", rc));
3028 }
3029
3030#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3031 /** @todo Make this a runtime-configurable entry! */
3032
3033 /*
3034 * The ValidationKit backend.
3035 */
3036 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%RU8", uAudioLUN);
3037 rc = i_configAudioDriver(audioAdapter, virtualBox, pMachine, pLunL0,
3038 "ValidationKitAudio");
3039 if (RT_SUCCESS(rc))
3040 uAudioLUN++;
3041#endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3042 }
3043
3044 /*
3045 * Shared Clipboard.
3046 */
3047 {
3048 ClipboardMode_T mode = ClipboardMode_Disabled;
3049 hrc = pMachine->COMGETTER(ClipboardMode)(&mode); H();
3050
3051 if (/* mode != ClipboardMode_Disabled */ true)
3052 {
3053 /* Load the service */
3054 rc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3055 if (RT_FAILURE(rc))
3056 {
3057 LogRel(("Shared clipboard is not available, rc=%Rrc\n", rc));
3058 /* That is not a fatal failure. */
3059 rc = VINF_SUCCESS;
3060 }
3061 else
3062 {
3063 LogRel(("Shared clipboard service loaded\n"));
3064
3065 i_changeClipboardMode(mode);
3066
3067 /* Setup the service. */
3068 VBOXHGCMSVCPARM parm;
3069 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
3070 parm.setUInt32(!i_useHostClipboard());
3071 pVMMDev->hgcmHostCall("VBoxSharedClipboard",
3072 VBOX_SHARED_CLIPBOARD_HOST_FN_SET_HEADLESS, 1, &parm);
3073 }
3074 }
3075 }
3076
3077 /*
3078 * HGCM HostChannel.
3079 */
3080 {
3081 Bstr value;
3082 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
3083 value.asOutParam());
3084
3085 if ( hrc == S_OK
3086 && value == "1")
3087 {
3088 rc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
3089 if (RT_FAILURE(rc))
3090 {
3091 LogRel(("VBoxHostChannel is not available, rc=%Rrc\n", rc));
3092 /* That is not a fatal failure. */
3093 rc = VINF_SUCCESS;
3094 }
3095 }
3096 }
3097
3098#ifdef VBOX_WITH_DRAG_AND_DROP
3099 /*
3100 * Drag and Drop.
3101 */
3102 {
3103 DnDMode_T enmMode = DnDMode_Disabled;
3104 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
3105
3106 /* Load the service */
3107 rc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
3108 if (RT_FAILURE(rc))
3109 {
3110 LogRel(("Drag and drop service is not available, rc=%Rrc\n", rc));
3111 /* That is not a fatal failure. */
3112 rc = VINF_SUCCESS;
3113 }
3114 else
3115 {
3116 HGCMSVCEXTHANDLE hDummy;
3117 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxDragAndDropSvc",
3118 &GuestDnD::notifyDnDDispatcher,
3119 GuestDnDInst());
3120 if (RT_FAILURE(rc))
3121 Log(("Cannot register VBoxDragAndDropSvc extension, rc=%Rrc\n", rc));
3122 else
3123 {
3124 LogRel(("Drag and drop service loaded\n"));
3125 rc = i_changeDnDMode(enmMode);
3126 }
3127 }
3128 }
3129#endif /* VBOX_WITH_DRAG_AND_DROP */
3130
3131#ifdef VBOX_WITH_CROGL
3132 /*
3133 * crOpenGL.
3134 */
3135 {
3136 BOOL fEnabled3D = false;
3137 hrc = pMachine->COMGETTER(Accelerate3DEnabled)(&fEnabled3D); H();
3138
3139 if ( fEnabled3D
3140# ifdef VBOX_WITH_VMSVGA3D
3141 && enmGraphicsController == GraphicsControllerType_VBoxVGA
3142# endif
3143 )
3144 {
3145 BOOL fSupports3D = VBoxOglIs3DAccelerationSupported();
3146 if (!fSupports3D)
3147 return VMR3SetError(pUVM, VERR_NOT_AVAILABLE, RT_SRC_POS,
3148 N_("This VM was configured to use 3D acceleration. However, the "
3149 "3D support of the host is not working properly and the "
3150 "VM cannot be started. To fix this problem, either "
3151 "fix the host 3D support (update the host graphics driver?) "
3152 "or disable 3D acceleration in the VM settings"));
3153
3154 /* Load the service. */
3155 rc = pVMMDev->hgcmLoadService("VBoxSharedCrOpenGL", "VBoxSharedCrOpenGL");
3156 if (RT_FAILURE(rc))
3157 {
3158 LogRel(("Failed to load Shared OpenGL service, rc=%Rrc\n", rc));
3159 /* That is not a fatal failure. */
3160 rc = VINF_SUCCESS;
3161 }
3162 else
3163 {
3164 LogRel(("Shared OpenGL service loaded -- 3D enabled\n"));
3165
3166 /* Setup the service. */
3167 VBOXHGCMSVCPARM parm;
3168 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3169
3170 parm.u.pointer.addr = (IConsole *)(Console *)this;
3171 parm.u.pointer.size = sizeof(IConsole *);
3172
3173 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_SET_CONSOLE,
3174 SHCRGL_CPARMS_SET_CONSOLE, &parm);
3175 if (!RT_SUCCESS(rc))
3176 AssertMsgFailed(("SHCRGL_HOST_FN_SET_CONSOLE failed with %Rrc\n", rc));
3177
3178 parm.u.pointer.addr = pVM;
3179 parm.u.pointer.size = sizeof(pVM);
3180 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL",
3181 SHCRGL_HOST_FN_SET_VM, SHCRGL_CPARMS_SET_VM, &parm);
3182 if (!RT_SUCCESS(rc))
3183 AssertMsgFailed(("SHCRGL_HOST_FN_SET_VM failed with %Rrc\n", rc));
3184 }
3185 }
3186 }
3187#endif
3188
3189#ifdef VBOX_WITH_GUEST_PROPS
3190 /*
3191 * Guest property service.
3192 */
3193 rc = i_configGuestProperties(this, pUVM);
3194#endif /* VBOX_WITH_GUEST_PROPS defined */
3195
3196#ifdef VBOX_WITH_GUEST_CONTROL
3197 /*
3198 * Guest control service.
3199 */
3200 rc = i_configGuestControl(this);
3201#endif /* VBOX_WITH_GUEST_CONTROL defined */
3202
3203 /*
3204 * ACPI
3205 */
3206 BOOL fACPI;
3207 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
3208 if (fACPI)
3209 {
3210 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.
3211 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the
3212 * intelppm driver refuses to register an idle state handler.
3213 * Always show CPU leafs for OS X guests. */
3214 BOOL fShowCpu = fOsXGuest;
3215 if (cCpus > 1 || fIOAPIC)
3216 fShowCpu = true;
3217
3218 BOOL fCpuHotPlug;
3219 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();
3220
3221 InsertConfigNode(pDevices, "acpi", &pDev);
3222 InsertConfigNode(pDev, "0", &pInst);
3223 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3224 InsertConfigNode(pInst, "Config", &pCfg);
3225 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
3226
3227 InsertConfigInteger(pCfg, "NumCPUs", cCpus);
3228
3229 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
3230 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);
3231 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);
3232 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);
3233 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);
3234 if (fOsXGuest && !llBootNics.empty())
3235 {
3236 BootNic aNic = llBootNics.front();
3237 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;
3238 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);
3239 }
3240 if (fOsXGuest && fAudioEnabled)
3241 {
3242 PCIBusAddress Address;
3243 if (pBusMgr->findPCIAddress("hda", 0, Address))
3244 {
3245 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;
3246 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);
3247 }
3248 }
3249 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);
3250 if (chipsetType == ChipsetType_ICH9)
3251 {
3252 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
3253 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
3254 /* 64-bit prefetch window root resource:
3255 * Only for ICH9 and if PAE or Long Mode is enabled.
3256 * And only with hardware virtualization (@bugref{5454}). */
3257 if ( (fEnablePAE || fIsGuest64Bit)
3258 && fSupportsHwVirtEx /* HwVirt needs to be supported by the host
3259 otherwise VMM falls back to raw mode */
3260 && fHMEnabled /* HwVirt needs to be enabled in VM config */)
3261 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
3262 }
3263 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
3264 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
3265 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);
3266
3267 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);
3268 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);
3269
3270 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);
3271 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);
3272
3273 if (auSerialIoPortBase[2])
3274 {
3275 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);
3276 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);
3277 }
3278
3279 if (auSerialIoPortBase[3])
3280 {
3281 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);
3282 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);
3283 }
3284
3285 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);
3286 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);
3287
3288 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);
3289 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);
3290
3291 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3292 InsertConfigString(pLunL0, "Driver", "ACPIHost");
3293 InsertConfigNode(pLunL0, "Config", &pCfg);
3294
3295 /* Attach the dummy CPU drivers */
3296 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)
3297 {
3298 BOOL fCpuAttached = true;
3299
3300 if (fCpuHotPlug)
3301 {
3302 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();
3303 }
3304
3305 if (fCpuAttached)
3306 {
3307 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);
3308 InsertConfigString(pLunL0, "Driver", "ACPICpu");
3309 InsertConfigNode(pLunL0, "Config", &pCfg);
3310 }
3311 }
3312 }
3313
3314 /*
3315 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).
3316 */
3317 {
3318 PCFGMNODE pDbgf;
3319 InsertConfigNode(pRoot, "DBGF", &pDbgf);
3320
3321 /* Paths to search for debug info and such things. */
3322 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
3323 Utf8Str strSettingsPath(bstr);
3324 bstr.setNull();
3325 strSettingsPath.stripFilename();
3326 strSettingsPath.append("/");
3327
3328 char szHomeDir[RTPATH_MAX + 1];
3329 int rc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
3330 if (RT_FAILURE(rc2))
3331 szHomeDir[0] = '\0';
3332 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
3333
3334
3335 Utf8Str strPath;
3336 strPath.append(strSettingsPath).append("debug/;");
3337 strPath.append(strSettingsPath).append(";");
3338 strPath.append(szHomeDir);
3339
3340 InsertConfigString(pDbgf, "Path", strPath.c_str());
3341
3342 /* Tracing configuration. */
3343 BOOL fTracingEnabled;
3344 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
3345 if (fTracingEnabled)
3346 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
3347
3348 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
3349 if (fTracingEnabled)
3350 InsertConfigString(pDbgf, "TracingConfig", bstr);
3351
3352 BOOL fAllowTracingToAccessVM;
3353 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3354 if (fAllowTracingToAccessVM)
3355 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3356
3357 /* Debugger console config. */
3358 PCFGMNODE pDbgc;
3359 InsertConfigNode(pRoot, "DBGC", &pDbgc);
3360
3361 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
3362 Utf8Str strVBoxHome = bstr;
3363 bstr.setNull();
3364 if (strVBoxHome.isNotEmpty())
3365 strVBoxHome.append("/");
3366 else
3367 {
3368 strVBoxHome = szHomeDir;
3369 strVBoxHome.append("/.vbox");
3370 }
3371
3372 Utf8Str strFile(strVBoxHome);
3373 strFile.append("dbgc-history");
3374 InsertConfigString(pDbgc, "HistoryFile", strFile);
3375
3376 strFile = strSettingsPath;
3377 strFile.append("dbgc-init");
3378 InsertConfigString(pDbgc, "LocalInitScript", strFile);
3379
3380 strFile = strVBoxHome;
3381 strFile.append("dbgc-init");
3382 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
3383 }
3384 }
3385 catch (ConfigError &x)
3386 {
3387 // InsertConfig threw something:
3388 return x.m_vrc;
3389 }
3390 catch (HRESULT hrcXcpt)
3391 {
3392 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
3393 }
3394
3395#ifdef VBOX_WITH_EXTPACK
3396 /*
3397 * Call the extension pack hooks if everything went well thus far.
3398 */
3399 if (RT_SUCCESS(rc))
3400 {
3401 pAlock->release();
3402 rc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM);
3403 pAlock->acquire();
3404 }
3405#endif
3406
3407 /*
3408 * Apply the CFGM overlay.
3409 */
3410 if (RT_SUCCESS(rc))
3411 rc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);
3412
3413 /*
3414 * Dump all extradata API settings tweaks, both global and per VM.
3415 */
3416 if (RT_SUCCESS(rc))
3417 rc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);
3418
3419#undef H
3420
3421 pAlock->release(); /* Avoid triggering the lock order inversion check. */
3422
3423 /*
3424 * Register VM state change handler.
3425 */
3426 int rc2 = VMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);
3427 AssertRC(rc2);
3428 if (RT_SUCCESS(rc))
3429 rc = rc2;
3430
3431 /*
3432 * Register VM runtime error handler.
3433 */
3434 rc2 = VMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);
3435 AssertRC(rc2);
3436 if (RT_SUCCESS(rc))
3437 rc = rc2;
3438
3439 pAlock->acquire();
3440
3441 LogFlowFunc(("vrc = %Rrc\n", rc));
3442 LogFlowFuncLeave();
3443
3444 return rc;
3445}
3446
3447/**
3448 * Retrieves an uint32_t value from the audio driver's extra data branch
3449 * (VBoxInternal2/Audio/DriverName/Value), or, if not found, use global branch
3450 * (VBoxInternal2/Audio/Value).
3451 *
3452 * The driver branch always supersedes the global branch.
3453 * If both branches are not found (empty), return the given default value.
3454 *
3455 * @return VBox status code.
3456 * @param pVirtualBox Pointer to IVirtualBox instance.
3457 * @param pMachine Pointer to IMachine instance.
3458 * @param pszDriverName Audio driver name to retrieve value for.
3459 * @param pszValue Value name to retrieve.
3460 * @param uDefault Default value to return if value not found / invalid.
3461 */
3462uint32_t Console::i_getAudioDriverValU32(IVirtualBox *pVirtualBox, IMachine *pMachine,
3463 const char *pszDriverName, const char *pszValue, uint32_t uDefault)
3464{
3465 Utf8Str strTmp;
3466
3467 Utf8StrFmt strPathDrv("VBoxInternal2/Audio/%s/%s", pszDriverName, pszValue);
3468 GetExtraDataBoth(pVirtualBox, pMachine, strPathDrv.c_str(), &strTmp);
3469 if (strTmp.isEmpty())
3470 {
3471 Utf8StrFmt strPathGlobal("VBoxInternal2/Audio/%s", pszValue);
3472 GetExtraDataBoth(pVirtualBox, pMachine, strPathGlobal.c_str(), &strTmp);
3473 if (strTmp.isNotEmpty())
3474 return strTmp.toUInt32();
3475 }
3476 else /* Return driver-specific value. */
3477 return strTmp.toUInt32();
3478
3479 return uDefault;
3480}
3481
3482/**
3483 * Configures an audio driver via CFGM by getting (optional) values from extra data.
3484 *
3485 * @return VBox status code.
3486 * @param pAudioAdapter Pointer to audio adapter instance. Needed for the driver's input / output configuration.
3487 * @param pVirtualBox Pointer to IVirtualBox instance.
3488 * @param pMachine Pointer to IMachine instance.
3489 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
3490 * @param pszDrvName Name of the driver to configure.
3491 */
3492int Console::i_configAudioDriver(IAudioAdapter *pAudioAdapter, IVirtualBox *pVirtualBox, IMachine *pMachine,
3493 PCFGMNODE pLUN, const char *pszDrvName)
3494{
3495#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3496
3497 HRESULT hrc;
3498
3499 Utf8Str strTmp;
3500 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3501 const uint64_t fDebugEnabled = (strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1")) ? 1 : 0;
3502
3503 BOOL fAudioEnabledIn = FALSE;
3504 hrc = pAudioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3505 BOOL fAudioEnabledOut = FALSE;
3506 hrc = pAudioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut);
3507
3508 InsertConfigString(pLUN, "Driver", "AUDIO");
3509
3510 PCFGMNODE pCfg;
3511 InsertConfigNode(pLUN, "Config", &pCfg);
3512 InsertConfigString (pCfg, "DriverName", pszDrvName);
3513 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
3514 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
3515
3516 if (fDebugEnabled)
3517 {
3518 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3519
3520 Utf8Str strDebugPathOut;
3521 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3522 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
3523 }
3524
3525 InsertConfigInteger(pCfg, "PeriodSizeMs",
3526 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PeriodSizeMs", 0 /* Default */));
3527 InsertConfigInteger(pCfg, "BufferSizeMs",
3528 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "BufferSizeMs", 0 /* Default */));
3529 InsertConfigInteger(pCfg, "PreBufferSizeMs",
3530 i_getAudioDriverValU32(pVirtualBox, pMachine, pszDrvName, "PreBufferSizeMs", UINT32_MAX /* Default */));
3531
3532 PCFGMNODE pLunL1;
3533 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
3534
3535 InsertConfigNode(pLunL1, "Config", &pCfg);
3536
3537 Bstr bstrTmp;
3538 hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
3539 InsertConfigString(pCfg, "StreamName", bstrTmp);
3540
3541 InsertConfigString(pLunL1, "Driver", pszDrvName);
3542
3543 LogFlowFunc(("szDrivName=%s, hrc=%Rhrc\n", pszDrvName, hrc));
3544 return hrc;
3545
3546#undef H
3547}
3548
3549/**
3550 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
3551 * values.
3552 *
3553 * @returns VBox status code.
3554 * @param pRoot The root of the configuration tree.
3555 * @param pVirtualBox Pointer to the IVirtualBox interface.
3556 * @param pMachine Pointer to the IMachine interface.
3557 */
3558/* static */
3559int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
3560{
3561 /*
3562 * CFGM overlay handling.
3563 *
3564 * Here we check the extra data entries for CFGM values
3565 * and create the nodes and insert the values on the fly. Existing
3566 * values will be removed and reinserted. CFGM is typed, so by default
3567 * we will guess whether it's a string or an integer (byte arrays are
3568 * not currently supported). It's possible to override this autodetection
3569 * by adding "string:", "integer:" or "bytes:" (future).
3570 *
3571 * We first perform a run on global extra data, then on the machine
3572 * extra data to support global settings with local overrides.
3573 */
3574 int rc = VINF_SUCCESS;
3575 try
3576 {
3577 /** @todo add support for removing nodes and byte blobs. */
3578 /*
3579 * Get the next key
3580 */
3581 SafeArray<BSTR> aGlobalExtraDataKeys;
3582 SafeArray<BSTR> aMachineExtraDataKeys;
3583 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3584 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3585
3586 // remember the no. of global values so we can call the correct method below
3587 size_t cGlobalValues = aGlobalExtraDataKeys.size();
3588
3589 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3590 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3591
3592 // build a combined list from global keys...
3593 std::list<Utf8Str> llExtraDataKeys;
3594
3595 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
3596 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
3597 // ... and machine keys
3598 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
3599 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
3600
3601 size_t i2 = 0;
3602 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
3603 it != llExtraDataKeys.end();
3604 ++it, ++i2)
3605 {
3606 const Utf8Str &strKey = *it;
3607
3608 /*
3609 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
3610 */
3611 if (!strKey.startsWith("VBoxInternal/"))
3612 continue;
3613
3614 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
3615
3616 // get the value
3617 Bstr bstrExtraDataValue;
3618 if (i2 < cGlobalValues)
3619 // this is still one of the global values:
3620 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3621 bstrExtraDataValue.asOutParam());
3622 else
3623 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3624 bstrExtraDataValue.asOutParam());
3625 if (FAILED(hrc))
3626 LogRel(("Warning: Cannot get extra data key %s, rc = %Rhrc\n", strKey.c_str(), hrc));
3627
3628 /*
3629 * The key will be in the format "Node1/Node2/Value" or simply "Value".
3630 * Split the two and get the node, delete the value and create the node
3631 * if necessary.
3632 */
3633 PCFGMNODE pNode;
3634 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
3635 if (pszCFGMValueName)
3636 {
3637 /* terminate the node and advance to the value (Utf8Str might not
3638 offically like this but wtf) */
3639 *(char*)pszCFGMValueName = '\0';
3640 ++pszCFGMValueName;
3641
3642 /* does the node already exist? */
3643 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
3644 if (pNode)
3645 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3646 else
3647 {
3648 /* create the node */
3649 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
3650 if (RT_FAILURE(rc))
3651 {
3652 AssertLogRelMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
3653 continue;
3654 }
3655 Assert(pNode);
3656 }
3657 }
3658 else
3659 {
3660 /* root value (no node path). */
3661 pNode = pRoot;
3662 pszCFGMValueName = pszExtraDataKey;
3663 pszExtraDataKey--;
3664 CFGMR3RemoveValue(pNode, pszCFGMValueName);
3665 }
3666
3667 /*
3668 * Now let's have a look at the value.
3669 * Empty strings means that we should remove the value, which we've
3670 * already done above.
3671 */
3672 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
3673 if (!strCFGMValueUtf8.isEmpty())
3674 {
3675 uint64_t u64Value;
3676
3677 /* check for type prefix first. */
3678 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
3679 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
3680 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
3681 {
3682 rc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
3683 if (RT_SUCCESS(rc))
3684 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3685 }
3686 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
3687 {
3688 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
3689 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
3690 if (cbValue > 0)
3691 {
3692 void *pvBytes = RTMemTmpAlloc(cbValue);
3693 if (pvBytes)
3694 {
3695 rc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
3696 if (RT_SUCCESS(rc))
3697 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
3698 RTMemTmpFree(pvBytes);
3699 }
3700 else
3701 rc = VERR_NO_TMP_MEMORY;
3702 }
3703 else if (cbValue == 0)
3704 rc = CFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
3705 else
3706 rc = VERR_INVALID_BASE64_ENCODING;
3707 }
3708 /* auto detect type. */
3709 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
3710 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
3711 else
3712 InsertConfigString(pNode, pszCFGMValueName, strCFGMValueUtf8);
3713 AssertLogRelMsgRCBreak(rc, ("failed to insert CFGM value '%s' to key '%s'\n",
3714 strCFGMValueUtf8.c_str(), pszExtraDataKey));
3715 }
3716 }
3717 }
3718 catch (ConfigError &x)
3719 {
3720 // InsertConfig threw something:
3721 return x.m_vrc;
3722 }
3723 return rc;
3724}
3725
3726/**
3727 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
3728 * values.
3729 *
3730 * @returns VBox status code.
3731 * @param pVirtualBox Pointer to the IVirtualBox interface.
3732 * @param pMachine Pointer to the IMachine interface.
3733 */
3734/* static */
3735int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
3736{
3737 {
3738 SafeArray<BSTR> aGlobalExtraDataKeys;
3739 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
3740 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
3741 bool hasKey = false;
3742 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
3743 {
3744 Utf8Str strKey(aGlobalExtraDataKeys[i]);
3745 if (!strKey.startsWith("VBoxInternal2/"))
3746 continue;
3747
3748 Bstr bstrValue;
3749 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
3750 bstrValue.asOutParam());
3751 if (FAILED(hrc))
3752 continue;
3753 if (!hasKey)
3754 LogRel(("Global extradata API settings:\n"));
3755 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3756 hasKey = true;
3757 }
3758 }
3759
3760 {
3761 SafeArray<BSTR> aMachineExtraDataKeys;
3762 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
3763 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
3764 bool hasKey = false;
3765 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
3766 {
3767 Utf8Str strKey(aMachineExtraDataKeys[i]);
3768 if (!strKey.startsWith("VBoxInternal2/"))
3769 continue;
3770
3771 Bstr bstrValue;
3772 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
3773 bstrValue.asOutParam());
3774 if (FAILED(hrc))
3775 continue;
3776 if (!hasKey)
3777 LogRel(("Per-VM extradata API settings:\n"));
3778 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
3779 hasKey = true;
3780 }
3781 }
3782
3783 return VINF_SUCCESS;
3784}
3785
3786int Console::i_configGraphicsController(PCFGMNODE pDevices,
3787 const GraphicsControllerType_T enmGraphicsController,
3788 BusAssignmentManager *pBusMgr,
3789 const ComPtr<IMachine> &ptrMachine,
3790 const ComPtr<IBIOSSettings> &ptrBiosSettings,
3791 bool fHMEnabled)
3792{
3793 // InsertConfig* throws
3794 try
3795 {
3796 PCFGMNODE pDev, pInst, pCfg, pLunL0;
3797 HRESULT hrc;
3798 Bstr bstr;
3799 const char *pcszDevice = "vga";
3800
3801#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3802 InsertConfigNode(pDevices, pcszDevice, &pDev);
3803 InsertConfigNode(pDev, "0", &pInst);
3804 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3805
3806 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
3807 InsertConfigNode(pInst, "Config", &pCfg);
3808 ULONG cVRamMBs;
3809 hrc = ptrMachine->COMGETTER(VRAMSize)(&cVRamMBs); H();
3810 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
3811 ULONG cMonitorCount;
3812 hrc = ptrMachine->COMGETTER(MonitorCount)(&cMonitorCount); H();
3813 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
3814#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3815 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);
3816#else
3817 NOREF(fHMEnabled);
3818#endif
3819 BOOL f3DEnabled;
3820 hrc = ptrMachine->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
3821 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
3822
3823 i_attachStatusDriver(pInst, &mapCrOglLed, 0, 0, NULL, NULL, 0);
3824
3825#ifdef VBOX_WITH_VMSVGA
3826 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
3827 {
3828 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
3829#ifdef VBOX_WITH_VMSVGA3D
3830 IFramebuffer *pFramebuffer = NULL;
3831 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3832 if (SUCCEEDED(hrc) && pFramebuffer)
3833 {
3834 LONG64 winId = 0;
3835 /** @todo deal with multimonitor setup */
3836 Assert(cMonitorCount == 1);
3837 hrc = pFramebuffer->COMGETTER(WinId)(&winId);
3838 InsertConfigInteger(pCfg, "HostWindowId", winId);
3839 pFramebuffer->Release();
3840 }
3841 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
3842#else
3843 LogRel(("VMSVGA3d not available in this build!\n"));
3844#endif
3845 }
3846#endif
3847
3848 /* Custom VESA mode list */
3849 unsigned cModes = 0;
3850 for (unsigned iMode = 1; iMode <= 16; ++iMode)
3851 {
3852 char szExtraDataKey[sizeof("CustomVideoModeXX")];
3853 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
3854 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
3855 if (bstr.isEmpty())
3856 break;
3857 InsertConfigString(pCfg, szExtraDataKey, bstr);
3858 ++cModes;
3859 }
3860 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
3861
3862 /* VESA height reduction */
3863 ULONG ulHeightReduction;
3864 IFramebuffer *pFramebuffer = NULL;
3865 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
3866 if (SUCCEEDED(hrc) && pFramebuffer)
3867 {
3868 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
3869 pFramebuffer->Release();
3870 pFramebuffer = NULL;
3871 }
3872 else
3873 {
3874 /* If framebuffer is not available, there is no height reduction. */
3875 ulHeightReduction = 0;
3876 }
3877 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
3878
3879 /*
3880 * BIOS logo
3881 */
3882 BOOL fFadeIn;
3883 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
3884 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
3885 BOOL fFadeOut;
3886 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
3887 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
3888 ULONG logoDisplayTime;
3889 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
3890 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
3891 Bstr logoImagePath;
3892 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
3893 InsertConfigString(pCfg, "LogoFile", Utf8Str(!logoImagePath.isEmpty() ? logoImagePath : "") );
3894
3895 /*
3896 * Boot menu
3897 */
3898 BIOSBootMenuMode_T eBootMenuMode;
3899 int iShowBootMenu;
3900 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();
3901 switch (eBootMenuMode)
3902 {
3903 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;
3904 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
3905 default: iShowBootMenu = 2; break;
3906 }
3907 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
3908
3909 /* Attach the display. */
3910 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3911 InsertConfigString(pLunL0, "Driver", "MainDisplay");
3912 InsertConfigNode(pLunL0, "Config", &pCfg);
3913 Display *pDisplay = mDisplay;
3914 InsertConfigInteger(pCfg, "Object", (uintptr_t)pDisplay);
3915 }
3916 catch (ConfigError &x)
3917 {
3918 // InsertConfig threw something:
3919 return x.m_vrc;
3920 }
3921
3922#undef H
3923
3924 return VINF_SUCCESS;
3925}
3926
3927
3928/**
3929 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
3930 */
3931void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
3932{
3933 va_list va;
3934 va_start(va, pszFormat);
3935 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
3936 va_end(va);
3937}
3938
3939/* XXX introduce RT format specifier */
3940static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
3941{
3942 if (u64Size > INT64_C(5000)*_1G)
3943 {
3944 *pszUnit = "TB";
3945 return u64Size / _1T;
3946 }
3947 else if (u64Size > INT64_C(5000)*_1M)
3948 {
3949 *pszUnit = "GB";
3950 return u64Size / _1G;
3951 }
3952 else
3953 {
3954 *pszUnit = "MB";
3955 return u64Size / _1M;
3956 }
3957}
3958
3959/**
3960 * Checks the location of the given medium for known bugs affecting the usage
3961 * of the host I/O cache setting.
3962 *
3963 * @returns VBox status code.
3964 * @param pMedium The medium to check.
3965 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
3966 */
3967int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
3968{
3969#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3970 /*
3971 * Some sanity checks.
3972 */
3973 RT_NOREF(pfUseHostIOCache);
3974 ComPtr<IMediumFormat> pMediumFormat;
3975 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
3976 ULONG uCaps = 0;
3977 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
3978 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
3979
3980 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
3981 uCaps |= mediumFormatCap[j];
3982
3983 if (uCaps & MediumFormatCapabilities_File)
3984 {
3985 Bstr strFile;
3986 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
3987 Utf8Str utfFile = Utf8Str(strFile);
3988 Bstr strSnap;
3989 ComPtr<IMachine> pMachine = i_machine();
3990 hrc = pMachine->COMGETTER(SnapshotFolder)(strSnap.asOutParam()); H();
3991 Utf8Str utfSnap = Utf8Str(strSnap);
3992 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
3993 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
3994 int rc2 = RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
3995 AssertMsgRCReturn(rc2, ("Querying the file type of '%s' failed!\n", utfFile.c_str()), rc2);
3996 /* Ignore the error code. On error, the file system type is still 'unknown' so
3997 * none of the following paths are taken. This can happen for new VMs which
3998 * still don't have a snapshot folder. */
3999 (void)RTFsQueryType(utfSnap.c_str(), &enmFsTypeSnap);
4000 if (!mfSnapshotFolderDiskTypeShown)
4001 {
4002 LogRel(("File system of '%s' (snapshots) is %s\n",
4003 utfSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
4004 mfSnapshotFolderDiskTypeShown = true;
4005 }
4006 LogRel(("File system of '%s' is %s\n", utfFile.c_str(), RTFsTypeName(enmFsTypeFile)));
4007 LONG64 i64Size;
4008 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
4009#ifdef RT_OS_WINDOWS
4010 if ( enmFsTypeFile == RTFSTYPE_FAT
4011 && i64Size >= _4G)
4012 {
4013 const char *pszUnit;
4014 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
4015 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4016 N_("The medium '%ls' has a logical size of %RU64%s "
4017 "but the file system the medium is located on seems "
4018 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
4019 "We strongly recommend to put all your virtual disk images and "
4020 "the snapshot folder onto an NTFS partition"),
4021 strFile.raw(), u64Print, pszUnit);
4022 }
4023#else /* !RT_OS_WINDOWS */
4024 if ( enmFsTypeFile == RTFSTYPE_FAT
4025 || enmFsTypeFile == RTFSTYPE_EXT
4026 || enmFsTypeFile == RTFSTYPE_EXT2
4027 || enmFsTypeFile == RTFSTYPE_EXT3
4028 || enmFsTypeFile == RTFSTYPE_EXT4)
4029 {
4030 RTFILE file;
4031 int rc = RTFileOpen(&file, utfFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4032 if (RT_SUCCESS(rc))
4033 {
4034 RTFOFF maxSize;
4035 /* Careful: This function will work only on selected local file systems! */
4036 rc = RTFileGetMaxSizeEx(file, &maxSize);
4037 RTFileClose(file);
4038 if ( RT_SUCCESS(rc)
4039 && maxSize > 0
4040 && i64Size > (LONG64)maxSize)
4041 {
4042 const char *pszUnitSiz;
4043 const char *pszUnitMax;
4044 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
4045 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
4046 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
4047 N_("The medium '%ls' has a logical size of %RU64%s "
4048 "but the file system the medium is located on can "
4049 "only handle files up to %RU64%s in theory.\n"
4050 "We strongly recommend to put all your virtual disk "
4051 "images and the snapshot folder onto a proper "
4052 "file system (e.g. ext3) with a sufficient size"),
4053 strFile.raw(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
4054 }
4055 }
4056 }
4057#endif /* !RT_OS_WINDOWS */
4058
4059 /*
4060 * Snapshot folder:
4061 * Here we test only for a FAT partition as we had to create a dummy file otherwise
4062 */
4063 if ( enmFsTypeSnap == RTFSTYPE_FAT
4064 && i64Size >= _4G
4065 && !mfSnapshotFolderSizeWarningShown)
4066 {
4067 const char *pszUnit;
4068 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
4069 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
4070#ifdef RT_OS_WINDOWS
4071 N_("The snapshot folder of this VM '%ls' seems to be located on "
4072 "a FAT(32) file system. The logical size of the medium '%ls' "
4073 "(%RU64%s) is bigger than the maximum file size this file "
4074 "system can handle (4GB).\n"
4075 "We strongly recommend to put all your virtual disk images and "
4076 "the snapshot folder onto an NTFS partition"),
4077#else
4078 N_("The snapshot folder of this VM '%ls' seems to be located on "
4079 "a FAT(32) file system. The logical size of the medium '%ls' "
4080 "(%RU64%s) is bigger than the maximum file size this file "
4081 "system can handle (4GB).\n"
4082 "We strongly recommend to put all your virtual disk images and "
4083 "the snapshot folder onto a proper file system (e.g. ext3)"),
4084#endif
4085 strSnap.raw(), strFile.raw(), u64Print, pszUnit);
4086 /* Show this particular warning only once */
4087 mfSnapshotFolderSizeWarningShown = true;
4088 }
4089
4090#ifdef RT_OS_LINUX
4091 /*
4092 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
4093 * on an ext4 partition.
4094 * This bug apparently applies to the XFS file system as well.
4095 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
4096 */
4097
4098 char szOsRelease[128];
4099 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
4100 bool fKernelHasODirectBug = RT_FAILURE(rc)
4101 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
4102
4103 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4104 && !*pfUseHostIOCache
4105 && fKernelHasODirectBug)
4106 {
4107 if ( enmFsTypeFile == RTFSTYPE_EXT4
4108 || enmFsTypeFile == RTFSTYPE_XFS)
4109 {
4110 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4111 N_("The host I/O cache for at least one controller is disabled "
4112 "and the medium '%ls' for this VM "
4113 "is located on an %s partition. There is a known Linux "
4114 "kernel bug which can lead to the corruption of the virtual "
4115 "disk image under these conditions.\n"
4116 "Either enable the host I/O cache permanently in the VM "
4117 "settings or put the disk image and the snapshot folder "
4118 "onto a different file system.\n"
4119 "The host I/O cache will now be enabled for this medium"),
4120 strFile.raw(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4121 *pfUseHostIOCache = true;
4122 }
4123 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
4124 || enmFsTypeSnap == RTFSTYPE_XFS)
4125 && !mfSnapshotFolderExt4WarningShown)
4126 {
4127 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
4128 N_("The host I/O cache for at least one controller is disabled "
4129 "and the snapshot folder for this VM "
4130 "is located on an %s partition. There is a known Linux "
4131 "kernel bug which can lead to the corruption of the virtual "
4132 "disk image under these conditions.\n"
4133 "Either enable the host I/O cache permanently in the VM "
4134 "settings or put the disk image and the snapshot folder "
4135 "onto a different file system.\n"
4136 "The host I/O cache will now be enabled for this medium"),
4137 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
4138 *pfUseHostIOCache = true;
4139 mfSnapshotFolderExt4WarningShown = true;
4140 }
4141 }
4142
4143 /*
4144 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
4145 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
4146 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
4147 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
4148 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
4149 */
4150 bool fKernelAsyncUnreliable = RT_FAILURE(rc)
4151 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
4152 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
4153 && !*pfUseHostIOCache
4154 && fKernelAsyncUnreliable)
4155 {
4156 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
4157 N_("The host I/O cache for at least one controller is disabled. "
4158 "There is a known Linux kernel bug which can lead to kernel "
4159 "oopses under heavy load. To our knowledge this bug affects "
4160 "all 2.6.18 kernels.\n"
4161 "Either enable the host I/O cache permanently in the VM "
4162 "settings or switch to a newer host kernel.\n"
4163 "The host I/O cache will now be enabled for this medium"));
4164 *pfUseHostIOCache = true;
4165 }
4166#endif
4167 }
4168#undef H
4169
4170 return VINF_SUCCESS;
4171}
4172
4173/**
4174 * Unmounts the specified medium from the specified device.
4175 *
4176 * @returns VBox status code.
4177 * @param pUVM The usermode VM handle.
4178 * @param enmBus The storage bus.
4179 * @param enmDevType The device type.
4180 * @param pcszDevice The device emulation.
4181 * @param uInstance Instance of the device.
4182 * @param uLUN The LUN on the device.
4183 * @param fForceUnmount Whether to force unmounting.
4184 */
4185int Console::i_unmountMediumFromGuest(PUVM pUVM, StorageBus_T enmBus, DeviceType_T enmDevType,
4186 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
4187 bool fForceUnmount)
4188{
4189 /* Unmount existing media only for floppy and DVD drives. */
4190 int rc = VINF_SUCCESS;
4191 PPDMIBASE pBase;
4192 if (enmBus == StorageBus_USB)
4193 rc = PDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4194 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4195 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
4196 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
4197 else /* IDE or Floppy */
4198 rc = PDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
4199
4200 if (RT_FAILURE(rc))
4201 {
4202 if (rc == VERR_PDM_LUN_NOT_FOUND || rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4203 rc = VINF_SUCCESS;
4204 AssertRC(rc);
4205 }
4206 else
4207 {
4208 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
4209 AssertReturn(pIMount, VERR_INVALID_POINTER);
4210
4211 /* Unmount the media (but do not eject the medium!) */
4212 rc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
4213 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
4214 rc = VINF_SUCCESS;
4215 /* for example if the medium is locked */
4216 else if (RT_FAILURE(rc))
4217 return rc;
4218 }
4219
4220 return rc;
4221}
4222
4223/**
4224 * Removes the currently attached medium driver form the specified device
4225 * taking care of the controlelr specific configs wrt. to the attached driver chain.
4226 *
4227 * @returns VBox status code.
4228 * @param pCtlInst The controler instance node in the CFGM tree.
4229 * @param pcszDevice The device name.
4230 * @param uInstance The device instance.
4231 * @param uLUN The device LUN.
4232 * @param enmBus The storage bus.
4233 * @param fAttachDetach Flag whether this is a change while the VM is running
4234 * @param fHotplug Flag whether the guest should be notified about the device change.
4235 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
4236 * @param pUVM The usermode VM handle.
4237 * @param enmDevType The device type.
4238 * @param ppLunL0 Where to store the node to attach the new config to on success.
4239 */
4240int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
4241 const char *pcszDevice,
4242 unsigned uInstance,
4243 unsigned uLUN,
4244 StorageBus_T enmBus,
4245 bool fAttachDetach,
4246 bool fHotplug,
4247 bool fForceUnmount,
4248 PUVM pUVM,
4249 DeviceType_T enmDevType,
4250 PCFGMNODE *ppLunL0)
4251{
4252 int rc = VINF_SUCCESS;
4253 bool fAddLun = false;
4254
4255 /* First check if the LUN already exists. */
4256 PCFGMNODE pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4257 AssertReturn(!VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
4258
4259 if (pLunL0)
4260 {
4261 /*
4262 * Unmount the currently mounted medium if we don't just hot remove the
4263 * complete device (SATA) and it supports unmounting (DVD).
4264 */
4265 if ( (enmDevType != DeviceType_HardDisk)
4266 && !fHotplug)
4267 {
4268 rc = i_unmountMediumFromGuest(pUVM, enmBus, enmDevType, pcszDevice,
4269 uInstance, uLUN, fForceUnmount);
4270 if (RT_FAILURE(rc))
4271 return rc;
4272 }
4273
4274 /*
4275 * Don't detach the SCSI driver when unmounting the current medium
4276 * (we are not ripping out the device but only eject the medium).
4277 */
4278 char *pszDriverDetach = NULL;
4279 if ( !fHotplug
4280 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
4281 || enmBus == StorageBus_SAS
4282 || enmBus == StorageBus_SCSI
4283 || enmBus == StorageBus_USB))
4284 {
4285 /* Get the current attached driver we have to detach. */
4286 PCFGMNODE pDrvLun = CFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
4287 if (pDrvLun)
4288 {
4289 char szDriver[128];
4290 RT_ZERO(szDriver);
4291 rc = CFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
4292 if (RT_SUCCESS(rc))
4293 pszDriverDetach = RTStrDup(&szDriver[0]);
4294
4295 pLunL0 = pDrvLun;
4296 }
4297 }
4298
4299 if (enmBus == StorageBus_USB)
4300 rc = PDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4301 pszDriverDetach, 0 /* iOccurence */,
4302 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4303 else
4304 rc = PDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN,
4305 pszDriverDetach, 0 /* iOccurence */,
4306 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
4307
4308 if (pszDriverDetach)
4309 {
4310 RTStrFree(pszDriverDetach);
4311 /* Remove the complete node and create new for the new config. */
4312 CFGMR3RemoveNode(pLunL0);
4313 pLunL0 = CFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4314 if (pLunL0)
4315 {
4316 try
4317 {
4318 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4319 }
4320 catch (ConfigError &x)
4321 {
4322 // InsertConfig threw something:
4323 return x.m_vrc;
4324 }
4325 }
4326 }
4327 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4328 rc = VINF_SUCCESS;
4329 AssertRCReturn(rc, rc);
4330
4331 /*
4332 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
4333 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
4334 */
4335 if ( fHotplug
4336 || enmBus == StorageBus_IDE
4337 || enmBus == StorageBus_Floppy
4338 || enmBus == StorageBus_PCIe
4339 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
4340 {
4341 fAddLun = true;
4342 CFGMR3RemoveNode(pLunL0);
4343 }
4344 }
4345 else
4346 fAddLun = true;
4347
4348 try
4349 {
4350 if (fAddLun)
4351 InsertConfigNode(pCtlInst, Utf8StrFmt("LUN#%u", uLUN).c_str(), &pLunL0);
4352 }
4353 catch (ConfigError &x)
4354 {
4355 // InsertConfig threw something:
4356 return x.m_vrc;
4357 }
4358
4359 if (ppLunL0)
4360 *ppLunL0 = pLunL0;
4361
4362 return rc;
4363}
4364
4365int Console::i_configMediumAttachment(const char *pcszDevice,
4366 unsigned uInstance,
4367 StorageBus_T enmBus,
4368 bool fUseHostIOCache,
4369 bool fBuiltinIOCache,
4370 bool fInsertDiskIntegrityDrv,
4371 bool fSetupMerge,
4372 unsigned uMergeSource,
4373 unsigned uMergeTarget,
4374 IMediumAttachment *pMediumAtt,
4375 MachineState_T aMachineState,
4376 HRESULT *phrc,
4377 bool fAttachDetach,
4378 bool fForceUnmount,
4379 bool fHotplug,
4380 PUVM pUVM,
4381 DeviceType_T *paLedDevType,
4382 PCFGMNODE *ppLunL0)
4383{
4384 // InsertConfig* throws
4385 try
4386 {
4387 int rc = VINF_SUCCESS;
4388 HRESULT hrc;
4389 Bstr bstr;
4390 PCFGMNODE pCtlInst = NULL;
4391
4392// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc\n", rc), rc)
4393#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
4394
4395 LONG lDev;
4396 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4397 LONG lPort;
4398 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4399 DeviceType_T lType;
4400 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4401 BOOL fNonRotational;
4402 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
4403 BOOL fDiscard;
4404 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
4405
4406 if (lType == DeviceType_DVD)
4407 fInsertDiskIntegrityDrv = false;
4408
4409 unsigned uLUN;
4410 PCFGMNODE pLunL0 = NULL;
4411 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4412
4413 /* Determine the base path for the device instance. */
4414 if (enmBus != StorageBus_USB)
4415 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4416 else
4417 {
4418 /* If we hotplug a USB device create a new CFGM tree. */
4419 if (!fHotplug)
4420 pCtlInst = CFGMR3GetChildF(CFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
4421 else
4422 pCtlInst = CFGMR3CreateTree(pUVM);
4423 }
4424 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
4425
4426 if (enmBus == StorageBus_USB)
4427 {
4428 PCFGMNODE pCfg = NULL;
4429
4430 /* Create correct instance. */
4431 if (!fHotplug)
4432 {
4433 if (!fAttachDetach)
4434 InsertConfigNode(pCtlInst, Utf8StrFmt("%d", lPort).c_str(), &pCtlInst);
4435 else
4436 pCtlInst = CFGMR3GetChildF(pCtlInst, "%d/", lPort);
4437 }
4438
4439 if (!fAttachDetach)
4440 InsertConfigNode(pCtlInst, "Config", &pCfg);
4441
4442 uInstance = lPort; /* Overwrite uInstance with the correct one. */
4443
4444 if (!fHotplug && !fAttachDetach)
4445 {
4446 char aszUuid[RTUUID_STR_LENGTH + 1];
4447 USBStorageDevice UsbMsd = USBStorageDevice();
4448
4449 memset(aszUuid, 0, sizeof(aszUuid));
4450 rc = RTUuidCreate(&UsbMsd.mUuid);
4451 AssertRCReturn(rc, rc);
4452 rc = RTUuidToStr(&UsbMsd.mUuid, aszUuid, sizeof(aszUuid));
4453 AssertRCReturn(rc, rc);
4454
4455 UsbMsd.iPort = uInstance;
4456
4457 InsertConfigString(pCtlInst, "UUID", aszUuid);
4458 mUSBStorageDevices.push_back(UsbMsd);
4459
4460 /** @todo No LED after hotplugging. */
4461 /* Attach the status driver */
4462 Assert(cLedUsb >= 8);
4463 i_attachStatusDriver(pCtlInst, &mapStorageLeds[iLedUsb], 0, 7,
4464 &mapMediumAttachments, pcszDevice, 0);
4465 paLedDevType = &maStorageDevType[iLedUsb];
4466 }
4467 }
4468
4469 rc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
4470 fHotplug, fForceUnmount, pUVM, lType, &pLunL0);
4471 if (RT_FAILURE(rc))
4472 return rc;
4473 if (ppLunL0)
4474 *ppLunL0 = pLunL0;
4475
4476 Utf8Str devicePath = Utf8StrFmt("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4477 mapMediumAttachments[devicePath] = pMediumAtt;
4478
4479 ComPtr<IMedium> pMedium;
4480 hrc = pMediumAtt->COMGETTER(Medium)(pMedium.asOutParam()); H();
4481
4482 /*
4483 * 1. Only check this for hard disk images.
4484 * 2. Only check during VM creation and not later, especially not during
4485 * taking an online snapshot!
4486 */
4487 if ( lType == DeviceType_HardDisk
4488 && ( aMachineState == MachineState_Starting
4489 || aMachineState == MachineState_Restoring))
4490 {
4491 rc = i_checkMediumLocation(pMedium, &fUseHostIOCache);
4492 if (RT_FAILURE(rc))
4493 return rc;
4494 }
4495
4496 BOOL fPassthrough = FALSE;
4497 if (pMedium)
4498 {
4499 BOOL fHostDrive;
4500 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4501 if ( ( lType == DeviceType_DVD
4502 || lType == DeviceType_Floppy)
4503 && !fHostDrive)
4504 {
4505 /*
4506 * Informative logging.
4507 */
4508 Bstr strFile;
4509 hrc = pMedium->COMGETTER(Location)(strFile.asOutParam()); H();
4510 Utf8Str utfFile = Utf8Str(strFile);
4511 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
4512 (void)RTFsQueryType(utfFile.c_str(), &enmFsTypeFile);
4513 LogRel(("File system of '%s' (%s) is %s\n",
4514 utfFile.c_str(), lType == DeviceType_DVD ? "DVD" : "Floppy",
4515 RTFsTypeName(enmFsTypeFile)));
4516 }
4517
4518 if (fHostDrive)
4519 {
4520 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
4521 }
4522 }
4523
4524 ComObjPtr<IBandwidthGroup> pBwGroup;
4525 Bstr strBwGroup;
4526 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
4527
4528 if (!pBwGroup.isNull())
4529 {
4530 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
4531 }
4532
4533 /*
4534 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
4535 * or for SATA if the new device is a CD/DVD drive.
4536 */
4537 if ( (fHotplug || !fAttachDetach)
4538 && ( (enmBus == StorageBus_SCSI || enmBus == StorageBus_SAS || enmBus == StorageBus_USB)
4539 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD && !fPassthrough)))
4540 {
4541 InsertConfigString(pLunL0, "Driver", "SCSI");
4542 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4543 }
4544
4545 rc = i_configMedium(pLunL0,
4546 !!fPassthrough,
4547 lType,
4548 fUseHostIOCache,
4549 fBuiltinIOCache,
4550 fInsertDiskIntegrityDrv,
4551 fSetupMerge,
4552 uMergeSource,
4553 uMergeTarget,
4554 strBwGroup.isEmpty() ? NULL : Utf8Str(strBwGroup).c_str(),
4555 !!fDiscard,
4556 !!fNonRotational,
4557 pMedium,
4558 aMachineState,
4559 phrc);
4560 if (RT_FAILURE(rc))
4561 return rc;
4562
4563 if (fAttachDetach)
4564 {
4565 /* Attach the new driver. */
4566 if (enmBus == StorageBus_USB)
4567 {
4568 if (fHotplug)
4569 {
4570 USBStorageDevice UsbMsd = USBStorageDevice();
4571 RTUuidCreate(&UsbMsd.mUuid);
4572 UsbMsd.iPort = uInstance;
4573 rc = PDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
4574 if (RT_SUCCESS(rc))
4575 mUSBStorageDevices.push_back(UsbMsd);
4576 }
4577 else
4578 rc = PDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4579 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4580 }
4581 else if ( !fHotplug
4582 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI)
4583 || (enmBus == StorageBus_SATA && lType == DeviceType_DVD)))
4584 rc = PDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
4585 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4586 else
4587 rc = PDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
4588 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
4589 AssertRCReturn(rc, rc);
4590
4591 /*
4592 * Make the secret key helper interface known to the VD driver if it is attached,
4593 * so we can get notified about missing keys.
4594 */
4595 PPDMIBASE pIBase = NULL;
4596 rc = PDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
4597 if (RT_SUCCESS(rc) && pIBase)
4598 {
4599 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4600 if (pIMedium)
4601 {
4602 rc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
4603 Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
4604 }
4605 }
4606
4607 /* There is no need to handle removable medium mounting, as we
4608 * unconditionally replace everthing including the block driver level.
4609 * This means the new medium will be picked up automatically. */
4610 }
4611
4612 if (paLedDevType)
4613 paLedDevType[uLUN] = lType;
4614
4615 /* Dump the changed LUN if possible, dump the complete device otherwise */
4616 if ( aMachineState != MachineState_Starting
4617 && aMachineState != MachineState_Restoring)
4618 CFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
4619 }
4620 catch (ConfigError &x)
4621 {
4622 // InsertConfig threw something:
4623 return x.m_vrc;
4624 }
4625
4626#undef H
4627
4628 return VINF_SUCCESS;
4629}
4630
4631int Console::i_configMedium(PCFGMNODE pLunL0,
4632 bool fPassthrough,
4633 DeviceType_T enmType,
4634 bool fUseHostIOCache,
4635 bool fBuiltinIOCache,
4636 bool fInsertDiskIntegrityDrv,
4637 bool fSetupMerge,
4638 unsigned uMergeSource,
4639 unsigned uMergeTarget,
4640 const char *pcszBwGroup,
4641 bool fDiscard,
4642 bool fNonRotational,
4643 IMedium *pMedium,
4644 MachineState_T aMachineState,
4645 HRESULT *phrc)
4646{
4647 // InsertConfig* throws
4648 try
4649 {
4650 HRESULT hrc;
4651 Bstr bstr;
4652 PCFGMNODE pCfg = NULL;
4653
4654#define H() \
4655 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
4656
4657
4658 BOOL fHostDrive = FALSE;
4659 MediumType_T mediumType = MediumType_Normal;
4660 if (pMedium)
4661 {
4662 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive); H();
4663 hrc = pMedium->COMGETTER(Type)(&mediumType); H();
4664 }
4665
4666 if (fHostDrive)
4667 {
4668 Assert(pMedium);
4669 if (enmType == DeviceType_DVD)
4670 {
4671 InsertConfigString(pLunL0, "Driver", "HostDVD");
4672 InsertConfigNode(pLunL0, "Config", &pCfg);
4673
4674 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4675 InsertConfigString(pCfg, "Path", bstr);
4676
4677 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
4678 }
4679 else if (enmType == DeviceType_Floppy)
4680 {
4681 InsertConfigString(pLunL0, "Driver", "HostFloppy");
4682 InsertConfigNode(pLunL0, "Config", &pCfg);
4683
4684 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4685 InsertConfigString(pCfg, "Path", bstr);
4686 }
4687 }
4688 else
4689 {
4690 if (fInsertDiskIntegrityDrv)
4691 {
4692 /*
4693 * The actual configuration is done through CFGM extra data
4694 * for each inserted driver separately.
4695 */
4696 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
4697 InsertConfigNode(pLunL0, "Config", &pCfg);
4698 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
4699 }
4700
4701 InsertConfigString(pLunL0, "Driver", "VD");
4702 InsertConfigNode(pLunL0, "Config", &pCfg);
4703 switch (enmType)
4704 {
4705 case DeviceType_DVD:
4706 InsertConfigString(pCfg, "Type", "DVD");
4707 InsertConfigInteger(pCfg, "Mountable", 1);
4708 break;
4709 case DeviceType_Floppy:
4710 InsertConfigString(pCfg, "Type", "Floppy 1.44");
4711 InsertConfigInteger(pCfg, "Mountable", 1);
4712 break;
4713 case DeviceType_HardDisk:
4714 default:
4715 InsertConfigString(pCfg, "Type", "HardDisk");
4716 InsertConfigInteger(pCfg, "Mountable", 0);
4717 }
4718
4719 if ( pMedium
4720 && ( enmType == DeviceType_DVD
4721 || enmType == DeviceType_Floppy)
4722 )
4723 {
4724 // if this medium represents an ISO image and this image is inaccessible,
4725 // the ignore it instead of causing a failure; this can happen when we
4726 // restore a VM state and the ISO has disappeared, e.g. because the Guest
4727 // Additions were mounted and the user upgraded VirtualBox. Previously
4728 // we failed on startup, but that's not good because the only way out then
4729 // would be to discard the VM state...
4730 MediumState_T mediumState;
4731 hrc = pMedium->RefreshState(&mediumState); H();
4732 if (mediumState == MediumState_Inaccessible)
4733 {
4734 Bstr loc;
4735 hrc = pMedium->COMGETTER(Location)(loc.asOutParam()); H();
4736 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
4737 "The image file '%ls' is inaccessible and is being ignored. "
4738 "Please select a different image file for the virtual %s drive.",
4739 loc.raw(),
4740 enmType == DeviceType_DVD ? "DVD" : "floppy");
4741 pMedium = NULL;
4742 }
4743 }
4744
4745 if (pMedium)
4746 {
4747 /* Start with length of parent chain, as the list is reversed */
4748 unsigned uImage = 0;
4749 IMedium *pTmp = pMedium;
4750 while (pTmp)
4751 {
4752 uImage++;
4753 hrc = pTmp->COMGETTER(Parent)(&pTmp); H();
4754 }
4755 /* Index of last image */
4756 uImage--;
4757
4758# ifdef VBOX_WITH_EXTPACK
4759 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
4760 {
4761 /* Configure loading the VDPlugin. */
4762 static const char s_szVDPlugin[] = "VDPluginCrypt";
4763 PCFGMNODE pCfgPlugins = NULL;
4764 PCFGMNODE pCfgPlugin = NULL;
4765 Utf8Str strPlugin;
4766 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
4767 // Don't fail, this is optional!
4768 if (SUCCEEDED(hrc))
4769 {
4770 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
4771 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
4772 InsertConfigString(pCfgPlugin, "Path", strPlugin.c_str());
4773 }
4774 }
4775# endif
4776
4777 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4778 InsertConfigString(pCfg, "Path", bstr);
4779
4780 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4781 InsertConfigString(pCfg, "Format", bstr);
4782
4783 if (mediumType == MediumType_Readonly)
4784 InsertConfigInteger(pCfg, "ReadOnly", 1);
4785 else if (enmType == DeviceType_Floppy)
4786 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
4787
4788 /* Start without exclusive write access to the images. */
4789 /** @todo Live Migration: I don't quite like this, we risk screwing up when
4790 * we're resuming the VM if some 3rd dude have any of the VDIs open
4791 * with write sharing denied. However, if the two VMs are sharing a
4792 * image it really is necessary....
4793 *
4794 * So, on the "lock-media" command, the target teleporter should also
4795 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
4796 * that. Grumble. */
4797 if ( enmType == DeviceType_HardDisk
4798 && ( aMachineState == MachineState_TeleportingIn
4799 || aMachineState == MachineState_FaultTolerantSyncing))
4800 InsertConfigInteger(pCfg, "TempReadOnly", 1);
4801
4802 /* Flag for opening the medium for sharing between VMs. This
4803 * is done at the moment only for the first (and only) medium
4804 * in the chain, as shared media can have no diffs. */
4805 if (mediumType == MediumType_Shareable)
4806 InsertConfigInteger(pCfg, "Shareable", 1);
4807
4808 if (!fUseHostIOCache)
4809 {
4810 InsertConfigInteger(pCfg, "UseNewIo", 1);
4811 /*
4812 * Activate the builtin I/O cache for harddisks only.
4813 * It caches writes only which doesn't make sense for DVD drives
4814 * and just increases the overhead.
4815 */
4816 if ( fBuiltinIOCache
4817 && (enmType == DeviceType_HardDisk))
4818 InsertConfigInteger(pCfg, "BlockCache", 1);
4819 }
4820
4821 if (fSetupMerge)
4822 {
4823 InsertConfigInteger(pCfg, "SetupMerge", 1);
4824 if (uImage == uMergeSource)
4825 InsertConfigInteger(pCfg, "MergeSource", 1);
4826 else if (uImage == uMergeTarget)
4827 InsertConfigInteger(pCfg, "MergeTarget", 1);
4828 }
4829
4830 if (pcszBwGroup)
4831 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
4832
4833 if (fDiscard)
4834 InsertConfigInteger(pCfg, "Discard", 1);
4835
4836 if (fNonRotational)
4837 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
4838
4839 /* Pass all custom parameters. */
4840 bool fHostIP = true;
4841 bool fEncrypted = false;
4842 hrc = i_configMediumProperties(pCfg, pMedium, &fHostIP, &fEncrypted); H();
4843
4844 /* Create an inverted list of parents. */
4845 uImage--;
4846 IMedium *pParentMedium = pMedium;
4847 for (PCFGMNODE pParent = pCfg;; uImage--)
4848 {
4849 hrc = pParentMedium->COMGETTER(Parent)(&pMedium); H();
4850 if (!pMedium)
4851 break;
4852
4853 PCFGMNODE pCur;
4854 InsertConfigNode(pParent, "Parent", &pCur);
4855 hrc = pMedium->COMGETTER(Location)(bstr.asOutParam()); H();
4856 InsertConfigString(pCur, "Path", bstr);
4857
4858 hrc = pMedium->COMGETTER(Format)(bstr.asOutParam()); H();
4859 InsertConfigString(pCur, "Format", bstr);
4860
4861 if (fSetupMerge)
4862 {
4863 if (uImage == uMergeSource)
4864 InsertConfigInteger(pCur, "MergeSource", 1);
4865 else if (uImage == uMergeTarget)
4866 InsertConfigInteger(pCur, "MergeTarget", 1);
4867 }
4868
4869 /* Configure medium properties. */
4870 hrc = i_configMediumProperties(pCur, pMedium, &fHostIP, &fEncrypted); H();
4871
4872 /* next */
4873 pParent = pCur;
4874 pParentMedium = pMedium;
4875 }
4876
4877 /* Custom code: put marker to not use host IP stack to driver
4878 * configuration node. Simplifies life of DrvVD a bit. */
4879 if (!fHostIP)
4880 InsertConfigInteger(pCfg, "HostIPStack", 0);
4881
4882 if (fEncrypted)
4883 m_cDisksEncrypted++;
4884 }
4885 else
4886 {
4887 /* Set empty drive flag for DVD or floppy without media. */
4888 if ( enmType == DeviceType_DVD
4889 || enmType == DeviceType_Floppy)
4890 InsertConfigInteger(pCfg, "EmptyDrive", 1);
4891 }
4892 }
4893#undef H
4894 }
4895 catch (ConfigError &x)
4896 {
4897 // InsertConfig threw something:
4898 return x.m_vrc;
4899 }
4900
4901 return VINF_SUCCESS;
4902}
4903
4904/**
4905 * Adds the medium properties to the CFGM tree.
4906 *
4907 * @returns VBox status code.
4908 * @param pCur The current CFGM node.
4909 * @param pMedium The medium object to configure.
4910 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
4911 * @param pfEncrypted Where to return whether the medium is encrypted.
4912 */
4913int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
4914{
4915 /* Pass all custom parameters. */
4916 SafeArray<BSTR> aNames;
4917 SafeArray<BSTR> aValues;
4918 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames),
4919 ComSafeArrayAsOutParam(aValues));
4920
4921 if ( SUCCEEDED(hrc)
4922 && aNames.size() != 0)
4923 {
4924 PCFGMNODE pVDC;
4925 InsertConfigNode(pCur, "VDConfig", &pVDC);
4926 for (size_t ii = 0; ii < aNames.size(); ++ii)
4927 {
4928 if (aValues[ii] && *aValues[ii])
4929 {
4930 Utf8Str name = aNames[ii];
4931 Utf8Str value = aValues[ii];
4932 size_t offSlash = name.find("/", 0);
4933 if ( offSlash != name.npos
4934 && !name.startsWith("Special/"))
4935 {
4936 com::Utf8Str strFilter;
4937 com::Utf8Str strKey;
4938
4939 hrc = strFilter.assignEx(name, 0, offSlash);
4940 if (FAILED(hrc))
4941 break;
4942
4943 hrc = strKey.assignEx(name, offSlash + 1, name.length() - offSlash - 1); /* Skip slash */
4944 if (FAILED(hrc))
4945 break;
4946
4947 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pVDC, strFilter.c_str());
4948 if (!pCfgFilterConfig)
4949 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
4950
4951 InsertConfigString(pCfgFilterConfig, strKey.c_str(), value);
4952 }
4953 else
4954 {
4955 InsertConfigString(pVDC, name.c_str(), value);
4956 if ( name.compare("HostIPStack") == 0
4957 && value.compare("0") == 0)
4958 *pfHostIP = false;
4959 }
4960
4961 if ( name.compare("CRYPT/KeyId") == 0
4962 && pfEncrypted)
4963 *pfEncrypted = true;
4964 }
4965 }
4966 }
4967
4968 return hrc;
4969}
4970
4971
4972/**
4973 * Construct the Network configuration tree
4974 *
4975 * @returns VBox status code.
4976 *
4977 * @param pszDevice The PDM device name.
4978 * @param uInstance The PDM device instance.
4979 * @param uLun The PDM LUN number of the drive.
4980 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
4981 * @param pCfg Configuration node for the device
4982 * @param pLunL0 To store the pointer to the LUN#0.
4983 * @param pInst The instance CFGM node
4984 * @param fAttachDetach To determine if the network attachment should
4985 * be attached/detached after/before
4986 * configuration.
4987 * @param fIgnoreConnectFailure
4988 * True if connection failures should be ignored
4989 * (makes only sense for bridged/host-only networks).
4990 *
4991 * @note Locks this object for writing.
4992 * @thread EMT
4993 */
4994int Console::i_configNetwork(const char *pszDevice,
4995 unsigned uInstance,
4996 unsigned uLun,
4997 INetworkAdapter *aNetworkAdapter,
4998 PCFGMNODE pCfg,
4999 PCFGMNODE pLunL0,
5000 PCFGMNODE pInst,
5001 bool fAttachDetach,
5002 bool fIgnoreConnectFailure)
5003{
5004 RT_NOREF(fIgnoreConnectFailure);
5005 AutoCaller autoCaller(this);
5006 AssertComRCReturn(autoCaller.rc(), VERR_ACCESS_DENIED);
5007
5008 // InsertConfig* throws
5009 try
5010 {
5011 int rc = VINF_SUCCESS;
5012 HRESULT hrc;
5013 Bstr bstr;
5014
5015#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
5016
5017 /*
5018 * Locking the object before doing VMR3* calls is quite safe here, since
5019 * we're on EMT. Write lock is necessary because we indirectly modify the
5020 * meAttachmentType member.
5021 */
5022 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5023
5024 ComPtr<IMachine> pMachine = i_machine();
5025
5026 ComPtr<IVirtualBox> virtualBox;
5027 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
5028
5029 ComPtr<IHost> host;
5030 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
5031
5032 BOOL fSniffer;
5033 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
5034
5035 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
5036 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
5037 const char *pszPromiscuousGuestPolicy;
5038 switch (enmPromiscModePolicy)
5039 {
5040 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
5041 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
5042 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
5043 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
5044 }
5045
5046 if (fAttachDetach)
5047 {
5048 rc = PDMR3DeviceDetach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
5049 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
5050 rc = VINF_SUCCESS;
5051 AssertLogRelRCReturn(rc, rc);
5052
5053 /* Nuke anything which might have been left behind. */
5054 CFGMR3RemoveNode(CFGMR3GetChildF(pInst, "LUN#%u", uLun));
5055 }
5056
5057#ifdef VBOX_WITH_NETSHAPER
5058 ComObjPtr<IBandwidthGroup> pBwGroup;
5059 Bstr strBwGroup;
5060 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
5061
5062 if (!pBwGroup.isNull())
5063 {
5064 hrc = pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); H();
5065 }
5066#endif /* VBOX_WITH_NETSHAPER */
5067
5068 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
5069 CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", uLun);
5070
5071#ifdef VBOX_WITH_NETSHAPER
5072 if (!strBwGroup.isEmpty())
5073 {
5074 InsertConfigString(pLunL0, "Driver", "NetShaper");
5075 InsertConfigNode(pLunL0, "Config", &pCfg);
5076 InsertConfigString(pCfg, "BwGroup", strBwGroup);
5077 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5078 }
5079#endif /* VBOX_WITH_NETSHAPER */
5080
5081 if (fSniffer)
5082 {
5083 InsertConfigString(pLunL0, "Driver", "NetSniffer");
5084 InsertConfigNode(pLunL0, "Config", &pCfg);
5085 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
5086 if (!bstr.isEmpty()) /* check convention for indicating default file. */
5087 InsertConfigString(pCfg, "File", bstr);
5088 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
5089 }
5090
5091
5092 Bstr networkName, trunkName, trunkType;
5093 NetworkAttachmentType_T eAttachmentType;
5094 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
5095 switch (eAttachmentType)
5096 {
5097 case NetworkAttachmentType_Null:
5098 break;
5099
5100 case NetworkAttachmentType_NAT:
5101 {
5102 ComPtr<INATEngine> natEngine;
5103 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
5104 InsertConfigString(pLunL0, "Driver", "NAT");
5105 InsertConfigNode(pLunL0, "Config", &pCfg);
5106
5107 /* Configure TFTP prefix and boot filename. */
5108 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
5109 if (!bstr.isEmpty())
5110 InsertConfigString(pCfg, "TFTPPrefix", Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP"));
5111 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
5112 InsertConfigString(pCfg, "BootFile", Utf8StrFmt("%ls.pxe", bstr.raw()));
5113
5114 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
5115 if (!bstr.isEmpty())
5116 InsertConfigString(pCfg, "Network", bstr);
5117 else
5118 {
5119 ULONG uSlot;
5120 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
5121 InsertConfigString(pCfg, "Network", Utf8StrFmt("10.0.%d.0/24", uSlot+2));
5122 }
5123 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
5124 if (!bstr.isEmpty())
5125 InsertConfigString(pCfg, "BindIP", bstr);
5126 ULONG mtu = 0;
5127 ULONG sockSnd = 0;
5128 ULONG sockRcv = 0;
5129 ULONG tcpSnd = 0;
5130 ULONG tcpRcv = 0;
5131 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
5132 if (mtu)
5133 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
5134 if (sockRcv)
5135 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
5136 if (sockSnd)
5137 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
5138 if (tcpRcv)
5139 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
5140 if (tcpSnd)
5141 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
5142 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
5143 if (!bstr.isEmpty())
5144 {
5145 RemoveConfigValue(pCfg, "TFTPPrefix");
5146 InsertConfigString(pCfg, "TFTPPrefix", bstr);
5147 }
5148 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
5149 if (!bstr.isEmpty())
5150 {
5151 RemoveConfigValue(pCfg, "BootFile");
5152 InsertConfigString(pCfg, "BootFile", bstr);
5153 }
5154 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
5155 if (!bstr.isEmpty())
5156 InsertConfigString(pCfg, "NextServer", bstr);
5157 BOOL fDNSFlag;
5158 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
5159 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
5160 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
5161 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
5162 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
5163 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
5164
5165 ULONG aliasMode;
5166 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
5167 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
5168
5169 /* port-forwarding */
5170 SafeArray<BSTR> pfs;
5171 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
5172
5173 PCFGMNODE pPFTree = NULL;
5174 if (pfs.size() > 0)
5175 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
5176
5177 for (unsigned int i = 0; i < pfs.size(); ++i)
5178 {
5179 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
5180
5181 uint16_t port = 0;
5182 BSTR r = pfs[i];
5183 Utf8Str utf = Utf8Str(r);
5184 Utf8Str strName;
5185 Utf8Str strProto;
5186 Utf8Str strHostPort;
5187 Utf8Str strHostIP;
5188 Utf8Str strGuestPort;
5189 Utf8Str strGuestIP;
5190 size_t pos, ppos;
5191 pos = ppos = 0;
5192#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
5193 { \
5194 pos = str.find(",", ppos); \
5195 if (pos == Utf8Str::npos) \
5196 { \
5197 Log(( #res " extracting from %s is failed\n", str.c_str())); \
5198 continue; \
5199 } \
5200 res = str.substr(ppos, pos - ppos); \
5201 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
5202 ppos = pos + 1; \
5203 } /* no do { ... } while because of 'continue' */
5204 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
5205 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
5206 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
5207 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
5208 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
5209 strGuestPort = utf.substr(ppos, utf.length() - ppos);
5210#undef ITERATE_TO_NEXT_TERM
5211
5212 uint32_t proto = strProto.toUInt32();
5213 bool fValid = true;
5214 switch (proto)
5215 {
5216 case NATProtocol_UDP:
5217 strProto = "UDP";
5218 break;
5219 case NATProtocol_TCP:
5220 strProto = "TCP";
5221 break;
5222 default:
5223 fValid = false;
5224 }
5225 /* continue with next rule if no valid proto was passed */
5226 if (!fValid)
5227 continue;
5228
5229 InsertConfigNode(pPFTree, Utf8StrFmt("%u", i).c_str(), &pPF);
5230
5231 if (!strName.isEmpty())
5232 InsertConfigString(pPF, "Name", strName);
5233
5234 InsertConfigString(pPF, "Protocol", strProto);
5235
5236 if (!strHostIP.isEmpty())
5237 InsertConfigString(pPF, "BindIP", strHostIP);
5238
5239 if (!strGuestIP.isEmpty())
5240 InsertConfigString(pPF, "GuestIP", strGuestIP);
5241
5242 port = RTStrToUInt16(strHostPort.c_str());
5243 if (port)
5244 InsertConfigInteger(pPF, "HostPort", port);
5245
5246 port = RTStrToUInt16(strGuestPort.c_str());
5247 if (port)
5248 InsertConfigInteger(pPF, "GuestPort", port);
5249 }
5250 break;
5251 }
5252
5253 case NetworkAttachmentType_Bridged:
5254 {
5255#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
5256 hrc = i_attachToTapInterface(aNetworkAdapter);
5257 if (FAILED(hrc))
5258 {
5259 switch (hrc)
5260 {
5261 case VERR_ACCESS_DENIED:
5262 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5263 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5264 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
5265 "change the group of that node and make yourself a member of that group. Make "
5266 "sure that these changes are permanent, especially if you are "
5267 "using udev"));
5268 default:
5269 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5270 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5271 "Failed to initialize Host Interface Networking"));
5272 }
5273 }
5274
5275 Assert((intptr_t)maTapFD[uInstance] >= 0);
5276 if ((intptr_t)maTapFD[uInstance] >= 0)
5277 {
5278 InsertConfigString(pLunL0, "Driver", "HostInterface");
5279 InsertConfigNode(pLunL0, "Config", &pCfg);
5280 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5281 }
5282
5283#elif defined(VBOX_WITH_NETFLT)
5284 /*
5285 * This is the new VBoxNetFlt+IntNet stuff.
5286 */
5287 Bstr BridgedIfName;
5288 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
5289 if (FAILED(hrc))
5290 {
5291 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
5292 H();
5293 }
5294
5295 Utf8Str BridgedIfNameUtf8(BridgedIfName);
5296 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
5297
5298 ComPtr<IHostNetworkInterface> hostInterface;
5299 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
5300 hostInterface.asOutParam());
5301 if (!SUCCEEDED(hrc))
5302 {
5303 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, rc=%Rhrc (0x%x)", hrc, hrc));
5304 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5305 N_("Nonexistent host networking interface, name '%ls'"),
5306 BridgedIfName.raw());
5307 }
5308
5309# if defined(RT_OS_DARWIN)
5310 /* The name is on the form 'ifX: long name', chop it off at the colon. */
5311 char szTrunk[8];
5312 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
5313 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5314// Quick fix for @bugref{5633}
5315// if (!pszColon)
5316// {
5317// /*
5318// * Dynamic changing of attachment causes an attempt to configure
5319// * network with invalid host adapter (as it is must be changed before
5320// * the attachment), calling Detach here will cause a deadlock.
5321// * See @bugref{4750}.
5322// * hrc = aNetworkAdapter->Detach(); H();
5323// */
5324// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5325// N_("Malformed host interface networking name '%ls'"),
5326// BridgedIfName.raw());
5327// }
5328 if (pszColon)
5329 *pszColon = '\0';
5330 const char *pszTrunk = szTrunk;
5331
5332# elif defined(RT_OS_SOLARIS)
5333 /* The name is on the form format 'ifX[:1] - long name, chop it off at space. */
5334 char szTrunk[256];
5335 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
5336 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
5337
5338 /*
5339 * Currently don't bother about malformed names here for the sake of people using
5340 * VBoxManage and setting only the NIC name from there. If there is a space we
5341 * chop it off and proceed, otherwise just use whatever we've got.
5342 */
5343 if (pszSpace)
5344 *pszSpace = '\0';
5345
5346 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
5347 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
5348 if (pszColon)
5349 *pszColon = '\0';
5350
5351 const char *pszTrunk = szTrunk;
5352
5353# elif defined(RT_OS_WINDOWS)
5354 HostNetworkInterfaceType_T eIfType;
5355 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5356 if (FAILED(hrc))
5357 {
5358 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5359 H();
5360 }
5361
5362 if (eIfType != HostNetworkInterfaceType_Bridged)
5363 {
5364 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5365 N_("Interface ('%ls') is not a Bridged Adapter interface"),
5366 BridgedIfName.raw());
5367 }
5368
5369 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5370 if (FAILED(hrc))
5371 {
5372 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5373 H();
5374 }
5375 Guid hostIFGuid(bstr);
5376
5377 INetCfg *pNc;
5378 ComPtr<INetCfgComponent> pAdaptorComponent;
5379 LPWSTR pszApp;
5380
5381 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5382 Assert(hrc == S_OK);
5383 if (hrc != S_OK)
5384 {
5385 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5386 H();
5387 }
5388
5389 /* get the adapter's INetCfgComponent*/
5390 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5391 pAdaptorComponent.asOutParam());
5392 if (hrc != S_OK)
5393 {
5394 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5395 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
5396 H();
5397 }
5398# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5399 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5400 char *pszTrunkName = szTrunkName;
5401 wchar_t * pswzBindName;
5402 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5403 Assert(hrc == S_OK);
5404 if (hrc == S_OK)
5405 {
5406 int cwBindName = (int)wcslen(pswzBindName) + 1;
5407 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5408 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5409 {
5410 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5411 pszTrunkName += cbFullBindNamePrefix-1;
5412 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5413 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5414 {
5415 DWORD err = GetLastError();
5416 hrc = HRESULT_FROM_WIN32(err);
5417 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
5418 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5419 hrc, hrc, err));
5420 }
5421 }
5422 else
5423 {
5424 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
5425 /** @todo set appropriate error code */
5426 hrc = E_FAIL;
5427 }
5428
5429 if (hrc != S_OK)
5430 {
5431 AssertFailed();
5432 CoTaskMemFree(pswzBindName);
5433 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5434 H();
5435 }
5436
5437 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
5438 }
5439 else
5440 {
5441 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5442 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
5443 hrc));
5444 H();
5445 }
5446
5447 const char *pszTrunk = szTrunkName;
5448 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
5449
5450# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
5451# if defined(RT_OS_FREEBSD)
5452 /*
5453 * If we bridge to a tap interface open it the `old' direct way.
5454 * This works and performs better than bridging a physical
5455 * interface via the current FreeBSD vboxnetflt implementation.
5456 */
5457 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
5458 hrc = i_attachToTapInterface(aNetworkAdapter);
5459 if (FAILED(hrc))
5460 {
5461 switch (hrc)
5462 {
5463 case VERR_ACCESS_DENIED:
5464 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5465 "Failed to open '/dev/%s' for read/write access. Please check the "
5466 "permissions of that node, and that the net.link.tap.user_open "
5467 "sysctl is set. Either run 'chmod 0666 /dev/%s' or "
5468 "change the group of that node to vboxusers and make yourself "
5469 "a member of that group. Make sure that these changes are permanent."),
5470 pszBridgedIfName, pszBridgedIfName);
5471 default:
5472 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
5473 return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5474 "Failed to initialize Host Interface Networking"));
5475 }
5476 }
5477
5478 Assert((intptr_t)maTapFD[uInstance] >= 0);
5479 if ((intptr_t)maTapFD[uInstance] >= 0)
5480 {
5481 InsertConfigString(pLunL0, "Driver", "HostInterface");
5482 InsertConfigNode(pLunL0, "Config", &pCfg);
5483 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
5484 }
5485 break;
5486 }
5487# endif
5488 /** @todo Check for malformed names. */
5489 const char *pszTrunk = pszBridgedIfName;
5490
5491 /* Issue a warning if the interface is down */
5492 {
5493 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
5494 if (iSock >= 0)
5495 {
5496 struct ifreq Req;
5497 RT_ZERO(Req);
5498 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
5499 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
5500 if ((Req.ifr_flags & IFF_UP) == 0)
5501 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
5502 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
5503 pszBridgedIfName);
5504
5505 close(iSock);
5506 }
5507 }
5508
5509# else
5510# error "PORTME (VBOX_WITH_NETFLT)"
5511# endif
5512
5513 InsertConfigString(pLunL0, "Driver", "IntNet");
5514 InsertConfigNode(pLunL0, "Config", &pCfg);
5515 InsertConfigString(pCfg, "Trunk", pszTrunk);
5516 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5517 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
5518 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5519 char szNetwork[INTNET_MAX_NETWORK_NAME];
5520
5521# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
5522 /*
5523 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
5524 * interface name + optional description. We must not pass any description to the VM as it can differ
5525 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
5526 */
5527 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
5528# else
5529 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
5530# endif
5531 InsertConfigString(pCfg, "Network", szNetwork);
5532 networkName = Bstr(szNetwork);
5533 trunkName = Bstr(pszTrunk);
5534 trunkType = Bstr(TRUNKTYPE_NETFLT);
5535
5536 BOOL fSharedMacOnWire = false;
5537 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
5538 if (FAILED(hrc))
5539 {
5540 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
5541 H();
5542 }
5543 else if (fSharedMacOnWire)
5544 {
5545 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
5546 Log(("Set SharedMacOnWire\n"));
5547 }
5548
5549# if defined(RT_OS_SOLARIS)
5550# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
5551 /* Zone access restriction, don't allow snooping the global zone. */
5552 zoneid_t ZoneId = getzoneid();
5553 if (ZoneId != GLOBAL_ZONEID)
5554 {
5555 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
5556 }
5557# endif
5558# endif
5559
5560#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
5561 /* NOTHING TO DO HERE */
5562#elif defined(RT_OS_LINUX)
5563/// @todo aleksey: is there anything to be done here?
5564#elif defined(RT_OS_FREEBSD)
5565/** @todo FreeBSD: Check out this later (HIF networking). */
5566#else
5567# error "Port me"
5568#endif
5569 break;
5570 }
5571
5572 case NetworkAttachmentType_Internal:
5573 {
5574 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
5575 if (!bstr.isEmpty())
5576 {
5577 InsertConfigString(pLunL0, "Driver", "IntNet");
5578 InsertConfigNode(pLunL0, "Config", &pCfg);
5579 InsertConfigString(pCfg, "Network", bstr);
5580 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5581 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5582 networkName = bstr;
5583 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5584 }
5585 break;
5586 }
5587
5588 case NetworkAttachmentType_HostOnly:
5589 {
5590 InsertConfigString(pLunL0, "Driver", "IntNet");
5591 InsertConfigNode(pLunL0, "Config", &pCfg);
5592
5593 Bstr HostOnlyName;
5594 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
5595 if (FAILED(hrc))
5596 {
5597 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
5598 H();
5599 }
5600
5601 Utf8Str HostOnlyNameUtf8(HostOnlyName);
5602 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
5603 ComPtr<IHostNetworkInterface> hostInterface;
5604 rc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
5605 hostInterface.asOutParam());
5606 if (!SUCCEEDED(rc))
5607 {
5608 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, rc (0x%x)\n", rc));
5609 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5610 N_("Nonexistent host networking interface, name '%ls'"),
5611 HostOnlyName.raw());
5612 }
5613
5614 char szNetwork[INTNET_MAX_NETWORK_NAME];
5615 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
5616
5617#if defined(RT_OS_WINDOWS)
5618# ifndef VBOX_WITH_NETFLT
5619 hrc = E_NOTIMPL;
5620 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
5621 H();
5622# else /* defined VBOX_WITH_NETFLT*/
5623 /** @todo r=bird: Put this in a function. */
5624
5625 HostNetworkInterfaceType_T eIfType;
5626 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
5627 if (FAILED(hrc))
5628 {
5629 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
5630 H();
5631 }
5632
5633 if (eIfType != HostNetworkInterfaceType_HostOnly)
5634 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
5635 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
5636 HostOnlyName.raw());
5637
5638 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
5639 if (FAILED(hrc))
5640 {
5641 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
5642 H();
5643 }
5644 Guid hostIFGuid(bstr);
5645
5646 INetCfg *pNc;
5647 ComPtr<INetCfgComponent> pAdaptorComponent;
5648 LPWSTR pszApp;
5649 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
5650 Assert(hrc == S_OK);
5651 if (hrc != S_OK)
5652 {
5653 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5654 H();
5655 }
5656
5657 /* get the adapter's INetCfgComponent*/
5658 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
5659 pAdaptorComponent.asOutParam());
5660 if (hrc != S_OK)
5661 {
5662 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5663 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
5664 H();
5665 }
5666# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
5667 char szTrunkName[INTNET_MAX_TRUNK_NAME];
5668 bool fNdis6 = false;
5669 wchar_t * pwszHelpText;
5670 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
5671 Assert(hrc == S_OK);
5672 if (hrc == S_OK)
5673 {
5674 Log(("help-text=%ls\n", pwszHelpText));
5675 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
5676 fNdis6 = true;
5677 CoTaskMemFree(pwszHelpText);
5678 }
5679 if (fNdis6)
5680 {
5681 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
5682 Log(("trunk=%s\n", szTrunkName));
5683 }
5684 else
5685 {
5686 char *pszTrunkName = szTrunkName;
5687 wchar_t * pswzBindName;
5688 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
5689 Assert(hrc == S_OK);
5690 if (hrc == S_OK)
5691 {
5692 int cwBindName = (int)wcslen(pswzBindName) + 1;
5693 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
5694 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
5695 {
5696 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
5697 pszTrunkName += cbFullBindNamePrefix-1;
5698 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
5699 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
5700 {
5701 DWORD err = GetLastError();
5702 hrc = HRESULT_FROM_WIN32(err);
5703 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
5704 hrc, hrc, err));
5705 }
5706 }
5707 else
5708 {
5709 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
5710 /** @todo set appropriate error code */
5711 hrc = E_FAIL;
5712 }
5713
5714 if (hrc != S_OK)
5715 {
5716 AssertFailed();
5717 CoTaskMemFree(pswzBindName);
5718 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5719 H();
5720 }
5721 }
5722 else
5723 {
5724 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5725 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
5726 hrc, hrc));
5727 H();
5728 }
5729
5730
5731 CoTaskMemFree(pswzBindName);
5732 }
5733
5734 trunkType = TRUNKTYPE_NETADP;
5735 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5736
5737 pAdaptorComponent.setNull();
5738 /* release the pNc finally */
5739 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
5740
5741 const char *pszTrunk = szTrunkName;
5742
5743 InsertConfigString(pCfg, "Trunk", pszTrunk);
5744 InsertConfigString(pCfg, "Network", szNetwork);
5745 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
5746 windows only?? */
5747 networkName = Bstr(szNetwork);
5748 trunkName = Bstr(pszTrunk);
5749# endif /* defined VBOX_WITH_NETFLT*/
5750#elif defined(RT_OS_DARWIN)
5751 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5752 InsertConfigString(pCfg, "Network", szNetwork);
5753 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
5754 networkName = Bstr(szNetwork);
5755 trunkName = Bstr(pszHostOnlyName);
5756 trunkType = TRUNKTYPE_NETADP;
5757#else
5758 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
5759 InsertConfigString(pCfg, "Network", szNetwork);
5760 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
5761 networkName = Bstr(szNetwork);
5762 trunkName = Bstr(pszHostOnlyName);
5763 trunkType = TRUNKTYPE_NETFLT;
5764#endif
5765 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5766
5767#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
5768
5769 Bstr tmpAddr, tmpMask;
5770
5771 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
5772 pszHostOnlyName).raw(),
5773 tmpAddr.asOutParam());
5774 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
5775 {
5776 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
5777 pszHostOnlyName).raw(),
5778 tmpMask.asOutParam());
5779 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
5780 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5781 tmpMask.raw());
5782 else
5783 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
5784 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5785 }
5786 else
5787 {
5788 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
5789 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
5790 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
5791 }
5792
5793 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5794
5795 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
5796 pszHostOnlyName).raw(),
5797 tmpAddr.asOutParam());
5798 if (SUCCEEDED(hrc))
5799 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
5800 tmpMask.asOutParam());
5801 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
5802 {
5803 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
5804 Utf8Str(tmpMask).toUInt32());
5805 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
5806 }
5807#endif
5808 break;
5809 }
5810
5811 case NetworkAttachmentType_Generic:
5812 {
5813 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
5814 SafeArray<BSTR> names;
5815 SafeArray<BSTR> values;
5816 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
5817 ComSafeArrayAsOutParam(names),
5818 ComSafeArrayAsOutParam(values)); H();
5819
5820 InsertConfigString(pLunL0, "Driver", bstr);
5821 InsertConfigNode(pLunL0, "Config", &pCfg);
5822 for (size_t ii = 0; ii < names.size(); ++ii)
5823 {
5824 if (values[ii] && *values[ii])
5825 {
5826 Utf8Str name = names[ii];
5827 Utf8Str value = values[ii];
5828 InsertConfigString(pCfg, name.c_str(), value);
5829 }
5830 }
5831 break;
5832 }
5833
5834 case NetworkAttachmentType_NATNetwork:
5835 {
5836 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
5837 if (!bstr.isEmpty())
5838 {
5839 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
5840 InsertConfigString(pLunL0, "Driver", "IntNet");
5841 InsertConfigNode(pLunL0, "Config", &pCfg);
5842 InsertConfigString(pCfg, "Network", bstr);
5843 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
5844 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
5845 networkName = bstr;
5846 trunkType = Bstr(TRUNKTYPE_WHATEVER);
5847 }
5848 break;
5849 }
5850
5851 default:
5852 AssertMsgFailed(("should not get here!\n"));
5853 break;
5854 }
5855
5856 /*
5857 * Attempt to attach the driver.
5858 */
5859 switch (eAttachmentType)
5860 {
5861 case NetworkAttachmentType_Null:
5862 break;
5863
5864 case NetworkAttachmentType_Bridged:
5865 case NetworkAttachmentType_Internal:
5866 case NetworkAttachmentType_HostOnly:
5867 case NetworkAttachmentType_NAT:
5868 case NetworkAttachmentType_Generic:
5869 case NetworkAttachmentType_NATNetwork:
5870 {
5871 if (SUCCEEDED(hrc) && RT_SUCCESS(rc))
5872 {
5873 if (fAttachDetach)
5874 {
5875 rc = PDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
5876 //AssertRC(rc);
5877 }
5878
5879 {
5880 /** @todo pritesh: get the dhcp server name from the
5881 * previous network configuration and then stop the server
5882 * else it may conflict with the dhcp server running with
5883 * the current attachment type
5884 */
5885 /* Stop the hostonly DHCP Server */
5886 }
5887
5888 /*
5889 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
5890 */
5891 if ( !networkName.isEmpty()
5892 && eAttachmentType != NetworkAttachmentType_NATNetwork)
5893 {
5894 /*
5895 * Until we implement service reference counters DHCP Server will be stopped
5896 * by DHCPServerRunner destructor.
5897 */
5898 ComPtr<IDHCPServer> dhcpServer;
5899 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(),
5900 dhcpServer.asOutParam());
5901 if (SUCCEEDED(hrc))
5902 {
5903 /* there is a DHCP server available for this network */
5904 BOOL fEnabledDhcp;
5905 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
5906 if (FAILED(hrc))
5907 {
5908 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
5909 H();
5910 }
5911
5912 if (fEnabledDhcp)
5913 hrc = dhcpServer->Start(networkName.raw(),
5914 trunkName.raw(),
5915 trunkType.raw());
5916 }
5917 else
5918 hrc = S_OK;
5919 }
5920 }
5921
5922 break;
5923 }
5924
5925 default:
5926 AssertMsgFailed(("should not get here!\n"));
5927 break;
5928 }
5929
5930 meAttachmentType[uInstance] = eAttachmentType;
5931 }
5932 catch (ConfigError &x)
5933 {
5934 // InsertConfig threw something:
5935 return x.m_vrc;
5936 }
5937
5938#undef H
5939
5940 return VINF_SUCCESS;
5941}
5942
5943
5944/**
5945 * Configures the serial port at the given CFGM node with the supplied parameters.
5946 *
5947 * @returns VBox status code.
5948 * @param pInst The instance CFGM node.
5949 * @param ePortMode The port mode to sue.
5950 * @param pszPath The serial port path.
5951 * @param fServer Flag whether the port should act as a server
5952 * for the pipe and TCP mode or connect as a client.
5953 */
5954int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
5955{
5956 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5957 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
5958 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
5959
5960 try
5961 {
5962 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5963 if (ePortMode == PortMode_HostPipe)
5964 {
5965 InsertConfigString(pLunL0, "Driver", "Char");
5966 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5967 InsertConfigString(pLunL1, "Driver", "NamedPipe");
5968 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5969 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5970 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5971 }
5972 else if (ePortMode == PortMode_HostDevice)
5973 {
5974 InsertConfigString(pLunL0, "Driver", "Host Serial");
5975 InsertConfigNode(pLunL0, "Config", &pLunL1);
5976 InsertConfigString(pLunL1, "DevicePath", pszPath);
5977 }
5978 else if (ePortMode == PortMode_TCP)
5979 {
5980 InsertConfigString(pLunL0, "Driver", "Char");
5981 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5982 InsertConfigString(pLunL1, "Driver", "TCP");
5983 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5984 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5985 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
5986 }
5987 else if (ePortMode == PortMode_RawFile)
5988 {
5989 InsertConfigString(pLunL0, "Driver", "Char");
5990 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
5991 InsertConfigString(pLunL1, "Driver", "RawFile");
5992 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
5993 InsertConfigString(pLunL1Cfg, "Location", pszPath);
5994 }
5995 }
5996 catch (ConfigError &x)
5997 {
5998 /* InsertConfig threw something */
5999 return x.m_vrc;
6000 }
6001
6002 return VINF_SUCCESS;
6003}
6004
6005
6006#ifdef VBOX_WITH_GUEST_PROPS
6007
6008/**
6009 * Set an array of guest properties
6010 */
6011static void configSetProperties(VMMDev * const pVMMDev,
6012 void *names,
6013 void *values,
6014 void *timestamps,
6015 void *flags)
6016{
6017 VBOXHGCMSVCPARM parms[4];
6018
6019 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
6020 parms[0].u.pointer.addr = names;
6021 parms[0].u.pointer.size = 0; /* We don't actually care. */
6022 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
6023 parms[1].u.pointer.addr = values;
6024 parms[1].u.pointer.size = 0; /* We don't actually care. */
6025 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
6026 parms[2].u.pointer.addr = timestamps;
6027 parms[2].u.pointer.size = 0; /* We don't actually care. */
6028 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
6029 parms[3].u.pointer.addr = flags;
6030 parms[3].u.pointer.size = 0; /* We don't actually care. */
6031
6032 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROPS, 4, &parms[0]);
6033}
6034
6035/**
6036 * Set a single guest property
6037 */
6038static void configSetProperty(VMMDev * const pVMMDev,
6039 const char *pszName,
6040 const char *pszValue,
6041 const char *pszFlags)
6042{
6043 VBOXHGCMSVCPARM parms[4];
6044
6045 AssertPtrReturnVoid(pszName);
6046 AssertPtrReturnVoid(pszValue);
6047 AssertPtrReturnVoid(pszFlags);
6048 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
6049 parms[0].u.pointer.addr = (void *)pszName;
6050 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
6051 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
6052 parms[1].u.pointer.addr = (void *)pszValue;
6053 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
6054 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
6055 parms[2].u.pointer.addr = (void *)pszFlags;
6056 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
6057 pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP, 3, &parms[0]);
6058}
6059
6060/**
6061 * Set the global flags value by calling the service
6062 * @returns the status returned by the call to the service
6063 *
6064 * @param pTable the service instance handle
6065 * @param eFlags the flags to set
6066 */
6067int configSetGlobalPropertyFlags(VMMDev * const pVMMDev, uint32_t fFlags)
6068{
6069 VBOXHGCMSVCPARM paParm;
6070 paParm.setUInt32(fFlags);
6071 int rc = pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS, 1, &paParm);
6072 if (RT_FAILURE(rc))
6073 {
6074 char szFlags[GUEST_PROP_MAX_FLAGS_LEN];
6075 if (RT_FAILURE(GuestPropWriteFlags(fFlags, szFlags)))
6076 Log(("Failed to set the global flags.\n"));
6077 else
6078 Log(("Failed to set the global flags \"%s\".\n", szFlags));
6079 }
6080 return rc;
6081}
6082
6083#endif /* VBOX_WITH_GUEST_PROPS */
6084
6085/**
6086 * Set up the Guest Property service, populate it with properties read from
6087 * the machine XML and set a couple of initial properties.
6088 */
6089/* static */ int Console::i_configGuestProperties(void *pvConsole, PUVM pUVM)
6090{
6091#ifdef VBOX_WITH_GUEST_PROPS
6092 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6093 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6094 AssertReturn(pConsole->m_pVMMDev, VERR_INVALID_POINTER);
6095
6096 /* Load the service */
6097 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
6098
6099 if (RT_FAILURE(rc))
6100 {
6101 LogRel(("VBoxGuestPropSvc is not available. rc = %Rrc\n", rc));
6102 /* That is not a fatal failure. */
6103 rc = VINF_SUCCESS;
6104 }
6105 else
6106 {
6107 /*
6108 * Initialize built-in properties that can be changed and saved.
6109 *
6110 * These are typically transient properties that the guest cannot
6111 * change.
6112 */
6113
6114 {
6115 VBOXHGCMSVCPARM Params[2];
6116 int rc2 = pConsole->m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_GET_DBGF_INFO, 2, &Params[0]);
6117 if (RT_SUCCESS(rc2))
6118 {
6119 PFNDBGFHANDLEREXT pfnHandler = (PFNDBGFHANDLEREXT)(uintptr_t)Params[0].u.pointer.addr;
6120 void *pvService = Params[1].u.pointer.addr;
6121 DBGFR3InfoRegisterExternal(pUVM, "guestprops", "Display the guest properties", pfnHandler, pvService);
6122 }
6123 }
6124
6125 /* Sysprep execution by VBoxService. */
6126 configSetProperty(pConsole->m_pVMMDev,
6127 "/VirtualBox/HostGuest/SysprepExec", "",
6128 "TRANSIENT, RDONLYGUEST");
6129 configSetProperty(pConsole->m_pVMMDev,
6130 "/VirtualBox/HostGuest/SysprepArgs", "",
6131 "TRANSIENT, RDONLYGUEST");
6132
6133 /*
6134 * Pull over the properties from the server.
6135 */
6136 SafeArray<BSTR> namesOut;
6137 SafeArray<BSTR> valuesOut;
6138 SafeArray<LONG64> timestampsOut;
6139 SafeArray<BSTR> flagsOut;
6140 HRESULT hrc;
6141 hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
6142 ComSafeArrayAsOutParam(valuesOut),
6143 ComSafeArrayAsOutParam(timestampsOut),
6144 ComSafeArrayAsOutParam(flagsOut));
6145 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
6146 size_t cProps = namesOut.size();
6147 size_t cAlloc = cProps + 1;
6148 if ( valuesOut.size() != cProps
6149 || timestampsOut.size() != cProps
6150 || flagsOut.size() != cProps
6151 )
6152 AssertFailedReturn(VERR_INVALID_PARAMETER);
6153
6154 char **papszNames, **papszValues, **papszFlags;
6155 char szEmpty[] = "";
6156 LONG64 *pai64Timestamps;
6157 papszNames = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6158 papszValues = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6159 pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
6160 papszFlags = (char **)RTMemTmpAllocZ(sizeof(void *) * cAlloc);
6161 if (papszNames && papszValues && pai64Timestamps && papszFlags)
6162 {
6163 for (unsigned i = 0; RT_SUCCESS(rc) && i < cProps; ++i)
6164 {
6165 AssertPtrBreakStmt(namesOut[i], rc = VERR_INVALID_PARAMETER);
6166 rc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
6167 if (RT_FAILURE(rc))
6168 break;
6169 if (valuesOut[i])
6170 rc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
6171 else
6172 papszValues[i] = szEmpty;
6173 if (RT_FAILURE(rc))
6174 break;
6175 pai64Timestamps[i] = timestampsOut[i];
6176 if (flagsOut[i])
6177 rc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
6178 else
6179 papszFlags[i] = szEmpty;
6180 }
6181 if (RT_SUCCESS(rc))
6182 configSetProperties(pConsole->m_pVMMDev,
6183 (void *)papszNames,
6184 (void *)papszValues,
6185 (void *)pai64Timestamps,
6186 (void *)papszFlags);
6187 for (unsigned i = 0; i < cProps; ++i)
6188 {
6189 RTStrFree(papszNames[i]);
6190 if (valuesOut[i])
6191 RTStrFree(papszValues[i]);
6192 if (flagsOut[i])
6193 RTStrFree(papszFlags[i]);
6194 }
6195 }
6196 else
6197 rc = VERR_NO_MEMORY;
6198 RTMemTmpFree(papszNames);
6199 RTMemTmpFree(papszValues);
6200 RTMemTmpFree(pai64Timestamps);
6201 RTMemTmpFree(papszFlags);
6202 AssertRCReturn(rc, rc);
6203
6204 /*
6205 * These properties have to be set before pulling over the properties
6206 * from the machine XML, to ensure that properties saved in the XML
6207 * will override them.
6208 */
6209 /* Set the raw VBox version string as a guest property. Used for host/guest
6210 * version comparison. */
6211 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVer",
6212 VBOX_VERSION_STRING_RAW, "TRANSIENT, RDONLYGUEST");
6213 /* Set the full VBox version string as a guest property. Can contain vendor-specific
6214 * information/branding and/or pre-release tags. */
6215 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxVerExt",
6216 VBOX_VERSION_STRING, "TRANSIENT, RDONLYGUEST");
6217 /* Set the VBox SVN revision as a guest property */
6218 configSetProperty(pConsole->m_pVMMDev, "/VirtualBox/HostInfo/VBoxRev",
6219 RTBldCfgRevisionStr(), "TRANSIENT, RDONLYGUEST");
6220
6221 /*
6222 * Register the host notification callback
6223 */
6224 HGCMSVCEXTHANDLE hDummy;
6225 HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestPropSvc",
6226 Console::i_doGuestPropNotification,
6227 pvConsole);
6228
6229#ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
6230 rc = configSetGlobalPropertyFlags(pConsole->m_pVMMDev, GUEST_PROP_F_RDONLYGUEST);
6231 AssertRCReturn(rc, rc);
6232#endif
6233
6234 Log(("Set VBoxGuestPropSvc property store\n"));
6235 }
6236 return VINF_SUCCESS;
6237#else /* !VBOX_WITH_GUEST_PROPS */
6238 return VERR_NOT_SUPPORTED;
6239#endif /* !VBOX_WITH_GUEST_PROPS */
6240}
6241
6242/**
6243 * Set up the Guest Control service.
6244 */
6245/* static */ int Console::i_configGuestControl(void *pvConsole)
6246{
6247#ifdef VBOX_WITH_GUEST_CONTROL
6248 AssertReturn(pvConsole, VERR_INVALID_POINTER);
6249 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
6250
6251 /* Load the service */
6252 int rc = pConsole->m_pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
6253
6254 if (RT_FAILURE(rc))
6255 {
6256 LogRel(("VBoxGuestControlSvc is not available. rc = %Rrc\n", rc));
6257 /* That is not a fatal failure. */
6258 rc = VINF_SUCCESS;
6259 }
6260 else
6261 {
6262 HGCMSVCEXTHANDLE hDummy;
6263 rc = HGCMHostRegisterServiceExtension(&hDummy, "VBoxGuestControlSvc",
6264 &Guest::i_notifyCtrlDispatcher,
6265 pConsole->i_getGuest());
6266 if (RT_FAILURE(rc))
6267 Log(("Cannot register VBoxGuestControlSvc extension!\n"));
6268 else
6269 LogRel(("Guest Control service loaded\n"));
6270 }
6271
6272 return rc;
6273#else /* !VBOX_WITH_GUEST_CONTROL */
6274 return VERR_NOT_SUPPORTED;
6275#endif /* !VBOX_WITH_GUEST_CONTROL */
6276}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use