Changeset 99909 in vbox for trunk/src/VBox/Main
- Timestamp:
- May 22, 2023 5:02:32 PM (19 months ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
- 1 copied
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/Makefile.kmk
r99845 r99909 1155 1155 src-client/ClientTokenHolder.cpp \ 1156 1156 src-client/ConsoleImpl.cpp \ 1157 src-client/ConsoleImpl2.cpp \ 1157 src-client/ConsoleImplConfigCommon.cpp \ 1158 src-client/ConsoleImplConfigX86.cpp \ 1158 1159 src-client/ConsoleImplTeleporter.cpp \ 1159 1160 src-client/ConsoleVRDPServer.cpp \ -
trunk/src/VBox/Main/include/ConsoleImpl.h
r98340 r99909 31 31 # pragma once 32 32 #endif 33 34 #include <iprt/cpp/exception.h> 33 35 34 36 #include "VirtualBoxBase.h" … … 720 722 void i_configAudioDriver(IVirtualBox *pVirtualBox, IMachine *pMachine, PCFGMNODE pLUN, const char *pszDriverName, 721 723 bool fAudioEnabledIn, bool fAudioEnabledOut); 722 int i_configConstructorInner (PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock);724 int i_configConstructorInnerX86(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock); 723 725 int i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine); 724 726 int i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine); … … 1219 1221 }; 1220 1222 1223 1224 class ConfigError : public RTCError 1225 { 1226 public: 1227 1228 ConfigError(const char *pcszFunction, 1229 int vrc, 1230 const char *pcszName) 1231 : RTCError(Utf8StrFmt(Console::tr("%s failed: vrc=%Rrc, pcszName=%s"), pcszFunction, vrc, pcszName)), 1232 m_vrc(vrc) 1233 { 1234 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here 1235 } 1236 1237 int m_vrc; 1238 }; 1239 1240 DECL_HIDDEN_THROW(Utf8Str *) GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue); 1241 1221 1242 #endif /* !MAIN_INCLUDED_ConsoleImpl_h */ 1222 1243 /* vi: set tabstop=4 shiftwidth=4 expandtab: */ -
trunk/src/VBox/Main/src-client/ConsoleImplConfigCommon.cpp
r99884 r99909 71 71 #include <iprt/string.h> 72 72 #include <iprt/system.h> 73 #include <iprt/cpp/exception.h>74 73 #if 0 /* enable to play with lots of memory. */ 75 74 # include <iprt/env.h> … … 90 89 #include <VBox/vmm/pdmdev.h> /* For PDMAPICMODE enum. */ 91 90 #include <VBox/vmm/pdmstorageifs.h> 92 #include <VBox/vmm/gcm.h>93 91 #include <VBox/version.h> 94 92 #ifdef VBOX_WITH_SHARED_CLIPBOARD … … 141 139 #endif 142 140 #include "NetworkServiceRunner.h" 143 #include "BusAssignmentManager.h"144 141 #ifdef VBOX_WITH_EXTPACK 145 142 # include "ExtPackManagerImpl.h" … … 150 147 * Internal Functions * 151 148 *********************************************************************************************************************************/ 152 static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);153 154 149 155 150 /* Darwin compile kludge */ 156 151 #undef PVM 157 158 /* Comment out the following line to remove VMWare compatibility hack. */159 #define VMWARE_NET_IN_SLOT_11160 161 /**162 * Translate IDE StorageControllerType_T to string representation.163 */164 static const char* controllerString(StorageControllerType_T enmType)165 {166 switch (enmType)167 {168 case StorageControllerType_PIIX3:169 return "PIIX3";170 case StorageControllerType_PIIX4:171 return "PIIX4";172 case StorageControllerType_ICH6:173 return "ICH6";174 default:175 return "Unknown";176 }177 }178 179 /**180 * Simple class for storing network boot information.181 */182 struct BootNic183 {184 ULONG mInstance;185 PCIBusAddress mPCIAddress;186 187 ULONG mBootPrio;188 bool operator < (const BootNic &rhs) const189 {190 ULONG lval = mBootPrio - 1; /* 0 will wrap around and get the lowest priority. */191 ULONG rval = rhs.mBootPrio - 1;192 return lval < rval; /* Zero compares as highest number (lowest prio). */193 }194 };195 196 #ifndef VBOX_WITH_EFI_IN_DD2197 static int findEfiRom(IVirtualBox* vbox, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)198 {199 Bstr aFilePath, empty;200 BOOL fPresent = FALSE;201 HRESULT hrc = vbox->CheckFirmwarePresent(aFirmwareType, empty.raw(),202 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);203 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));204 205 if (!fPresent)206 {207 LogRel(("Failed to find an EFI ROM file.\n"));208 return VERR_FILE_NOT_FOUND;209 }210 211 *pEfiRomFile = Utf8Str(aFilePath);212 213 return VINF_SUCCESS;214 }215 #endif216 217 /**218 * @throws HRESULT on extra data retrival error.219 */220 static int getSmcDeviceKey(IVirtualBox *pVirtualBox, IMachine *pMachine, Utf8Str *pStrKey, bool *pfGetKeyFromRealSMC)221 {222 *pfGetKeyFromRealSMC = false;223 224 /*225 * The extra data takes precedence (if non-zero).226 */227 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/SmcDeviceKey", pStrKey);228 if (pStrKey->isNotEmpty())229 return VINF_SUCCESS;230 231 #ifdef RT_OS_DARWIN232 233 /*234 * Work done in EFI/DevSmc235 */236 *pfGetKeyFromRealSMC = true;237 int vrc = VINF_SUCCESS;238 239 #else240 /*241 * Is it apple hardware in bootcamp?242 */243 /** @todo implement + test RTSYSDMISTR_MANUFACTURER on all hosts.244 * Currently falling back on the product name. */245 char szManufacturer[256];246 szManufacturer[0] = '\0';247 RTSystemQueryDmiString(RTSYSDMISTR_MANUFACTURER, szManufacturer, sizeof(szManufacturer));248 if (szManufacturer[0] != '\0')249 {250 if ( !strcmp(szManufacturer, "Apple Computer, Inc.")251 || !strcmp(szManufacturer, "Apple Inc.")252 )253 *pfGetKeyFromRealSMC = true;254 }255 else256 {257 char szProdName[256];258 szProdName[0] = '\0';259 RTSystemQueryDmiString(RTSYSDMISTR_PRODUCT_NAME, szProdName, sizeof(szProdName));260 if ( ( !strncmp(szProdName, RT_STR_TUPLE("Mac"))261 || !strncmp(szProdName, RT_STR_TUPLE("iMac"))262 || !strncmp(szProdName, RT_STR_TUPLE("Xserve"))263 )264 && !strchr(szProdName, ' ') /* no spaces */265 && RT_C_IS_DIGIT(szProdName[strlen(szProdName) - 1]) /* version number */266 )267 *pfGetKeyFromRealSMC = true;268 }269 270 int vrc = VINF_SUCCESS;271 #endif272 273 return vrc;274 }275 276 277 /*278 * VC++ 8 / amd64 has some serious trouble with the next functions.279 * As a temporary measure, we'll drop global optimizations.280 */281 #if defined(_MSC_VER) && defined(RT_ARCH_AMD64)282 # if _MSC_VER >= RT_MSC_VER_VC80 && _MSC_VER < RT_MSC_VER_VC100283 # pragma optimize("g", off)284 # endif285 #endif286 287 class ConfigError : public RTCError288 {289 public:290 291 ConfigError(const char *pcszFunction,292 int vrc,293 const char *pcszName)294 : RTCError(Utf8StrFmt(Console::tr("%s failed: vrc=%Rrc, pcszName=%s"), pcszFunction, vrc, pcszName)),295 m_vrc(vrc)296 {297 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here298 }299 300 int m_vrc;301 };302 303 152 304 153 /** … … 461 310 * found). 462 311 */ 463 static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)312 DECL_HIDDEN_THROW(Utf8Str *) GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue) 464 313 { 465 314 pStrValue->setNull(); … … 481 330 return pStrValue; 482 331 } 483 484 485 /** Helper that finds out the next HBA port used486 */487 static LONG GetNextUsedPort(LONG aPortUsed[30], LONG lBaseVal, uint32_t u32Size)488 {489 LONG lNextPortUsed = 30;490 for (size_t j = 0; j < u32Size; ++j)491 {492 if ( aPortUsed[j] > lBaseVal493 && aPortUsed[j] <= lNextPortUsed)494 lNextPortUsed = aPortUsed[j];495 }496 return lNextPortUsed;497 }498 499 #define MAX_BIOS_LUN_COUNT 4500 501 int Console::SetBiosDiskInfo(ComPtr<IMachine> pMachine, PCFGMNODE pCfg, PCFGMNODE pBiosCfg,502 Bstr controllerName, const char * const s_apszBiosConfig[4])503 {504 RT_NOREF(pCfg);505 HRESULT hrc;506 #define MAX_DEVICES 30507 #define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)508 509 LONG lPortLUN[MAX_BIOS_LUN_COUNT];510 LONG lPortUsed[MAX_DEVICES];511 uint32_t u32HDCount = 0;512 513 /* init to max value */514 lPortLUN[0] = MAX_DEVICES;515 516 com::SafeIfaceArray<IMediumAttachment> atts;517 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),518 ComSafeArrayAsOutParam(atts)); H();519 size_t uNumAttachments = atts.size();520 if (uNumAttachments > MAX_DEVICES)521 {522 LogRel(("Number of Attachments > Max=%d.\n", uNumAttachments));523 uNumAttachments = MAX_DEVICES;524 }525 526 /* Find the relevant ports/IDs, i.e the ones to which a HD is attached. */527 for (size_t j = 0; j < uNumAttachments; ++j)528 {529 IMediumAttachment *pMediumAtt = atts[j];530 LONG lPortNum = 0;531 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();532 if (SUCCEEDED(hrc))533 {534 DeviceType_T lType;535 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();536 if (SUCCEEDED(hrc) && lType == DeviceType_HardDisk)537 {538 /* find min port number used for HD */539 if (lPortNum < lPortLUN[0])540 lPortLUN[0] = lPortNum;541 lPortUsed[u32HDCount++] = lPortNum;542 LogFlowFunc(("HD port Count=%d\n", u32HDCount));543 }544 }545 }546 547 548 /* Pick only the top 4 used HD Ports as CMOS doesn't have space549 * to save details for all 30 ports550 */551 uint32_t u32MaxPortCount = MAX_BIOS_LUN_COUNT;552 if (u32HDCount < MAX_BIOS_LUN_COUNT)553 u32MaxPortCount = u32HDCount;554 for (size_t j = 1; j < u32MaxPortCount; j++)555 lPortLUN[j] = GetNextUsedPort(lPortUsed, lPortLUN[j-1], u32HDCount);556 if (pBiosCfg)557 {558 for (size_t j = 0; j < u32MaxPortCount; j++)559 {560 InsertConfigInteger(pBiosCfg, s_apszBiosConfig[j], lPortLUN[j]);561 LogFlowFunc(("Top %d HBA ports = %s, %d\n", j, s_apszBiosConfig[j], lPortLUN[j]));562 }563 }564 return VINF_SUCCESS;565 }566 567 #ifdef VBOX_WITH_PCI_PASSTHROUGH568 HRESULT Console::i_attachRawPCIDevices(PUVM pUVM, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices)569 {570 # ifndef VBOX_WITH_EXTPACK571 RT_NOREF(pUVM);572 # endif573 HRESULT hrc = S_OK;574 PCFGMNODE pInst, pCfg, pLunL0, pLunL1;575 576 SafeIfaceArray<IPCIDeviceAttachment> assignments;577 ComPtr<IMachine> aMachine = i_machine();578 579 hrc = aMachine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments));580 if ( hrc != S_OK581 || assignments.size() < 1)582 return hrc;583 584 /*585 * PCI passthrough is only available if the proper ExtPack is installed.586 *587 * Note. Configuring PCI passthrough here and providing messages about588 * the missing extpack isn't exactly clean, but it is a necessary evil589 * to patch over legacy compatability issues introduced by the new590 * distribution model.591 */592 # ifdef VBOX_WITH_EXTPACK593 static const char *s_pszPCIRawExtPackName = "Oracle VM VirtualBox Extension Pack";594 if (!mptrExtPackManager->i_isExtPackUsable(s_pszPCIRawExtPackName))595 /* Always fatal! */596 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,597 N_("Implementation of the PCI passthrough framework not found!\n"598 "The VM cannot be started. To fix this problem, either "599 "install the '%s' or disable PCI passthrough via VBoxManage"),600 s_pszPCIRawExtPackName);601 # endif602 603 /* Now actually add devices */604 PCFGMNODE pPCIDevs = NULL;605 606 if (assignments.size() > 0)607 {608 InsertConfigNode(pDevices, "pciraw", &pPCIDevs);609 610 PCFGMNODE pRoot = CFGMR3GetParent(pDevices); Assert(pRoot);611 612 /* Tell PGM to tell GPCIRaw about guest mappings. */613 CFGMR3InsertNode(pRoot, "PGM", NULL);614 InsertConfigInteger(CFGMR3GetChild(pRoot, "PGM"), "PciPassThrough", 1);615 616 /*617 * Currently, using IOMMU needed for PCI passthrough618 * requires RAM preallocation.619 */620 /** @todo check if we can lift this requirement */621 CFGMR3RemoveValue(pRoot, "RamPreAlloc");622 InsertConfigInteger(pRoot, "RamPreAlloc", 1);623 }624 625 for (size_t iDev = 0; iDev < assignments.size(); iDev++)626 {627 ComPtr<IPCIDeviceAttachment> const assignment = assignments[iDev];628 629 LONG host;630 hrc = assignment->COMGETTER(HostAddress)(&host); H();631 LONG guest;632 hrc = assignment->COMGETTER(GuestAddress)(&guest); H();633 Bstr bstrDevName;634 hrc = assignment->COMGETTER(Name)(bstrDevName.asOutParam()); H();635 636 InsertConfigNodeF(pPCIDevs, &pInst, "%d", iDev);637 InsertConfigInteger(pInst, "Trusted", 1);638 639 PCIBusAddress HostPCIAddress(host);640 Assert(HostPCIAddress.valid());641 InsertConfigNode(pInst, "Config", &pCfg);642 InsertConfigString(pCfg, "DeviceName", bstrDevName);643 644 InsertConfigInteger(pCfg, "DetachHostDriver", 1);645 InsertConfigInteger(pCfg, "HostPCIBusNo", HostPCIAddress.miBus);646 InsertConfigInteger(pCfg, "HostPCIDeviceNo", HostPCIAddress.miDevice);647 InsertConfigInteger(pCfg, "HostPCIFunctionNo", HostPCIAddress.miFn);648 649 PCIBusAddress GuestPCIAddress(guest);650 Assert(GuestPCIAddress.valid());651 hrc = pBusMgr->assignHostPCIDevice("pciraw", pInst, HostPCIAddress, GuestPCIAddress, true);652 if (hrc != S_OK)653 return hrc;654 655 InsertConfigInteger(pCfg, "GuestPCIBusNo", GuestPCIAddress.miBus);656 InsertConfigInteger(pCfg, "GuestPCIDeviceNo", GuestPCIAddress.miDevice);657 InsertConfigInteger(pCfg, "GuestPCIFunctionNo", GuestPCIAddress.miFn);658 659 /* the driver */660 InsertConfigNode(pInst, "LUN#0", &pLunL0);661 InsertConfigString(pLunL0, "Driver", "pciraw");662 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);663 664 /* the Main driver */665 InsertConfigString(pLunL1, "Driver", "MainPciRaw");666 InsertConfigNode(pLunL1, "Config", &pCfg);667 PCIRawDev *pMainDev = new PCIRawDev(this);668 # error This is not allowed any more669 InsertConfigInteger(pCfg, "Object", (uintptr_t)pMainDev);670 }671 672 return hrc;673 }674 #endif675 332 676 333 … … 820 477 try 821 478 { 822 vrc = pConsole->i_configConstructorInner (pUVM, pVM, pVMM, &alock);479 vrc = pConsole->i_configConstructorInnerX86(pUVM, pVM, pVMM, &alock); 823 480 } 824 481 catch (...) … … 835 492 } 836 493 837 838 /**839 * Worker for configConstructor.840 *841 * @return VBox status code.842 * @param pUVM The user mode VM handle.843 * @param pVM The cross context VM handle.844 * @param pVMM The VMM vtable.845 * @param pAlock The automatic lock instance. This is for when we have846 * to leave it in order to avoid deadlocks (ext packs and847 * more).848 */849 int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)850 {851 RT_NOREF(pVM /* when everything is disabled */);852 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);853 ComPtr<IMachine> pMachine = i_machine();854 855 int vrc;856 HRESULT hrc;857 Utf8Str strTmp;858 Bstr bstr;859 860 #define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)861 862 /*863 * Get necessary objects and frequently used parameters.864 */865 ComPtr<IVirtualBox> virtualBox;866 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();867 868 ComPtr<IHost> host;869 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();870 871 ComPtr<ISystemProperties> systemProperties;872 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();873 874 ComPtr<IBIOSSettings> biosSettings;875 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();876 877 ComPtr<INvramStore> nvramStore;878 hrc = pMachine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam()); H();879 880 hrc = pMachine->COMGETTER(HardwareUUID)(bstr.asOutParam()); H();881 RTUUID HardwareUuid;882 vrc = RTUuidFromUtf16(&HardwareUuid, bstr.raw());883 AssertRCReturn(vrc, vrc);884 885 ULONG cRamMBs;886 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();887 #if 0 /* enable to play with lots of memory. */888 if (RTEnvExist("VBOX_RAM_SIZE"))889 cRamMBs = RTStrToUInt64(RTEnvGet("VBOX_RAM_SIZE"));890 #endif891 uint64_t const cbRam = cRamMBs * (uint64_t)_1M;892 uint32_t cbRamHole = MM_RAM_HOLE_SIZE_DEFAULT;893 uint64_t uMcfgBase = 0;894 uint32_t cbMcfgLength = 0;895 896 ParavirtProvider_T enmParavirtProvider;897 hrc = pMachine->GetEffectiveParavirtProvider(&enmParavirtProvider); H();898 899 Bstr strParavirtDebug;900 hrc = pMachine->COMGETTER(ParavirtDebug)(strParavirtDebug.asOutParam()); H();901 902 BOOL fIOAPIC;903 uint32_t uIoApicPciAddress = NIL_PCIBDF;904 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();905 906 ChipsetType_T chipsetType;907 hrc = pMachine->COMGETTER(ChipsetType)(&chipsetType); H();908 if (chipsetType == ChipsetType_ICH9)909 {910 /* We'd better have 0x10000000 region, to cover 256 buses but this put911 * too much load on hypervisor heap. Linux 4.8 currently complains with912 * ``acpi PNP0A03:00: [Firmware Info]: MMCONFIG for domain 0000 [bus 00-3f]913 * only partially covers this bridge'' */914 cbMcfgLength = 0x4000000; //0x10000000;915 cbRamHole += cbMcfgLength;916 uMcfgBase = _4G - cbRamHole;917 }918 919 /* Get the CPU profile name. */920 Bstr bstrCpuProfile;921 hrc = pMachine->COMGETTER(CPUProfile)(bstrCpuProfile.asOutParam()); H();922 923 /* Check if long mode is enabled. */924 BOOL fIsGuest64Bit;925 hrc = pMachine->GetCPUProperty(CPUPropertyType_LongMode, &fIsGuest64Bit); H();926 927 /*928 * Figure out the IOMMU config.929 */930 #if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL)931 IommuType_T enmIommuType;932 hrc = pMachine->COMGETTER(IommuType)(&enmIommuType); H();933 934 /* Resolve 'automatic' type to an Intel or AMD IOMMU based on the host CPU. */935 if (enmIommuType == IommuType_Automatic)936 {937 if ( bstrCpuProfile.startsWith("AMD")938 || bstrCpuProfile.startsWith("Quad-Core AMD")939 || bstrCpuProfile.startsWith("Hygon"))940 enmIommuType = IommuType_AMD;941 else if (bstrCpuProfile.startsWith("Intel"))942 {943 if ( bstrCpuProfile.equals("Intel 8086")944 || bstrCpuProfile.equals("Intel 80186")945 || bstrCpuProfile.equals("Intel 80286")946 || bstrCpuProfile.equals("Intel 80386")947 || bstrCpuProfile.equals("Intel 80486"))948 enmIommuType = IommuType_None;949 else950 enmIommuType = IommuType_Intel;951 }952 # if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)953 else if (ASMIsAmdCpu())954 enmIommuType = IommuType_AMD;955 else if (ASMIsIntelCpu())956 enmIommuType = IommuType_Intel;957 # endif958 else959 {960 /** @todo Should we handle other CPUs like Shanghai, VIA etc. here? */961 LogRel(("WARNING! Unrecognized CPU type, IOMMU disabled.\n"));962 enmIommuType = IommuType_None;963 }964 }965 966 if (enmIommuType == IommuType_AMD)967 {968 # ifdef VBOX_WITH_IOMMU_AMD969 /*970 * Reserve the specific PCI address of the "SB I/O APIC" when using971 * an AMD IOMMU. Required by Linux guests, see @bugref{9654#c23}.972 */973 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;974 # else975 LogRel(("WARNING! AMD IOMMU not supported, IOMMU disabled.\n"));976 enmIommuType = IommuType_None;977 # endif978 }979 980 if (enmIommuType == IommuType_Intel)981 {982 # ifdef VBOX_WITH_IOMMU_INTEL983 /*984 * Reserve a unique PCI address for the I/O APIC when using985 * an Intel IOMMU. For convenience we use the same address as986 * we do on AMD, see @bugref{9967#c13}.987 */988 uIoApicPciAddress = VBOX_PCI_BDF_SB_IOAPIC;989 # else990 LogRel(("WARNING! Intel IOMMU not supported, IOMMU disabled.\n"));991 enmIommuType = IommuType_None;992 # endif993 }994 995 if ( enmIommuType == IommuType_AMD996 || enmIommuType == IommuType_Intel)997 {998 if (chipsetType != ChipsetType_ICH9)999 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1000 N_("IOMMU uses MSIs which requires the ICH9 chipset implementation."));1001 if (!fIOAPIC)1002 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1003 N_("IOMMU requires an I/O APIC for remapping interrupts."));1004 }1005 #else1006 IommuType_T const enmIommuType = IommuType_None;1007 #endif1008 1009 /* Instantiate the bus assignment manager. */1010 Assert(enmIommuType != IommuType_Automatic);1011 BusAssignmentManager *pBusMgr = mBusMgr = BusAssignmentManager::createInstance(pVMM, chipsetType, enmIommuType);1012 1013 ULONG cCpus = 1;1014 hrc = pMachine->COMGETTER(CPUCount)(&cCpus); H();1015 1016 ULONG ulCpuExecutionCap = 100;1017 hrc = pMachine->COMGETTER(CPUExecutionCap)(&ulCpuExecutionCap); H();1018 1019 Bstr osTypeId;1020 hrc = pMachine->COMGETTER(OSTypeId)(osTypeId.asOutParam()); H();1021 LogRel(("Guest OS type: '%s'\n", Utf8Str(osTypeId).c_str()));1022 1023 APICMode_T apicMode;1024 hrc = biosSettings->COMGETTER(APICMode)(&apicMode); H();1025 uint32_t uFwAPIC;1026 switch (apicMode)1027 {1028 case APICMode_Disabled:1029 uFwAPIC = 0;1030 break;1031 case APICMode_APIC:1032 uFwAPIC = 1;1033 break;1034 case APICMode_X2APIC:1035 uFwAPIC = 2;1036 break;1037 default:1038 AssertMsgFailed(("Invalid APICMode=%d\n", apicMode));1039 uFwAPIC = 1;1040 break;1041 }1042 1043 ComPtr<IGuestOSType> pGuestOSType;1044 virtualBox->GetGuestOSType(osTypeId.raw(), pGuestOSType.asOutParam());1045 1046 BOOL fOsXGuest = FALSE;1047 BOOL fWinGuest = FALSE;1048 BOOL fOs2Guest = FALSE;1049 BOOL fW9xGuest = FALSE;1050 BOOL fDosGuest = FALSE;1051 if (!pGuestOSType.isNull())1052 {1053 Bstr guestTypeFamilyId;1054 hrc = pGuestOSType->COMGETTER(FamilyId)(guestTypeFamilyId.asOutParam()); H();1055 fOsXGuest = guestTypeFamilyId == Bstr("MacOS");1056 fWinGuest = guestTypeFamilyId == Bstr("Windows");1057 fOs2Guest = osTypeId.startsWith("OS2");1058 fW9xGuest = osTypeId.startsWith("Windows9"); /* Does not include Windows Me. */1059 fDosGuest = osTypeId.startsWith("DOS") || osTypeId.startsWith("Windows31");1060 }1061 1062 ULONG maxNetworkAdapters;1063 hrc = systemProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters); H();1064 1065 /*1066 * Get root node first.1067 * This is the only node in the tree.1068 */1069 PCFGMNODE pRoot = pVMM->pfnCFGMR3GetRootU(pUVM);1070 Assert(pRoot);1071 1072 // catching throws from InsertConfigString and friends.1073 try1074 {1075 1076 /*1077 * Set the root (and VMM) level values.1078 */1079 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();1080 InsertConfigString(pRoot, "Name", bstr);1081 InsertConfigBytes(pRoot, "UUID", &HardwareUuid, sizeof(HardwareUuid));1082 InsertConfigInteger(pRoot, "RamSize", cbRam);1083 InsertConfigInteger(pRoot, "RamHoleSize", cbRamHole);1084 InsertConfigInteger(pRoot, "NumCPUs", cCpus);1085 InsertConfigInteger(pRoot, "CpuExecutionCap", ulCpuExecutionCap);1086 InsertConfigInteger(pRoot, "TimerMillies", 10);1087 1088 BOOL fPageFusion = FALSE;1089 hrc = pMachine->COMGETTER(PageFusionEnabled)(&fPageFusion); H();1090 InsertConfigInteger(pRoot, "PageFusionAllowed", fPageFusion); /* boolean */1091 1092 /* Not necessary, but makes sure this setting ends up in the release log. */1093 ULONG ulBalloonSize = 0;1094 hrc = pMachine->COMGETTER(MemoryBalloonSize)(&ulBalloonSize); H();1095 InsertConfigInteger(pRoot, "MemBalloonSize", ulBalloonSize);1096 1097 /*1098 * EM values (before CPUM as it may need to set IemExecutesAll).1099 */1100 PCFGMNODE pEM;1101 InsertConfigNode(pRoot, "EM", &pEM);1102 1103 /* Triple fault behavior. */1104 BOOL fTripleFaultReset = false;1105 hrc = pMachine->GetCPUProperty(CPUPropertyType_TripleFaultReset, &fTripleFaultReset); H();1106 InsertConfigInteger(pEM, "TripleFaultReset", fTripleFaultReset);1107 1108 /*1109 * CPUM values.1110 */1111 PCFGMNODE pCPUM;1112 InsertConfigNode(pRoot, "CPUM", &pCPUM);1113 PCFGMNODE pIsaExts;1114 InsertConfigNode(pCPUM, "IsaExts", &pIsaExts);1115 1116 /* Host CPUID leaf overrides. */1117 for (uint32_t iOrdinal = 0; iOrdinal < _4K; iOrdinal++)1118 {1119 ULONG uLeaf, uSubLeaf, uEax, uEbx, uEcx, uEdx;1120 hrc = pMachine->GetCPUIDLeafByOrdinal(iOrdinal, &uLeaf, &uSubLeaf, &uEax, &uEbx, &uEcx, &uEdx);1121 if (hrc == E_INVALIDARG)1122 break;1123 H();1124 PCFGMNODE pLeaf;1125 InsertConfigNode(pCPUM, Utf8StrFmt("HostCPUID/%RX32", uLeaf).c_str(), &pLeaf);1126 /** @todo Figure out how to tell the VMM about uSubLeaf */1127 InsertConfigInteger(pLeaf, "eax", uEax);1128 InsertConfigInteger(pLeaf, "ebx", uEbx);1129 InsertConfigInteger(pLeaf, "ecx", uEcx);1130 InsertConfigInteger(pLeaf, "edx", uEdx);1131 }1132 1133 /* We must limit CPUID count for Windows NT 4, as otherwise it stops1134 with error 0x3e (MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED). */1135 if (osTypeId == "WindowsNT4")1136 {1137 LogRel(("Limiting CPUID leaf count for NT4 guests\n"));1138 InsertConfigInteger(pCPUM, "NT4LeafLimit", true);1139 }1140 1141 if (fOsXGuest)1142 {1143 /* Expose extended MWAIT features to Mac OS X guests. */1144 LogRel(("Using MWAIT extensions\n"));1145 InsertConfigInteger(pIsaExts, "MWaitExtensions", true);1146 1147 /* Fake the CPU family/model so the guest works. This is partly1148 because older mac releases really doesn't work on newer cpus,1149 and partly because mac os x expects more from systems with newer1150 cpus (MSRs, power features, whatever). */1151 uint32_t uMaxIntelFamilyModelStep = UINT32_MAX;1152 if ( osTypeId == "MacOS"1153 || osTypeId == "MacOS_64")1154 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482. */1155 else if ( osTypeId == "MacOS106"1156 || osTypeId == "MacOS106_64")1157 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */1158 else if ( osTypeId == "MacOS107"1159 || osTypeId == "MacOS107_64")1160 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out1161 what is required here. */1162 else if ( osTypeId == "MacOS108"1163 || osTypeId == "MacOS108_64")1164 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure out1165 what is required here. */1166 else if ( osTypeId == "MacOS109"1167 || osTypeId == "MacOS109_64")1168 uMaxIntelFamilyModelStep = RT_MAKE_U32_FROM_U8(1, 23, 6, 0); /* Penryn / X5482 */ /** @todo figure1169 out what is required here. */1170 if (uMaxIntelFamilyModelStep != UINT32_MAX)1171 InsertConfigInteger(pCPUM, "MaxIntelFamilyModelStep", uMaxIntelFamilyModelStep);1172 }1173 1174 /* CPU Portability level, */1175 ULONG uCpuIdPortabilityLevel = 0;1176 hrc = pMachine->COMGETTER(CPUIDPortabilityLevel)(&uCpuIdPortabilityLevel); H();1177 InsertConfigInteger(pCPUM, "PortableCpuIdLevel", uCpuIdPortabilityLevel);1178 1179 /* Physical Address Extension (PAE) */1180 BOOL fEnablePAE = false;1181 hrc = pMachine->GetCPUProperty(CPUPropertyType_PAE, &fEnablePAE); H();1182 fEnablePAE |= fIsGuest64Bit;1183 InsertConfigInteger(pRoot, "EnablePAE", fEnablePAE);1184 1185 /* 64-bit guests (long mode) */1186 InsertConfigInteger(pCPUM, "Enable64bit", fIsGuest64Bit);1187 1188 /* APIC/X2APIC configuration */1189 BOOL fEnableAPIC = true;1190 BOOL fEnableX2APIC = true;1191 hrc = pMachine->GetCPUProperty(CPUPropertyType_APIC, &fEnableAPIC); H();1192 hrc = pMachine->GetCPUProperty(CPUPropertyType_X2APIC, &fEnableX2APIC); H();1193 if (fEnableX2APIC)1194 Assert(fEnableAPIC);1195 1196 /* CPUM profile name. */1197 InsertConfigString(pCPUM, "GuestCpuName", bstrCpuProfile);1198 1199 /*1200 * Temporary(?) hack to make sure we emulate the ancient 16-bit CPUs1201 * correctly. There are way too many #UDs we'll miss using VT-x,1202 * raw-mode or qemu for the 186 and 286, while we'll get undefined opcodes1203 * dead wrong on 8086 (see http://www.os2museum.com/wp/undocumented-8086-opcodes/).1204 */1205 if ( bstrCpuProfile.equals("Intel 80386") /* just for now */1206 || bstrCpuProfile.equals("Intel 80286")1207 || bstrCpuProfile.equals("Intel 80186")1208 || bstrCpuProfile.equals("Nec V20")1209 || bstrCpuProfile.equals("Intel 8086") )1210 {1211 InsertConfigInteger(pEM, "IemExecutesAll", true);1212 if (!bstrCpuProfile.equals("Intel 80386"))1213 {1214 fEnableAPIC = false;1215 fIOAPIC = false;1216 }1217 fEnableX2APIC = false;1218 }1219 1220 /* Adjust firmware APIC handling to stay within the VCPU limits. */1221 if (uFwAPIC == 2 && !fEnableX2APIC)1222 {1223 if (fEnableAPIC)1224 uFwAPIC = 1;1225 else1226 uFwAPIC = 0;1227 LogRel(("Limiting the firmware APIC level from x2APIC to %s\n", fEnableAPIC ? "APIC" : "Disabled"));1228 }1229 else if (uFwAPIC == 1 && !fEnableAPIC)1230 {1231 uFwAPIC = 0;1232 LogRel(("Limiting the firmware APIC level from APIC to Disabled\n"));1233 }1234 1235 /* Speculation Control. */1236 BOOL fSpecCtrl = FALSE;1237 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrl, &fSpecCtrl); H();1238 InsertConfigInteger(pCPUM, "SpecCtrl", fSpecCtrl);1239 1240 /* Nested VT-x / AMD-V. */1241 BOOL fNestedHWVirt = FALSE;1242 hrc = pMachine->GetCPUProperty(CPUPropertyType_HWVirt, &fNestedHWVirt); H();1243 InsertConfigInteger(pCPUM, "NestedHWVirt", fNestedHWVirt ? true : false);1244 1245 /*1246 * Hardware virtualization extensions.1247 */1248 /* Sanitize valid/useful APIC combinations, see @bugref{8868}. */1249 if (!fEnableAPIC)1250 {1251 if (fIsGuest64Bit)1252 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1253 N_("Cannot disable the APIC for a 64-bit guest."));1254 if (cCpus > 1)1255 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1256 N_("Cannot disable the APIC for an SMP guest."));1257 if (fIOAPIC)1258 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1259 N_("Cannot disable the APIC when the I/O APIC is present."));1260 }1261 1262 BOOL fHMEnabled;1263 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &fHMEnabled); H();1264 if (cCpus > 1 && !fHMEnabled)1265 {1266 LogRel(("Forced fHMEnabled to TRUE by SMP guest.\n"));1267 fHMEnabled = TRUE;1268 }1269 1270 BOOL fHMForced;1271 fHMEnabled = fHMForced = TRUE;1272 LogRel(("fHMForced=true - No raw-mode support in this build!\n"));1273 if (!fHMForced) /* No need to query if already forced above. */1274 {1275 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_Force, &fHMForced); H();1276 if (fHMForced)1277 LogRel(("fHMForced=true - HWVirtExPropertyType_Force\n"));1278 }1279 InsertConfigInteger(pRoot, "HMEnabled", fHMEnabled);1280 1281 /* /HM/xyz */1282 PCFGMNODE pHM;1283 InsertConfigNode(pRoot, "HM", &pHM);1284 InsertConfigInteger(pHM, "HMForced", fHMForced);1285 if (fHMEnabled)1286 {1287 /* Indicate whether 64-bit guests are supported or not. */1288 InsertConfigInteger(pHM, "64bitEnabled", fIsGuest64Bit);1289 1290 /** @todo Not exactly pretty to check strings; VBOXOSTYPE would be better,1291 but that requires quite a bit of API change in Main. */1292 if ( fIOAPIC1293 && ( osTypeId == "WindowsNT4"1294 || osTypeId == "Windows2000"1295 || osTypeId == "WindowsXP"1296 || osTypeId == "Windows2003"))1297 {1298 /* Only allow TPR patching for NT, Win2k, XP and Windows Server 2003. (32 bits mode)1299 * We may want to consider adding more guest OSes (Solaris) later on.1300 */1301 InsertConfigInteger(pHM, "TPRPatchingEnabled", 1);1302 }1303 }1304 1305 /* HWVirtEx exclusive mode */1306 BOOL fHMExclusive = true;1307 hrc = systemProperties->COMGETTER(ExclusiveHwVirt)(&fHMExclusive); H();1308 InsertConfigInteger(pHM, "Exclusive", fHMExclusive);1309 1310 /* Nested paging (VT-x/AMD-V) */1311 BOOL fEnableNestedPaging = false;1312 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &fEnableNestedPaging); H();1313 InsertConfigInteger(pHM, "EnableNestedPaging", fEnableNestedPaging);1314 1315 /* Large pages; requires nested paging */1316 BOOL fEnableLargePages = false;1317 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &fEnableLargePages); H();1318 InsertConfigInteger(pHM, "EnableLargePages", fEnableLargePages);1319 1320 /* VPID (VT-x) */1321 BOOL fEnableVPID = false;1322 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &fEnableVPID); H();1323 InsertConfigInteger(pHM, "EnableVPID", fEnableVPID);1324 1325 /* Unrestricted execution aka UX (VT-x) */1326 BOOL fEnableUX = false;1327 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &fEnableUX); H();1328 InsertConfigInteger(pHM, "EnableUX", fEnableUX);1329 1330 /* Virtualized VMSAVE/VMLOAD (AMD-V) */1331 BOOL fVirtVmsaveVmload = true;1332 hrc = host->GetProcessorFeature(ProcessorFeature_VirtVmsaveVmload, &fVirtVmsaveVmload); H();1333 InsertConfigInteger(pHM, "SvmVirtVmsaveVmload", fVirtVmsaveVmload);1334 1335 /* Indirect branch prediction boundraries. */1336 BOOL fIBPBOnVMExit = false;1337 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMExit, &fIBPBOnVMExit); H();1338 InsertConfigInteger(pHM, "IBPBOnVMExit", fIBPBOnVMExit);1339 1340 BOOL fIBPBOnVMEntry = false;1341 hrc = pMachine->GetCPUProperty(CPUPropertyType_IBPBOnVMEntry, &fIBPBOnVMEntry); H();1342 InsertConfigInteger(pHM, "IBPBOnVMEntry", fIBPBOnVMEntry);1343 1344 BOOL fSpecCtrlByHost = false;1345 hrc = pMachine->GetCPUProperty(CPUPropertyType_SpecCtrlByHost, &fSpecCtrlByHost); H();1346 InsertConfigInteger(pHM, "SpecCtrlByHost", fSpecCtrlByHost);1347 1348 BOOL fL1DFlushOnSched = true;1349 hrc = pMachine->GetCPUProperty(CPUPropertyType_L1DFlushOnEMTScheduling, &fL1DFlushOnSched); H();1350 InsertConfigInteger(pHM, "L1DFlushOnSched", fL1DFlushOnSched);1351 1352 BOOL fL1DFlushOnVMEntry = false;1353 hrc = pMachine->GetCPUProperty(CPUPropertyType_L1DFlushOnVMEntry, &fL1DFlushOnVMEntry); H();1354 InsertConfigInteger(pHM, "L1DFlushOnVMEntry", fL1DFlushOnVMEntry);1355 1356 BOOL fMDSClearOnSched = true;1357 hrc = pMachine->GetCPUProperty(CPUPropertyType_MDSClearOnEMTScheduling, &fMDSClearOnSched); H();1358 InsertConfigInteger(pHM, "MDSClearOnSched", fMDSClearOnSched);1359 1360 BOOL fMDSClearOnVMEntry = false;1361 hrc = pMachine->GetCPUProperty(CPUPropertyType_MDSClearOnVMEntry, &fMDSClearOnVMEntry); H();1362 InsertConfigInteger(pHM, "MDSClearOnVMEntry", fMDSClearOnVMEntry);1363 1364 /* Reset overwrite. */1365 mfTurnResetIntoPowerOff = GetExtraDataBoth(virtualBox, pMachine,1366 "VBoxInternal2/TurnResetIntoPowerOff", &strTmp)->equals("1");1367 if (mfTurnResetIntoPowerOff)1368 InsertConfigInteger(pRoot, "PowerOffInsteadOfReset", 1);1369 1370 /* Use NEM rather than HM. */1371 BOOL fUseNativeApi = false;1372 hrc = pMachine->GetHWVirtExProperty(HWVirtExPropertyType_UseNativeApi, &fUseNativeApi); H();1373 InsertConfigInteger(pHM, "UseNEMInstead", fUseNativeApi);1374 1375 /* Enable workaround for missing TLB flush for OS/2 guests, see ticketref:20625. */1376 if (osTypeId.startsWith("OS2"))1377 InsertConfigInteger(pHM, "MissingOS2TlbFlushWorkaround", 1);1378 1379 /*1380 * NEM1381 */1382 PCFGMNODE pNEM;1383 InsertConfigNode(pRoot, "NEM", &pNEM);1384 InsertConfigInteger(pNEM, "Allow64BitGuests", fIsGuest64Bit);1385 1386 /*1387 * Paravirt. provider.1388 */1389 PCFGMNODE pParavirtNode;1390 InsertConfigNode(pRoot, "GIM", &pParavirtNode);1391 const char *pcszParavirtProvider;1392 bool fGimDeviceNeeded = true;1393 switch (enmParavirtProvider)1394 {1395 case ParavirtProvider_None:1396 pcszParavirtProvider = "None";1397 fGimDeviceNeeded = false;1398 break;1399 1400 case ParavirtProvider_Minimal:1401 pcszParavirtProvider = "Minimal";1402 break;1403 1404 case ParavirtProvider_HyperV:1405 pcszParavirtProvider = "HyperV";1406 break;1407 1408 case ParavirtProvider_KVM:1409 pcszParavirtProvider = "KVM";1410 break;1411 1412 default:1413 AssertMsgFailed(("Invalid enmParavirtProvider=%d\n", enmParavirtProvider));1414 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("Invalid paravirt. provider '%d'"),1415 enmParavirtProvider);1416 }1417 InsertConfigString(pParavirtNode, "Provider", pcszParavirtProvider);1418 1419 /*1420 * Parse paravirt. debug options.1421 */1422 bool fGimDebug = false;1423 com::Utf8Str strGimDebugAddress = "127.0.0.1";1424 uint32_t uGimDebugPort = 50000;1425 if (strParavirtDebug.isNotEmpty())1426 {1427 /* Hyper-V debug options. */1428 if (enmParavirtProvider == ParavirtProvider_HyperV)1429 {1430 bool fGimHvDebug = false;1431 com::Utf8Str strGimHvVendor;1432 bool fGimHvVsIf = false;1433 bool fGimHvHypercallIf = false;1434 1435 size_t uPos = 0;1436 com::Utf8Str strDebugOptions = strParavirtDebug;1437 com::Utf8Str strKey;1438 com::Utf8Str strVal;1439 while ((uPos = strDebugOptions.parseKeyValue(strKey, strVal, uPos)) != com::Utf8Str::npos)1440 {1441 if (strKey == "enabled")1442 {1443 if (strVal.toUInt32() == 1)1444 {1445 /* Apply defaults.1446 The defaults are documented in the user manual,1447 changes need to be reflected accordingly. */1448 fGimHvDebug = true;1449 strGimHvVendor = "Microsoft Hv";1450 fGimHvVsIf = true;1451 fGimHvHypercallIf = false;1452 }1453 /* else: ignore, i.e. don't assert below with 'enabled=0'. */1454 }1455 else if (strKey == "address")1456 strGimDebugAddress = strVal;1457 else if (strKey == "port")1458 uGimDebugPort = strVal.toUInt32();1459 else if (strKey == "vendor")1460 strGimHvVendor = strVal;1461 else if (strKey == "vsinterface")1462 fGimHvVsIf = RT_BOOL(strVal.toUInt32());1463 else if (strKey == "hypercallinterface")1464 fGimHvHypercallIf = RT_BOOL(strVal.toUInt32());1465 else1466 {1467 AssertMsgFailed(("Unrecognized Hyper-V debug option '%s'\n", strKey.c_str()));1468 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1469 N_("Unrecognized Hyper-V debug option '%s' in '%s'"), strKey.c_str(),1470 strDebugOptions.c_str());1471 }1472 }1473 1474 /* Update HyperV CFGM node with active debug options. */1475 if (fGimHvDebug)1476 {1477 PCFGMNODE pHvNode;1478 InsertConfigNode(pParavirtNode, "HyperV", &pHvNode);1479 InsertConfigString(pHvNode, "VendorID", strGimHvVendor);1480 InsertConfigInteger(pHvNode, "VSInterface", fGimHvVsIf ? 1 : 0);1481 InsertConfigInteger(pHvNode, "HypercallDebugInterface", fGimHvHypercallIf ? 1 : 0);1482 fGimDebug = true;1483 }1484 }1485 }1486 1487 /*1488 * Guest Compatibility Manager.1489 */1490 PCFGMNODE pGcmNode;1491 uint32_t u32FixerSet = 0;1492 InsertConfigNode(pRoot, "GCM", &pGcmNode);1493 /* OS/2 and Win9x guests can run DOS apps so they get1494 * the DOS specific fixes as well.1495 */1496 if (fOs2Guest)1497 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_OS2;1498 else if (fW9xGuest)1499 u32FixerSet = GCMFIXER_DBZ_DOS | GCMFIXER_DBZ_WIN9X;1500 else if (fDosGuest)1501 u32FixerSet = GCMFIXER_DBZ_DOS;1502 InsertConfigInteger(pGcmNode, "FixerSet", u32FixerSet);1503 1504 1505 /*1506 * MM values.1507 */1508 PCFGMNODE pMM;1509 InsertConfigNode(pRoot, "MM", &pMM);1510 InsertConfigInteger(pMM, "CanUseLargerHeap", chipsetType == ChipsetType_ICH9);1511 1512 /*1513 * PDM config.1514 * Load drivers in VBoxC.[so|dll]1515 */1516 PCFGMNODE pPDM;1517 PCFGMNODE pNode;1518 PCFGMNODE pMod;1519 InsertConfigNode(pRoot, "PDM", &pPDM);1520 InsertConfigNode(pPDM, "Devices", &pNode);1521 InsertConfigNode(pPDM, "Drivers", &pNode);1522 InsertConfigNode(pNode, "VBoxC", &pMod);1523 #ifdef VBOX_WITH_XPCOM1524 // VBoxC is located in the components subdirectory1525 char szPathVBoxC[RTPATH_MAX];1526 vrc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX - sizeof("/components/VBoxC")); AssertRC(vrc);1527 strcat(szPathVBoxC, "/components/VBoxC");1528 InsertConfigString(pMod, "Path", szPathVBoxC);1529 #else1530 InsertConfigString(pMod, "Path", "VBoxC");1531 #endif1532 1533 1534 /*1535 * Block cache settings.1536 */1537 PCFGMNODE pPDMBlkCache;1538 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);1539 1540 /* I/O cache size */1541 ULONG ioCacheSize = 5;1542 hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();1543 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);1544 1545 /*1546 * Bandwidth groups.1547 */1548 ComPtr<IBandwidthControl> bwCtrl;1549 1550 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();1551 1552 com::SafeIfaceArray<IBandwidthGroup> bwGroups;1553 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();1554 1555 PCFGMNODE pAc;1556 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);1557 PCFGMNODE pAcFile;1558 InsertConfigNode(pAc, "File", &pAcFile);1559 PCFGMNODE pAcFileBwGroups;1560 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);1561 #ifdef VBOX_WITH_NETSHAPER1562 PCFGMNODE pNetworkShaper;1563 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);1564 PCFGMNODE pNetworkBwGroups;1565 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);1566 #endif /* VBOX_WITH_NETSHAPER */1567 1568 for (size_t i = 0; i < bwGroups.size(); i++)1569 {1570 Bstr strName;1571 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();1572 if (strName.isEmpty())1573 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));1574 1575 BandwidthGroupType_T enmType = BandwidthGroupType_Null;1576 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();1577 LONG64 cMaxBytesPerSec = 0;1578 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();1579 1580 if (enmType == BandwidthGroupType_Disk)1581 {1582 PCFGMNODE pBwGroup;1583 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);1584 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);1585 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);1586 InsertConfigInteger(pBwGroup, "Step", 0);1587 }1588 #ifdef VBOX_WITH_NETSHAPER1589 else if (enmType == BandwidthGroupType_Network)1590 {1591 /* Network bandwidth groups. */1592 PCFGMNODE pBwGroup;1593 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);1594 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);1595 }1596 #endif /* VBOX_WITH_NETSHAPER */1597 }1598 1599 /*1600 * Devices1601 */1602 PCFGMNODE pDevices = NULL; /* /Devices */1603 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */1604 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */1605 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */1606 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */1607 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */1608 PCFGMNODE pBiosCfg = NULL; /* /Devices/pcbios/0/Config/ */1609 PCFGMNODE pNetBootCfg = NULL; /* /Devices/pcbios/0/Config/NetBoot/ */1610 1611 InsertConfigNode(pRoot, "Devices", &pDevices);1612 1613 /*1614 * GIM Device1615 */1616 if (fGimDeviceNeeded)1617 {1618 InsertConfigNode(pDevices, "GIMDev", &pDev);1619 InsertConfigNode(pDev, "0", &pInst);1620 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1621 //InsertConfigNode(pInst, "Config", &pCfg);1622 1623 if (fGimDebug)1624 {1625 InsertConfigNode(pInst, "LUN#998", &pLunL0);1626 InsertConfigString(pLunL0, "Driver", "UDP");1627 InsertConfigNode(pLunL0, "Config", &pLunL1);1628 InsertConfigString(pLunL1, "ServerAddress", strGimDebugAddress);1629 InsertConfigInteger(pLunL1, "ServerPort", uGimDebugPort);1630 }1631 }1632 1633 /*1634 * PC Arch.1635 */1636 InsertConfigNode(pDevices, "pcarch", &pDev);1637 InsertConfigNode(pDev, "0", &pInst);1638 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1639 InsertConfigNode(pInst, "Config", &pCfg);1640 1641 /*1642 * The time offset1643 */1644 LONG64 timeOffset;1645 hrc = biosSettings->COMGETTER(TimeOffset)(&timeOffset); H();1646 PCFGMNODE pTMNode;1647 InsertConfigNode(pRoot, "TM", &pTMNode);1648 InsertConfigInteger(pTMNode, "UTCOffset", timeOffset * 1000000);1649 1650 /*1651 * DMA1652 */1653 InsertConfigNode(pDevices, "8237A", &pDev);1654 InsertConfigNode(pDev, "0", &pInst);1655 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1656 1657 /*1658 * PCI buses.1659 */1660 uint32_t uIocPCIAddress, uHbcPCIAddress;1661 switch (chipsetType)1662 {1663 default:1664 AssertFailed();1665 RT_FALL_THRU();1666 case ChipsetType_PIIX3:1667 /* Create the base for adding bridges on demand */1668 InsertConfigNode(pDevices, "pcibridge", NULL);1669 1670 InsertConfigNode(pDevices, "pci", &pDev);1671 uHbcPCIAddress = (0x0 << 16) | 0;1672 uIocPCIAddress = (0x1 << 16) | 0; // ISA controller1673 break;1674 case ChipsetType_ICH9:1675 /* Create the base for adding bridges on demand */1676 InsertConfigNode(pDevices, "ich9pcibridge", NULL);1677 1678 InsertConfigNode(pDevices, "ich9pci", &pDev);1679 uHbcPCIAddress = (0x1e << 16) | 0;1680 uIocPCIAddress = (0x1f << 16) | 0; // LPC controller1681 break;1682 }1683 InsertConfigNode(pDev, "0", &pInst);1684 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1685 InsertConfigNode(pInst, "Config", &pCfg);1686 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);1687 if (chipsetType == ChipsetType_ICH9)1688 {1689 /* Provide MCFG info */1690 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);1691 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);1692 1693 #ifdef VBOX_WITH_PCI_PASSTHROUGH1694 /* Add PCI passthrough devices */1695 hrc = i_attachRawPCIDevices(pUVM, pBusMgr, pDevices); H();1696 #endif1697 1698 if (enmIommuType == IommuType_AMD)1699 {1700 /* AMD IOMMU. */1701 InsertConfigNode(pDevices, "iommu-amd", &pDev);1702 InsertConfigNode(pDev, "0", &pInst);1703 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1704 InsertConfigNode(pInst, "Config", &pCfg);1705 hrc = pBusMgr->assignPCIDevice("iommu-amd", pInst); H();1706 1707 /* The AMD IOMMU device needs to know which PCI slot it's in, see @bugref{9654#c104}. */1708 {1709 PCIBusAddress Address;1710 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))1711 {1712 uint32_t const u32IommuAddress = (Address.miDevice << 16) | Address.miFn;1713 InsertConfigInteger(pCfg, "PCIAddress", u32IommuAddress);1714 }1715 else1716 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1717 N_("Failed to find PCI address of the assigned IOMMU device!"));1718 }1719 1720 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);1721 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();1722 }1723 else if (enmIommuType == IommuType_Intel)1724 {1725 /* Intel IOMMU. */1726 InsertConfigNode(pDevices, "iommu-intel", &pDev);1727 InsertConfigNode(pDev, "0", &pInst);1728 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1729 InsertConfigNode(pInst, "Config", &pCfg);1730 hrc = pBusMgr->assignPCIDevice("iommu-intel", pInst); H();1731 1732 PCIBusAddress PCIAddr = PCIBusAddress((int32_t)uIoApicPciAddress);1733 hrc = pBusMgr->assignPCIDevice("sb-ioapic", NULL /* pCfg */, PCIAddr, true /*fGuestAddressRequired*/); H();1734 }1735 }1736 1737 /*1738 * Enable the following devices: HPET, SMC and LPC on MacOS X guests or on ICH9 chipset1739 */1740 1741 /*1742 * High Precision Event Timer (HPET)1743 */1744 BOOL fHPETEnabled;1745 /* Other guests may wish to use HPET too, but MacOS X not functional without it */1746 hrc = pMachine->COMGETTER(HPETEnabled)(&fHPETEnabled); H();1747 /* so always enable HPET in extended profile */1748 fHPETEnabled |= fOsXGuest;1749 /* HPET is always present on ICH9 */1750 fHPETEnabled |= (chipsetType == ChipsetType_ICH9);1751 if (fHPETEnabled)1752 {1753 InsertConfigNode(pDevices, "hpet", &pDev);1754 InsertConfigNode(pDev, "0", &pInst);1755 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1756 InsertConfigNode(pInst, "Config", &pCfg);1757 InsertConfigInteger(pCfg, "ICH9", (chipsetType == ChipsetType_ICH9) ? 1 : 0); /* boolean */1758 }1759 1760 /*1761 * System Management Controller (SMC)1762 */1763 BOOL fSmcEnabled;1764 fSmcEnabled = fOsXGuest;1765 if (fSmcEnabled)1766 {1767 InsertConfigNode(pDevices, "smc", &pDev);1768 InsertConfigNode(pDev, "0", &pInst);1769 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1770 InsertConfigNode(pInst, "Config", &pCfg);1771 1772 bool fGetKeyFromRealSMC;1773 Utf8Str strKey;1774 vrc = getSmcDeviceKey(virtualBox, pMachine, &strKey, &fGetKeyFromRealSMC);1775 AssertRCReturn(vrc, vrc);1776 1777 if (!fGetKeyFromRealSMC)1778 InsertConfigString(pCfg, "DeviceKey", strKey);1779 InsertConfigInteger(pCfg, "GetKeyFromRealSMC", fGetKeyFromRealSMC);1780 }1781 1782 /*1783 * Low Pin Count (LPC) bus1784 */1785 BOOL fLpcEnabled;1786 /** @todo implement appropriate getter */1787 fLpcEnabled = fOsXGuest || (chipsetType == ChipsetType_ICH9);1788 if (fLpcEnabled)1789 {1790 InsertConfigNode(pDevices, "lpc", &pDev);1791 InsertConfigNode(pDev, "0", &pInst);1792 hrc = pBusMgr->assignPCIDevice("lpc", pInst); H();1793 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1794 }1795 1796 BOOL fShowRtc;1797 fShowRtc = fOsXGuest || (chipsetType == ChipsetType_ICH9);1798 1799 /*1800 * PS/2 keyboard & mouse.1801 */1802 InsertConfigNode(pDevices, "pckbd", &pDev);1803 InsertConfigNode(pDev, "0", &pInst);1804 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1805 InsertConfigNode(pInst, "Config", &pCfg);1806 1807 KeyboardHIDType_T aKbdHID;1808 hrc = pMachine->COMGETTER(KeyboardHIDType)(&aKbdHID); H();1809 if (aKbdHID != KeyboardHIDType_None)1810 {1811 InsertConfigNode(pInst, "LUN#0", &pLunL0);1812 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");1813 InsertConfigNode(pLunL0, "Config", &pCfg);1814 InsertConfigInteger(pCfg, "QueueSize", 64);1815 1816 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);1817 InsertConfigString(pLunL1, "Driver", "MainKeyboard");1818 }1819 1820 PointingHIDType_T aPointingHID;1821 hrc = pMachine->COMGETTER(PointingHIDType)(&aPointingHID); H();1822 if (aPointingHID != PointingHIDType_None)1823 {1824 InsertConfigNode(pInst, "LUN#1", &pLunL0);1825 InsertConfigString(pLunL0, "Driver", "MouseQueue");1826 InsertConfigNode(pLunL0, "Config", &pCfg);1827 InsertConfigInteger(pCfg, "QueueSize", 128);1828 1829 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);1830 InsertConfigString(pLunL1, "Driver", "MainMouse");1831 }1832 1833 /*1834 * i8254 Programmable Interval Timer And Dummy Speaker1835 */1836 InsertConfigNode(pDevices, "i8254", &pDev);1837 InsertConfigNode(pDev, "0", &pInst);1838 InsertConfigNode(pInst, "Config", &pCfg);1839 #ifdef DEBUG1840 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1841 #endif1842 1843 /*1844 * i8259 Programmable Interrupt Controller.1845 */1846 InsertConfigNode(pDevices, "i8259", &pDev);1847 InsertConfigNode(pDev, "0", &pInst);1848 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1849 InsertConfigNode(pInst, "Config", &pCfg);1850 1851 /*1852 * Advanced Programmable Interrupt Controller.1853 * SMP: Each CPU has a LAPIC, but we have a single device representing all LAPICs states,1854 * thus only single insert1855 */1856 if (fEnableAPIC)1857 {1858 InsertConfigNode(pDevices, "apic", &pDev);1859 InsertConfigNode(pDev, "0", &pInst);1860 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1861 InsertConfigNode(pInst, "Config", &pCfg);1862 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);1863 PDMAPICMODE enmAPICMode = PDMAPICMODE_APIC;1864 if (fEnableX2APIC)1865 enmAPICMode = PDMAPICMODE_X2APIC;1866 else if (!fEnableAPIC)1867 enmAPICMode = PDMAPICMODE_NONE;1868 InsertConfigInteger(pCfg, "Mode", enmAPICMode);1869 InsertConfigInteger(pCfg, "NumCPUs", cCpus);1870 1871 if (fIOAPIC)1872 {1873 /*1874 * I/O Advanced Programmable Interrupt Controller.1875 */1876 InsertConfigNode(pDevices, "ioapic", &pDev);1877 InsertConfigNode(pDev, "0", &pInst);1878 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1879 InsertConfigNode(pInst, "Config", &pCfg);1880 InsertConfigInteger(pCfg, "NumCPUs", cCpus);1881 if (enmIommuType == IommuType_AMD)1882 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);1883 else if (enmIommuType == IommuType_Intel)1884 {1885 InsertConfigString(pCfg, "ChipType", "DMAR");1886 InsertConfigInteger(pCfg, "PCIAddress", uIoApicPciAddress);1887 }1888 }1889 }1890 1891 /*1892 * RTC MC146818.1893 */1894 InsertConfigNode(pDevices, "mc146818", &pDev);1895 InsertConfigNode(pDev, "0", &pInst);1896 InsertConfigNode(pInst, "Config", &pCfg);1897 BOOL fRTCUseUTC;1898 hrc = pMachine->COMGETTER(RTCUseUTC)(&fRTCUseUTC); H();1899 InsertConfigInteger(pCfg, "UseUTC", fRTCUseUTC ? 1 : 0);1900 1901 /*1902 * VGA.1903 */1904 ComPtr<IGraphicsAdapter> pGraphicsAdapter;1905 hrc = pMachine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); H();1906 GraphicsControllerType_T enmGraphicsController;1907 hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphicsController); H();1908 switch (enmGraphicsController)1909 {1910 case GraphicsControllerType_Null:1911 break;1912 #ifdef VBOX_WITH_VMSVGA1913 case GraphicsControllerType_VMSVGA:1914 InsertConfigInteger(pHM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */1915 InsertConfigInteger(pNEM, "LovelyMesaDrvWorkaround", 1); /* hits someone else logging backdoor. */1916 RT_FALL_THROUGH();1917 case GraphicsControllerType_VBoxSVGA:1918 #endif1919 case GraphicsControllerType_VBoxVGA:1920 vrc = i_configGraphicsController(pDevices, enmGraphicsController, pBusMgr, pMachine, pGraphicsAdapter, biosSettings,1921 RT_BOOL(fHMEnabled));1922 if (FAILED(vrc))1923 return vrc;1924 break;1925 default:1926 AssertMsgFailed(("Invalid graphicsController=%d\n", enmGraphicsController));1927 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1928 N_("Invalid graphics controller type '%d'"), enmGraphicsController);1929 }1930 1931 /*1932 * Firmware.1933 */1934 FirmwareType_T eFwType = FirmwareType_BIOS;1935 hrc = pMachine->COMGETTER(FirmwareType)(&eFwType); H();1936 1937 #ifdef VBOX_WITH_EFI1938 BOOL fEfiEnabled = (eFwType >= FirmwareType_EFI) && (eFwType <= FirmwareType_EFIDUAL);1939 #else1940 BOOL fEfiEnabled = false;1941 #endif1942 if (!fEfiEnabled)1943 {1944 /*1945 * PC Bios.1946 */1947 InsertConfigNode(pDevices, "pcbios", &pDev);1948 InsertConfigNode(pDev, "0", &pInst);1949 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */1950 InsertConfigNode(pInst, "Config", &pBiosCfg);1951 InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);1952 InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");1953 InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");1954 InsertConfigInteger(pBiosCfg, "IOAPIC", fIOAPIC);1955 InsertConfigInteger(pBiosCfg, "APIC", uFwAPIC);1956 BOOL fPXEDebug;1957 hrc = biosSettings->COMGETTER(PXEDebugEnabled)(&fPXEDebug); H();1958 InsertConfigInteger(pBiosCfg, "PXEDebug", fPXEDebug);1959 InsertConfigBytes(pBiosCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));1960 BOOL fUuidLe;1961 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();1962 InsertConfigInteger(pBiosCfg, "UuidLe", fUuidLe);1963 InsertConfigNode(pBiosCfg, "NetBoot", &pNetBootCfg);1964 InsertConfigInteger(pBiosCfg, "McfgBase", uMcfgBase);1965 InsertConfigInteger(pBiosCfg, "McfgLength", cbMcfgLength);1966 1967 AssertMsgReturn(SchemaDefs::MaxBootPosition <= 9, ("Too many boot devices %d\n", SchemaDefs::MaxBootPosition),1968 VERR_INVALID_PARAMETER);1969 1970 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; ++pos)1971 {1972 DeviceType_T enmBootDevice;1973 hrc = pMachine->GetBootOrder(pos, &enmBootDevice); H();1974 1975 char szParamName[] = "BootDeviceX";1976 szParamName[sizeof(szParamName) - 2] = (char)(pos - 1 + '0');1977 1978 const char *pszBootDevice;1979 switch (enmBootDevice)1980 {1981 case DeviceType_Null:1982 pszBootDevice = "NONE";1983 break;1984 case DeviceType_HardDisk:1985 pszBootDevice = "IDE";1986 break;1987 case DeviceType_DVD:1988 pszBootDevice = "DVD";1989 break;1990 case DeviceType_Floppy:1991 pszBootDevice = "FLOPPY";1992 break;1993 case DeviceType_Network:1994 pszBootDevice = "LAN";1995 break;1996 default:1997 AssertMsgFailed(("Invalid enmBootDevice=%d\n", enmBootDevice));1998 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,1999 N_("Invalid boot device '%d'"), enmBootDevice);2000 }2001 InsertConfigString(pBiosCfg, szParamName, pszBootDevice);2002 }2003 2004 /** @todo @bugref{7145}: We might want to enable this by default for new VMs. For now,2005 * this is required for Windows 2012 guests. */2006 if (osTypeId == "Windows2012_64")2007 InsertConfigInteger(pBiosCfg, "DmiExposeMemoryTable", 1); /* boolean */2008 }2009 else2010 {2011 /* Autodetect firmware type, basing on guest type */2012 if (eFwType == FirmwareType_EFI)2013 eFwType = fIsGuest64Bit ? FirmwareType_EFI64 : FirmwareType_EFI32;2014 bool const f64BitEntry = eFwType == FirmwareType_EFI64;2015 2016 Assert(eFwType == FirmwareType_EFI64 || eFwType == FirmwareType_EFI32 || eFwType == FirmwareType_EFIDUAL);2017 #ifdef VBOX_WITH_EFI_IN_DD22018 const char *pszEfiRomFile = eFwType == FirmwareType_EFIDUAL ? "VBoxEFIDual.fd"2019 : eFwType == FirmwareType_EFI32 ? "VBoxEFI32.fd"2020 : "VBoxEFI64.fd";2021 #else2022 Utf8Str efiRomFile;2023 vrc = findEfiRom(virtualBox, eFwType, &efiRomFile);2024 AssertRCReturn(vrc, vrc);2025 const char *pszEfiRomFile = efiRomFile.c_str();2026 #endif2027 2028 /* Get boot args */2029 Utf8Str bootArgs;2030 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiBootArgs", &bootArgs);2031 2032 /* Get device props */2033 Utf8Str deviceProps;2034 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiDeviceProps", &deviceProps);2035 2036 /* Get NVRAM file name */2037 Utf8Str strNvram = mptrNvramStore->i_getNonVolatileStorageFile();2038 2039 BOOL fUuidLe;2040 hrc = biosSettings->COMGETTER(SMBIOSUuidLittleEndian)(&fUuidLe); H();2041 2042 /* Get graphics mode settings */2043 uint32_t u32GraphicsMode = UINT32_MAX;2044 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsMode", &strTmp);2045 if (strTmp.isEmpty())2046 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGopMode", &strTmp);2047 if (!strTmp.isEmpty())2048 u32GraphicsMode = strTmp.toUInt32();2049 2050 /* Get graphics resolution settings, with some sanity checking */2051 Utf8Str strResolution;2052 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiGraphicsResolution", &strResolution);2053 if (!strResolution.isEmpty())2054 {2055 size_t pos = strResolution.find("x");2056 if (pos != strResolution.npos)2057 {2058 Utf8Str strH, strV;2059 strH.assignEx(strResolution, 0, pos);2060 strV.assignEx(strResolution, pos+1, strResolution.length()-pos-1);2061 uint32_t u32H = strH.toUInt32();2062 uint32_t u32V = strV.toUInt32();2063 if (u32H == 0 || u32V == 0)2064 strResolution.setNull();2065 }2066 else2067 strResolution.setNull();2068 }2069 else2070 {2071 uint32_t u32H = 0;2072 uint32_t u32V = 0;2073 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiHorizontalResolution", &strTmp);2074 if (strTmp.isEmpty())2075 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaHorizontalResolution", &strTmp);2076 if (!strTmp.isEmpty())2077 u32H = strTmp.toUInt32();2078 2079 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiVerticalResolution", &strTmp);2080 if (strTmp.isEmpty())2081 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/EfiUgaVerticalResolution", &strTmp);2082 if (!strTmp.isEmpty())2083 u32V = strTmp.toUInt32();2084 if (u32H != 0 && u32V != 0)2085 strResolution = Utf8StrFmt("%ux%u", u32H, u32V);2086 }2087 2088 /*2089 * EFI subtree.2090 */2091 InsertConfigNode(pDevices, "efi", &pDev);2092 InsertConfigNode(pDev, "0", &pInst);2093 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */2094 InsertConfigNode(pInst, "Config", &pCfg);2095 InsertConfigInteger(pCfg, "NumCPUs", cCpus);2096 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);2097 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);2098 InsertConfigString(pCfg, "EfiRom", pszEfiRomFile);2099 InsertConfigString(pCfg, "BootArgs", bootArgs);2100 InsertConfigString(pCfg, "DeviceProps", deviceProps);2101 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);2102 InsertConfigInteger(pCfg, "APIC", uFwAPIC);2103 InsertConfigBytes(pCfg, "UUID", &HardwareUuid,sizeof(HardwareUuid));2104 InsertConfigInteger(pCfg, "UuidLe", fUuidLe);2105 InsertConfigInteger(pCfg, "64BitEntry", f64BitEntry); /* boolean */2106 InsertConfigString(pCfg, "NvramFile", strNvram);2107 if (u32GraphicsMode != UINT32_MAX)2108 InsertConfigInteger(pCfg, "GraphicsMode", u32GraphicsMode);2109 if (!strResolution.isEmpty())2110 InsertConfigString(pCfg, "GraphicsResolution", strResolution);2111 2112 /* For OS X guests we'll force passing host's DMI info to the guest */2113 if (fOsXGuest)2114 {2115 InsertConfigInteger(pCfg, "DmiUseHostInfo", 1);2116 InsertConfigInteger(pCfg, "DmiExposeMemoryTable", 1);2117 }2118 2119 /* Attach the NVRAM storage driver. */2120 InsertConfigNode(pInst, "LUN#0", &pLunL0);2121 InsertConfigString(pLunL0, "Driver", "NvramStore");2122 }2123 2124 /*2125 * The USB Controllers.2126 */2127 com::SafeIfaceArray<IUSBController> usbCtrls;2128 hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));2129 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */2130 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */2131 2132 if (SUCCEEDED(hrc))2133 {2134 for (size_t i = 0; i < usbCtrls.size(); ++i)2135 {2136 USBControllerType_T enmCtrlType;2137 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();2138 if (enmCtrlType == USBControllerType_OHCI)2139 {2140 fOhciPresent = true;2141 break;2142 }2143 else if (enmCtrlType == USBControllerType_XHCI)2144 {2145 fXhciPresent = true;2146 break;2147 }2148 }2149 }2150 else if (hrc != E_NOTIMPL)2151 {2152 H();2153 }2154 2155 /*2156 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.2157 */2158 if (fOhciPresent || fXhciPresent)2159 mfVMHasUsbController = true;2160 2161 PCFGMNODE pUsbDevices = NULL; /**< Required for USB storage controller later. */2162 if (mfVMHasUsbController)2163 {2164 for (size_t i = 0; i < usbCtrls.size(); ++i)2165 {2166 USBControllerType_T enmCtrlType;2167 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();2168 2169 if (enmCtrlType == USBControllerType_OHCI)2170 {2171 InsertConfigNode(pDevices, "usb-ohci", &pDev);2172 InsertConfigNode(pDev, "0", &pInst);2173 InsertConfigNode(pInst, "Config", &pCfg);2174 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */2175 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();2176 InsertConfigNode(pInst, "LUN#0", &pLunL0);2177 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");2178 InsertConfigNode(pLunL0, "Config", &pCfg);2179 2180 /*2181 * Attach the status driver.2182 */2183 i_attachStatusDriver(pInst, DeviceType_USB);2184 }2185 #ifdef VBOX_WITH_EHCI2186 else if (enmCtrlType == USBControllerType_EHCI)2187 {2188 InsertConfigNode(pDevices, "usb-ehci", &pDev);2189 InsertConfigNode(pDev, "0", &pInst);2190 InsertConfigNode(pInst, "Config", &pCfg);2191 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */2192 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();2193 2194 InsertConfigNode(pInst, "LUN#0", &pLunL0);2195 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");2196 InsertConfigNode(pLunL0, "Config", &pCfg);2197 2198 /*2199 * Attach the status driver.2200 */2201 i_attachStatusDriver(pInst, DeviceType_USB);2202 }2203 #endif2204 else if (enmCtrlType == USBControllerType_XHCI)2205 {2206 InsertConfigNode(pDevices, "usb-xhci", &pDev);2207 InsertConfigNode(pDev, "0", &pInst);2208 InsertConfigNode(pInst, "Config", &pCfg);2209 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */2210 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();2211 2212 InsertConfigNode(pInst, "LUN#0", &pLunL0);2213 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");2214 InsertConfigNode(pLunL0, "Config", &pCfg);2215 2216 InsertConfigNode(pInst, "LUN#1", &pLunL1);2217 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");2218 InsertConfigNode(pLunL1, "Config", &pCfg);2219 2220 /*2221 * Attach the status driver.2222 */2223 i_attachStatusDriver(pInst, DeviceType_USB, 2);2224 }2225 } /* for every USB controller. */2226 2227 2228 /*2229 * Virtual USB Devices.2230 */2231 InsertConfigNode(pRoot, "USB", &pUsbDevices);2232 2233 #ifdef VBOX_WITH_USB2234 {2235 /*2236 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing2237 * on a per device level now.2238 */2239 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);2240 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);2241 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.2242 //InsertConfigInteger(pCfg, "Force11Device", true);2243 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so2244 // that it's documented somewhere.) Users needing it can use:2245 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 12246 //InsertConfigInteger(pCfg, "Force11PacketSize", true);2247 }2248 #endif2249 2250 #ifdef VBOX_WITH_USB_CARDREADER2251 BOOL aEmulatedUSBCardReaderEnabled = FALSE;2252 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();2253 if (aEmulatedUSBCardReaderEnabled)2254 {2255 InsertConfigNode(pUsbDevices, "CardReader", &pDev);2256 InsertConfigNode(pDev, "0", &pInst);2257 InsertConfigNode(pInst, "Config", &pCfg);2258 2259 InsertConfigNode(pInst, "LUN#0", &pLunL0);2260 # ifdef VBOX_WITH_USB_CARDREADER_TEST2261 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");2262 InsertConfigNode(pLunL0, "Config", &pCfg);2263 # else2264 InsertConfigString(pLunL0, "Driver", "UsbCardReader");2265 InsertConfigNode(pLunL0, "Config", &pCfg);2266 # endif2267 }2268 #endif2269 2270 /* Virtual USB Mouse/Tablet */2271 if ( aPointingHID == PointingHIDType_USBMouse2272 || aPointingHID == PointingHIDType_USBTablet2273 || aPointingHID == PointingHIDType_USBMultiTouch2274 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)2275 {2276 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);2277 InsertConfigNode(pDev, "0", &pInst);2278 InsertConfigNode(pInst, "Config", &pCfg);2279 2280 if (aPointingHID == PointingHIDType_USBMouse)2281 InsertConfigString(pCfg, "Mode", "relative");2282 else2283 InsertConfigString(pCfg, "Mode", "absolute");2284 InsertConfigNode(pInst, "LUN#0", &pLunL0);2285 InsertConfigString(pLunL0, "Driver", "MouseQueue");2286 InsertConfigNode(pLunL0, "Config", &pCfg);2287 InsertConfigInteger(pCfg, "QueueSize", 128);2288 2289 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);2290 InsertConfigString(pLunL1, "Driver", "MainMouse");2291 }2292 if ( aPointingHID == PointingHIDType_USBMultiTouch2293 || aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)2294 {2295 InsertConfigNode(pDev, "1", &pInst);2296 InsertConfigNode(pInst, "Config", &pCfg);2297 2298 InsertConfigString(pCfg, "Mode", "multitouch");2299 InsertConfigNode(pInst, "LUN#0", &pLunL0);2300 InsertConfigString(pLunL0, "Driver", "MouseQueue");2301 InsertConfigNode(pLunL0, "Config", &pCfg);2302 InsertConfigInteger(pCfg, "QueueSize", 128);2303 2304 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);2305 InsertConfigString(pLunL1, "Driver", "MainMouse");2306 }2307 if (aPointingHID == PointingHIDType_USBMultiTouchScreenPlusPad)2308 {2309 InsertConfigNode(pDev, "2", &pInst);2310 InsertConfigNode(pInst, "Config", &pCfg);2311 2312 InsertConfigString(pCfg, "Mode", "touchpad");2313 InsertConfigNode(pInst, "LUN#0", &pLunL0);2314 InsertConfigString(pLunL0, "Driver", "MouseQueue");2315 InsertConfigNode(pLunL0, "Config", &pCfg);2316 InsertConfigInteger(pCfg, "QueueSize", 128);2317 2318 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);2319 InsertConfigString(pLunL1, "Driver", "MainMouse");2320 }2321 2322 /* Virtual USB Keyboard */2323 if (aKbdHID == KeyboardHIDType_USBKeyboard)2324 {2325 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);2326 InsertConfigNode(pDev, "0", &pInst);2327 InsertConfigNode(pInst, "Config", &pCfg);2328 2329 InsertConfigNode(pInst, "LUN#0", &pLunL0);2330 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");2331 InsertConfigNode(pLunL0, "Config", &pCfg);2332 InsertConfigInteger(pCfg, "QueueSize", 64);2333 2334 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);2335 InsertConfigString(pLunL1, "Driver", "MainKeyboard");2336 }2337 }2338 2339 /*2340 * Storage controllers.2341 */2342 com::SafeIfaceArray<IStorageController> ctrls;2343 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};2344 hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();2345 2346 bool fFdcEnabled = false;2347 for (size_t i = 0; i < ctrls.size(); ++i)2348 {2349 DeviceType_T *paLedDevType = NULL;2350 2351 StorageControllerType_T enmCtrlType;2352 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();2353 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)2354 || enmCtrlType == StorageControllerType_USB);2355 2356 StorageBus_T enmBus;2357 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();2358 2359 Bstr controllerName;2360 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();2361 2362 ULONG ulInstance = 999;2363 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();2364 2365 BOOL fUseHostIOCache;2366 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();2367 2368 BOOL fBootable;2369 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();2370 2371 PCFGMNODE pCtlInst = NULL;2372 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);2373 if (enmCtrlType != StorageControllerType_USB)2374 {2375 /* /Devices/<ctrldev>/ */2376 pDev = aCtrlNodes[enmCtrlType];2377 if (!pDev)2378 {2379 InsertConfigNode(pDevices, pszCtrlDev, &pDev);2380 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */2381 }2382 2383 /* /Devices/<ctrldev>/<instance>/ */2384 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);2385 2386 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */2387 InsertConfigInteger(pCtlInst, "Trusted", 1);2388 InsertConfigNode(pCtlInst, "Config", &pCfg);2389 }2390 2391 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =2392 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };2393 2394 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =2395 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };2396 2397 switch (enmCtrlType)2398 {2399 case StorageControllerType_LsiLogic:2400 {2401 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();2402 2403 InsertConfigInteger(pCfg, "Bootable", fBootable);2404 2405 /* BIOS configuration values, first SCSI controller only. */2406 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)2407 && !pBusMgr->hasPCIDevice("buslogic", 0)2408 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)2409 && pBiosCfg)2410 {2411 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");2412 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();2413 }2414 2415 /* Attach the status driver */2416 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),2417 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);2418 break;2419 }2420 2421 case StorageControllerType_BusLogic:2422 {2423 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();2424 2425 InsertConfigInteger(pCfg, "Bootable", fBootable);2426 2427 /* BIOS configuration values, first SCSI controller only. */2428 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)2429 && !pBusMgr->hasPCIDevice("buslogic", 1)2430 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)2431 && pBiosCfg)2432 {2433 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");2434 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();2435 }2436 2437 /* Attach the status driver */2438 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),2439 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);2440 break;2441 }2442 2443 case StorageControllerType_IntelAhci:2444 {2445 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();2446 2447 ULONG cPorts = 0;2448 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();2449 InsertConfigInteger(pCfg, "PortCount", cPorts);2450 InsertConfigInteger(pCfg, "Bootable", fBootable);2451 2452 com::SafeIfaceArray<IMediumAttachment> atts;2453 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),2454 ComSafeArrayAsOutParam(atts)); H();2455 2456 /* Configure the hotpluggable flag for the port. */2457 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)2458 {2459 IMediumAttachment *pMediumAtt = atts[idxAtt];2460 2461 LONG lPortNum = 0;2462 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();2463 2464 BOOL fHotPluggable = FALSE;2465 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();2466 if (SUCCEEDED(hrc))2467 {2468 PCFGMNODE pPortCfg;2469 char szName[24];2470 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);2471 2472 InsertConfigNode(pCfg, szName, &pPortCfg);2473 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);2474 }2475 }2476 2477 /* BIOS configuration values, first AHCI controller only. */2478 if ( !pBusMgr->hasPCIDevice("ahci", 1)2479 && pBiosCfg)2480 {2481 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");2482 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();2483 }2484 2485 /* Attach the status driver */2486 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),2487 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);2488 break;2489 }2490 2491 case StorageControllerType_PIIX3:2492 case StorageControllerType_PIIX4:2493 case StorageControllerType_ICH6:2494 {2495 /*2496 * IDE (update this when the main interface changes)2497 */2498 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();2499 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));2500 2501 /* Attach the status driver */2502 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),2503 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);2504 2505 /* IDE flavors */2506 aCtrlNodes[StorageControllerType_PIIX3] = pDev;2507 aCtrlNodes[StorageControllerType_PIIX4] = pDev;2508 aCtrlNodes[StorageControllerType_ICH6] = pDev;2509 break;2510 }2511 2512 case StorageControllerType_I82078:2513 {2514 /*2515 * i82078 Floppy drive controller2516 */2517 fFdcEnabled = true;2518 InsertConfigInteger(pCfg, "IRQ", 6);2519 InsertConfigInteger(pCfg, "DMA", 2);2520 InsertConfigInteger(pCfg, "MemMapped", 0 );2521 InsertConfigInteger(pCfg, "IOBase", 0x3f0);2522 2523 /* Attach the status driver */2524 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),2525 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);2526 break;2527 }2528 2529 case StorageControllerType_LsiLogicSas:2530 {2531 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();2532 2533 InsertConfigString(pCfg, "ControllerType", "SAS1068");2534 InsertConfigInteger(pCfg, "Bootable", fBootable);2535 2536 /* BIOS configuration values, first SCSI controller only. */2537 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)2538 && !pBusMgr->hasPCIDevice("buslogic", 0)2539 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)2540 && pBiosCfg)2541 {2542 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");2543 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();2544 }2545 2546 ULONG cPorts = 0;2547 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();2548 InsertConfigInteger(pCfg, "NumPorts", cPorts);2549 2550 /* Attach the status driver */2551 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,2552 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);2553 break;2554 }2555 2556 case StorageControllerType_USB:2557 {2558 if (pUsbDevices)2559 {2560 /*2561 * USB MSDs are handled a bit different as the device instance2562 * doesn't match the storage controller instance but the port.2563 */2564 InsertConfigNode(pUsbDevices, "Msd", &pDev);2565 pCtlInst = pDev;2566 }2567 else2568 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,2569 N_("There is no USB controller enabled but there\n"2570 "is at least one USB storage device configured for this VM.\n"2571 "To fix this problem either enable the USB controller or remove\n"2572 "the storage device from the VM"));2573 break;2574 }2575 2576 case StorageControllerType_NVMe:2577 {2578 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();2579 2580 ULONG cPorts = 0;2581 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();2582 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);2583 2584 /* Attach the status driver */2585 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),2586 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);2587 break;2588 }2589 2590 case StorageControllerType_VirtioSCSI:2591 {2592 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();2593 2594 ULONG cPorts = 0;2595 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();2596 InsertConfigInteger(pCfg, "NumTargets", cPorts);2597 InsertConfigInteger(pCfg, "Bootable", fBootable);2598 2599 /* Attach the status driver */2600 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,2601 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);2602 break;2603 }2604 2605 default:2606 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);2607 }2608 2609 /* Attach the media to the storage controllers. */2610 com::SafeIfaceArray<IMediumAttachment> atts;2611 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),2612 ComSafeArrayAsOutParam(atts)); H();2613 2614 /* Builtin I/O cache - per device setting. */2615 BOOL fBuiltinIOCache = true;2616 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();2617 2618 bool fInsertDiskIntegrityDrv = false;2619 Bstr strDiskIntegrityFlag;2620 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),2621 strDiskIntegrityFlag.asOutParam());2622 if ( hrc == S_OK2623 && strDiskIntegrityFlag == "1")2624 fInsertDiskIntegrityDrv = true;2625 2626 for (size_t j = 0; j < atts.size(); ++j)2627 {2628 IMediumAttachment *pMediumAtt = atts[j];2629 vrc = i_configMediumAttachment(pszCtrlDev,2630 ulInstance,2631 enmBus,2632 !!fUseHostIOCache,2633 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,2634 fInsertDiskIntegrityDrv,2635 false /* fSetupMerge */,2636 0 /* uMergeSource */,2637 0 /* uMergeTarget */,2638 pMediumAtt,2639 mMachineState,2640 NULL /* phrc */,2641 false /* fAttachDetach */,2642 false /* fForceUnmount */,2643 false /* fHotplug */,2644 pUVM,2645 pVMM,2646 paLedDevType,2647 NULL /* ppLunL0 */);2648 if (RT_FAILURE(vrc))2649 return vrc;2650 }2651 H();2652 }2653 H();2654 2655 /*2656 * Network adapters2657 */2658 #ifdef VMWARE_NET_IN_SLOT_112659 bool fSwapSlots3and11 = false;2660 #endif2661 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */2662 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);2663 #ifdef VBOX_WITH_E10002664 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */2665 InsertConfigNode(pDevices, "e1000", &pDevE1000);2666 #endif2667 #ifdef VBOX_WITH_VIRTIO2668 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */2669 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);2670 #endif /* VBOX_WITH_VIRTIO */2671 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */2672 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);2673 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */2674 InsertConfigNode(pDevices, "3c501", &pDev3C501);2675 2676 std::list<BootNic> llBootNics;2677 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)2678 {2679 ComPtr<INetworkAdapter> networkAdapter;2680 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();2681 BOOL fEnabledNetAdapter = FALSE;2682 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();2683 if (!fEnabledNetAdapter)2684 continue;2685 2686 /*2687 * The virtual hardware type. Create appropriate device first.2688 */2689 const char *pszAdapterName = "pcnet";2690 NetworkAdapterType_T adapterType;2691 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();2692 switch (adapterType)2693 {2694 case NetworkAdapterType_Am79C970A:2695 case NetworkAdapterType_Am79C973:2696 case NetworkAdapterType_Am79C960:2697 pDev = pDevPCNet;2698 break;2699 #ifdef VBOX_WITH_E10002700 case NetworkAdapterType_I82540EM:2701 case NetworkAdapterType_I82543GC:2702 case NetworkAdapterType_I82545EM:2703 pDev = pDevE1000;2704 pszAdapterName = "e1000";2705 break;2706 #endif2707 #ifdef VBOX_WITH_VIRTIO2708 case NetworkAdapterType_Virtio:2709 pDev = pDevVirtioNet;2710 pszAdapterName = "virtio-net";2711 break;2712 #endif /* VBOX_WITH_VIRTIO */2713 case NetworkAdapterType_NE1000:2714 case NetworkAdapterType_NE2000:2715 case NetworkAdapterType_WD8003:2716 case NetworkAdapterType_WD8013:2717 case NetworkAdapterType_ELNK2:2718 pDev = pDevDP8390;2719 break;2720 case NetworkAdapterType_ELNK1:2721 pDev = pDev3C501;2722 break;2723 default:2724 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));2725 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,2726 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);2727 }2728 2729 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);2730 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */2731 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,2732 * next 4 get 16..19. */2733 int iPCIDeviceNo;2734 switch (uInstance)2735 {2736 case 0:2737 iPCIDeviceNo = 3;2738 break;2739 case 1: case 2: case 3:2740 iPCIDeviceNo = uInstance - 1 + 8;2741 break;2742 case 4: case 5: case 6: case 7:2743 iPCIDeviceNo = uInstance - 4 + 16;2744 break;2745 default:2746 /* auto assignment */2747 iPCIDeviceNo = -1;2748 break;2749 }2750 #ifdef VMWARE_NET_IN_SLOT_112751 /*2752 * Dirty hack for PCI slot compatibility with VMWare,2753 * it assigns slot 0x11 to the first network controller.2754 */2755 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)2756 {2757 iPCIDeviceNo = 0x11;2758 fSwapSlots3and11 = true;2759 }2760 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)2761 iPCIDeviceNo = 3;2762 #endif2763 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);2764 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();2765 2766 InsertConfigNode(pInst, "Config", &pCfg);2767 #ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */2768 if (pDev == pDevPCNet)2769 InsertConfigInteger(pCfg, "R0Enabled", false);2770 #endif2771 /*2772 * Collect information needed for network booting and add it to the list.2773 */2774 BootNic nic;2775 2776 nic.mInstance = uInstance;2777 /* Could be updated by reference, if auto assigned */2778 nic.mPCIAddress = PCIAddr;2779 2780 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();2781 2782 llBootNics.push_back(nic);2783 2784 /*2785 * The virtual hardware type. PCNet supports three types, E1000 three,2786 * but VirtIO only one.2787 */2788 switch (adapterType)2789 {2790 case NetworkAdapterType_Am79C970A:2791 InsertConfigString(pCfg, "ChipType", "Am79C970A");2792 break;2793 case NetworkAdapterType_Am79C973:2794 InsertConfigString(pCfg, "ChipType", "Am79C973");2795 break;2796 case NetworkAdapterType_Am79C960:2797 InsertConfigString(pCfg, "ChipType", "Am79C960");2798 break;2799 case NetworkAdapterType_I82540EM:2800 InsertConfigInteger(pCfg, "AdapterType", 0);2801 break;2802 case NetworkAdapterType_I82543GC:2803 InsertConfigInteger(pCfg, "AdapterType", 1);2804 break;2805 case NetworkAdapterType_I82545EM:2806 InsertConfigInteger(pCfg, "AdapterType", 2);2807 break;2808 case NetworkAdapterType_Virtio:2809 break;2810 case NetworkAdapterType_NE1000:2811 InsertConfigString(pCfg, "DeviceType", "NE1000");2812 break;2813 case NetworkAdapterType_NE2000:2814 InsertConfigString(pCfg, "DeviceType", "NE2000");2815 break;2816 case NetworkAdapterType_WD8003:2817 InsertConfigString(pCfg, "DeviceType", "WD8003");2818 break;2819 case NetworkAdapterType_WD8013:2820 InsertConfigString(pCfg, "DeviceType", "WD8013");2821 break;2822 case NetworkAdapterType_ELNK2:2823 InsertConfigString(pCfg, "DeviceType", "3C503");2824 break;2825 case NetworkAdapterType_ELNK1:2826 break;2827 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */2828 #ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK2829 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */2830 #endif2831 }2832 2833 /*2834 * Get the MAC address and convert it to binary representation2835 */2836 Bstr macAddr;2837 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();2838 Assert(!macAddr.isEmpty());2839 Utf8Str macAddrUtf8 = macAddr;2840 #ifdef VBOX_WITH_CLOUD_NET2841 NetworkAttachmentType_T eAttachmentType;2842 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();2843 if (eAttachmentType == NetworkAttachmentType_Cloud)2844 {2845 mGateway.setLocalMacAddress(macAddrUtf8);2846 /* We'll insert cloud MAC later, when it becomes known. */2847 }2848 else2849 {2850 #endif2851 char *macStr = (char*)macAddrUtf8.c_str();2852 Assert(strlen(macStr) == 12);2853 RTMAC Mac;2854 RT_ZERO(Mac);2855 char *pMac = (char*)&Mac;2856 for (uint32_t i = 0; i < 6; ++i)2857 {2858 int c1 = *macStr++ - '0';2859 if (c1 > 9)2860 c1 -= 7;2861 int c2 = *macStr++ - '0';2862 if (c2 > 9)2863 c2 -= 7;2864 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));2865 }2866 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));2867 #ifdef VBOX_WITH_CLOUD_NET2868 }2869 #endif2870 /*2871 * Check if the cable is supposed to be unplugged2872 */2873 BOOL fCableConnected;2874 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();2875 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);2876 2877 /*2878 * Line speed to report from custom drivers2879 */2880 ULONG ulLineSpeed;2881 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();2882 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);2883 2884 /*2885 * Attach the status driver.2886 */2887 i_attachStatusDriver(pInst, DeviceType_Network);2888 2889 /*2890 * Configure the network card now2891 */2892 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;2893 vrc = i_configNetwork(pszAdapterName,2894 uInstance,2895 0,2896 networkAdapter,2897 pCfg,2898 pLunL0,2899 pInst,2900 false /*fAttachDetach*/,2901 fIgnoreConnectFailure,2902 pUVM,2903 pVMM);2904 if (RT_FAILURE(vrc))2905 return vrc;2906 }2907 2908 /*2909 * Build network boot information and transfer it to the BIOS.2910 */2911 if (pNetBootCfg && !llBootNics.empty()) /* NetBoot node doesn't exist for EFI! */2912 {2913 llBootNics.sort(); /* Sort the list by boot priority. */2914 2915 char achBootIdx[] = "0";2916 unsigned uBootIdx = 0;2917 2918 for (std::list<BootNic>::iterator it = llBootNics.begin(); it != llBootNics.end(); ++it)2919 {2920 /* A NIC with priority 0 is only used if it's first in the list. */2921 if (it->mBootPrio == 0 && uBootIdx != 0)2922 break;2923 2924 PCFGMNODE pNetBtDevCfg;2925 achBootIdx[0] = (char)('0' + uBootIdx++); /* Boot device order. */2926 InsertConfigNode(pNetBootCfg, achBootIdx, &pNetBtDevCfg);2927 InsertConfigInteger(pNetBtDevCfg, "NIC", it->mInstance);2928 InsertConfigInteger(pNetBtDevCfg, "PCIBusNo", it->mPCIAddress.miBus);2929 InsertConfigInteger(pNetBtDevCfg, "PCIDeviceNo", it->mPCIAddress.miDevice);2930 InsertConfigInteger(pNetBtDevCfg, "PCIFunctionNo", it->mPCIAddress.miFn);2931 }2932 }2933 2934 /*2935 * Serial (UART) Ports2936 */2937 /* serial enabled mask to be passed to dev ACPI */2938 uint16_t auSerialIoPortBase[SchemaDefs::SerialPortCount] = {0};2939 uint8_t auSerialIrq[SchemaDefs::SerialPortCount] = {0};2940 InsertConfigNode(pDevices, "serial", &pDev);2941 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::SerialPortCount; ++ulInstance)2942 {2943 ComPtr<ISerialPort> serialPort;2944 hrc = pMachine->GetSerialPort(ulInstance, serialPort.asOutParam()); H();2945 BOOL fEnabledSerPort = FALSE;2946 if (serialPort)2947 {2948 hrc = serialPort->COMGETTER(Enabled)(&fEnabledSerPort); H();2949 }2950 if (!fEnabledSerPort)2951 {2952 m_aeSerialPortMode[ulInstance] = PortMode_Disconnected;2953 continue;2954 }2955 2956 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);2957 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */2958 InsertConfigNode(pInst, "Config", &pCfg);2959 2960 ULONG ulIRQ;2961 hrc = serialPort->COMGETTER(IRQ)(&ulIRQ); H();2962 InsertConfigInteger(pCfg, "IRQ", ulIRQ);2963 auSerialIrq[ulInstance] = (uint8_t)ulIRQ;2964 2965 ULONG ulIOBase;2966 hrc = serialPort->COMGETTER(IOBase)(&ulIOBase); H();2967 InsertConfigInteger(pCfg, "IOBase", ulIOBase);2968 auSerialIoPortBase[ulInstance] = (uint16_t)ulIOBase;2969 2970 BOOL fServer;2971 hrc = serialPort->COMGETTER(Server)(&fServer); H();2972 hrc = serialPort->COMGETTER(Path)(bstr.asOutParam()); H();2973 UartType_T eUartType;2974 const char *pszUartType;2975 hrc = serialPort->COMGETTER(UartType)(&eUartType); H();2976 switch (eUartType)2977 {2978 case UartType_U16450: pszUartType = "16450"; break;2979 case UartType_U16750: pszUartType = "16750"; break;2980 default: AssertFailed(); RT_FALL_THRU();2981 case UartType_U16550A: pszUartType = "16550A"; break;2982 }2983 InsertConfigString(pCfg, "UartType", pszUartType);2984 2985 PortMode_T eHostMode;2986 hrc = serialPort->COMGETTER(HostMode)(&eHostMode); H();2987 2988 m_aeSerialPortMode[ulInstance] = eHostMode;2989 if (eHostMode != PortMode_Disconnected)2990 {2991 vrc = i_configSerialPort(pInst, eHostMode, Utf8Str(bstr).c_str(), RT_BOOL(fServer));2992 if (RT_FAILURE(vrc))2993 return vrc;2994 }2995 }2996 2997 /*2998 * Parallel (LPT) Ports2999 */3000 /* parallel enabled mask to be passed to dev ACPI */3001 uint16_t auParallelIoPortBase[SchemaDefs::ParallelPortCount] = {0};3002 uint8_t auParallelIrq[SchemaDefs::ParallelPortCount] = {0};3003 InsertConfigNode(pDevices, "parallel", &pDev);3004 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::ParallelPortCount; ++ulInstance)3005 {3006 ComPtr<IParallelPort> parallelPort;3007 hrc = pMachine->GetParallelPort(ulInstance, parallelPort.asOutParam()); H();3008 BOOL fEnabledParPort = FALSE;3009 if (parallelPort)3010 {3011 hrc = parallelPort->COMGETTER(Enabled)(&fEnabledParPort); H();3012 }3013 if (!fEnabledParPort)3014 continue;3015 3016 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pInst);3017 InsertConfigNode(pInst, "Config", &pCfg);3018 3019 ULONG ulIRQ;3020 hrc = parallelPort->COMGETTER(IRQ)(&ulIRQ); H();3021 InsertConfigInteger(pCfg, "IRQ", ulIRQ);3022 auParallelIrq[ulInstance] = (uint8_t)ulIRQ;3023 ULONG ulIOBase;3024 hrc = parallelPort->COMGETTER(IOBase)(&ulIOBase); H();3025 InsertConfigInteger(pCfg, "IOBase", ulIOBase);3026 auParallelIoPortBase[ulInstance] = (uint16_t)ulIOBase;3027 3028 hrc = parallelPort->COMGETTER(Path)(bstr.asOutParam()); H();3029 if (!bstr.isEmpty())3030 {3031 InsertConfigNode(pInst, "LUN#0", &pLunL0);3032 InsertConfigString(pLunL0, "Driver", "HostParallel");3033 InsertConfigNode(pLunL0, "Config", &pLunL1);3034 InsertConfigString(pLunL1, "DevicePath", bstr);3035 }3036 }3037 3038 /*3039 * VMM Device3040 */3041 InsertConfigNode(pDevices, "VMMDev", &pDev);3042 InsertConfigNode(pDev, "0", &pInst);3043 InsertConfigNode(pInst, "Config", &pCfg);3044 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */3045 hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();3046 3047 Bstr hwVersion;3048 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();3049 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */3050 InsertConfigInteger(pCfg, "HeapEnabled", 0);3051 Bstr snapshotFolder;3052 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();3053 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);3054 3055 /* the VMM device's Main driver */3056 InsertConfigNode(pInst, "LUN#0", &pLunL0);3057 InsertConfigString(pLunL0, "Driver", "HGCM");3058 InsertConfigNode(pLunL0, "Config", &pCfg);3059 3060 /*3061 * Attach the status driver.3062 */3063 i_attachStatusDriver(pInst, DeviceType_SharedFolder);3064 3065 /*3066 * Audio configuration.3067 */3068 3069 /*3070 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.3071 */3072 ComPtr<IAudioSettings> audioSettings;3073 hrc = pMachine->COMGETTER(AudioSettings)(audioSettings.asOutParam()); H();3074 3075 BOOL fAudioEnabled = FALSE;3076 ComPtr<IAudioAdapter> audioAdapter;3077 hrc = audioSettings->COMGETTER(Adapter)(audioAdapter.asOutParam()); H();3078 if (audioAdapter)3079 {3080 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();3081 }3082 3083 if (fAudioEnabled)3084 {3085 AudioControllerType_T enmAudioController;3086 hrc = audioAdapter->COMGETTER(AudioController)(&enmAudioController); H();3087 AudioCodecType_T enmAudioCodec;3088 hrc = audioAdapter->COMGETTER(AudioCodec)(&enmAudioCodec); H();3089 3090 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/TimerHz", &strTmp);3091 const uint64_t uTimerHz = strTmp.toUInt64();3092 3093 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeInMs", &strTmp);3094 const uint64_t uBufSizeInMs = strTmp.toUInt64();3095 3096 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeOutMs", &strTmp);3097 const uint64_t uBufSizeOutMs = strTmp.toUInt64();3098 3099 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);3100 const bool fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");3101 3102 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/Level", &strTmp);3103 const uint32_t uDebugLevel = strTmp.toUInt32();3104 3105 Utf8Str strDebugPathOut;3106 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);3107 3108 #ifdef VBOX_WITH_AUDIO_VALIDATIONKIT3109 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/VaKit/Enabled", &strTmp); /* Deprecated; do not use! */3110 if (strTmp.isEmpty())3111 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/ValKit/Enabled", &strTmp);3112 /* Whether the Validation Kit audio backend runs as the primary backend.3113 * Can also be used with VBox release builds. */3114 const bool fValKitEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");3115 #endif3116 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff3117 * without duplicating (more) code. */3118 3119 const char *pszAudioDevice;3120 switch (enmAudioController)3121 {3122 case AudioControllerType_AC97:3123 {3124 /* ICH AC'97. */3125 pszAudioDevice = "ichac97";3126 3127 InsertConfigNode(pDevices, pszAudioDevice, &pDev);3128 InsertConfigNode(pDev, "0", &pInst);3129 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */3130 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();3131 InsertConfigNode(pInst, "Config", &pCfg);3132 switch (enmAudioCodec)3133 {3134 case AudioCodecType_STAC9700:3135 InsertConfigString(pCfg, "Codec", "STAC9700");3136 break;3137 case AudioCodecType_AD1980:3138 InsertConfigString(pCfg, "Codec", "AD1980");3139 break;3140 default: AssertFailedBreak();3141 }3142 if (uTimerHz)3143 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);3144 if (uBufSizeInMs)3145 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);3146 if (uBufSizeOutMs)3147 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);3148 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);3149 if (strDebugPathOut.isNotEmpty())3150 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);3151 break;3152 }3153 case AudioControllerType_SB16:3154 {3155 /* Legacy SoundBlaster16. */3156 pszAudioDevice = "sb16";3157 3158 InsertConfigNode(pDevices, pszAudioDevice, &pDev);3159 InsertConfigNode(pDev, "0", &pInst);3160 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */3161 InsertConfigNode(pInst, "Config", &pCfg);3162 InsertConfigInteger(pCfg, "IRQ", 5);3163 InsertConfigInteger(pCfg, "DMA", 1);3164 InsertConfigInteger(pCfg, "DMA16", 5);3165 InsertConfigInteger(pCfg, "Port", 0x220);3166 InsertConfigInteger(pCfg, "Version", 0x0405);3167 if (uTimerHz)3168 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);3169 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);3170 if (strDebugPathOut.isNotEmpty())3171 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);3172 break;3173 }3174 case AudioControllerType_HDA:3175 {3176 /* Intel HD Audio. */3177 pszAudioDevice = "hda";3178 3179 InsertConfigNode(pDevices, pszAudioDevice, &pDev);3180 InsertConfigNode(pDev, "0", &pInst);3181 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */3182 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();3183 InsertConfigNode(pInst, "Config", &pCfg);3184 if (uBufSizeInMs)3185 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);3186 if (uBufSizeOutMs)3187 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);3188 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);3189 if (strDebugPathOut.isNotEmpty())3190 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);3191 3192 /* macOS guests uses a different HDA variant to make 10.14+ (or maybe 10.13?) recognize the device. */3193 if (fOsXGuest)3194 InsertConfigString(pCfg, "DeviceName", "Intel Sunrise Point");3195 break;3196 }3197 default:3198 pszAudioDevice = "oops";3199 AssertFailedBreak();3200 }3201 3202 PCFGMNODE pCfgAudioAdapter = NULL;3203 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);3204 SafeArray<BSTR> audioProps;3205 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();3206 3207 std::list<Utf8Str> audioPropertyNamesList;3208 for (size_t i = 0; i < audioProps.size(); ++i)3209 {3210 Bstr bstrValue;3211 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));3212 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());3213 Utf8Str strKey(audioProps[i]);3214 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);3215 }3216 3217 /*3218 * The audio driver.3219 */3220 const char *pszAudioDriver = NULL;3221 #ifdef VBOX_WITH_AUDIO_VALIDATIONKIT3222 if (fValKitEnabled)3223 {3224 pszAudioDriver = "ValidationKitAudio";3225 LogRel(("Audio: ValidationKit driver active\n"));3226 }3227 #endif3228 /* If nothing else was selected before, ask the API. */3229 if (pszAudioDriver == NULL)3230 {3231 AudioDriverType_T enmAudioDriver;3232 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();3233 3234 /* The "Default" audio driver needs special treatment, as we need to figure out which driver to use3235 * by default on the current platform. */3236 bool const fUseDefaultDrv = enmAudioDriver == AudioDriverType_Default;3237 3238 AudioDriverType_T const enmDefaultAudioDriver = settings::MachineConfigFile::getHostDefaultAudioDriver();3239 3240 if (fUseDefaultDrv)3241 {3242 enmAudioDriver = enmDefaultAudioDriver;3243 if (enmAudioDriver == AudioDriverType_Null)3244 LogRel(("Audio: Warning: No default driver detected for current platform -- defaulting to Null audio backend\n"));3245 }3246 3247 switch (enmAudioDriver)3248 {3249 case AudioDriverType_Default: /* Can't happen, but handle it anyway. */3250 RT_FALL_THROUGH();3251 case AudioDriverType_Null:3252 pszAudioDriver = "NullAudio";3253 break;3254 #ifdef RT_OS_WINDOWS3255 # ifdef VBOX_WITH_WINMM3256 case AudioDriverType_WinMM:3257 # error "Port WinMM audio backend!" /** @todo Still needed? */3258 break;3259 # endif3260 case AudioDriverType_DirectSound:3261 /* Use the Windows Audio Session (WAS) API rather than Direct Sound on Windows3262 versions we've tested it on (currently W7+). Since Vista, Direct Sound has3263 been emulated on top of WAS according to the docs, so better use WAS directly.3264 3265 Set extradata value "VBoxInternal2/Audio/WindowsDrv" "dsound" to no use WasAPI.3266 3267 Keep this hack for backwards compatibility (introduced < 7.0).3268 */3269 GetExtraDataBoth(virtualBox, pMachine, "VBoxInternal2/Audio/WindowsDrv", &strTmp); H();3270 if ( enmDefaultAudioDriver == AudioDriverType_WAS3271 && ( strTmp.isEmpty()3272 || strTmp.equalsIgnoreCase("was")3273 || strTmp.equalsIgnoreCase("wasapi")) )3274 {3275 /* Nothing to do here, fall through to WAS driver. */3276 }3277 else3278 {3279 pszAudioDriver = "DSoundAudio";3280 break;3281 }3282 RT_FALL_THROUGH();3283 case AudioDriverType_WAS:3284 if (enmDefaultAudioDriver == AudioDriverType_WAS) /* WAS supported? */3285 pszAudioDriver = "HostAudioWas";3286 else if (enmDefaultAudioDriver == AudioDriverType_DirectSound)3287 {3288 LogRel(("Audio: Warning: Windows Audio Session (WAS) not supported, defaulting to DirectSound backend\n"));3289 pszAudioDriver = "DSoundAudio";3290 }3291 break;3292 #endif /* RT_OS_WINDOWS */3293 #ifdef RT_OS_SOLARIS3294 case AudioDriverType_SolAudio:3295 /* Should not happen, as the Solaris Audio backend is not around anymore.3296 * Remove this sometime later. */3297 LogRel(("Audio: Warning: Solaris Audio is deprecated, please switch to OSS!\n"));3298 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));3299 3300 /* Manually set backend to OSS for now. */3301 pszAudioDriver = "OSSAudio";3302 break;3303 #endif3304 #ifdef VBOX_WITH_AUDIO_OSS3305 case AudioDriverType_OSS:3306 pszAudioDriver = "OSSAudio";3307 break;3308 #endif3309 #ifdef VBOX_WITH_AUDIO_ALSA3310 case AudioDriverType_ALSA:3311 pszAudioDriver = "ALSAAudio";3312 break;3313 #endif3314 #ifdef VBOX_WITH_AUDIO_PULSE3315 case AudioDriverType_Pulse:3316 pszAudioDriver = "PulseAudio";3317 break;3318 #endif3319 #ifdef RT_OS_DARWIN3320 case AudioDriverType_CoreAudio:3321 pszAudioDriver = "CoreAudio";3322 break;3323 #endif3324 default:3325 pszAudioDriver = "oops";3326 AssertFailedBreak();3327 }3328 3329 if (fUseDefaultDrv)3330 LogRel(("Audio: Detected default audio driver type is '%s'\n", pszAudioDriver));3331 }3332 3333 BOOL fAudioEnabledIn = FALSE;3334 hrc = audioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();3335 BOOL fAudioEnabledOut = FALSE;3336 hrc = audioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut); H();3337 3338 unsigned idxAudioLun = 0;3339 3340 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);3341 i_configAudioDriver(virtualBox, pMachine, pLunL0, pszAudioDriver, !!fAudioEnabledIn, !!fAudioEnabledOut);3342 idxAudioLun++;3343 3344 #ifdef VBOX_WITH_AUDIO_VRDE3345 /* Insert dummy audio driver to have the LUN configured. */3346 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);3347 InsertConfigString(pLunL0, "Driver", "AUDIO");3348 {3349 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVRDE",3350 !!fAudioEnabledIn, !!fAudioEnabledOut);3351 vrc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);3352 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "mAudioVRDE->InitializeConfig failed"));3353 }3354 idxAudioLun++;3355 #endif3356 3357 #ifdef VBOX_WITH_AUDIO_RECORDING3358 /* Insert dummy audio driver to have the LUN configured. */3359 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);3360 InsertConfigString(pLunL0, "Driver", "AUDIO");3361 {3362 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVideoRec",3363 false /*a_fEnabledIn*/, true /*a_fEnabledOut*/);3364 vrc = mRecording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);3365 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "Recording.mAudioRec->InitializeConfig failed"));3366 }3367 idxAudioLun++;3368 #endif3369 3370 if (fDebugEnabled)3371 {3372 #ifdef VBOX_WITH_AUDIO_DEBUG3373 # ifdef VBOX_WITH_AUDIO_VALIDATIONKIT3374 /*3375 * When both, ValidationKit and Debug mode (for audio) are enabled,3376 * skip configuring the Debug audio driver, as both modes can3377 * mess with the audio data and would lead to side effects.3378 *3379 * The ValidationKit audio driver has precedence over the Debug audio driver.3380 *3381 * This also can (and will) be used in VBox release builds.3382 */3383 if (fValKitEnabled)3384 {3385 LogRel(("Audio: Warning: ValidationKit running and Debug mode enabled -- disabling Debug driver\n"));3386 }3387 else /* Debug mode active -- run both (nice for catching errors / doing development). */3388 {3389 /*3390 * The ValidationKit backend.3391 */3392 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);3393 i_configAudioDriver(virtualBox, pMachine, pLunL0, "ValidationKitAudio",3394 !!fAudioEnabledIn, !!fAudioEnabledOut);3395 idxAudioLun++;3396 # endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */3397 /*3398 * The Debug audio backend.3399 */3400 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);3401 i_configAudioDriver(virtualBox, pMachine, pLunL0, "DebugAudio",3402 !!fAudioEnabledIn, !!fAudioEnabledOut);3403 idxAudioLun++;3404 # ifdef VBOX_WITH_AUDIO_VALIDATIONKIT3405 }3406 # endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */3407 #endif /* VBOX_WITH_AUDIO_DEBUG */3408 3409 /*3410 * Tweak the logging groups.3411 */3412 Utf8Str strGroups("drv_audio.e.l.l2.l3.f"3413 " audio_mixer.e.l.l2.l3.f"3414 " dev_hda_codec.e.l.l2.l3.f"3415 " dev_hda.e.l.l2.l3.f"3416 " dev_ac97.e.l.l2.l3.f"3417 " dev_sb16.e.l.l2.l3.f");3418 3419 LogRel(("Audio: Debug level set to %RU32\n", uDebugLevel));3420 3421 switch (uDebugLevel)3422 {3423 case 0:3424 strGroups += " drv_host_audio.e.l.l2.l3.f";3425 break;3426 case 1:3427 RT_FALL_THROUGH();3428 case 2:3429 RT_FALL_THROUGH();3430 case 3:3431 strGroups += " drv_host_audio.e.l.l2.l3.f+audio_test.e.l.l2.l3.f";3432 break;3433 case 4:3434 RT_FALL_THROUGH();3435 default:3436 strGroups += " drv_host_audio.e.l.l2.l3.l4.f+audio_test.e.l.l2.l3.l4.f";3437 break;3438 }3439 3440 vrc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strGroups.c_str());3441 if (RT_FAILURE(vrc))3442 LogRel(("Audio: Setting debug logging failed, vrc=%Rrc\n", vrc));3443 }3444 }3445 3446 #ifdef VBOX_WITH_SHARED_CLIPBOARD3447 /*3448 * Shared Clipboard.3449 */3450 {3451 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;3452 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();3453 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS3454 BOOL fFileTransfersEnabled;3455 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();3456 #endif3457 3458 /* Load the service */3459 vrc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");3460 if (RT_SUCCESS(vrc))3461 {3462 LogRel(("Shared Clipboard: Service loaded\n"));3463 3464 /* Set initial clipboard mode. */3465 vrc = i_changeClipboardMode(enmClipboardMode);3466 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): vrc=%Rrc\n",3467 enmClipboardMode, vrc));3468 3469 /* Setup the service. */3470 VBOXHGCMSVCPARM parm;3471 HGCMSvcSetU32(&parm, !i_useHostClipboard());3472 vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);3473 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): vrc=%Rrc\n",3474 !i_useHostClipboard(), vrc));3475 3476 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS3477 vrc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));3478 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial file transfers mode (%u): vrc=%Rrc\n",3479 fFileTransfersEnabled, vrc));3480 3481 /** @todo Register area callbacks? (See also deregistration todo in Console::i_powerDown.) */3482 # endif3483 }3484 else3485 LogRel(("Shared Clipboard: Not available, vrc=%Rrc\n", vrc));3486 vrc = VINF_SUCCESS; /* None of the potential failures above are fatal. */3487 }3488 #endif /* VBOX_WITH_SHARED_CLIPBOARD */3489 3490 /*3491 * HGCM HostChannel.3492 */3493 {3494 Bstr value;3495 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),3496 value.asOutParam());3497 3498 if ( hrc == S_OK3499 && value == "1")3500 {3501 vrc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");3502 if (RT_FAILURE(vrc))3503 {3504 LogRel(("VBoxHostChannel is not available, vrc=%Rrc\n", vrc));3505 /* That is not a fatal failure. */3506 vrc = VINF_SUCCESS;3507 }3508 }3509 }3510 3511 #ifdef VBOX_WITH_DRAG_AND_DROP3512 /*3513 * Drag and Drop.3514 */3515 {3516 DnDMode_T enmMode = DnDMode_Disabled;3517 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();3518 3519 /* Load the service */3520 vrc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");3521 if (RT_FAILURE(vrc))3522 {3523 LogRel(("Drag and drop service is not available, vrc=%Rrc\n", vrc));3524 /* That is not a fatal failure. */3525 vrc = VINF_SUCCESS;3526 }3527 else3528 {3529 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",3530 &GuestDnD::notifyDnDDispatcher,3531 GuestDnDInst());3532 if (RT_FAILURE(vrc))3533 Log(("Cannot register VBoxDragAndDropSvc extension, vrc=%Rrc\n", vrc));3534 else3535 {3536 LogRel(("Drag and drop service loaded\n"));3537 vrc = i_changeDnDMode(enmMode);3538 }3539 }3540 }3541 #endif /* VBOX_WITH_DRAG_AND_DROP */3542 3543 #if defined(VBOX_WITH_TPM)3544 /*3545 * Configure the Trusted Platform Module.3546 */3547 ComObjPtr<ITrustedPlatformModule> ptrTpm;3548 TpmType_T enmTpmType = TpmType_None;3549 3550 hrc = pMachine->COMGETTER(TrustedPlatformModule)(ptrTpm.asOutParam()); H();3551 hrc = ptrTpm->COMGETTER(Type)(&enmTpmType); H();3552 if (enmTpmType != TpmType_None)3553 {3554 InsertConfigNode(pDevices, "tpm", &pDev);3555 InsertConfigNode(pDev, "0", &pInst);3556 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */3557 InsertConfigNode(pInst, "Config", &pCfg);3558 InsertConfigNode(pInst, "LUN#0", &pLunL0);3559 3560 switch (enmTpmType)3561 {3562 case TpmType_v1_2:3563 case TpmType_v2_0:3564 InsertConfigString(pLunL0, "Driver", "TpmEmuTpms");3565 InsertConfigNode(pLunL0, "Config", &pCfg);3566 InsertConfigInteger(pCfg, "TpmVersion", enmTpmType == TpmType_v1_2 ? 1 : 2);3567 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);3568 InsertConfigString(pLunL1, "Driver", "NvramStore");3569 break;3570 case TpmType_Host:3571 #if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)3572 InsertConfigString(pLunL0, "Driver", "TpmHost");3573 InsertConfigNode(pLunL0, "Config", &pCfg);3574 #endif3575 break;3576 case TpmType_Swtpm:3577 hrc = ptrTpm->COMGETTER(Location)(bstr.asOutParam()); H();3578 InsertConfigString(pLunL0, "Driver", "TpmEmu");3579 InsertConfigNode(pLunL0, "Config", &pCfg);3580 InsertConfigString(pCfg, "Location", bstr);3581 break;3582 default:3583 AssertFailedBreak();3584 }3585 }3586 #endif3587 3588 /*3589 * ACPI3590 */3591 BOOL fACPI;3592 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();3593 if (fACPI)3594 {3595 /* Always show the CPU leafs when we have multiple VCPUs or when the IO-APIC is enabled.3596 * The Windows SMP kernel needs a CPU leaf or else its idle loop will burn cpu cycles; the3597 * intelppm driver refuses to register an idle state handler.3598 * Always show CPU leafs for OS X guests. */3599 BOOL fShowCpu = fOsXGuest;3600 if (cCpus > 1 || fIOAPIC)3601 fShowCpu = true;3602 3603 BOOL fCpuHotPlug;3604 hrc = pMachine->COMGETTER(CPUHotPlugEnabled)(&fCpuHotPlug); H();3605 3606 InsertConfigNode(pDevices, "acpi", &pDev);3607 InsertConfigNode(pDev, "0", &pInst);3608 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */3609 InsertConfigNode(pInst, "Config", &pCfg);3610 hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();3611 3612 InsertConfigInteger(pCfg, "NumCPUs", cCpus);3613 3614 InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);3615 InsertConfigInteger(pCfg, "FdcEnabled", fFdcEnabled);3616 InsertConfigInteger(pCfg, "HpetEnabled", fHPETEnabled);3617 InsertConfigInteger(pCfg, "SmcEnabled", fSmcEnabled);3618 InsertConfigInteger(pCfg, "ShowRtc", fShowRtc);3619 if (fOsXGuest && !llBootNics.empty())3620 {3621 BootNic aNic = llBootNics.front();3622 uint32_t u32NicPCIAddr = (aNic.mPCIAddress.miDevice << 16) | aNic.mPCIAddress.miFn;3623 InsertConfigInteger(pCfg, "NicPciAddress", u32NicPCIAddr);3624 }3625 if (fOsXGuest && fAudioEnabled)3626 {3627 PCIBusAddress Address;3628 if (pBusMgr->findPCIAddress("hda", 0, Address))3629 {3630 uint32_t u32AudioPCIAddr = (Address.miDevice << 16) | Address.miFn;3631 InsertConfigInteger(pCfg, "AudioPciAddress", u32AudioPCIAddr);3632 }3633 }3634 if (fOsXGuest)3635 {3636 PCIBusAddress Address;3637 if (pBusMgr->findPCIAddress("nvme", 0, Address))3638 {3639 uint32_t u32NvmePCIAddr = (Address.miDevice << 16) | Address.miFn;3640 InsertConfigInteger(pCfg, "NvmePciAddress", u32NvmePCIAddr);3641 }3642 }3643 if (enmIommuType == IommuType_AMD)3644 {3645 PCIBusAddress Address;3646 if (pBusMgr->findPCIAddress("iommu-amd", 0, Address))3647 {3648 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;3649 InsertConfigInteger(pCfg, "IommuAmdEnabled", true);3650 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);3651 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))3652 {3653 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;3654 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);3655 }3656 else3657 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,3658 N_("AMD IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));3659 }3660 }3661 else if (enmIommuType == IommuType_Intel)3662 {3663 PCIBusAddress Address;3664 if (pBusMgr->findPCIAddress("iommu-intel", 0, Address))3665 {3666 uint32_t u32IommuAddress = (Address.miDevice << 16) | Address.miFn;3667 InsertConfigInteger(pCfg, "IommuIntelEnabled", true);3668 InsertConfigInteger(pCfg, "IommuPciAddress", u32IommuAddress);3669 if (pBusMgr->findPCIAddress("sb-ioapic", 0, Address))3670 {3671 uint32_t const u32SbIoapicAddress = (Address.miDevice << 16) | Address.miFn;3672 InsertConfigInteger(pCfg, "SbIoApicPciAddress", u32SbIoapicAddress);3673 }3674 else3675 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,3676 N_("Intel IOMMU is enabled, but the I/O APIC is not assigned a PCI address!"));3677 }3678 }3679 3680 InsertConfigInteger(pCfg, "IocPciAddress", uIocPCIAddress);3681 if (chipsetType == ChipsetType_ICH9)3682 {3683 InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);3684 InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);3685 /* 64-bit prefetch window root resource: Only for ICH9 and if PAE or Long Mode is enabled (@bugref{5454}). */3686 if (fIsGuest64Bit || fEnablePAE)3687 InsertConfigInteger(pCfg, "PciPref64Enabled", 1);3688 }3689 InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);3690 InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);3691 InsertConfigInteger(pCfg, "CpuHotPlug", fCpuHotPlug);3692 3693 InsertConfigInteger(pCfg, "Serial0IoPortBase", auSerialIoPortBase[0]);3694 InsertConfigInteger(pCfg, "Serial0Irq", auSerialIrq[0]);3695 3696 InsertConfigInteger(pCfg, "Serial1IoPortBase", auSerialIoPortBase[1]);3697 InsertConfigInteger(pCfg, "Serial1Irq", auSerialIrq[1]);3698 3699 if (auSerialIoPortBase[2])3700 {3701 InsertConfigInteger(pCfg, "Serial2IoPortBase", auSerialIoPortBase[2]);3702 InsertConfigInteger(pCfg, "Serial2Irq", auSerialIrq[2]);3703 }3704 3705 if (auSerialIoPortBase[3])3706 {3707 InsertConfigInteger(pCfg, "Serial3IoPortBase", auSerialIoPortBase[3]);3708 InsertConfigInteger(pCfg, "Serial3Irq", auSerialIrq[3]);3709 }3710 3711 InsertConfigInteger(pCfg, "Parallel0IoPortBase", auParallelIoPortBase[0]);3712 InsertConfigInteger(pCfg, "Parallel0Irq", auParallelIrq[0]);3713 3714 InsertConfigInteger(pCfg, "Parallel1IoPortBase", auParallelIoPortBase[1]);3715 InsertConfigInteger(pCfg, "Parallel1Irq", auParallelIrq[1]);3716 3717 #if defined(VBOX_WITH_TPM)3718 switch (enmTpmType)3719 {3720 case TpmType_v1_2:3721 InsertConfigString(pCfg, "TpmMode", "tis1.2");3722 break;3723 case TpmType_v2_0:3724 InsertConfigString(pCfg, "TpmMode", "fifo2.0");3725 break;3726 /** @todo Host and swtpm. */3727 default:3728 break;3729 }3730 #endif3731 3732 InsertConfigNode(pInst, "LUN#0", &pLunL0);3733 InsertConfigString(pLunL0, "Driver", "ACPIHost");3734 InsertConfigNode(pLunL0, "Config", &pCfg);3735 3736 /* Attach the dummy CPU drivers */3737 for (ULONG iCpuCurr = 1; iCpuCurr < cCpus; iCpuCurr++)3738 {3739 BOOL fCpuAttached = true;3740 3741 if (fCpuHotPlug)3742 {3743 hrc = pMachine->GetCPUStatus(iCpuCurr, &fCpuAttached); H();3744 }3745 3746 if (fCpuAttached)3747 {3748 InsertConfigNode(pInst, Utf8StrFmt("LUN#%u", iCpuCurr).c_str(), &pLunL0);3749 InsertConfigString(pLunL0, "Driver", "ACPICpu");3750 InsertConfigNode(pLunL0, "Config", &pCfg);3751 }3752 }3753 }3754 3755 /*3756 * Configure DBGF (Debug(ger) Facility) and DBGC (Debugger Console).3757 */3758 {3759 PCFGMNODE pDbgf;3760 InsertConfigNode(pRoot, "DBGF", &pDbgf);3761 3762 /* Paths to search for debug info and such things. */3763 hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();3764 Utf8Str strSettingsPath(bstr);3765 bstr.setNull();3766 strSettingsPath.stripFilename();3767 strSettingsPath.append("/");3768 3769 char szHomeDir[RTPATH_MAX + 1];3770 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);3771 if (RT_FAILURE(vrc2))3772 szHomeDir[0] = '\0';3773 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));3774 3775 3776 Utf8Str strPath;3777 strPath.append(strSettingsPath).append("debug/;");3778 strPath.append(strSettingsPath).append(";");3779 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */3780 strPath.append(szHomeDir);3781 3782 InsertConfigString(pDbgf, "Path", strPath.c_str());3783 3784 /* Tracing configuration. */3785 BOOL fTracingEnabled;3786 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();3787 if (fTracingEnabled)3788 InsertConfigInteger(pDbgf, "TracingEnabled", 1);3789 3790 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();3791 if (fTracingEnabled)3792 InsertConfigString(pDbgf, "TracingConfig", bstr);3793 3794 BOOL fAllowTracingToAccessVM;3795 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();3796 if (fAllowTracingToAccessVM)3797 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);3798 3799 /* Debugger console config. */3800 PCFGMNODE pDbgc;3801 InsertConfigNode(pRoot, "DBGC", &pDbgc);3802 3803 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();3804 Utf8Str strVBoxHome = bstr;3805 bstr.setNull();3806 if (strVBoxHome.isNotEmpty())3807 strVBoxHome.append("/");3808 else3809 {3810 strVBoxHome = szHomeDir;3811 strVBoxHome.append("/.vbox");3812 }3813 3814 Utf8Str strFile(strVBoxHome);3815 strFile.append("dbgc-history");3816 InsertConfigString(pDbgc, "HistoryFile", strFile);3817 3818 strFile = strSettingsPath;3819 strFile.append("dbgc-init");3820 InsertConfigString(pDbgc, "LocalInitScript", strFile);3821 3822 strFile = strVBoxHome;3823 strFile.append("dbgc-init");3824 InsertConfigString(pDbgc, "GlobalInitScript", strFile);3825 3826 /*3827 * Configure guest debug settings.3828 */3829 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;3830 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;3831 3832 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();3833 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();3834 if (enmGstDbgProvider != GuestDebugProvider_None)3835 {3836 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;3837 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();3838 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();3839 Utf8Str strAddress = bstr;3840 bstr.setNull();3841 3842 ULONG ulPort = 0;3843 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();3844 3845 PCFGMNODE pDbgSettings;3846 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);3847 InsertConfigString(pDbgSettings, "Address", strAddress);3848 InsertConfigInteger(pDbgSettings, "Port", ulPort);3849 3850 switch (enmGstDbgProvider)3851 {3852 case GuestDebugProvider_Native:3853 InsertConfigString(pDbgSettings, "StubType", "Native");3854 break;3855 case GuestDebugProvider_GDB:3856 InsertConfigString(pDbgSettings, "StubType", "Gdb");3857 break;3858 case GuestDebugProvider_KD:3859 InsertConfigString(pDbgSettings, "StubType", "Kd");3860 break;3861 default:3862 AssertFailed();3863 break;3864 }3865 3866 switch (enmGstDbgIoProvider)3867 {3868 case GuestDebugIoProvider_TCP:3869 InsertConfigString(pDbgSettings, "Provider", "tcp");3870 break;3871 case GuestDebugIoProvider_UDP:3872 InsertConfigString(pDbgSettings, "Provider", "udp");3873 break;3874 case GuestDebugIoProvider_IPC:3875 InsertConfigString(pDbgSettings, "Provider", "ipc");3876 break;3877 default:3878 AssertFailed();3879 break;3880 }3881 }3882 }3883 }3884 catch (ConfigError &x)3885 {3886 // InsertConfig threw something:3887 pVMM->pfnVMR3SetError(pUVM, x.m_vrc, RT_SRC_POS, "Caught ConfigError: %Rrc - %s", x.m_vrc, x.what());3888 return x.m_vrc;3889 }3890 catch (HRESULT hrcXcpt)3891 {3892 AssertLogRelMsgFailedReturn(("hrc=%Rhrc\n", hrcXcpt), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);3893 }3894 3895 #ifdef VBOX_WITH_EXTPACK3896 /*3897 * Call the extension pack hooks if everything went well thus far.3898 */3899 if (RT_SUCCESS(vrc))3900 {3901 pAlock->release();3902 vrc = mptrExtPackManager->i_callAllVmConfigureVmmHooks(this, pVM, pVMM);3903 pAlock->acquire();3904 }3905 #endif3906 3907 /*3908 * Apply the CFGM overlay.3909 */3910 if (RT_SUCCESS(vrc))3911 vrc = i_configCfgmOverlay(pRoot, virtualBox, pMachine);3912 3913 /*3914 * Dump all extradata API settings tweaks, both global and per VM.3915 */3916 if (RT_SUCCESS(vrc))3917 vrc = i_configDumpAPISettingsTweaks(virtualBox, pMachine);3918 3919 #undef H3920 3921 pAlock->release(); /* Avoid triggering the lock order inversion check. */3922 3923 /*3924 * Register VM state change handler.3925 */3926 int vrc2 = pVMM->pfnVMR3AtStateRegister(pUVM, Console::i_vmstateChangeCallback, this);3927 AssertRC(vrc2);3928 if (RT_SUCCESS(vrc))3929 vrc = vrc2;3930 3931 /*3932 * Register VM runtime error handler.3933 */3934 vrc2 = pVMM->pfnVMR3AtRuntimeErrorRegister(pUVM, Console::i_atVMRuntimeErrorCallback, this);3935 AssertRC(vrc2);3936 if (RT_SUCCESS(vrc))3937 vrc = vrc2;3938 3939 pAlock->acquire();3940 3941 LogFlowFunc(("vrc = %Rrc\n", vrc));3942 LogFlowFuncLeave();3943 3944 return vrc;3945 }3946 494 3947 495 /** … … 4303 851 } 4304 852 } 4305 4306 return VINF_SUCCESS;4307 }4308 4309 int Console::i_configGraphicsController(PCFGMNODE pDevices,4310 const GraphicsControllerType_T enmGraphicsController,4311 BusAssignmentManager *pBusMgr,4312 const ComPtr<IMachine> &ptrMachine,4313 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,4314 const ComPtr<IBIOSSettings> &ptrBiosSettings,4315 bool fHMEnabled)4316 {4317 // InsertConfig* throws4318 try4319 {4320 PCFGMNODE pDev, pInst, pCfg, pLunL0;4321 HRESULT hrc;4322 Bstr bstr;4323 const char *pcszDevice = "vga";4324 4325 #define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)4326 InsertConfigNode(pDevices, pcszDevice, &pDev);4327 InsertConfigNode(pDev, "0", &pInst);4328 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */4329 4330 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();4331 InsertConfigNode(pInst, "Config", &pCfg);4332 ULONG cVRamMBs;4333 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();4334 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);4335 ULONG cMonitorCount;4336 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();4337 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);4338 #ifdef VBOX_WITH_2X_4GB_ADDR_SPACE4339 InsertConfigInteger(pCfg, "R0Enabled", fHMEnabled);4340 #else4341 NOREF(fHMEnabled);4342 #endif4343 BOOL f3DEnabled;4344 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();4345 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);4346 4347 i_attachStatusDriver(pInst, DeviceType_Graphics3D);4348 4349 #ifdef VBOX_WITH_VMSVGA4350 if ( enmGraphicsController == GraphicsControllerType_VMSVGA4351 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)4352 {4353 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);4354 if (enmGraphicsController == GraphicsControllerType_VMSVGA)4355 {4356 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);4357 InsertConfigInteger(pCfg, "VMSVGAPciId", true);4358 }4359 # ifdef VBOX_WITH_VMSVGA3D4360 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);4361 # else4362 LogRel(("VMSVGA3d not available in this build!\n"));4363 # endif /* VBOX_WITH_VMSVGA3D */4364 }4365 #else4366 RT_NOREF(enmGraphicsController);4367 #endif /* VBOX_WITH_VMSVGA */4368 4369 /* Custom VESA mode list */4370 unsigned cModes = 0;4371 for (unsigned iMode = 1; iMode <= 16; ++iMode)4372 {4373 char szExtraDataKey[sizeof("CustomVideoModeXX")];4374 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);4375 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();4376 if (bstr.isEmpty())4377 break;4378 InsertConfigString(pCfg, szExtraDataKey, bstr);4379 ++cModes;4380 }4381 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);4382 4383 /* VESA height reduction */4384 ULONG ulHeightReduction;4385 IFramebuffer *pFramebuffer = NULL;4386 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);4387 if (SUCCEEDED(hrc) && pFramebuffer)4388 {4389 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();4390 pFramebuffer->Release();4391 pFramebuffer = NULL;4392 }4393 else4394 {4395 /* If framebuffer is not available, there is no height reduction. */4396 ulHeightReduction = 0;4397 }4398 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);4399 4400 /*4401 * BIOS logo4402 */4403 BOOL fFadeIn;4404 hrc = ptrBiosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();4405 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);4406 BOOL fFadeOut;4407 hrc = ptrBiosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();4408 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);4409 ULONG logoDisplayTime;4410 hrc = ptrBiosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();4411 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);4412 Bstr bstrLogoImagePath;4413 hrc = ptrBiosSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();4414 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);4415 4416 /*4417 * Boot menu4418 */4419 BIOSBootMenuMode_T eBootMenuMode;4420 int iShowBootMenu;4421 hrc = ptrBiosSettings->COMGETTER(BootMenuMode)(&eBootMenuMode); H();4422 switch (eBootMenuMode)4423 {4424 case BIOSBootMenuMode_Disabled: iShowBootMenu = 0; break;4425 case BIOSBootMenuMode_MenuOnly: iShowBootMenu = 1; break;4426 default: iShowBootMenu = 2; break;4427 }4428 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);4429 4430 /* Attach the display. */4431 InsertConfigNode(pInst, "LUN#0", &pLunL0);4432 InsertConfigString(pLunL0, "Driver", "MainDisplay");4433 InsertConfigNode(pLunL0, "Config", &pCfg);4434 }4435 catch (ConfigError &x)4436 {4437 // InsertConfig threw something:4438 return x.m_vrc;4439 }4440 4441 #undef H4442 853 4443 854 return VINF_SUCCESS; -
trunk/src/VBox/Main/src-client/ConsoleImplConfigX86.cpp
r99908 r99909 71 71 #include <iprt/string.h> 72 72 #include <iprt/system.h> 73 #include <iprt/cpp/exception.h>74 73 #if 0 /* enable to play with lots of memory. */ 75 74 # include <iprt/env.h> … … 150 149 * Internal Functions * 151 150 *********************************************************************************************************************************/ 152 static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue);153 154 151 155 152 /* Darwin compile kludge */ … … 285 282 #endif 286 283 287 class ConfigError : public RTCError288 {289 public:290 291 ConfigError(const char *pcszFunction,292 int vrc,293 const char *pcszName)294 : RTCError(Utf8StrFmt(Console::tr("%s failed: vrc=%Rrc, pcszName=%s"), pcszFunction, vrc, pcszName)),295 m_vrc(vrc)296 {297 AssertMsgFailed(("%s\n", what())); // in strict mode, hit a breakpoint here298 }299 300 int m_vrc;301 };302 303 304 /**305 * Helper that calls CFGMR3InsertString and throws an RTCError if that306 * fails (C-string variant).307 * @param pNode See CFGMR3InsertString.308 * @param pcszName See CFGMR3InsertString.309 * @param pcszValue The string value.310 */311 void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const char *pcszValue)312 {313 int vrc = mpVMM->pfnCFGMR3InsertString(pNode, pcszName, pcszValue);314 if (RT_FAILURE(vrc))315 throw ConfigError("CFGMR3InsertString", vrc, pcszName);316 }317 318 /**319 * Helper that calls CFGMR3InsertString and throws an RTCError if that320 * fails (Utf8Str variant).321 * @param pNode See CFGMR3InsertStringN.322 * @param pcszName See CFGMR3InsertStringN.323 * @param rStrValue The string value.324 */325 void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)326 {327 int vrc = mpVMM->pfnCFGMR3InsertStringN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());328 if (RT_FAILURE(vrc))329 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);330 }331 332 /**333 * Helper that calls CFGMR3InsertString and throws an RTCError if that334 * fails (Bstr variant).335 *336 * @param pNode See CFGMR3InsertStringN.337 * @param pcszName See CFGMR3InsertStringN.338 * @param rBstrValue The string value.339 */340 void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Bstr &rBstrValue)341 {342 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));343 }344 345 /**346 * Helper that calls CFGMR3InsertStringFV and throws an RTCError if that fails.347 * @param pNode See CFGMR3InsertStringF.348 * @param pcszName See CFGMR3InsertStringF.349 * @param pszFormat See CFGMR3InsertStringF.350 * @param ... See CFGMR3InsertStringF.351 */352 void Console::InsertConfigStringF(PCFGMNODE pNode, const char *pcszName, const char *pszFormat, ...)353 {354 va_list va;355 va_start(va, pszFormat);356 int vrc = mpVMM->pfnCFGMR3InsertStringFV(pNode, pcszName, pszFormat, va);357 va_end(va);358 if (RT_FAILURE(vrc))359 throw ConfigError("CFGMR3InsertStringFV", vrc, pcszName);360 }361 362 363 /**364 * Helper that calls CFGMR3InsertPassword and throws an RTCError if that365 * fails (Utf8Str variant).366 * @param pNode See CFGMR3InsertPasswordN.367 * @param pcszName See CFGMR3InsertPasswordN.368 * @param rStrValue The string value.369 */370 void Console::InsertConfigPassword(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)371 {372 int vrc = mpVMM->pfnCFGMR3InsertPasswordN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());373 if (RT_FAILURE(vrc))374 throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName);375 }376 377 /**378 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.379 *380 * @param pNode See CFGMR3InsertBytes.381 * @param pcszName See CFGMR3InsertBytes.382 * @param pvBytes See CFGMR3InsertBytes.383 * @param cbBytes See CFGMR3InsertBytes.384 */385 void Console::InsertConfigBytes(PCFGMNODE pNode, const char *pcszName, const void *pvBytes, size_t cbBytes)386 {387 int vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pcszName, pvBytes, cbBytes);388 if (RT_FAILURE(vrc))389 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);390 }391 392 /**393 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that394 * fails.395 *396 * @param pNode See CFGMR3InsertInteger.397 * @param pcszName See CFGMR3InsertInteger.398 * @param u64Integer See CFGMR3InsertInteger.399 */400 void Console::InsertConfigInteger(PCFGMNODE pNode, const char *pcszName, uint64_t u64Integer)401 {402 int vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pcszName, u64Integer);403 if (RT_FAILURE(vrc))404 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);405 }406 407 /**408 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.409 *410 * @param pNode See CFGMR3InsertNode.411 * @param pcszName See CFGMR3InsertNode.412 * @param ppChild See CFGMR3InsertNode.413 */414 void Console::InsertConfigNode(PCFGMNODE pNode, const char *pcszName, PCFGMNODE *ppChild)415 {416 int vrc = mpVMM->pfnCFGMR3InsertNode(pNode, pcszName, ppChild);417 if (RT_FAILURE(vrc))418 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);419 }420 421 /**422 * Helper that calls CFGMR3InsertNodeF and throws an RTCError if that fails.423 *424 * @param pNode See CFGMR3InsertNodeF.425 * @param ppChild See CFGMR3InsertNodeF.426 * @param pszNameFormat Name format string, see CFGMR3InsertNodeF.427 * @param ... Format arguments.428 */429 void Console::InsertConfigNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)430 {431 va_list va;432 va_start(va, pszNameFormat);433 int vrc = mpVMM->pfnCFGMR3InsertNodeF(pNode, ppChild, "%N", pszNameFormat, &va);434 va_end(va);435 if (RT_FAILURE(vrc))436 throw ConfigError("CFGMR3InsertNodeF", vrc, pszNameFormat);437 }438 439 /**440 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.441 *442 * @param pNode See CFGMR3RemoveValue.443 * @param pcszName See CFGMR3RemoveValue.444 */445 void Console::RemoveConfigValue(PCFGMNODE pNode, const char *pcszName)446 {447 int vrc = mpVMM->pfnCFGMR3RemoveValue(pNode, pcszName);448 if (RT_FAILURE(vrc))449 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);450 }451 452 /**453 * Gets an extra data value, consulting both machine and global extra data.454 *455 * @throws HRESULT on failure456 * @returns pStrValue for the callers convenience.457 * @param pVirtualBox Pointer to the IVirtualBox interface.458 * @param pMachine Pointer to the IMachine interface.459 * @param pszName The value to get.460 * @param pStrValue Where to return it's value (empty string if not461 * found).462 */463 static Utf8Str *GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)464 {465 pStrValue->setNull();466 467 Bstr bstrName(pszName);468 Bstr bstrValue;469 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());470 if (FAILED(hrc))471 throw hrc;472 if (bstrValue.isEmpty())473 {474 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());475 if (FAILED(hrc))476 throw hrc;477 }478 479 if (bstrValue.isNotEmpty())480 *pStrValue = bstrValue;481 return pStrValue;482 }483 484 485 284 /** Helper that finds out the next HBA port used 486 285 */ … … 676 475 677 476 /** 678 * Updates the device type for a LED.679 *680 * @param penmSubTypeEntry The sub-type entry to update.681 * @param enmNewType The new type.682 */683 void Console::i_setLedType(DeviceType_T *penmSubTypeEntry, DeviceType_T enmNewType)684 {685 /*686 * ASSUMES no race conditions here wrt concurrent type updating.687 */688 if (*penmSubTypeEntry != enmNewType)689 {690 *penmSubTypeEntry = enmNewType;691 ASMAtomicIncU32(&muLedGen);692 }693 }694 695 696 /**697 * Allocate a set of LEDs.698 *699 * This grabs a maLedSets entry and populates it with @a cLeds.700 *701 * @returns Index into maLedSets.702 * @param cLeds The number of LEDs in the set.703 * @param fTypes Bitmask of DeviceType_T values, e.g.704 * RT_BIT_32(DeviceType_Network).705 * @param ppaSubTypes When not NULL, subtypes for each LED and return the706 * array pointer here.707 */708 uint32_t Console::i_allocateDriverLeds(uint32_t cLeds, uint32_t fTypes, DeviceType_T **ppaSubTypes)709 {710 Assert(cLeds > 0);711 Assert(cLeds < 1024); /* Adjust if any driver supports >=1024 units! */712 Assert(!(fTypes & (RT_BIT_32(DeviceType_Null) | ~(RT_BIT_32(DeviceType_End) - 1))));713 714 /* Preallocate the arrays we need, bunching them together. */715 AssertCompile((unsigned)DeviceType_Null == 0);716 PPDMLED volatile *papLeds = (PPDMLED volatile *)RTMemAllocZ( (sizeof(PPDMLED) + (ppaSubTypes ? sizeof(**ppaSubTypes) : 0))717 * cLeds);718 AssertStmt(papLeds, throw E_OUTOFMEMORY);719 720 /* Take the LED lock in allocation mode and see if there are more LED set entries availalbe. */721 {722 AutoWriteLock alock(mLedLock COMMA_LOCKVAL_SRC_POS);723 uint32_t const idxLedSet = mcLedSets;724 if (idxLedSet < RT_ELEMENTS(maLedSets))725 {726 /* Initialize the set and return the index. */727 PLEDSET pLS = &maLedSets[idxLedSet];728 pLS->papLeds = papLeds;729 pLS->cLeds = cLeds;730 pLS->fTypes = fTypes;731 if (ppaSubTypes)732 *ppaSubTypes = pLS->paSubTypes = (DeviceType_T *)&papLeds[cLeds];733 else734 pLS->paSubTypes = NULL;735 736 mcLedSets = idxLedSet + 1;737 LogRel2(("return idxLedSet=%d (mcLedSets=%u out of max %zu)\n", idxLedSet, mcLedSets, RT_ELEMENTS(maLedSets)));738 return idxLedSet;739 }740 }741 742 RTMemFree((void *)papLeds);743 AssertFailed();744 throw ConfigError("AllocateDriverPapLeds", VERR_OUT_OF_RANGE, "Too many LED sets");745 }746 747 748 /**749 * @throws ConfigError and std::bad_alloc.750 */751 void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, uint32_t fTypes, uint32_t cLeds, DeviceType_T **ppaSubTypes,752 Console::MediumAttachmentMap *pmapMediumAttachments,753 const char *pcszDevice, unsigned uInstance)754 {755 PCFGMNODE pLunL0;756 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);757 InsertConfigString(pLunL0, "Driver", "MainStatus");758 PCFGMNODE pCfg;759 InsertConfigNode(pLunL0, "Config", &pCfg);760 uint32_t const iLedSet = i_allocateDriverLeds(cLeds, fTypes, ppaSubTypes);761 InsertConfigInteger(pCfg, "iLedSet", iLedSet);762 763 InsertConfigInteger(pCfg, "HasMediumAttachments", pmapMediumAttachments != NULL);764 if (pmapMediumAttachments)765 {766 AssertPtr(pcszDevice);767 InsertConfigStringF(pCfg, "DeviceInstance", "%s/%u", pcszDevice, uInstance);768 }769 InsertConfigInteger(pCfg, "First", 0);770 InsertConfigInteger(pCfg, "Last", cLeds - 1);771 }772 773 774 /**775 * @throws ConfigError and std::bad_alloc.776 */777 void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, DeviceType_T enmType, uint32_t cLeds /*= 1*/)778 {779 Assert(enmType > DeviceType_Null && enmType < DeviceType_End);780 i_attachStatusDriver(pCtlInst, RT_BIT_32(enmType), cLeds, NULL, NULL, NULL, 0);781 }782 783 784 /**785 * Construct the VM configuration tree (CFGM).786 *787 * This is a callback for VMR3Create() call. It is called from CFGMR3Init() in788 * the emulation thread (EMT). Any per thread COM/XPCOM initialization is done789 * here.790 *791 * @returns VBox status code.792 * @param pUVM The user mode VM handle.793 * @param pVM The cross context VM handle.794 * @param pVMM The VMM ring-3 vtable.795 * @param pvConsole Pointer to the VMPowerUpTask object.796 *797 * @note Locks the Console object for writing.798 */799 /*static*/ DECLCALLBACK(int)800 Console::i_configConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)801 {802 LogFlowFuncEnter();803 804 AssertReturn(pvConsole, VERR_INVALID_POINTER);805 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);806 807 AutoCaller autoCaller(pConsole);808 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);809 810 /* lock the console because we widely use internal fields and methods */811 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);812 813 /*814 * Set the VM handle and do the rest of the job in an worker method so we815 * can easily reset the VM handle on failure.816 */817 pConsole->mpUVM = pUVM;818 pVMM->pfnVMR3RetainUVM(pUVM);819 int vrc;820 try821 {822 vrc = pConsole->i_configConstructorInner(pUVM, pVM, pVMM, &alock);823 }824 catch (...)825 {826 vrc = VERR_UNEXPECTED_EXCEPTION;827 }828 if (RT_FAILURE(vrc))829 {830 pConsole->mpUVM = NULL;831 pVMM->pfnVMR3ReleaseUVM(pUVM);832 }833 834 return vrc;835 }836 837 838 /**839 477 * Worker for configConstructor. 840 478 * … … 847 485 * more). 848 486 */ 849 int Console::i_configConstructorInner (PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)487 int Console::i_configConstructorInnerX86(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock) 850 488 { 851 489 RT_NOREF(pVM /* when everything is disabled */); … … 3945 3583 } 3946 3584 3947 /**3948 * Configures an audio driver via CFGM by getting (optional) values from extra data.3949 *3950 * @param pVirtualBox Pointer to IVirtualBox instance.3951 * @param pMachine Pointer to IMachine instance.3952 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.3953 * @param pszDrvName Name of the driver to configure.3954 * @param fAudioEnabledIn IAudioAdapter::enabledIn value.3955 * @param fAudioEnabledOut IAudioAdapter::enabledOut value.3956 *3957 * @throws ConfigError or HRESULT on if there is trouble.3958 */3959 void Console::i_configAudioDriver(IVirtualBox *pVirtualBox, IMachine *pMachine, PCFGMNODE pLUN, const char *pszDrvName,3960 bool fAudioEnabledIn, bool fAudioEnabledOut)3961 {3962 #define H() AssertLogRelMsgStmt(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), \3963 throw ConfigError(__FUNCTION__, VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR, "line: " RT_XSTR(__LINE__)))3964 3965 InsertConfigString(pLUN, "Driver", "AUDIO");3966 3967 PCFGMNODE pCfg;3968 InsertConfigNode(pLUN, "Config", &pCfg);3969 InsertConfigString(pCfg, "DriverName", pszDrvName);3970 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);3971 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);3972 3973 Utf8Str strTmp;3974 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);3975 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");3976 if (fDebugEnabled)3977 {3978 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);3979 3980 Utf8Str strDebugPathOut;3981 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);3982 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());3983 }3984 3985 /*3986 * PCM input parameters (playback + recording).3987 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>3988 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>3989 */3990 for (unsigned iDir = 0; iDir < 2; iDir++)3991 {3992 static const struct3993 {3994 const char *pszExtraName;3995 const char *pszCfgmName;3996 } s_aToCopy[] =3997 { /* PCM parameters: */3998 { "PCMSampleBit", "PCMSampleBit" },3999 { "PCMSampleHz", "PCMSampleHz" },4000 { "PCMSampleSigned", "PCMSampleSigned" },4001 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },4002 { "PCMSampleChannels", "PCMSampleChannels" },4003 /* Buffering stuff: */4004 { "PeriodSizeMs", "PeriodSizeMs" },4005 { "BufferSizeMs", "BufferSizeMs" },4006 { "PreBufferSizeMs", "PreBufferSizeMs" },4007 };4008 4009 PCFGMNODE pDirNode = NULL;4010 const char *pszDir = iDir == 0 ? "In" : "Out";4011 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)4012 {4013 char szExtra[128];4014 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);4015 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */4016 if (strTmp.isEmpty())4017 {4018 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);4019 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);4020 if (strTmp.isEmpty())4021 continue;4022 }4023 4024 uint32_t uValue;4025 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);4026 if (RT_SUCCESS(vrc))4027 {4028 if (!pDirNode)4029 InsertConfigNode(pCfg, pszDir, &pDirNode);4030 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);4031 }4032 else4033 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));4034 }4035 }4036 4037 PCFGMNODE pLunL1;4038 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);4039 InsertConfigString(pLunL1, "Driver", pszDrvName);4040 InsertConfigNode(pLunL1, "Config", &pCfg);4041 4042 #ifdef RT_OS_WINDOWS4043 if (strcmp(pszDrvName, "HostAudioWas") == 0)4044 {4045 Bstr bstrTmp;4046 HRESULT hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();4047 InsertConfigString(pCfg, "VmUuid", bstrTmp);4048 }4049 #endif4050 4051 #if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)4052 if ( strcmp(pszDrvName, "HostAudioWas") == 04053 || strcmp(pszDrvName, "PulseAudio") == 0)4054 {4055 Bstr bstrTmp;4056 HRESULT hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();4057 InsertConfigString(pCfg, "VmName", bstrTmp);4058 }4059 #endif4060 4061 LogFlowFunc(("szDrivName=%s\n", pszDrvName));4062 4063 #undef H4064 }4065 4066 /**4067 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data4068 * values.4069 *4070 * @returns VBox status code.4071 * @param pRoot The root of the configuration tree.4072 * @param pVirtualBox Pointer to the IVirtualBox interface.4073 * @param pMachine Pointer to the IMachine interface.4074 */4075 /* static */4076 int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)4077 {4078 /*4079 * CFGM overlay handling.4080 *4081 * Here we check the extra data entries for CFGM values4082 * and create the nodes and insert the values on the fly. Existing4083 * values will be removed and reinserted. CFGM is typed, so by default4084 * we will guess whether it's a string or an integer (byte arrays are4085 * not currently supported). It's possible to override this autodetection4086 * by adding "string:", "integer:" or "bytes:" (future).4087 *4088 * We first perform a run on global extra data, then on the machine4089 * extra data to support global settings with local overrides.4090 */4091 int vrc = VINF_SUCCESS;4092 bool fFirst = true;4093 try4094 {4095 /** @todo add support for removing nodes and byte blobs. */4096 /*4097 * Get the next key4098 */4099 SafeArray<BSTR> aGlobalExtraDataKeys;4100 SafeArray<BSTR> aMachineExtraDataKeys;4101 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));4102 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));4103 4104 // remember the no. of global values so we can call the correct method below4105 size_t cGlobalValues = aGlobalExtraDataKeys.size();4106 4107 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));4108 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));4109 4110 // build a combined list from global keys...4111 std::list<Utf8Str> llExtraDataKeys;4112 4113 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)4114 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));4115 // ... and machine keys4116 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)4117 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));4118 4119 size_t i2 = 0;4120 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();4121 it != llExtraDataKeys.end();4122 ++it, ++i2)4123 {4124 const Utf8Str &strKey = *it;4125 4126 /*4127 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")4128 */4129 if (!strKey.startsWith("VBoxInternal/"))4130 continue;4131 4132 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;4133 4134 // get the value4135 Bstr bstrExtraDataValue;4136 if (i2 < cGlobalValues)4137 // this is still one of the global values:4138 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());4139 else4140 hrc = pMachine->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());4141 if (FAILED(hrc))4142 LogRel(("Warning: Cannot get extra data key %s, hrc = %Rhrc\n", strKey.c_str(), hrc));4143 4144 if (fFirst)4145 {4146 fFirst = false;4147 LogRel(("Extradata overrides:\n"));4148 }4149 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));4150 4151 /*4152 * The key will be in the format "Node1/Node2/Value" or simply "Value".4153 * Split the two and get the node, delete the value and create the node4154 * if necessary.4155 */4156 PCFGMNODE pNode;4157 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');4158 if (pszCFGMValueName)4159 {4160 /* terminate the node and advance to the value (Utf8Str might not4161 offically like this but wtf) */4162 *(char *)pszCFGMValueName = '\0';4163 ++pszCFGMValueName;4164 4165 /* does the node already exist? */4166 pNode = mpVMM->pfnCFGMR3GetChild(pRoot, pszExtraDataKey);4167 if (pNode)4168 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);4169 else4170 {4171 /* create the node */4172 vrc = mpVMM->pfnCFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);4173 if (RT_FAILURE(vrc))4174 {4175 AssertLogRelMsgRC(vrc, ("failed to insert node '%s'\n", pszExtraDataKey));4176 continue;4177 }4178 Assert(pNode);4179 }4180 }4181 else4182 {4183 /* root value (no node path). */4184 pNode = pRoot;4185 pszCFGMValueName = pszExtraDataKey;4186 pszExtraDataKey--;4187 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);4188 }4189 4190 /*4191 * Now let's have a look at the value.4192 * Empty strings means that we should remove the value, which we've4193 * already done above.4194 */4195 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);4196 if (strCFGMValueUtf8.isNotEmpty())4197 {4198 uint64_t u64Value;4199 4200 /* check for type prefix first. */4201 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))4202 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);4203 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))4204 {4205 vrc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);4206 if (RT_SUCCESS(vrc))4207 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);4208 }4209 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))4210 {4211 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;4212 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);4213 if (cbValue > 0)4214 {4215 void *pvBytes = RTMemTmpAlloc(cbValue);4216 if (pvBytes)4217 {4218 vrc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);4219 if (RT_SUCCESS(vrc))4220 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);4221 RTMemTmpFree(pvBytes);4222 }4223 else4224 vrc = VERR_NO_TMP_MEMORY;4225 }4226 else if (cbValue == 0)4227 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);4228 else4229 vrc = VERR_INVALID_BASE64_ENCODING;4230 }4231 /* auto detect type. */4232 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))4233 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);4234 else4235 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str());4236 AssertLogRelMsgRCBreak(vrc, ("failed to insert CFGM value '%s' to key '%s'\n",4237 strCFGMValueUtf8.c_str(), pszExtraDataKey));4238 }4239 }4240 }4241 catch (ConfigError &x)4242 {4243 // InsertConfig threw something:4244 return x.m_vrc;4245 }4246 return vrc;4247 }4248 4249 /**4250 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data4251 * values.4252 *4253 * @returns VBox status code.4254 * @param pVirtualBox Pointer to the IVirtualBox interface.4255 * @param pMachine Pointer to the IMachine interface.4256 */4257 /* static */4258 int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)4259 {4260 {4261 SafeArray<BSTR> aGlobalExtraDataKeys;4262 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));4263 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));4264 bool hasKey = false;4265 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)4266 {4267 Utf8Str strKey(aGlobalExtraDataKeys[i]);4268 if (!strKey.startsWith("VBoxInternal2/"))4269 continue;4270 4271 Bstr bstrValue;4272 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),4273 bstrValue.asOutParam());4274 if (FAILED(hrc))4275 continue;4276 if (!hasKey)4277 LogRel(("Global extradata API settings:\n"));4278 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));4279 hasKey = true;4280 }4281 }4282 4283 {4284 SafeArray<BSTR> aMachineExtraDataKeys;4285 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));4286 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));4287 bool hasKey = false;4288 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)4289 {4290 Utf8Str strKey(aMachineExtraDataKeys[i]);4291 if (!strKey.startsWith("VBoxInternal2/"))4292 continue;4293 4294 Bstr bstrValue;4295 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),4296 bstrValue.asOutParam());4297 if (FAILED(hrc))4298 continue;4299 if (!hasKey)4300 LogRel(("Per-VM extradata API settings:\n"));4301 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));4302 hasKey = true;4303 }4304 }4305 4306 return VINF_SUCCESS;4307 }4308 3585 4309 3586 int Console::i_configGraphicsController(PCFGMNODE pDevices, … … 4443 3720 return VINF_SUCCESS; 4444 3721 } 4445 4446 4447 /**4448 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.4449 */4450 void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)4451 {4452 va_list va;4453 va_start(va, pszFormat);4454 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);4455 va_end(va);4456 }4457 4458 /* XXX introduce RT format specifier */4459 static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)4460 {4461 if (u64Size > INT64_C(5000)*_1G)4462 {4463 *pszUnit = "TB";4464 return u64Size / _1T;4465 }4466 else if (u64Size > INT64_C(5000)*_1M)4467 {4468 *pszUnit = "GB";4469 return u64Size / _1G;4470 }4471 else4472 {4473 *pszUnit = "MB";4474 return u64Size / _1M;4475 }4476 }4477 4478 /**4479 * Checks the location of the given medium for known bugs affecting the usage4480 * of the host I/O cache setting.4481 *4482 * @returns VBox status code.4483 * @param pMedium The medium to check.4484 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.4485 */4486 int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)4487 {4488 #define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)4489 /*4490 * Some sanity checks.4491 */4492 RT_NOREF(pfUseHostIOCache);4493 ComPtr<IMediumFormat> pMediumFormat;4494 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();4495 ULONG uCaps = 0;4496 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;4497 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();4498 4499 for (ULONG j = 0; j < mediumFormatCap.size(); j++)4500 uCaps |= mediumFormatCap[j];4501 4502 if (uCaps & MediumFormatCapabilities_File)4503 {4504 Bstr bstrFile;4505 hrc = pMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();4506 Utf8Str const strFile(bstrFile);4507 4508 Bstr bstrSnap;4509 ComPtr<IMachine> pMachine = i_machine();4510 hrc = pMachine->COMGETTER(SnapshotFolder)(bstrSnap.asOutParam()); H();4511 Utf8Str const strSnap(bstrSnap);4512 4513 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;4514 int vrc2 = RTFsQueryType(strFile.c_str(), &enmFsTypeFile);4515 AssertMsgRCReturn(vrc2, ("Querying the file type of '%s' failed!\n", strFile.c_str()), vrc2);4516 4517 /* Any VM which hasn't created a snapshot or saved the current state of the VM4518 * won't have a Snapshot folder yet so no need to log anything about the file system4519 * type of the non-existent directory in such cases. */4520 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;4521 vrc2 = RTFsQueryType(strSnap.c_str(), &enmFsTypeSnap);4522 if (RT_SUCCESS(vrc2) && !mfSnapshotFolderDiskTypeShown)4523 {4524 LogRel(("File system of '%s' (snapshots) is %s\n", strSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));4525 mfSnapshotFolderDiskTypeShown = true;4526 }4527 LogRel(("File system of '%s' is %s\n", strFile.c_str(), RTFsTypeName(enmFsTypeFile)));4528 LONG64 i64Size;4529 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();4530 #ifdef RT_OS_WINDOWS4531 if ( enmFsTypeFile == RTFSTYPE_FAT4532 && i64Size >= _4G)4533 {4534 const char *pszUnit;4535 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);4536 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",4537 N_("The medium '%s' has a logical size of %RU64%s "4538 "but the file system the medium is located on seems "4539 "to be FAT(32) which cannot handle files bigger than 4GB.\n"4540 "We strongly recommend to put all your virtual disk images and "4541 "the snapshot folder onto an NTFS partition"),4542 strFile.c_str(), u64Print, pszUnit);4543 }4544 #else /* !RT_OS_WINDOWS */4545 if ( enmFsTypeFile == RTFSTYPE_FAT4546 || enmFsTypeFile == RTFSTYPE_EXT4547 || enmFsTypeFile == RTFSTYPE_EXT24548 || enmFsTypeFile == RTFSTYPE_EXT34549 || enmFsTypeFile == RTFSTYPE_EXT4)4550 {4551 RTFILE file;4552 int vrc = RTFileOpen(&file, strFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);4553 if (RT_SUCCESS(vrc))4554 {4555 RTFOFF maxSize;4556 /* Careful: This function will work only on selected local file systems! */4557 vrc = RTFileQueryMaxSizeEx(file, &maxSize);4558 RTFileClose(file);4559 if ( RT_SUCCESS(vrc)4560 && maxSize > 04561 && i64Size > (LONG64)maxSize)4562 {4563 const char *pszUnitSiz;4564 const char *pszUnitMax;4565 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);4566 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);4567 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */4568 N_("The medium '%s' has a logical size of %RU64%s "4569 "but the file system the medium is located on can "4570 "only handle files up to %RU64%s in theory.\n"4571 "We strongly recommend to put all your virtual disk "4572 "images and the snapshot folder onto a proper "4573 "file system (e.g. ext3) with a sufficient size"),4574 strFile.c_str(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);4575 }4576 }4577 }4578 #endif /* !RT_OS_WINDOWS */4579 4580 /*4581 * Snapshot folder:4582 * Here we test only for a FAT partition as we had to create a dummy file otherwise4583 */4584 if ( enmFsTypeSnap == RTFSTYPE_FAT4585 && i64Size >= _4G4586 && !mfSnapshotFolderSizeWarningShown)4587 {4588 const char *pszUnit;4589 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);4590 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",4591 #ifdef RT_OS_WINDOWS4592 N_("The snapshot folder of this VM '%s' seems to be located on "4593 "a FAT(32) file system. The logical size of the medium '%s' "4594 "(%RU64%s) is bigger than the maximum file size this file "4595 "system can handle (4GB).\n"4596 "We strongly recommend to put all your virtual disk images and "4597 "the snapshot folder onto an NTFS partition"),4598 #else4599 N_("The snapshot folder of this VM '%s' seems to be located on "4600 "a FAT(32) file system. The logical size of the medium '%s' "4601 "(%RU64%s) is bigger than the maximum file size this file "4602 "system can handle (4GB).\n"4603 "We strongly recommend to put all your virtual disk images and "4604 "the snapshot folder onto a proper file system (e.g. ext3)"),4605 #endif4606 strSnap.c_str(), strFile.c_str(), u64Print, pszUnit);4607 /* Show this particular warning only once */4608 mfSnapshotFolderSizeWarningShown = true;4609 }4610 4611 #ifdef RT_OS_LINUX4612 /*4613 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located4614 * on an ext4 partition.4615 * This bug apparently applies to the XFS file system as well.4616 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).4617 */4618 4619 char szOsRelease[128];4620 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));4621 bool fKernelHasODirectBug = RT_FAILURE(vrc)4622 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);4623 4624 if ( (uCaps & MediumFormatCapabilities_Asynchronous)4625 && !*pfUseHostIOCache4626 && fKernelHasODirectBug)4627 {4628 if ( enmFsTypeFile == RTFSTYPE_EXT44629 || enmFsTypeFile == RTFSTYPE_XFS)4630 {4631 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",4632 N_("The host I/O cache for at least one controller is disabled "4633 "and the medium '%s' for this VM "4634 "is located on an %s partition. There is a known Linux "4635 "kernel bug which can lead to the corruption of the virtual "4636 "disk image under these conditions.\n"4637 "Either enable the host I/O cache permanently in the VM "4638 "settings or put the disk image and the snapshot folder "4639 "onto a different file system.\n"4640 "The host I/O cache will now be enabled for this medium"),4641 strFile.c_str(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");4642 *pfUseHostIOCache = true;4643 }4644 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT44645 || enmFsTypeSnap == RTFSTYPE_XFS)4646 && !mfSnapshotFolderExt4WarningShown)4647 {4648 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",4649 N_("The host I/O cache for at least one controller is disabled "4650 "and the snapshot folder for this VM "4651 "is located on an %s partition. There is a known Linux "4652 "kernel bug which can lead to the corruption of the virtual "4653 "disk image under these conditions.\n"4654 "Either enable the host I/O cache permanently in the VM "4655 "settings or put the disk image and the snapshot folder "4656 "onto a different file system.\n"4657 "The host I/O cache will now be enabled for this medium"),4658 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");4659 *pfUseHostIOCache = true;4660 mfSnapshotFolderExt4WarningShown = true;4661 }4662 }4663 4664 /*4665 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running4666 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as4667 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such4668 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this4669 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.4670 */4671 bool fKernelAsyncUnreliable = RT_FAILURE(vrc)4672 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);4673 if ( (uCaps & MediumFormatCapabilities_Asynchronous)4674 && !*pfUseHostIOCache4675 && fKernelAsyncUnreliable)4676 {4677 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",4678 N_("The host I/O cache for at least one controller is disabled. "4679 "There is a known Linux kernel bug which can lead to kernel "4680 "oopses under heavy load. To our knowledge this bug affects "4681 "all 2.6.18 kernels.\n"4682 "Either enable the host I/O cache permanently in the VM "4683 "settings or switch to a newer host kernel.\n"4684 "The host I/O cache will now be enabled for this medium"));4685 *pfUseHostIOCache = true;4686 }4687 #endif4688 }4689 #undef H4690 4691 return VINF_SUCCESS;4692 }4693 4694 /**4695 * Unmounts the specified medium from the specified device.4696 *4697 * @returns VBox status code.4698 * @param pUVM The usermode VM handle.4699 * @param pVMM The VMM vtable.4700 * @param enmBus The storage bus.4701 * @param enmDevType The device type.4702 * @param pcszDevice The device emulation.4703 * @param uInstance Instance of the device.4704 * @param uLUN The LUN on the device.4705 * @param fForceUnmount Whether to force unmounting.4706 */4707 int Console::i_unmountMediumFromGuest(PUVM pUVM, PCVMMR3VTABLE pVMM, StorageBus_T enmBus, DeviceType_T enmDevType,4708 const char *pcszDevice, unsigned uInstance, unsigned uLUN,4709 bool fForceUnmount) RT_NOEXCEPT4710 {4711 /* Unmount existing media only for floppy and DVD drives. */4712 int vrc = VINF_SUCCESS;4713 PPDMIBASE pBase;4714 if (enmBus == StorageBus_USB)4715 vrc = pVMM->pfnPDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);4716 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)4717 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))4718 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);4719 else /* IDE or Floppy */4720 vrc = pVMM->pfnPDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);4721 4722 if (RT_FAILURE(vrc))4723 {4724 if (vrc == VERR_PDM_LUN_NOT_FOUND || vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)4725 vrc = VINF_SUCCESS;4726 AssertRC(vrc);4727 }4728 else4729 {4730 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);4731 AssertReturn(pIMount, VERR_INVALID_POINTER);4732 4733 /* Unmount the media (but do not eject the medium!) */4734 vrc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);4735 if (vrc == VERR_PDM_MEDIA_NOT_MOUNTED)4736 vrc = VINF_SUCCESS;4737 /* for example if the medium is locked */4738 else if (RT_FAILURE(vrc))4739 return vrc;4740 }4741 4742 return vrc;4743 }4744 4745 /**4746 * Removes the currently attached medium driver form the specified device4747 * taking care of the controlelr specific configs wrt. to the attached driver chain.4748 *4749 * @returns VBox status code.4750 * @param pCtlInst The controler instance node in the CFGM tree.4751 * @param pcszDevice The device name.4752 * @param uInstance The device instance.4753 * @param uLUN The device LUN.4754 * @param enmBus The storage bus.4755 * @param fAttachDetach Flag whether this is a change while the VM is running4756 * @param fHotplug Flag whether the guest should be notified about the device change.4757 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.4758 * @param pUVM The usermode VM handle.4759 * @param pVMM The VMM vtable.4760 * @param enmDevType The device type.4761 * @param ppLunL0 Where to store the node to attach the new config to on success.4762 */4763 int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,4764 const char *pcszDevice,4765 unsigned uInstance,4766 unsigned uLUN,4767 StorageBus_T enmBus,4768 bool fAttachDetach,4769 bool fHotplug,4770 bool fForceUnmount,4771 PUVM pUVM,4772 PCVMMR3VTABLE pVMM,4773 DeviceType_T enmDevType,4774 PCFGMNODE *ppLunL0)4775 {4776 int vrc = VINF_SUCCESS;4777 bool fAddLun = false;4778 4779 /* First check if the LUN already exists. */4780 PCFGMNODE pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);4781 AssertReturn(!RT_VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);4782 4783 if (pLunL0)4784 {4785 /*4786 * Unmount the currently mounted medium if we don't just hot remove the4787 * complete device (SATA) and it supports unmounting (DVD).4788 */4789 if ( (enmDevType != DeviceType_HardDisk)4790 && !fHotplug)4791 {4792 vrc = i_unmountMediumFromGuest(pUVM, pVMM, enmBus, enmDevType, pcszDevice, uInstance, uLUN, fForceUnmount);4793 if (RT_FAILURE(vrc))4794 return vrc;4795 }4796 4797 /*4798 * Don't detach the SCSI driver when unmounting the current medium4799 * (we are not ripping out the device but only eject the medium).4800 */4801 char *pszDriverDetach = NULL;4802 if ( !fHotplug4803 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)4804 || enmBus == StorageBus_SAS4805 || enmBus == StorageBus_SCSI4806 || enmBus == StorageBus_VirtioSCSI4807 || enmBus == StorageBus_USB))4808 {4809 /* Get the current attached driver we have to detach. */4810 PCFGMNODE pDrvLun = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);4811 if (pDrvLun)4812 {4813 char szDriver[128];4814 RT_ZERO(szDriver);4815 vrc = pVMM->pfnCFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));4816 if (RT_SUCCESS(vrc))4817 pszDriverDetach = RTStrDup(&szDriver[0]);4818 4819 pLunL0 = pDrvLun;4820 }4821 }4822 4823 if (enmBus == StorageBus_USB)4824 vrc = pVMM->pfnPDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,4825 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);4826 else4827 vrc = pVMM->pfnPDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,4828 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);4829 4830 if (pszDriverDetach)4831 {4832 RTStrFree(pszDriverDetach);4833 /* Remove the complete node and create new for the new config. */4834 pVMM->pfnCFGMR3RemoveNode(pLunL0);4835 pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);4836 if (pLunL0)4837 {4838 try4839 {4840 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);4841 }4842 catch (ConfigError &x)4843 {4844 // InsertConfig threw something:4845 return x.m_vrc;4846 }4847 }4848 }4849 if (vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)4850 vrc = VINF_SUCCESS;4851 AssertRCReturn(vrc, vrc);4852 4853 /*4854 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver4855 * even for DVD devices) or if there is a hotplug event which rips out the complete device.4856 */4857 if ( fHotplug4858 || enmBus == StorageBus_IDE4859 || enmBus == StorageBus_Floppy4860 || enmBus == StorageBus_PCIe4861 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))4862 {4863 fAddLun = true;4864 pVMM->pfnCFGMR3RemoveNode(pLunL0);4865 }4866 }4867 else4868 fAddLun = true;4869 4870 try4871 {4872 if (fAddLun)4873 InsertConfigNodeF(pCtlInst, &pLunL0, "LUN#%u", uLUN);4874 }4875 catch (ConfigError &x)4876 {4877 // InsertConfig threw something:4878 return x.m_vrc;4879 }4880 4881 if (ppLunL0)4882 *ppLunL0 = pLunL0;4883 4884 return vrc;4885 }4886 4887 int Console::i_configMediumAttachment(const char *pcszDevice,4888 unsigned uInstance,4889 StorageBus_T enmBus,4890 bool fUseHostIOCache,4891 bool fBuiltinIOCache,4892 bool fInsertDiskIntegrityDrv,4893 bool fSetupMerge,4894 unsigned uMergeSource,4895 unsigned uMergeTarget,4896 IMediumAttachment *pMediumAtt,4897 MachineState_T aMachineState,4898 HRESULT *phrc,4899 bool fAttachDetach,4900 bool fForceUnmount,4901 bool fHotplug,4902 PUVM pUVM,4903 PCVMMR3VTABLE pVMM,4904 DeviceType_T *paLedDevType,4905 PCFGMNODE *ppLunL0)4906 {4907 // InsertConfig* throws4908 try4909 {4910 int vrc = VINF_SUCCESS;4911 HRESULT hrc;4912 Bstr bstr;4913 PCFGMNODE pCtlInst = NULL;4914 4915 // #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)4916 #define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)4917 4918 LONG lDev;4919 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();4920 LONG lPort;4921 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();4922 DeviceType_T enmType;4923 hrc = pMediumAtt->COMGETTER(Type)(&enmType); H();4924 BOOL fNonRotational;4925 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();4926 BOOL fDiscard;4927 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();4928 4929 if (enmType == DeviceType_DVD)4930 fInsertDiskIntegrityDrv = false;4931 4932 unsigned uLUN;4933 PCFGMNODE pLunL0 = NULL;4934 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();4935 4936 /* Determine the base path for the device instance. */4937 if (enmBus != StorageBus_USB)4938 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);4939 else4940 {4941 /* If we hotplug a USB device create a new CFGM tree. */4942 if (!fHotplug)4943 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);4944 else4945 pCtlInst = pVMM->pfnCFGMR3CreateTree(pUVM); /** @todo r=bird: Leaked in error paths! */4946 }4947 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);4948 4949 if (enmBus == StorageBus_USB)4950 {4951 PCFGMNODE pCfg = NULL;4952 4953 /* Create correct instance. */4954 if (!fHotplug)4955 {4956 if (!fAttachDetach)4957 InsertConfigNodeF(pCtlInst, &pCtlInst, "%d", lPort);4958 else4959 pCtlInst = pVMM->pfnCFGMR3GetChildF(pCtlInst, "%d/", lPort);4960 }4961 4962 if (!fAttachDetach)4963 InsertConfigNode(pCtlInst, "Config", &pCfg);4964 4965 uInstance = lPort; /* Overwrite uInstance with the correct one. */4966 4967 /** @todo No LED after hotplugging. */4968 if (!fHotplug && !fAttachDetach)4969 {4970 USBStorageDevice UsbMsd;4971 UsbMsd.iPort = uInstance;4972 vrc = RTUuidCreate(&UsbMsd.mUuid);4973 AssertRCReturn(vrc, vrc);4974 4975 InsertConfigStringF(pCtlInst, "UUID", "%RTuuid", &UsbMsd.mUuid);4976 4977 mUSBStorageDevices.push_back(UsbMsd);4978 4979 /** @todo This LED set is not freed if the device is unplugged. We could4980 * keep the LED set index in the UsbMsd structure and clean it up in4981 * i_detachStorageDevice. */4982 /* Attach the status driver */4983 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),4984 8, &paLedDevType, &mapMediumAttachments, pcszDevice, 0);4985 }4986 }4987 4988 vrc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,4989 fHotplug, fForceUnmount, pUVM, pVMM, enmType, &pLunL0);4990 if (RT_FAILURE(vrc))4991 return vrc;4992 if (ppLunL0)4993 *ppLunL0 = pLunL0;4994 4995 Utf8StrFmt devicePath("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);4996 mapMediumAttachments[devicePath] = pMediumAtt;4997 4998 ComPtr<IMedium> ptrMedium;4999 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();5000 5001 /*5002 * 1. Only check this for hard disk images.5003 * 2. Only check during VM creation and not later, especially not during5004 * taking an online snapshot!5005 */5006 if ( enmType == DeviceType_HardDisk5007 && ( aMachineState == MachineState_Starting5008 || aMachineState == MachineState_Restoring))5009 {5010 vrc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);5011 if (RT_FAILURE(vrc))5012 return vrc;5013 }5014 5015 BOOL fPassthrough = FALSE;5016 if (ptrMedium.isNotNull())5017 {5018 BOOL fHostDrive;5019 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();5020 if ( ( enmType == DeviceType_DVD5021 || enmType == DeviceType_Floppy)5022 && !fHostDrive)5023 {5024 /*5025 * Informative logging.5026 */5027 Bstr bstrFile;5028 hrc = ptrMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();5029 Utf8Str strFile(bstrFile);5030 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;5031 (void)RTFsQueryType(strFile.c_str(), &enmFsTypeFile);5032 LogRel(("File system of '%s' (%s) is %s\n",5033 strFile.c_str(), enmType == DeviceType_DVD ? "DVD" : "Floppy", RTFsTypeName(enmFsTypeFile)));5034 }5035 5036 if (fHostDrive)5037 {5038 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();5039 }5040 }5041 5042 ComObjPtr<IBandwidthGroup> pBwGroup;5043 Bstr bstrBwGroup;5044 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();5045 5046 if (!pBwGroup.isNull())5047 {5048 hrc = pBwGroup->COMGETTER(Name)(bstrBwGroup.asOutParam()); H();5049 }5050 5051 /*5052 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers5053 * or for SATA if the new device is a CD/DVD drive.5054 */5055 if ( (fHotplug || !fAttachDetach)5056 && ( enmBus == StorageBus_SCSI5057 || enmBus == StorageBus_SAS5058 || enmBus == StorageBus_USB5059 || enmBus == StorageBus_VirtioSCSI5060 || (enmBus == StorageBus_SATA && enmType == DeviceType_DVD && !fPassthrough)))5061 {5062 InsertConfigString(pLunL0, "Driver", "SCSI");5063 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);5064 }5065 5066 vrc = i_configMedium(pLunL0,5067 !!fPassthrough,5068 enmType,5069 fUseHostIOCache,5070 fBuiltinIOCache,5071 fInsertDiskIntegrityDrv,5072 fSetupMerge,5073 uMergeSource,5074 uMergeTarget,5075 bstrBwGroup.isEmpty() ? NULL : Utf8Str(bstrBwGroup).c_str(),5076 !!fDiscard,5077 !!fNonRotational,5078 ptrMedium,5079 aMachineState,5080 phrc);5081 if (RT_FAILURE(vrc))5082 return vrc;5083 5084 if (fAttachDetach)5085 {5086 /* Attach the new driver. */5087 if (enmBus == StorageBus_USB)5088 {5089 if (fHotplug)5090 {5091 USBStorageDevice UsbMsd;5092 RTUuidCreate(&UsbMsd.mUuid);5093 UsbMsd.iPort = uInstance;5094 vrc = pVMM->pfnPDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);5095 if (RT_SUCCESS(vrc))5096 mUSBStorageDevices.push_back(UsbMsd);5097 }5098 else5099 vrc = pVMM->pfnPDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,5100 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);5101 }5102 else if ( !fHotplug5103 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)5104 || (enmBus == StorageBus_SATA && enmType == DeviceType_DVD)))5105 vrc = pVMM->pfnPDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,5106 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);5107 else5108 vrc = pVMM->pfnPDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,5109 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);5110 AssertRCReturn(vrc, vrc);5111 5112 /*5113 * Make the secret key helper interface known to the VD driver if it is attached,5114 * so we can get notified about missing keys.5115 */5116 PPDMIBASE pIBase = NULL;5117 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);5118 if (RT_SUCCESS(vrc) && pIBase)5119 {5120 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);5121 if (pIMedium)5122 {5123 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);5124 Assert(RT_SUCCESS(vrc) || vrc == VERR_NOT_SUPPORTED);5125 }5126 }5127 5128 /* There is no need to handle removable medium mounting, as we5129 * unconditionally replace everthing including the block driver level.5130 * This means the new medium will be picked up automatically. */5131 }5132 5133 if (paLedDevType)5134 i_setLedType(&paLedDevType[uLUN], enmType);5135 5136 /* Dump the changed LUN if possible, dump the complete device otherwise */5137 if ( aMachineState != MachineState_Starting5138 && aMachineState != MachineState_Restoring)5139 pVMM->pfnCFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);5140 }5141 catch (ConfigError &x)5142 {5143 // InsertConfig threw something:5144 return x.m_vrc;5145 }5146 5147 #undef H5148 5149 return VINF_SUCCESS;5150 }5151 5152 int Console::i_configMedium(PCFGMNODE pLunL0,5153 bool fPassthrough,5154 DeviceType_T enmType,5155 bool fUseHostIOCache,5156 bool fBuiltinIOCache,5157 bool fInsertDiskIntegrityDrv,5158 bool fSetupMerge,5159 unsigned uMergeSource,5160 unsigned uMergeTarget,5161 const char *pcszBwGroup,5162 bool fDiscard,5163 bool fNonRotational,5164 ComPtr<IMedium> ptrMedium,5165 MachineState_T aMachineState,5166 HRESULT *phrc)5167 {5168 // InsertConfig* throws5169 try5170 {5171 HRESULT hrc;5172 Bstr bstr;5173 PCFGMNODE pCfg = NULL;5174 5175 #define H() \5176 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))5177 5178 5179 BOOL fHostDrive = FALSE;5180 MediumType_T mediumType = MediumType_Normal;5181 if (ptrMedium.isNotNull())5182 {5183 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();5184 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();5185 }5186 5187 if (fHostDrive)5188 {5189 Assert(ptrMedium.isNotNull());5190 if (enmType == DeviceType_DVD)5191 {5192 InsertConfigString(pLunL0, "Driver", "HostDVD");5193 InsertConfigNode(pLunL0, "Config", &pCfg);5194 5195 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();5196 InsertConfigString(pCfg, "Path", bstr);5197 5198 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);5199 }5200 else if (enmType == DeviceType_Floppy)5201 {5202 InsertConfigString(pLunL0, "Driver", "HostFloppy");5203 InsertConfigNode(pLunL0, "Config", &pCfg);5204 5205 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();5206 InsertConfigString(pCfg, "Path", bstr);5207 }5208 }5209 else5210 {5211 if (fInsertDiskIntegrityDrv)5212 {5213 /*5214 * The actual configuration is done through CFGM extra data5215 * for each inserted driver separately.5216 */5217 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");5218 InsertConfigNode(pLunL0, "Config", &pCfg);5219 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);5220 }5221 5222 InsertConfigString(pLunL0, "Driver", "VD");5223 InsertConfigNode(pLunL0, "Config", &pCfg);5224 switch (enmType)5225 {5226 case DeviceType_DVD:5227 InsertConfigString(pCfg, "Type", "DVD");5228 InsertConfigInteger(pCfg, "Mountable", 1);5229 break;5230 case DeviceType_Floppy:5231 InsertConfigString(pCfg, "Type", "Floppy 1.44");5232 InsertConfigInteger(pCfg, "Mountable", 1);5233 break;5234 case DeviceType_HardDisk:5235 default:5236 InsertConfigString(pCfg, "Type", "HardDisk");5237 InsertConfigInteger(pCfg, "Mountable", 0);5238 }5239 5240 if ( ptrMedium.isNotNull()5241 && ( enmType == DeviceType_DVD5242 || enmType == DeviceType_Floppy)5243 )5244 {5245 // if this medium represents an ISO image and this image is inaccessible,5246 // the ignore it instead of causing a failure; this can happen when we5247 // restore a VM state and the ISO has disappeared, e.g. because the Guest5248 // Additions were mounted and the user upgraded VirtualBox. Previously5249 // we failed on startup, but that's not good because the only way out then5250 // would be to discard the VM state...5251 MediumState_T mediumState;5252 hrc = ptrMedium->RefreshState(&mediumState); H();5253 if (mediumState == MediumState_Inaccessible)5254 {5255 Bstr loc;5256 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();5257 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",5258 N_("The image file '%ls' is inaccessible and is being ignored. "5259 "Please select a different image file for the virtual %s drive."),5260 loc.raw(),5261 enmType == DeviceType_DVD ? "DVD" : "floppy");5262 ptrMedium.setNull();5263 }5264 }5265 5266 if (ptrMedium.isNotNull())5267 {5268 /* Start with length of parent chain, as the list is reversed */5269 unsigned uImage = 0;5270 ComPtr<IMedium> ptrTmp = ptrMedium;5271 while (ptrTmp.isNotNull())5272 {5273 uImage++;5274 ComPtr<IMedium> ptrParent;5275 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();5276 ptrTmp = ptrParent;5277 }5278 /* Index of last image */5279 uImage--;5280 5281 # ifdef VBOX_WITH_EXTPACK5282 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))5283 {5284 /* Configure loading the VDPlugin. */5285 static const char s_szVDPlugin[] = "VDPluginCrypt";5286 PCFGMNODE pCfgPlugins = NULL;5287 PCFGMNODE pCfgPlugin = NULL;5288 Utf8Str strPlugin;5289 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);5290 // Don't fail, this is optional!5291 if (SUCCEEDED(hrc))5292 {5293 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);5294 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);5295 InsertConfigString(pCfgPlugin, "Path", strPlugin);5296 }5297 }5298 # endif5299 5300 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();5301 InsertConfigString(pCfg, "Path", bstr);5302 5303 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();5304 InsertConfigString(pCfg, "Format", bstr);5305 5306 if (mediumType == MediumType_Readonly)5307 InsertConfigInteger(pCfg, "ReadOnly", 1);5308 else if (enmType == DeviceType_Floppy)5309 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);5310 5311 /* Start without exclusive write access to the images. */5312 /** @todo Live Migration: I don't quite like this, we risk screwing up when5313 * we're resuming the VM if some 3rd dude have any of the VDIs open5314 * with write sharing denied. However, if the two VMs are sharing a5315 * image it really is necessary....5316 *5317 * So, on the "lock-media" command, the target teleporter should also5318 * make DrvVD undo TempReadOnly. It gets interesting if we fail after5319 * that. Grumble. */5320 if ( enmType == DeviceType_HardDisk5321 && aMachineState == MachineState_TeleportingIn)5322 InsertConfigInteger(pCfg, "TempReadOnly", 1);5323 5324 /* Flag for opening the medium for sharing between VMs. This5325 * is done at the moment only for the first (and only) medium5326 * in the chain, as shared media can have no diffs. */5327 if (mediumType == MediumType_Shareable)5328 InsertConfigInteger(pCfg, "Shareable", 1);5329 5330 if (!fUseHostIOCache)5331 {5332 InsertConfigInteger(pCfg, "UseNewIo", 1);5333 /*5334 * Activate the builtin I/O cache for harddisks only.5335 * It caches writes only which doesn't make sense for DVD drives5336 * and just increases the overhead.5337 */5338 if ( fBuiltinIOCache5339 && (enmType == DeviceType_HardDisk))5340 InsertConfigInteger(pCfg, "BlockCache", 1);5341 }5342 5343 if (fSetupMerge)5344 {5345 InsertConfigInteger(pCfg, "SetupMerge", 1);5346 if (uImage == uMergeSource)5347 InsertConfigInteger(pCfg, "MergeSource", 1);5348 else if (uImage == uMergeTarget)5349 InsertConfigInteger(pCfg, "MergeTarget", 1);5350 }5351 5352 if (pcszBwGroup)5353 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);5354 5355 if (fDiscard)5356 InsertConfigInteger(pCfg, "Discard", 1);5357 5358 if (fNonRotational)5359 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);5360 5361 /* Pass all custom parameters. */5362 bool fHostIP = true;5363 bool fEncrypted = false;5364 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();5365 5366 /* Create an inverted list of parents. */5367 uImage--;5368 ComPtr<IMedium> ptrParentMedium = ptrMedium;5369 for (PCFGMNODE pParent = pCfg;; uImage--)5370 {5371 ComPtr<IMedium> ptrCurMedium;5372 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();5373 if (ptrCurMedium.isNull())5374 break;5375 5376 PCFGMNODE pCur;5377 InsertConfigNode(pParent, "Parent", &pCur);5378 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();5379 InsertConfigString(pCur, "Path", bstr);5380 5381 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();5382 InsertConfigString(pCur, "Format", bstr);5383 5384 if (fSetupMerge)5385 {5386 if (uImage == uMergeSource)5387 InsertConfigInteger(pCur, "MergeSource", 1);5388 else if (uImage == uMergeTarget)5389 InsertConfigInteger(pCur, "MergeTarget", 1);5390 }5391 5392 /* Configure medium properties. */5393 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();5394 5395 /* next */5396 pParent = pCur;5397 ptrParentMedium = ptrCurMedium;5398 }5399 5400 /* Custom code: put marker to not use host IP stack to driver5401 * configuration node. Simplifies life of DrvVD a bit. */5402 if (!fHostIP)5403 InsertConfigInteger(pCfg, "HostIPStack", 0);5404 5405 if (fEncrypted)5406 m_cDisksEncrypted++;5407 }5408 else5409 {5410 /* Set empty drive flag for DVD or floppy without media. */5411 if ( enmType == DeviceType_DVD5412 || enmType == DeviceType_Floppy)5413 InsertConfigInteger(pCfg, "EmptyDrive", 1);5414 }5415 }5416 #undef H5417 }5418 catch (ConfigError &x)5419 {5420 // InsertConfig threw something:5421 return x.m_vrc;5422 }5423 5424 return VINF_SUCCESS;5425 }5426 5427 /**5428 * Adds the medium properties to the CFGM tree.5429 *5430 * @returns VBox status code.5431 * @param pCur The current CFGM node.5432 * @param pMedium The medium object to configure.5433 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.5434 * @param pfEncrypted Where to return whether the medium is encrypted.5435 */5436 int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)5437 {5438 /* Pass all custom parameters. */5439 SafeArray<BSTR> aNames;5440 SafeArray<BSTR> aValues;5441 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames), ComSafeArrayAsOutParam(aValues));5442 if ( SUCCEEDED(hrc)5443 && aNames.size() != 0)5444 {5445 PCFGMNODE pVDC;5446 InsertConfigNode(pCur, "VDConfig", &pVDC);5447 for (size_t ii = 0; ii < aNames.size(); ++ii)5448 {5449 if (aValues[ii] && *aValues[ii])5450 {5451 Utf8Str const strName = aNames[ii];5452 Utf8Str const strValue = aValues[ii];5453 size_t offSlash = strName.find("/", 0);5454 if ( offSlash != strName.npos5455 && !strName.startsWith("Special/"))5456 {5457 com::Utf8Str strFilter;5458 hrc = strFilter.assignEx(strName, 0, offSlash);5459 if (FAILED(hrc))5460 break;5461 5462 com::Utf8Str strKey;5463 hrc = strKey.assignEx(strName, offSlash + 1, strName.length() - offSlash - 1); /* Skip slash */5464 if (FAILED(hrc))5465 break;5466 5467 PCFGMNODE pCfgFilterConfig = mpVMM->pfnCFGMR3GetChild(pVDC, strFilter.c_str());5468 if (!pCfgFilterConfig)5469 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);5470 5471 InsertConfigString(pCfgFilterConfig, strKey.c_str(), strValue);5472 }5473 else5474 {5475 InsertConfigString(pVDC, strName.c_str(), strValue);5476 if ( strName.compare("HostIPStack") == 05477 && strValue.compare("0") == 0)5478 *pfHostIP = false;5479 }5480 5481 if ( strName.compare("CRYPT/KeyId") == 05482 && pfEncrypted)5483 *pfEncrypted = true;5484 }5485 }5486 }5487 5488 return hrc;5489 }5490 5491 5492 /**5493 * Configure proxy parameters the Network configuration tree.5494 *5495 * Parameters may differ depending on the IP address being accessed.5496 *5497 * @returns VBox status code.5498 *5499 * @param virtualBox The VirtualBox object.5500 * @param pCfg Configuration node for the driver.5501 * @param pcszPrefix The prefix for CFGM parameters: "Primary" or "Secondary".5502 * @param strIpAddr The public IP address to be accessed via a proxy.5503 *5504 * @thread EMT5505 */5506 int Console::i_configProxy(ComPtr<IVirtualBox> virtualBox, PCFGMNODE pCfg, const char *pcszPrefix, const com::Utf8Str &strIpAddr)5507 {5508 /** @todo r=bird: This code doesn't handle cleanup correctly and may leak5509 * when hitting errors or throwing exceptions (bad_alloc). */5510 RTHTTPPROXYINFO ProxyInfo;5511 ComPtr<ISystemProperties> systemProperties;5512 ProxyMode_T enmProxyMode;5513 HRESULT hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());5514 if (FAILED(hrc))5515 {5516 LogRel(("CLOUD-NET: Failed to obtain system properties. hrc=%x\n", hrc));5517 return false;5518 }5519 hrc = systemProperties->COMGETTER(ProxyMode)(&enmProxyMode);5520 if (FAILED(hrc))5521 {5522 LogRel(("CLOUD-NET: Failed to obtain default machine folder. hrc=%x\n", hrc));5523 return VERR_INTERNAL_ERROR;5524 }5525 5526 RTHTTP hHttp;5527 int vrc = RTHttpCreate(&hHttp);5528 if (RT_FAILURE(vrc))5529 {5530 LogRel(("CLOUD-NET: Failed to create HTTP context (vrc=%Rrc)\n", vrc));5531 return vrc;5532 }5533 5534 char *pszProxyType = NULL;5535 5536 if (enmProxyMode == ProxyMode_Manual)5537 {5538 /*5539 * Unfortunately we cannot simply call RTHttpSetProxyByUrl because it never5540 * exposes proxy settings. Calling RTHttpQueryProxyInfoForUrl afterward5541 * won't help either as it uses system-wide proxy settings instead of5542 * parameters we would have set with RTHttpSetProxyByUrl. Hence we parse5543 * proxy URL ourselves here.5544 */5545 Bstr proxyUrl;5546 hrc = systemProperties->COMGETTER(ProxyURL)(proxyUrl.asOutParam());5547 if (FAILED(hrc))5548 {5549 LogRel(("CLOUD-NET: Failed to obtain proxy URL. hrc=%x\n", hrc));5550 return false;5551 }5552 Utf8Str strProxyUrl = proxyUrl;5553 if (!strProxyUrl.contains("://"))5554 strProxyUrl = "http://" + strProxyUrl;5555 const char *pcszProxyUrl = strProxyUrl.c_str();5556 RTURIPARSED Parsed;5557 vrc = RTUriParse(pcszProxyUrl, &Parsed);5558 if (RT_FAILURE(vrc))5559 {5560 LogRel(("CLOUD-NET: Failed to parse proxy URL: %ls (vrc=%Rrc)\n", proxyUrl.raw(), vrc));5561 return false;5562 }5563 5564 pszProxyType = RTUriParsedScheme(pcszProxyUrl, &Parsed);5565 if (!pszProxyType)5566 {5567 LogRel(("CLOUD-NET: Failed to get proxy scheme from proxy URL: %s\n", pcszProxyUrl));5568 return false;5569 }5570 RTStrToUpper(pszProxyType);5571 5572 ProxyInfo.pszProxyHost = RTUriParsedAuthorityHost(pcszProxyUrl, &Parsed);5573 if (!ProxyInfo.pszProxyHost)5574 {5575 LogRel(("CLOUD-NET: Failed to get proxy host name from proxy URL: %s\n", pcszProxyUrl));5576 return false;5577 }5578 ProxyInfo.uProxyPort = RTUriParsedAuthorityPort(pcszProxyUrl, &Parsed);5579 if (ProxyInfo.uProxyPort == UINT32_MAX)5580 {5581 LogRel(("CLOUD-NET: Failed to get proxy port from proxy URL: %s\n", pcszProxyUrl));5582 return false;5583 }5584 ProxyInfo.pszProxyUsername = RTUriParsedAuthorityUsername(pcszProxyUrl, &Parsed);5585 ProxyInfo.pszProxyPassword = RTUriParsedAuthorityPassword(pcszProxyUrl, &Parsed);5586 }5587 else if (enmProxyMode == ProxyMode_System)5588 {5589 vrc = RTHttpUseSystemProxySettings(hHttp);5590 if (RT_FAILURE(vrc))5591 {5592 LogRel(("%s: RTHttpUseSystemProxySettings() failed: %Rrc", __FUNCTION__, vrc));5593 RTHttpDestroy(hHttp);5594 return vrc;5595 }5596 vrc = RTHttpQueryProxyInfoForUrl(hHttp, ("http://" + strIpAddr).c_str(), &ProxyInfo);5597 RTHttpDestroy(hHttp);5598 if (RT_FAILURE(vrc))5599 {5600 LogRel(("CLOUD-NET: Failed to get proxy for %s (vrc=%Rrc)\n", strIpAddr.c_str(), vrc));5601 return vrc;5602 }5603 5604 switch (ProxyInfo.enmProxyType)5605 {5606 case RTHTTPPROXYTYPE_NOPROXY:5607 /* Nothing to do */5608 return VINF_SUCCESS;5609 case RTHTTPPROXYTYPE_HTTP:5610 pszProxyType = RTStrDup("HTTP");5611 break;5612 case RTHTTPPROXYTYPE_HTTPS:5613 case RTHTTPPROXYTYPE_SOCKS4:5614 case RTHTTPPROXYTYPE_SOCKS5:5615 /* break; -- Fall through until support is implemented */5616 case RTHTTPPROXYTYPE_UNKNOWN:5617 case RTHTTPPROXYTYPE_INVALID:5618 case RTHTTPPROXYTYPE_END:5619 case RTHTTPPROXYTYPE_32BIT_HACK:5620 LogRel(("CLOUD-NET: Unsupported proxy type %u\n", ProxyInfo.enmProxyType));5621 RTHttpFreeProxyInfo(&ProxyInfo);5622 return VERR_INVALID_PARAMETER;5623 }5624 }5625 else5626 {5627 Assert(enmProxyMode == ProxyMode_NoProxy);5628 return VINF_SUCCESS;5629 }5630 5631 /* Resolve proxy host name to IP address if necessary */5632 RTNETADDR addr;5633 RTSocketParseInetAddress(ProxyInfo.pszProxyHost, ProxyInfo.uProxyPort, &addr);5634 if (addr.enmType != RTNETADDRTYPE_IPV4)5635 {5636 LogRel(("CLOUD-NET: Unsupported address type %u\n", addr.enmType));5637 RTHttpFreeProxyInfo(&ProxyInfo);5638 return VERR_INVALID_PARAMETER;5639 }5640 5641 InsertConfigString( pCfg, Utf8StrFmt("%sProxyType", pcszPrefix).c_str(), pszProxyType);5642 InsertConfigInteger( pCfg, Utf8StrFmt("%sProxyPort", pcszPrefix).c_str(), ProxyInfo.uProxyPort);5643 if (ProxyInfo.pszProxyHost)5644 InsertConfigStringF( pCfg, Utf8StrFmt("%sProxyHost", pcszPrefix).c_str(), "%RTnaipv4", addr.uAddr.IPv4);5645 if (ProxyInfo.pszProxyUsername)5646 InsertConfigString( pCfg, Utf8StrFmt("%sProxyUser", pcszPrefix).c_str(), ProxyInfo.pszProxyUsername);5647 if (ProxyInfo.pszProxyPassword)5648 InsertConfigPassword(pCfg, Utf8StrFmt("%sProxyPassword", pcszPrefix).c_str(), ProxyInfo.pszProxyPassword);5649 5650 RTHttpFreeProxyInfo(&ProxyInfo);5651 RTStrFree(pszProxyType);5652 return vrc;5653 }5654 5655 5656 /**5657 * Construct the Network configuration tree5658 *5659 * @returns VBox status code.5660 *5661 * @param pszDevice The PDM device name.5662 * @param uInstance The PDM device instance.5663 * @param uLun The PDM LUN number of the drive.5664 * @param aNetworkAdapter The network adapter whose attachment needs to be changed5665 * @param pCfg Configuration node for the device5666 * @param pLunL0 To store the pointer to the LUN#0.5667 * @param pInst The instance CFGM node5668 * @param fAttachDetach To determine if the network attachment should5669 * be attached/detached after/before5670 * configuration.5671 * @param fIgnoreConnectFailure5672 * True if connection failures should be ignored5673 * (makes only sense for bridged/host-only networks).5674 * @param pUVM The usermode VM handle.5675 * @param pVMM The VMM vtable.5676 *5677 * @note Locks this object for writing.5678 * @thread EMT5679 */5680 int Console::i_configNetwork(const char *pszDevice,5681 unsigned uInstance,5682 unsigned uLun,5683 INetworkAdapter *aNetworkAdapter,5684 PCFGMNODE pCfg,5685 PCFGMNODE pLunL0,5686 PCFGMNODE pInst,5687 bool fAttachDetach,5688 bool fIgnoreConnectFailure,5689 PUVM pUVM,5690 PCVMMR3VTABLE pVMM)5691 {5692 RT_NOREF(fIgnoreConnectFailure);5693 AutoCaller autoCaller(this);5694 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);5695 5696 // InsertConfig* throws5697 try5698 {5699 int vrc = VINF_SUCCESS;5700 HRESULT hrc;5701 Bstr bstr;5702 5703 #ifdef VBOX_WITH_CLOUD_NET5704 /* We'll need device's pCfg for cloud attachments */5705 PCFGMNODE pDevCfg = pCfg;5706 #endif /* VBOX_WITH_CLOUD_NET */5707 5708 #define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)5709 5710 /*5711 * Locking the object before doing VMR3* calls is quite safe here, since5712 * we're on EMT. Write lock is necessary because we indirectly modify the5713 * meAttachmentType member.5714 */5715 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);5716 5717 ComPtr<IMachine> pMachine = i_machine();5718 5719 ComPtr<IVirtualBox> virtualBox;5720 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();5721 5722 ComPtr<IHost> host;5723 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();5724 5725 BOOL fSniffer;5726 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();5727 5728 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;5729 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();5730 const char *pszPromiscuousGuestPolicy;5731 switch (enmPromiscModePolicy)5732 {5733 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;5734 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;5735 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;5736 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);5737 }5738 5739 if (fAttachDetach)5740 {5741 vrc = pVMM->pfnPDMR3DeviceDetach(pUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);5742 if (vrc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)5743 vrc = VINF_SUCCESS;5744 AssertLogRelRCReturn(vrc, vrc);5745 5746 /* Nuke anything which might have been left behind. */5747 pVMM->pfnCFGMR3RemoveNode(pVMM->pfnCFGMR3GetChildF(pInst, "LUN#%u", uLun));5748 }5749 5750 Bstr networkName, trunkName, trunkType;5751 NetworkAttachmentType_T eAttachmentType;5752 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();5753 5754 #ifdef VBOX_WITH_NETSHAPER5755 ComObjPtr<IBandwidthGroup> pBwGroup;5756 Bstr bstrBwGroup;5757 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();5758 5759 if (!pBwGroup.isNull())5760 {5761 hrc = pBwGroup->COMGETTER(Name)(bstrBwGroup.asOutParam()); H();5762 }5763 #endif /* VBOX_WITH_NETSHAPER */5764 5765 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));5766 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);5767 5768 /*5769 * Do not insert neither a shaper nor a sniffer if we are not attached to anything.5770 * This way we can easily detect if we are attached to anything at the device level.5771 */5772 #ifdef VBOX_WITH_NETSHAPER5773 if (bstrBwGroup.isNotEmpty() && eAttachmentType != NetworkAttachmentType_Null)5774 {5775 InsertConfigString(pLunL0, "Driver", "NetShaper");5776 InsertConfigNode(pLunL0, "Config", &pCfg);5777 InsertConfigString(pCfg, "BwGroup", bstrBwGroup);5778 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);5779 }5780 #endif /* VBOX_WITH_NETSHAPER */5781 5782 if (fSniffer && eAttachmentType != NetworkAttachmentType_Null)5783 {5784 InsertConfigString(pLunL0, "Driver", "NetSniffer");5785 InsertConfigNode(pLunL0, "Config", &pCfg);5786 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();5787 if (!bstr.isEmpty()) /* check convention for indicating default file. */5788 InsertConfigString(pCfg, "File", bstr);5789 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);5790 }5791 5792 switch (eAttachmentType)5793 {5794 case NetworkAttachmentType_Null:5795 break;5796 5797 case NetworkAttachmentType_NAT:5798 {5799 ComPtr<INATEngine> natEngine;5800 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();5801 InsertConfigString(pLunL0, "Driver", "NAT");5802 InsertConfigNode(pLunL0, "Config", &pCfg);5803 5804 /* Configure TFTP prefix and boot filename. */5805 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();5806 if (!bstr.isEmpty())5807 InsertConfigStringF(pCfg, "TFTPPrefix", "%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP");5808 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();5809 InsertConfigStringF(pCfg, "BootFile", "%ls.pxe", bstr.raw());5810 5811 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();5812 if (!bstr.isEmpty())5813 InsertConfigString(pCfg, "Network", bstr);5814 else5815 {5816 ULONG uSlot;5817 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();5818 InsertConfigStringF(pCfg, "Network", "10.0.%d.0/24", uSlot+2);5819 }5820 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();5821 if (!bstr.isEmpty())5822 InsertConfigString(pCfg, "BindIP", bstr);5823 ULONG mtu = 0;5824 ULONG sockSnd = 0;5825 ULONG sockRcv = 0;5826 ULONG tcpSnd = 0;5827 ULONG tcpRcv = 0;5828 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();5829 if (mtu)5830 InsertConfigInteger(pCfg, "SlirpMTU", mtu);5831 if (sockRcv)5832 InsertConfigInteger(pCfg, "SockRcv", sockRcv);5833 if (sockSnd)5834 InsertConfigInteger(pCfg, "SockSnd", sockSnd);5835 if (tcpRcv)5836 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);5837 if (tcpSnd)5838 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);5839 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();5840 if (!bstr.isEmpty())5841 {5842 RemoveConfigValue(pCfg, "TFTPPrefix");5843 InsertConfigString(pCfg, "TFTPPrefix", bstr);5844 }5845 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();5846 if (!bstr.isEmpty())5847 {5848 RemoveConfigValue(pCfg, "BootFile");5849 InsertConfigString(pCfg, "BootFile", bstr);5850 }5851 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();5852 if (!bstr.isEmpty())5853 InsertConfigString(pCfg, "NextServer", bstr);5854 BOOL fDNSFlag;5855 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();5856 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);5857 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();5858 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);5859 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();5860 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);5861 5862 ULONG aliasMode;5863 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();5864 InsertConfigInteger(pCfg, "AliasMode", aliasMode);5865 5866 BOOL fLocalhostReachable;5867 hrc = natEngine->COMGETTER(LocalhostReachable)(&fLocalhostReachable); H();5868 InsertConfigInteger(pCfg, "LocalhostReachable", fLocalhostReachable);5869 5870 /* port-forwarding */5871 SafeArray<BSTR> pfs;5872 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();5873 5874 PCFGMNODE pPFTree = NULL;5875 if (pfs.size() > 0)5876 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);5877 5878 for (unsigned int i = 0; i < pfs.size(); ++i)5879 {5880 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */5881 5882 uint16_t port = 0;5883 Utf8Str utf = pfs[i];5884 Utf8Str strName;5885 Utf8Str strProto;5886 Utf8Str strHostPort;5887 Utf8Str strHostIP;5888 Utf8Str strGuestPort;5889 Utf8Str strGuestIP;5890 size_t pos, ppos;5891 pos = ppos = 0;5892 #define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \5893 { \5894 pos = str.find(",", ppos); \5895 if (pos == Utf8Str::npos) \5896 { \5897 Log(( #res " extracting from %s is failed\n", str.c_str())); \5898 continue; \5899 } \5900 res = str.substr(ppos, pos - ppos); \5901 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \5902 ppos = pos + 1; \5903 } /* no do { ... } while because of 'continue' */5904 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);5905 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);5906 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);5907 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);5908 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);5909 strGuestPort = utf.substr(ppos, utf.length() - ppos);5910 #undef ITERATE_TO_NEXT_TERM5911 5912 uint32_t proto = strProto.toUInt32();5913 bool fValid = true;5914 switch (proto)5915 {5916 case NATProtocol_UDP:5917 strProto = "UDP";5918 break;5919 case NATProtocol_TCP:5920 strProto = "TCP";5921 break;5922 default:5923 fValid = false;5924 }5925 /* continue with next rule if no valid proto was passed */5926 if (!fValid)5927 continue;5928 5929 InsertConfigNodeF(pPFTree, &pPF, "%u", i);5930 5931 if (!strName.isEmpty())5932 InsertConfigString(pPF, "Name", strName);5933 5934 InsertConfigString(pPF, "Protocol", strProto);5935 5936 if (!strHostIP.isEmpty())5937 InsertConfigString(pPF, "BindIP", strHostIP);5938 5939 if (!strGuestIP.isEmpty())5940 InsertConfigString(pPF, "GuestIP", strGuestIP);5941 5942 port = RTStrToUInt16(strHostPort.c_str());5943 if (port)5944 InsertConfigInteger(pPF, "HostPort", port);5945 5946 port = RTStrToUInt16(strGuestPort.c_str());5947 if (port)5948 InsertConfigInteger(pPF, "GuestPort", port);5949 }5950 break;5951 }5952 5953 case NetworkAttachmentType_Bridged:5954 {5955 #if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)5956 hrc = i_attachToTapInterface(aNetworkAdapter);5957 if (FAILED(hrc))5958 {5959 switch (hrc)5960 {5961 case E_ACCESSDENIED:5962 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(5963 "Failed to open '/dev/net/tun' for read/write access. Please check the "5964 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "5965 "change the group of that node and make yourself a member of that group. "5966 "Make sure that these changes are permanent, especially if you are "5967 "using udev"));5968 default:5969 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));5970 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,5971 N_("Failed to initialize Host Interface Networking"));5972 }5973 }5974 5975 Assert((intptr_t)maTapFD[uInstance] >= 0);5976 if ((intptr_t)maTapFD[uInstance] >= 0)5977 {5978 InsertConfigString(pLunL0, "Driver", "HostInterface");5979 InsertConfigNode(pLunL0, "Config", &pCfg);5980 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);5981 }5982 5983 #elif defined(VBOX_WITH_NETFLT)5984 /*5985 * This is the new VBoxNetFlt+IntNet stuff.5986 */5987 Bstr BridgedIfName;5988 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());5989 if (FAILED(hrc))5990 {5991 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));5992 H();5993 }5994 5995 Utf8Str BridgedIfNameUtf8(BridgedIfName);5996 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();5997 5998 ComPtr<IHostNetworkInterface> hostInterface;5999 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),6000 hostInterface.asOutParam());6001 if (!SUCCEEDED(hrc))6002 {6003 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));6004 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,6005 N_("Nonexistent host networking interface, name '%ls'"),6006 BridgedIfName.raw());6007 }6008 6009 # if defined(RT_OS_DARWIN)6010 /* The name is in the format 'ifX: long name', chop it off at the colon. */6011 char szTrunk[INTNET_MAX_TRUNK_NAME];6012 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);6013 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));6014 // Quick fix for @bugref{5633}6015 // if (!pszColon)6016 // {6017 // /*6018 // * Dynamic changing of attachment causes an attempt to configure6019 // * network with invalid host adapter (as it is must be changed before6020 // * the attachment), calling Detach here will cause a deadlock.6021 // * See @bugref{4750}.6022 // * hrc = aNetworkAdapter->Detach(); H();6023 // */6024 // return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,6025 // N_("Malformed host interface networking name '%ls'"),6026 // BridgedIfName.raw());6027 // }6028 if (pszColon)6029 *pszColon = '\0';6030 const char *pszTrunk = szTrunk;6031 6032 # elif defined(RT_OS_SOLARIS)6033 /* The name is in the format 'ifX[:1] - long name, chop it off at space. */6034 char szTrunk[256];6035 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));6036 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));6037 6038 /*6039 * Currently don't bother about malformed names here for the sake of people using6040 * VBoxManage and setting only the NIC name from there. If there is a space we6041 * chop it off and proceed, otherwise just use whatever we've got.6042 */6043 if (pszSpace)6044 *pszSpace = '\0';6045 6046 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */6047 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));6048 if (pszColon)6049 *pszColon = '\0';6050 6051 const char *pszTrunk = szTrunk;6052 6053 # elif defined(RT_OS_WINDOWS)6054 HostNetworkInterfaceType_T eIfType;6055 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);6056 if (FAILED(hrc))6057 {6058 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));6059 H();6060 }6061 6062 if (eIfType != HostNetworkInterfaceType_Bridged)6063 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,6064 N_("Interface ('%ls') is not a Bridged Adapter interface"),6065 BridgedIfName.raw());6066 6067 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());6068 if (FAILED(hrc))6069 {6070 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));6071 H();6072 }6073 Guid hostIFGuid(bstr);6074 6075 INetCfg *pNc;6076 ComPtr<INetCfgComponent> pAdaptorComponent;6077 LPWSTR pszApp;6078 6079 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);6080 Assert(hrc == S_OK);6081 if (hrc != S_OK)6082 {6083 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));6084 H();6085 }6086 6087 /* get the adapter's INetCfgComponent*/6088 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),6089 pAdaptorComponent.asOutParam());6090 if (hrc != S_OK)6091 {6092 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6093 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));6094 H();6095 }6096 # define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"6097 char szTrunkName[INTNET_MAX_TRUNK_NAME];6098 char *pszTrunkName = szTrunkName;6099 wchar_t * pswzBindName;6100 hrc = pAdaptorComponent->GetBindName(&pswzBindName);6101 Assert(hrc == S_OK);6102 if (hrc == S_OK)6103 {6104 int cwBindName = (int)wcslen(pswzBindName) + 1;6105 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);6106 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)6107 {6108 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);6109 pszTrunkName += cbFullBindNamePrefix-1;6110 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,6111 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))6112 {6113 DWORD err = GetLastError();6114 hrc = HRESULT_FROM_WIN32(err);6115 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));6116 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",6117 hrc, hrc, err));6118 }6119 }6120 else6121 {6122 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));6123 /** @todo set appropriate error code */6124 hrc = E_FAIL;6125 }6126 6127 if (hrc != S_OK)6128 {6129 AssertFailed();6130 CoTaskMemFree(pswzBindName);6131 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6132 H();6133 }6134 6135 /* we're not freeing the bind name since we'll use it later for detecting wireless*/6136 }6137 else6138 {6139 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6140 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",6141 hrc));6142 H();6143 }6144 6145 const char *pszTrunk = szTrunkName;6146 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */6147 6148 # elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)6149 # if defined(RT_OS_FREEBSD)6150 /*6151 * If we bridge to a tap interface open it the `old' direct way.6152 * This works and performs better than bridging a physical6153 * interface via the current FreeBSD vboxnetflt implementation.6154 */6155 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {6156 hrc = i_attachToTapInterface(aNetworkAdapter);6157 if (FAILED(hrc))6158 {6159 switch (hrc)6160 {6161 case E_ACCESSDENIED:6162 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(6163 "Failed to open '/dev/%s' for read/write access. Please check the "6164 "permissions of that node, and that the net.link.tap.user_open "6165 "sysctl is set. Either run 'chmod 0666 /dev/%s' or change the "6166 "group of that node to vboxusers and make yourself a member of "6167 "that group. Make sure that these changes are permanent."),6168 pszBridgedIfName, pszBridgedIfName);6169 default:6170 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));6171 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,6172 N_("Failed to initialize Host Interface Networking"));6173 }6174 }6175 6176 Assert((intptr_t)maTapFD[uInstance] >= 0);6177 if ((intptr_t)maTapFD[uInstance] >= 0)6178 {6179 InsertConfigString(pLunL0, "Driver", "HostInterface");6180 InsertConfigNode(pLunL0, "Config", &pCfg);6181 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);6182 }6183 break;6184 }6185 # endif6186 /** @todo Check for malformed names. */6187 const char *pszTrunk = pszBridgedIfName;6188 6189 /* Issue a warning if the interface is down */6190 {6191 int iSock = socket(AF_INET, SOCK_DGRAM, 0);6192 if (iSock >= 0)6193 {6194 struct ifreq Req;6195 RT_ZERO(Req);6196 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);6197 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)6198 if ((Req.ifr_flags & IFF_UP) == 0)6199 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",6200 N_("Bridged interface %s is down. Guest will not be able to use this interface"),6201 pszBridgedIfName);6202 6203 close(iSock);6204 }6205 }6206 6207 # else6208 # error "PORTME (VBOX_WITH_NETFLT)"6209 # endif6210 6211 # if defined(RT_OS_DARWIN) && defined(VBOX_WITH_VMNET)6212 InsertConfigString(pLunL0, "Driver", "VMNet");6213 InsertConfigNode(pLunL0, "Config", &pCfg);6214 InsertConfigString(pCfg, "Trunk", pszTrunk);6215 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);6216 # else6217 InsertConfigString(pLunL0, "Driver", "IntNet");6218 InsertConfigNode(pLunL0, "Config", &pCfg);6219 InsertConfigString(pCfg, "Trunk", pszTrunk);6220 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);6221 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);6222 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);6223 char szNetwork[INTNET_MAX_NETWORK_NAME];6224 6225 # if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)6226 /*6227 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains6228 * interface name + optional description. We must not pass any description to the VM as it can differ6229 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).6230 */6231 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);6232 # else6233 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);6234 # endif6235 InsertConfigString(pCfg, "Network", szNetwork);6236 networkName = Bstr(szNetwork);6237 trunkName = Bstr(pszTrunk);6238 trunkType = Bstr(TRUNKTYPE_NETFLT);6239 6240 BOOL fSharedMacOnWire = false;6241 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);6242 if (FAILED(hrc))6243 {6244 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));6245 H();6246 }6247 else if (fSharedMacOnWire)6248 {6249 InsertConfigInteger(pCfg, "SharedMacOnWire", true);6250 Log(("Set SharedMacOnWire\n"));6251 }6252 6253 # if defined(RT_OS_SOLARIS)6254 # if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */6255 /* Zone access restriction, don't allow snooping the global zone. */6256 zoneid_t ZoneId = getzoneid();6257 if (ZoneId != GLOBAL_ZONEID)6258 {6259 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);6260 }6261 # endif6262 # endif6263 # endif6264 6265 #elif defined(RT_OS_WINDOWS) /* not defined NetFlt */6266 /* NOTHING TO DO HERE */6267 #elif defined(RT_OS_LINUX)6268 /// @todo aleksey: is there anything to be done here?6269 #elif defined(RT_OS_FREEBSD)6270 /** @todo FreeBSD: Check out this later (HIF networking). */6271 #else6272 # error "Port me"6273 #endif6274 break;6275 }6276 6277 case NetworkAttachmentType_Internal:6278 {6279 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();6280 if (!bstr.isEmpty())6281 {6282 InsertConfigString(pLunL0, "Driver", "IntNet");6283 InsertConfigNode(pLunL0, "Config", &pCfg);6284 InsertConfigString(pCfg, "Network", bstr);6285 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);6286 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);6287 networkName = bstr;6288 trunkType = Bstr(TRUNKTYPE_WHATEVER);6289 }6290 break;6291 }6292 6293 case NetworkAttachmentType_HostOnly:6294 {6295 InsertConfigString(pLunL0, "Driver", "IntNet");6296 InsertConfigNode(pLunL0, "Config", &pCfg);6297 6298 Bstr HostOnlyName;6299 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());6300 if (FAILED(hrc))6301 {6302 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));6303 H();6304 }6305 6306 Utf8Str HostOnlyNameUtf8(HostOnlyName);6307 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();6308 #ifdef VBOX_WITH_VMNET6309 /* Check if the matching host-only network has already been created. */6310 Bstr bstrLowerIP, bstrUpperIP, bstrNetworkMask;6311 BstrFmt bstrNetworkName("Legacy %s Network", pszHostOnlyName);6312 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;6313 hrc = virtualBox->FindHostOnlyNetworkByName(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());6314 if (FAILED(hrc))6315 {6316 /*6317 * With VMNET there is no VBoxNetAdp to create vboxnetX adapters,6318 * which means that the Host object won't be able to re-create6319 * them from extra data. Go through existing DHCP/adapter config6320 * to derive the parameters for the new network.6321 */6322 BstrFmt bstrOldNetworkName("HostInterfaceNetworking-%s", pszHostOnlyName);6323 ComPtr<IDHCPServer> dhcpServer;6324 hrc = virtualBox->FindDHCPServerByNetworkName(bstrOldNetworkName.raw(),6325 dhcpServer.asOutParam());6326 if (SUCCEEDED(hrc))6327 {6328 /* There is a DHCP server available for this network. */6329 hrc = dhcpServer->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());6330 if (FAILED(hrc))6331 {6332 LogRel(("Console::i_configNetwork: COMGETTER(LowerIP) failed, hrc (%Rhrc)\n", hrc));6333 H();6334 }6335 hrc = dhcpServer->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());6336 if (FAILED(hrc))6337 {6338 LogRel(("Console::i_configNetwork: COMGETTER(UpperIP) failed, hrc (%Rhrc)\n", hrc));6339 H();6340 }6341 hrc = dhcpServer->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());6342 if (FAILED(hrc))6343 {6344 LogRel(("Console::i_configNetwork: COMGETTER(NetworkMask) failed, hrc (%Rhrc)\n", hrc));6345 H();6346 }6347 }6348 else6349 {6350 /* No DHCP server for this hostonly interface, let's look at extra data */6351 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",6352 pszHostOnlyName).raw(),6353 bstrLowerIP.asOutParam());6354 if (SUCCEEDED(hrc) && !bstrLowerIP.isEmpty())6355 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",6356 pszHostOnlyName).raw(),6357 bstrNetworkMask.asOutParam());6358 6359 }6360 RTNETADDRIPV4 ipAddr, ipMask;6361 vrc = bstrLowerIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);6362 if (RT_FAILURE(vrc))6363 {6364 /* We failed to locate any valid config of this vboxnetX interface, assume defaults. */6365 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing lower IP '%ls', using '%ls' instead.\n",6366 bstrLowerIP.raw(), getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw()));6367 bstrLowerIP = getDefaultIPv4Address(Bstr(pszHostOnlyName));6368 bstrNetworkMask.setNull();6369 bstrUpperIP.setNull();6370 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);6371 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrLowerIP.raw(), vrc),6372 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);6373 }6374 vrc = bstrNetworkMask.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);6375 if (RT_FAILURE(vrc))6376 {6377 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing network mask '%ls', using '%s' instead.\n",6378 bstrNetworkMask.raw(), VBOXNET_IPV4MASK_DEFAULT));6379 bstrNetworkMask = VBOXNET_IPV4MASK_DEFAULT;6380 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);6381 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrNetworkMask.raw(), vrc),6382 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);6383 }6384 vrc = bstrUpperIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrUpperIP).c_str(), &ipAddr);6385 if (RT_FAILURE(vrc))6386 {6387 ipAddr.au32[0] = RT_H2N_U32((RT_N2H_U32(ipAddr.au32[0]) | ~RT_N2H_U32(ipMask.au32[0])) - 1); /* Do we need to exlude the last IP? */6388 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing upper IP '%ls', using '%RTnaipv4' instead.\n",6389 bstrUpperIP.raw(), ipAddr));6390 bstrUpperIP = BstrFmt("%RTnaipv4", ipAddr);6391 }6392 6393 /* All parameters are set, create the new network. */6394 hrc = virtualBox->CreateHostOnlyNetwork(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());6395 if (FAILED(hrc))6396 {6397 LogRel(("NetworkAttachmentType_HostOnly: failed to create host-only network, hrc (0x%x)\n", hrc));6398 H();6399 }6400 hrc = hostOnlyNetwork->COMSETTER(NetworkMask)(bstrNetworkMask.raw());6401 if (FAILED(hrc))6402 {6403 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));6404 H();6405 }6406 hrc = hostOnlyNetwork->COMSETTER(LowerIP)(bstrLowerIP.raw());6407 if (FAILED(hrc))6408 {6409 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(LowerIP) failed, hrc (0x%x)\n", hrc));6410 H();6411 }6412 hrc = hostOnlyNetwork->COMSETTER(UpperIP)(bstrUpperIP.raw());6413 if (FAILED(hrc))6414 {6415 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(UpperIP) failed, hrc (0x%x)\n", hrc));6416 H();6417 }6418 LogRel(("Console: created host-only network '%ls' with mask '%ls' and range '%ls'-'%ls'\n",6419 bstrNetworkName.raw(), bstrNetworkMask.raw(), bstrLowerIP.raw(), bstrUpperIP.raw()));6420 }6421 else6422 {6423 /* The matching host-only network already exists. Tell the user to switch to it. */6424 hrc = hostOnlyNetwork->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());6425 if (FAILED(hrc))6426 {6427 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));6428 H();6429 }6430 hrc = hostOnlyNetwork->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());6431 if (FAILED(hrc))6432 {6433 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(LowerIP) failed, hrc (0x%x)\n", hrc));6434 H();6435 }6436 hrc = hostOnlyNetwork->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());6437 if (FAILED(hrc))6438 {6439 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(UpperIP) failed, hrc (0x%x)\n", hrc));6440 H();6441 }6442 }6443 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,6444 N_("Host-only adapters are no longer supported!\n"6445 "For your convenience a host-only network named '%ls' has been "6446 "created with network mask '%ls' and IP address range '%ls' - '%ls'.\n"6447 "To fix this problem, switch to 'Host-only Network' "6448 "attachment type in the VM settings.\n"),6449 bstrNetworkName.raw(), bstrNetworkMask.raw(),6450 bstrLowerIP.raw(), bstrUpperIP.raw());6451 #endif /* VBOX_WITH_VMNET */6452 ComPtr<IHostNetworkInterface> hostInterface;6453 hrc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),6454 hostInterface.asOutParam());6455 if (!SUCCEEDED(hrc))6456 {6457 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, vrc=%Rrc\n", vrc));6458 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,6459 N_("Nonexistent host networking interface, name '%ls'"), HostOnlyName.raw());6460 }6461 6462 char szNetwork[INTNET_MAX_NETWORK_NAME];6463 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);6464 6465 #if defined(RT_OS_WINDOWS)6466 # ifndef VBOX_WITH_NETFLT6467 hrc = E_NOTIMPL;6468 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));6469 H();6470 # else /* defined VBOX_WITH_NETFLT*/6471 /** @todo r=bird: Put this in a function. */6472 6473 HostNetworkInterfaceType_T eIfType;6474 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);6475 if (FAILED(hrc))6476 {6477 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));6478 H();6479 }6480 6481 if (eIfType != HostNetworkInterfaceType_HostOnly)6482 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,6483 N_("Interface ('%ls') is not a Host-Only Adapter interface"),6484 HostOnlyName.raw());6485 6486 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());6487 if (FAILED(hrc))6488 {6489 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));6490 H();6491 }6492 Guid hostIFGuid(bstr);6493 6494 INetCfg *pNc;6495 ComPtr<INetCfgComponent> pAdaptorComponent;6496 LPWSTR pszApp;6497 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);6498 Assert(hrc == S_OK);6499 if (hrc != S_OK)6500 {6501 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));6502 H();6503 }6504 6505 /* get the adapter's INetCfgComponent*/6506 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),6507 pAdaptorComponent.asOutParam());6508 if (hrc != S_OK)6509 {6510 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6511 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));6512 H();6513 }6514 # define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"6515 char szTrunkName[INTNET_MAX_TRUNK_NAME];6516 bool fNdis6 = false;6517 wchar_t * pwszHelpText;6518 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);6519 Assert(hrc == S_OK);6520 if (hrc == S_OK)6521 {6522 Log(("help-text=%ls\n", pwszHelpText));6523 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))6524 fNdis6 = true;6525 CoTaskMemFree(pwszHelpText);6526 }6527 if (fNdis6)6528 {6529 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);6530 Log(("trunk=%s\n", szTrunkName));6531 }6532 else6533 {6534 char *pszTrunkName = szTrunkName;6535 wchar_t * pswzBindName;6536 hrc = pAdaptorComponent->GetBindName(&pswzBindName);6537 Assert(hrc == S_OK);6538 if (hrc == S_OK)6539 {6540 int cwBindName = (int)wcslen(pswzBindName) + 1;6541 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);6542 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)6543 {6544 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);6545 pszTrunkName += cbFullBindNamePrefix-1;6546 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,6547 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))6548 {6549 DWORD err = GetLastError();6550 hrc = HRESULT_FROM_WIN32(err);6551 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",6552 hrc, hrc, err));6553 }6554 }6555 else6556 {6557 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));6558 /** @todo set appropriate error code */6559 hrc = E_FAIL;6560 }6561 6562 if (hrc != S_OK)6563 {6564 AssertFailed();6565 CoTaskMemFree(pswzBindName);6566 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6567 H();6568 }6569 }6570 else6571 {6572 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6573 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",6574 hrc, hrc));6575 H();6576 }6577 6578 6579 CoTaskMemFree(pswzBindName);6580 }6581 6582 trunkType = TRUNKTYPE_NETADP;6583 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);6584 6585 pAdaptorComponent.setNull();6586 /* release the pNc finally */6587 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);6588 6589 const char *pszTrunk = szTrunkName;6590 6591 InsertConfigString(pCfg, "Trunk", pszTrunk);6592 InsertConfigString(pCfg, "Network", szNetwork);6593 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this6594 windows only?? */6595 networkName = Bstr(szNetwork);6596 trunkName = Bstr(pszTrunk);6597 # endif /* defined VBOX_WITH_NETFLT*/6598 #elif defined(RT_OS_DARWIN)6599 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);6600 InsertConfigString(pCfg, "Network", szNetwork);6601 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);6602 networkName = Bstr(szNetwork);6603 trunkName = Bstr(pszHostOnlyName);6604 trunkType = TRUNKTYPE_NETADP;6605 #else6606 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);6607 InsertConfigString(pCfg, "Network", szNetwork);6608 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);6609 networkName = Bstr(szNetwork);6610 trunkName = Bstr(pszHostOnlyName);6611 trunkType = TRUNKTYPE_NETFLT;6612 #endif6613 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);6614 6615 #if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)6616 6617 Bstr tmpAddr, tmpMask;6618 6619 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",6620 pszHostOnlyName).raw(),6621 tmpAddr.asOutParam());6622 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())6623 {6624 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",6625 pszHostOnlyName).raw(),6626 tmpMask.asOutParam());6627 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())6628 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),6629 tmpMask.raw());6630 else6631 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),6632 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());6633 }6634 else6635 {6636 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */6637 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),6638 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());6639 }6640 6641 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */6642 6643 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",6644 pszHostOnlyName).raw(),6645 tmpAddr.asOutParam());6646 if (SUCCEEDED(hrc))6647 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),6648 tmpMask.asOutParam());6649 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())6650 {6651 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),6652 Utf8Str(tmpMask).toUInt32());6653 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */6654 }6655 #endif6656 break;6657 }6658 6659 case NetworkAttachmentType_Generic:6660 {6661 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();6662 SafeArray<BSTR> names;6663 SafeArray<BSTR> values;6664 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),6665 ComSafeArrayAsOutParam(names),6666 ComSafeArrayAsOutParam(values)); H();6667 6668 InsertConfigString(pLunL0, "Driver", bstr);6669 InsertConfigNode(pLunL0, "Config", &pCfg);6670 for (size_t ii = 0; ii < names.size(); ++ii)6671 {6672 if (values[ii] && *values[ii])6673 {6674 Utf8Str const strName(names[ii]);6675 Utf8Str const strValue(values[ii]);6676 InsertConfigString(pCfg, strName.c_str(), strValue);6677 }6678 }6679 break;6680 }6681 6682 case NetworkAttachmentType_NATNetwork:6683 {6684 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();6685 if (!bstr.isEmpty())6686 {6687 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */6688 InsertConfigString(pLunL0, "Driver", "IntNet");6689 InsertConfigNode(pLunL0, "Config", &pCfg);6690 InsertConfigString(pCfg, "Network", bstr);6691 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);6692 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);6693 networkName = bstr;6694 trunkType = Bstr(TRUNKTYPE_WHATEVER);6695 }6696 break;6697 }6698 6699 #ifdef VBOX_WITH_CLOUD_NET6700 case NetworkAttachmentType_Cloud:6701 {6702 static const char *s_pszCloudExtPackName = "Oracle VM VirtualBox Extension Pack";6703 /*6704 * Cloud network attachments do not work wihout installed extpack.6705 * Without extpack support they won't work either.6706 */6707 # ifdef VBOX_WITH_EXTPACK6708 if (!mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName))6709 # endif6710 {6711 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,6712 N_("Implementation of the cloud network attachment not found!\n"6713 "To fix this problem, either install the '%s' or switch to "6714 "another network attachment type in the VM settings."),6715 s_pszCloudExtPackName);6716 }6717 6718 ComPtr<ICloudNetwork> network;6719 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();6720 hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam()); H();6721 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();6722 hrc = generateKeys(mGateway);6723 if (FAILED(hrc))6724 {6725 if (hrc == E_NOTIMPL)6726 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,6727 N_("Failed to generate a key pair due to missing libssh\n"6728 "To fix this problem, either build VirtualBox with libssh "6729 "support or switch to another network attachment type in "6730 "the VM settings."));6731 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,6732 N_("Failed to generate a key pair due to libssh error!"));6733 }6734 hrc = startCloudGateway(virtualBox, network, mGateway);6735 if (FAILED(hrc))6736 {6737 if (hrc == VBOX_E_OBJECT_NOT_FOUND)6738 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,6739 N_("Failed to start cloud gateway instance.\nCould not find suitable "6740 "standard cloud images. Make sure you ran 'VBoxManage cloud network setup' "6741 "with correct '--gateway-os-name' and '--gateway-os-version' parameters. "6742 "Check VBoxSVC.log for actual values used to look up cloud images."));6743 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,6744 N_("Failed to start cloud gateway instance.\nMake sure you set up "6745 "cloud networking properly with 'VBoxManage cloud network setup'. "6746 "Check VBoxSVC.log for details."));6747 }6748 InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));6749 if (!bstr.isEmpty())6750 {6751 InsertConfigString(pLunL0, "Driver", "CloudTunnel");6752 InsertConfigNode(pLunL0, "Config", &pCfg);6753 InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);6754 InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);6755 InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);6756 InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));6757 hrc = i_configProxy(virtualBox, pCfg, "Primary", mGateway.mCloudPublicIp);6758 if (FAILED(hrc))6759 {6760 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,6761 N_("Failed to configure proxy for accessing cloud gateway instance via primary VNIC.\n"6762 "Check VirtualBox.log for details."));6763 }6764 hrc = i_configProxy(virtualBox, pCfg, "Secondary", mGateway.mCloudSecondaryPublicIp);6765 if (FAILED(hrc))6766 {6767 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,6768 N_("Failed to configure proxy for accessing cloud gateway instance via secondary VNIC.\n"6769 "Check VirtualBox.log for details."));6770 }6771 networkName = bstr;6772 trunkType = Bstr(TRUNKTYPE_WHATEVER);6773 }6774 break;6775 }6776 #endif /* VBOX_WITH_CLOUD_NET */6777 6778 #ifdef VBOX_WITH_VMNET6779 case NetworkAttachmentType_HostOnlyNetwork:6780 {6781 Bstr bstrId, bstrNetMask, bstrLowerIP, bstrUpperIP;6782 ComPtr<IHostOnlyNetwork> network;6783 hrc = aNetworkAdapter->COMGETTER(HostOnlyNetwork)(bstr.asOutParam()); H();6784 hrc = virtualBox->FindHostOnlyNetworkByName(bstr.raw(), network.asOutParam());6785 if (FAILED(hrc))6786 {6787 LogRel(("NetworkAttachmentType_HostOnlyNetwork: FindByName failed, hrc (0x%x)\n", hrc));6788 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,6789 N_("Nonexistent host-only network '%ls'"), bstr.raw());6790 }6791 hrc = network->COMGETTER(Id)(bstrId.asOutParam()); H();6792 hrc = network->COMGETTER(NetworkMask)(bstrNetMask.asOutParam()); H();6793 hrc = network->COMGETTER(LowerIP)(bstrLowerIP.asOutParam()); H();6794 hrc = network->COMGETTER(UpperIP)(bstrUpperIP.asOutParam()); H();6795 if (!bstr.isEmpty())6796 {6797 InsertConfigString(pLunL0, "Driver", "VMNet");6798 InsertConfigNode(pLunL0, "Config", &pCfg);6799 // InsertConfigString(pCfg, "Trunk", bstr);6800 // InsertConfigStringF(pCfg, "Network", "HostOnlyNetworking-%ls", bstr.raw());6801 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);6802 InsertConfigString(pCfg, "Id", bstrId);6803 InsertConfigString(pCfg, "NetworkMask", bstrNetMask);6804 InsertConfigString(pCfg, "LowerIP", bstrLowerIP);6805 InsertConfigString(pCfg, "UpperIP", bstrUpperIP);6806 // InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);6807 networkName.setNull(); // We do not want DHCP server on our network!6808 // trunkType = Bstr(TRUNKTYPE_WHATEVER);6809 }6810 break;6811 }6812 #endif /* VBOX_WITH_VMNET */6813 6814 default:6815 AssertMsgFailed(("should not get here!\n"));6816 break;6817 }6818 6819 /*6820 * Attempt to attach the driver.6821 */6822 switch (eAttachmentType)6823 {6824 case NetworkAttachmentType_Null:6825 break;6826 6827 case NetworkAttachmentType_Bridged:6828 case NetworkAttachmentType_Internal:6829 case NetworkAttachmentType_HostOnly:6830 #ifdef VBOX_WITH_VMNET6831 case NetworkAttachmentType_HostOnlyNetwork:6832 #endif /* VBOX_WITH_VMNET */6833 case NetworkAttachmentType_NAT:6834 case NetworkAttachmentType_Generic:6835 case NetworkAttachmentType_NATNetwork:6836 #ifdef VBOX_WITH_CLOUD_NET6837 case NetworkAttachmentType_Cloud:6838 #endif /* VBOX_WITH_CLOUD_NET */6839 {6840 if (SUCCEEDED(hrc) && RT_SUCCESS(vrc))6841 {6842 if (fAttachDetach)6843 {6844 vrc = pVMM->pfnPDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);6845 //AssertRC(vrc);6846 }6847 6848 {6849 /** @todo pritesh: get the dhcp server name from the6850 * previous network configuration and then stop the server6851 * else it may conflict with the dhcp server running with6852 * the current attachment type6853 */6854 /* Stop the hostonly DHCP Server */6855 }6856 6857 /*6858 * NAT networks start their DHCP server theirself, see NATNetwork::Start()6859 */6860 if ( !networkName.isEmpty()6861 && eAttachmentType != NetworkAttachmentType_NATNetwork)6862 {6863 /*6864 * Until we implement service reference counters DHCP Server will be stopped6865 * by DHCPServerRunner destructor.6866 */6867 ComPtr<IDHCPServer> dhcpServer;6868 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(), dhcpServer.asOutParam());6869 if (SUCCEEDED(hrc))6870 {6871 /* there is a DHCP server available for this network */6872 BOOL fEnabledDhcp;6873 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);6874 if (FAILED(hrc))6875 {6876 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));6877 H();6878 }6879 6880 if (fEnabledDhcp)6881 hrc = dhcpServer->Start(trunkName.raw(), trunkType.raw());6882 }6883 else6884 hrc = S_OK;6885 }6886 }6887 6888 break;6889 }6890 6891 default:6892 AssertMsgFailed(("should not get here!\n"));6893 break;6894 }6895 6896 meAttachmentType[uInstance] = eAttachmentType;6897 }6898 catch (ConfigError &x)6899 {6900 // InsertConfig threw something:6901 return x.m_vrc;6902 }6903 6904 #undef H6905 6906 return VINF_SUCCESS;6907 }6908 6909 6910 /**6911 * Configures the serial port at the given CFGM node with the supplied parameters.6912 *6913 * @returns VBox status code.6914 * @param pInst The instance CFGM node.6915 * @param ePortMode The port mode to sue.6916 * @param pszPath The serial port path.6917 * @param fServer Flag whether the port should act as a server6918 * for the pipe and TCP mode or connect as a client.6919 */6920 int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)6921 {6922 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */6923 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */6924 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */6925 6926 try6927 {6928 InsertConfigNode(pInst, "LUN#0", &pLunL0);6929 if (ePortMode == PortMode_HostPipe)6930 {6931 InsertConfigString(pLunL0, "Driver", "Char");6932 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);6933 InsertConfigString(pLunL1, "Driver", "NamedPipe");6934 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);6935 InsertConfigString(pLunL1Cfg, "Location", pszPath);6936 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);6937 }6938 else if (ePortMode == PortMode_HostDevice)6939 {6940 InsertConfigString(pLunL0, "Driver", "Host Serial");6941 InsertConfigNode(pLunL0, "Config", &pLunL1);6942 InsertConfigString(pLunL1, "DevicePath", pszPath);6943 }6944 else if (ePortMode == PortMode_TCP)6945 {6946 InsertConfigString(pLunL0, "Driver", "Char");6947 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);6948 InsertConfigString(pLunL1, "Driver", "TCP");6949 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);6950 InsertConfigString(pLunL1Cfg, "Location", pszPath);6951 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);6952 }6953 else if (ePortMode == PortMode_RawFile)6954 {6955 InsertConfigString(pLunL0, "Driver", "Char");6956 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);6957 InsertConfigString(pLunL1, "Driver", "RawFile");6958 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);6959 InsertConfigString(pLunL1Cfg, "Location", pszPath);6960 }6961 }6962 catch (ConfigError &x)6963 {6964 /* InsertConfig threw something */6965 return x.m_vrc;6966 }6967 6968 return VINF_SUCCESS;6969 }6970
Note:
See TracChangeset
for help on using the changeset viewer.