VirtualBox

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

Last change on this file since 88653 was 88653, checked in by vboxsync, 4 years ago

Audio/SB16: Makes now also use of the common stream debugging (file) facilities (drops VBOX_AUDIO_DEBUG_DUMP_PCM_DATA).

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

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