/* $Id: PlatformPropertiesImpl.cpp 106384 2024-10-16 13:58:41Z vboxsync $ */ /** @file * VirtualBox COM class implementation - Platform properties. */ /* * Copyright (C) 2023-2024 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * SPDX-License-Identifier: GPL-3.0-only */ #define LOG_GROUP LOG_GROUP_MAIN_PLATFORMPROPERTIES #include "PlatformPropertiesImpl.h" #include "GraphicsAdapterImpl.h" /* For static helper functions. */ #include "VirtualBoxImpl.h" #include "LoggingNew.h" #include "Global.h" #include #include #include #include /* For VRAM ranges. */ #include // generated header #include "SchemaDefs.h" /* * PlatformProperties implementation. */ PlatformProperties::PlatformProperties() : mParent(NULL) , mPlatformArchitecture(PlatformArchitecture_None) , mfIsHost(false) { } PlatformProperties::~PlatformProperties() { uninit(); } HRESULT PlatformProperties::FinalConstruct() { return BaseFinalConstruct(); } void PlatformProperties::FinalRelease() { uninit(); BaseFinalRelease(); } /** * Initializes platform properties. * * @returns HRESULT * @param aParent Pointer to IVirtualBox parent object (weak). * @param fIsHost Set to \c true if this instance handles platform properties of the host, * or set to \c false for guests (default). */ HRESULT PlatformProperties::init(VirtualBox *aParent, bool fIsHost /* = false */) { /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); AssertReturn(autoInitSpan.isOk(), E_FAIL); unconst(mParent) = aParent; m = new settings::PlatformProperties; unconst(mfIsHost) = fIsHost; if (mfIsHost) { /* On Windows, macOS and Solaris hosts, HW virtualization use isn't exclusive * by default so that VT-x or AMD-V can be shared with other * hypervisors without requiring user intervention. * NB: See also PlatformProperties constructor in settings.h */ #if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) m->fExclusiveHwVirt = false; /** @todo BUGBUG Applies for MacOS on ARM as well? */ #else m->fExclusiveHwVirt = true; #endif } /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); return S_OK; } /** * Sets the platform architecture. * * @returns HRESULT * @param aArchitecture Platform architecture to set. * * @note Usually only called when creating a new machine. */ HRESULT PlatformProperties::i_setArchitecture(PlatformArchitecture_T aArchitecture) { /* sanity */ AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.hrc(), autoCaller.hrc()); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); mPlatformArchitecture = aArchitecture; return S_OK; } /** * Returns the host's platform architecture. * * @returns The host's platform architecture. */ PlatformArchitecture_T PlatformProperties::s_getHostPlatformArchitecture() { #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) return PlatformArchitecture_x86; #elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) return PlatformArchitecture_ARM; #else # error "Port me!" return PlatformArchitecture_None; #endif } void PlatformProperties::uninit() { /* Enclose the state transition Ready->InUninit->NotReady */ AutoUninitSpan autoUninitSpan(this); if (autoUninitSpan.uninitDone()) return; if (m) { delete m; m = NULL; } } HRESULT PlatformProperties::getSerialPortCount(ULONG *count) { /* no need to lock, this is const */ *count = SchemaDefs::SerialPortCount; return S_OK; } HRESULT PlatformProperties::getParallelPortCount(ULONG *count) { /* no need to lock, this is const */ *count = SchemaDefs::ParallelPortCount; return S_OK; } HRESULT PlatformProperties::getMaxBootPosition(ULONG *aMaxBootPosition) { /* no need to lock, this is const */ *aMaxBootPosition = SchemaDefs::MaxBootPosition; return S_OK; } HRESULT PlatformProperties::getRawModeSupported(BOOL *aRawModeSupported) { *aRawModeSupported = FALSE; return S_OK; } HRESULT PlatformProperties::getExclusiveHwVirt(BOOL *aExclusiveHwVirt) { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); *aExclusiveHwVirt = m->fExclusiveHwVirt; /* Makes no sense for guest platform properties, but we return FALSE anyway. */ return S_OK; } HRESULT PlatformProperties::setExclusiveHwVirt(BOOL aExclusiveHwVirt) { /* Only makes sense when running in VBoxSVC, as this is a pure host setting -- ignored within clients. */ #ifdef IN_VBOXSVC /* No locking required, as mfIsHost is const. */ if (!mfIsHost) /* Ignore setting the attribute if not host properties. */ return S_OK; AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); m->fExclusiveHwVirt = !!aExclusiveHwVirt; alock.release(); // VirtualBox::i_saveSettings() needs vbox write lock AutoWriteLock vboxLock(mParent COMMA_LOCKVAL_SRC_POS); return mParent->i_saveSettings(); #else /* VBoxC */ RT_NOREF(aExclusiveHwVirt); return VBOX_E_NOT_SUPPORTED; #endif } /* static */ ULONG PlatformProperties::s_getMaxNetworkAdapters(ChipsetType_T aChipset) { AssertReturn(aChipset != ChipsetType_Null, 0); /* no need for locking, no state */ switch (aChipset) { case ChipsetType_PIIX3: return 8; case ChipsetType_ICH9: return 36; case ChipsetType_ARMv8Virtual: return 64; /** @todo BUGBUG Put a sane value here. Just a wild guess for now. */ case ChipsetType_Null: RT_FALL_THROUGH(); default: break; } AssertMsgFailedReturn(("Chipset type %#x not handled\n", aChipset), 0); } HRESULT PlatformProperties::getMaxNetworkAdapters(ChipsetType_T aChipset, ULONG *aMaxNetworkAdapters) { *aMaxNetworkAdapters = PlatformProperties::s_getMaxNetworkAdapters(aChipset); return S_OK; } /* static */ ULONG PlatformProperties::s_getMaxNetworkAdaptersOfType(ChipsetType_T aChipset, NetworkAttachmentType_T aType) { /* no need for locking, no state */ uint32_t cMaxNetworkAdapters = PlatformProperties::s_getMaxNetworkAdapters(aChipset); switch (aType) { case NetworkAttachmentType_NAT: case NetworkAttachmentType_Internal: case NetworkAttachmentType_NATNetwork: /* chipset default is OK */ break; case NetworkAttachmentType_Bridged: /* Maybe use current host interface count here? */ break; case NetworkAttachmentType_HostOnly: cMaxNetworkAdapters = RT_MIN(cMaxNetworkAdapters, 8); break; default: AssertMsgFailed(("Unhandled attachment type %d\n", aType)); } return cMaxNetworkAdapters; } HRESULT PlatformProperties::getMaxNetworkAdaptersOfType(ChipsetType_T aChipset, NetworkAttachmentType_T aType, ULONG *aMaxNetworkAdapters) { *aMaxNetworkAdapters = PlatformProperties::s_getMaxNetworkAdaptersOfType(aChipset, aType); return S_OK; } HRESULT PlatformProperties::getMaxDevicesPerPortForStorageBus(StorageBus_T aBus, ULONG *aMaxDevicesPerPort) { /* no need to lock, this is const */ switch (aBus) { case StorageBus_SATA: case StorageBus_SCSI: case StorageBus_SAS: case StorageBus_USB: case StorageBus_PCIe: case StorageBus_VirtioSCSI: { /* SATA and both SCSI controllers only support one device per port. */ *aMaxDevicesPerPort = 1; break; } case StorageBus_IDE: case StorageBus_Floppy: { /* The IDE and Floppy controllers support 2 devices. One as master * and one as slave (or floppy drive 0 and 1). */ *aMaxDevicesPerPort = 2; break; } default: AssertMsgFailed(("Invalid bus type %d\n", aBus)); } return S_OK; } HRESULT PlatformProperties::getMinPortCountForStorageBus(StorageBus_T aBus, ULONG *aMinPortCount) { /* no need to lock, this is const */ switch (aBus) { case StorageBus_SATA: case StorageBus_SAS: case StorageBus_PCIe: case StorageBus_VirtioSCSI: { *aMinPortCount = 1; break; } case StorageBus_SCSI: { *aMinPortCount = 16; break; } case StorageBus_IDE: { *aMinPortCount = 2; break; } case StorageBus_Floppy: { *aMinPortCount = 1; break; } case StorageBus_USB: { *aMinPortCount = 8; break; } default: AssertMsgFailed(("Invalid bus type %d\n", aBus)); } return S_OK; } HRESULT PlatformProperties::getMaxPortCountForStorageBus(StorageBus_T aBus, ULONG *aMaxPortCount) { /* no need to lock, this is const */ switch (aBus) { case StorageBus_SATA: { *aMaxPortCount = 30; break; } case StorageBus_SCSI: { *aMaxPortCount = 16; break; } case StorageBus_IDE: { *aMaxPortCount = 2; break; } case StorageBus_Floppy: { *aMaxPortCount = 1; break; } case StorageBus_SAS: case StorageBus_PCIe: { *aMaxPortCount = 255; break; } case StorageBus_USB: { *aMaxPortCount = 8; break; } case StorageBus_VirtioSCSI: { *aMaxPortCount = 256; break; } default: AssertMsgFailed(("Invalid bus type %d\n", aBus)); } return S_OK; } HRESULT PlatformProperties::getMaxInstancesOfStorageBus(ChipsetType_T aChipset, StorageBus_T aBus, ULONG *aMaxInstances) { ULONG cCtrs = 0; /* no need to lock, this is const */ switch (aBus) { case StorageBus_SATA: case StorageBus_SCSI: case StorageBus_SAS: case StorageBus_PCIe: case StorageBus_VirtioSCSI: cCtrs = aChipset == ChipsetType_ICH9 || aChipset == ChipsetType_ARMv8Virtual ? 8 : 1; break; case StorageBus_USB: case StorageBus_IDE: case StorageBus_Floppy: { cCtrs = 1; break; } default: AssertMsgFailed(("Invalid bus type %d\n", aBus)); } *aMaxInstances = cCtrs; return S_OK; } HRESULT PlatformProperties::getDeviceTypesForStorageBus(StorageBus_T aBus, std::vector &aDeviceTypes) { aDeviceTypes.resize(0); /* no need to lock, this is const */ switch (aBus) { case StorageBus_IDE: case StorageBus_SATA: case StorageBus_SCSI: case StorageBus_SAS: case StorageBus_USB: case StorageBus_VirtioSCSI: { aDeviceTypes.resize(2); aDeviceTypes[0] = DeviceType_DVD; aDeviceTypes[1] = DeviceType_HardDisk; break; } case StorageBus_Floppy: { aDeviceTypes.resize(1); aDeviceTypes[0] = DeviceType_Floppy; break; } case StorageBus_PCIe: { aDeviceTypes.resize(1); aDeviceTypes[0] = DeviceType_HardDisk; break; } default: AssertMsgFailed(("Invalid bus type %d\n", aBus)); } return S_OK; } HRESULT PlatformProperties::getStorageBusForControllerType(StorageControllerType_T aStorageControllerType, StorageBus_T *aStorageBus) { /* no need to lock, this is const */ switch (aStorageControllerType) { case StorageControllerType_LsiLogic: case StorageControllerType_BusLogic: *aStorageBus = StorageBus_SCSI; break; case StorageControllerType_IntelAhci: *aStorageBus = StorageBus_SATA; break; case StorageControllerType_PIIX3: case StorageControllerType_PIIX4: case StorageControllerType_ICH6: *aStorageBus = StorageBus_IDE; break; case StorageControllerType_I82078: *aStorageBus = StorageBus_Floppy; break; case StorageControllerType_LsiLogicSas: *aStorageBus = StorageBus_SAS; break; case StorageControllerType_USB: *aStorageBus = StorageBus_USB; break; case StorageControllerType_NVMe: *aStorageBus = StorageBus_PCIe; break; case StorageControllerType_VirtioSCSI: *aStorageBus = StorageBus_VirtioSCSI; break; default: return setError(E_FAIL, tr("Invalid storage controller type %d\n"), aStorageBus); } return S_OK; } HRESULT PlatformProperties::getStorageControllerTypesForBus(StorageBus_T aStorageBus, std::vector &aStorageControllerTypes) { aStorageControllerTypes.resize(0); /* no need to lock, this is const */ switch (aStorageBus) { case StorageBus_IDE: aStorageControllerTypes.resize(3); aStorageControllerTypes[0] = StorageControllerType_PIIX4; aStorageControllerTypes[1] = StorageControllerType_PIIX3; aStorageControllerTypes[2] = StorageControllerType_ICH6; break; case StorageBus_SATA: aStorageControllerTypes.resize(1); aStorageControllerTypes[0] = StorageControllerType_IntelAhci; break; case StorageBus_SCSI: aStorageControllerTypes.resize(2); aStorageControllerTypes[0] = StorageControllerType_LsiLogic; aStorageControllerTypes[1] = StorageControllerType_BusLogic; break; case StorageBus_Floppy: aStorageControllerTypes.resize(1); aStorageControllerTypes[0] = StorageControllerType_I82078; break; case StorageBus_SAS: aStorageControllerTypes.resize(1); aStorageControllerTypes[0] = StorageControllerType_LsiLogicSas; break; case StorageBus_USB: aStorageControllerTypes.resize(1); aStorageControllerTypes[0] = StorageControllerType_USB; break; case StorageBus_PCIe: aStorageControllerTypes.resize(1); aStorageControllerTypes[0] = StorageControllerType_NVMe; break; case StorageBus_VirtioSCSI: aStorageControllerTypes.resize(1); aStorageControllerTypes[0] = StorageControllerType_VirtioSCSI; break; default: return setError(E_FAIL, tr("Invalid storage bus %d\n"), aStorageBus); } return S_OK; } HRESULT PlatformProperties::getStorageControllerHotplugCapable(StorageControllerType_T aControllerType, BOOL *aHotplugCapable) { switch (aControllerType) { case StorageControllerType_IntelAhci: case StorageControllerType_USB: *aHotplugCapable = true; break; case StorageControllerType_LsiLogic: case StorageControllerType_LsiLogicSas: case StorageControllerType_BusLogic: case StorageControllerType_NVMe: case StorageControllerType_VirtioSCSI: case StorageControllerType_PIIX3: case StorageControllerType_PIIX4: case StorageControllerType_ICH6: case StorageControllerType_I82078: *aHotplugCapable = false; break; default: AssertMsgFailedReturn(("Invalid controller type %d\n", aControllerType), E_FAIL); } return S_OK; } HRESULT PlatformProperties::getMaxInstancesOfUSBControllerType(ChipsetType_T aChipset, USBControllerType_T aType, ULONG *aMaxInstances) { NOREF(aChipset); ULONG cCtrs = 0; /* no need to lock, this is const */ switch (aType) { case USBControllerType_OHCI: case USBControllerType_EHCI: case USBControllerType_XHCI: { cCtrs = 1; break; } default: AssertMsgFailed(("Invalid bus type %d\n", aType)); } *aMaxInstances = cCtrs; return S_OK; } HRESULT PlatformProperties::getSupportedParavirtProviders(std::vector &aSupportedParavirtProviders) { static const ParavirtProvider_T aParavirtProviders[] = { ParavirtProvider_None, ParavirtProvider_Default, ParavirtProvider_Legacy, ParavirtProvider_Minimal, ParavirtProvider_HyperV, ParavirtProvider_KVM, }; aSupportedParavirtProviders.assign(aParavirtProviders, aParavirtProviders + RT_ELEMENTS(aParavirtProviders)); return S_OK; } HRESULT PlatformProperties::getSupportedFirmwareTypes(std::vector &aSupportedFirmwareTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const FirmwareType_T aFirmwareTypes[] = { FirmwareType_BIOS, FirmwareType_EFI, FirmwareType_EFI32, FirmwareType_EFI64, FirmwareType_EFIDUAL }; aSupportedFirmwareTypes.assign(aFirmwareTypes, aFirmwareTypes + RT_ELEMENTS(aFirmwareTypes)); break; } case PlatformArchitecture_ARM: { static const FirmwareType_T aFirmwareTypes[] = { FirmwareType_EFI, FirmwareType_EFI32, FirmwareType_EFI64, FirmwareType_EFIDUAL }; aSupportedFirmwareTypes.assign(aFirmwareTypes, aFirmwareTypes + RT_ELEMENTS(aFirmwareTypes)); break; } default: AssertFailedStmt(aSupportedFirmwareTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedGfxControllerTypes(std::vector &aSupportedGraphicsControllerTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const GraphicsControllerType_T aGraphicsControllerTypes[] = { GraphicsControllerType_Null, GraphicsControllerType_VBoxVGA, GraphicsControllerType_VBoxSVGA #ifdef VBOX_WITH_VMSVGA , GraphicsControllerType_VMSVGA #endif }; aSupportedGraphicsControllerTypes.assign(aGraphicsControllerTypes + 1 /* Don't include _Null */, aGraphicsControllerTypes + RT_ELEMENTS(aGraphicsControllerTypes)); break; } case PlatformArchitecture_ARM: { static const GraphicsControllerType_T aGraphicsControllerTypes[] = { GraphicsControllerType_Null, GraphicsControllerType_QemuRamFB #ifdef VBOX_WITH_VMSVGA , GraphicsControllerType_VMSVGA #endif }; aSupportedGraphicsControllerTypes.assign(aGraphicsControllerTypes + 1 /* Don't include _Null */, aGraphicsControllerTypes + RT_ELEMENTS(aGraphicsControllerTypes)); break; } default: AssertFailedStmt(aSupportedGraphicsControllerTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedGuestOSTypes(std::vector > &aSupportedGuestOSTypes) { /* We only have all supported guest OS types as part of VBoxSVC, not in VBoxC itself. */ #ifdef IN_VBOXSVC std::vector vecArchitectures(1 /* Size */, mPlatformArchitecture); return mParent->i_getSupportedGuestOSTypes(vecArchitectures, aSupportedGuestOSTypes); #else /* VBoxC */ RT_NOREF(aSupportedGuestOSTypes); return VBOX_E_NOT_SUPPORTED; #endif } HRESULT PlatformProperties::getSupportedNetAdpPromiscModePols(std::vector &aSupportedNetworkAdapterPromiscModePolicies) { static const NetworkAdapterPromiscModePolicy_T aNetworkAdapterPromiscModePolicies[] = { NetworkAdapterPromiscModePolicy_Deny, NetworkAdapterPromiscModePolicy_AllowNetwork, NetworkAdapterPromiscModePolicy_AllowAll }; aSupportedNetworkAdapterPromiscModePolicies.assign(aNetworkAdapterPromiscModePolicies, aNetworkAdapterPromiscModePolicies + RT_ELEMENTS(aNetworkAdapterPromiscModePolicies)); return S_OK; } HRESULT PlatformProperties::getSupportedNetworkAdapterTypes(std::vector &aSupportedNetworkAdapterTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const NetworkAdapterType_T aNetworkAdapterTypes[] = { NetworkAdapterType_Null, NetworkAdapterType_Am79C970A, NetworkAdapterType_Am79C973 #ifdef VBOX_WITH_E1000 , NetworkAdapterType_I82540EM , NetworkAdapterType_I82543GC , NetworkAdapterType_I82545EM #endif #ifdef VBOX_WITH_VIRTIO , NetworkAdapterType_Virtio #endif }; aSupportedNetworkAdapterTypes.assign(aNetworkAdapterTypes + 1 /* Don't include _Null */, aNetworkAdapterTypes + RT_ELEMENTS(aNetworkAdapterTypes)); break; } case PlatformArchitecture_ARM: { static const NetworkAdapterType_T aNetworkAdapterTypes[] = { NetworkAdapterType_Null #ifdef VBOX_WITH_E1000 , NetworkAdapterType_I82540EM , NetworkAdapterType_I82543GC , NetworkAdapterType_I82545EM #endif #ifdef VBOX_WITH_VIRTIO , NetworkAdapterType_Virtio #endif }; aSupportedNetworkAdapterTypes.assign(aNetworkAdapterTypes + 1 /* Don't include _Null */, aNetworkAdapterTypes + RT_ELEMENTS(aNetworkAdapterTypes)); break; } default: AssertFailedStmt(aSupportedNetworkAdapterTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedUartTypes(std::vector &aSupportedUartTypes) { static const UartType_T aUartTypes[] = { UartType_U16450, UartType_U16550A, UartType_U16750 }; aSupportedUartTypes.assign(aUartTypes, aUartTypes + RT_ELEMENTS(aUartTypes)); return S_OK; } HRESULT PlatformProperties::getSupportedUSBControllerTypes(std::vector &aSupportedUSBControllerTypes) { static const USBControllerType_T aUSBControllerTypes[] = { USBControllerType_OHCI, USBControllerType_EHCI, USBControllerType_XHCI }; aSupportedUSBControllerTypes.assign(aUSBControllerTypes, aUSBControllerTypes + RT_ELEMENTS(aUSBControllerTypes)); return S_OK; } /** * Static helper function to return all supported features for a given graphics controller. * * @returns VBox status code. * @param enmArchitecture Platform architecture to query a feature for. * @param enmController Graphics controller to return supported features for. * @param vecSupportedGraphicsFeatures Returned features on success. */ /* static */ int PlatformProperties::s_getSupportedGraphicsControllerFeatures(PlatformArchitecture_T enmArchitecture, GraphicsControllerType_T enmController, std::vector &vecSupportedGraphicsFeatures) { vecSupportedGraphicsFeatures.clear(); /* Note! The legacy VHWA acceleration has been disabled completely (see @bugref{9691}). */ switch (enmArchitecture) { case PlatformArchitecture_x86: case PlatformArchitecture_ARM: { switch (enmController) { case GraphicsControllerType_VMSVGA: case GraphicsControllerType_VBoxSVGA: #ifdef VBOX_WITH_VMSVGA # ifdef VBOX_WITH_3D_ACCELERATION vecSupportedGraphicsFeatures.push_back(GraphicsFeature_Acceleration3D); # endif #endif return VINF_SUCCESS; case GraphicsControllerType_VBoxVGA: case GraphicsControllerType_QemuRamFB: /* None supported. */ return VINF_SUCCESS; /* (no default to get compiler warnings) */ case GraphicsControllerType_Null: #ifdef VBOX_WITH_XPCOM case GraphicsControllerType_32BitHack: #endif break; } break; } /* (no default to get compiler warnings) */ case PlatformArchitecture_None: #ifdef VBOX_WITH_XPCOM case PlatformArchitecture_32BitHack: #endif break; } return VERR_INVALID_PARAMETER; } /** * Static helper function to return whether a given graphics feature for a graphics controller is enabled or not. * * @returns \c true if the given feature is supported, or \c false if not. * @param enmArchitecture Platform architecture to query a feature for. * @param enmController Graphics controlller to query a feature for. * @param enmFeature Feature to query. */ /* static */ bool PlatformProperties::s_isGraphicsControllerFeatureSupported(PlatformArchitecture_T enmArchitecture, GraphicsControllerType_T enmController, GraphicsFeature_T enmFeature) { std::vector vecSupportedGraphicsFeatures; int vrc = PlatformProperties::s_getSupportedGraphicsControllerFeatures(enmArchitecture, enmController, vecSupportedGraphicsFeatures); if (RT_SUCCESS(vrc)) return std::find(vecSupportedGraphicsFeatures.begin(), vecSupportedGraphicsFeatures.end(), enmFeature) != vecSupportedGraphicsFeatures.end(); return false; } /** * Returns the [minimum, maximum] VRAM range and stride size for a given graphics controller. * * @returns HRESULT * @param aGraphicsControllerType Graphics controller type to return values for. * @param fAccelerate3DEnabled whether 3D acceleration is enabled / disabled for the selected graphics controller. * @param aMinMB Where to return the minimum VRAM (in MB). * @param aMaxMB Where to return the maximum VRAM (in MB). * @param aStrideSizeMB Where to return stride size (in MB). Optional, can be NULL. */ /* static */ HRESULT PlatformProperties::s_getSupportedVRAMRange(GraphicsControllerType_T aGraphicsControllerType, BOOL fAccelerate3DEnabled, ULONG *aMinMB, ULONG *aMaxMB, ULONG *aStrideSizeMB) { size_t cbMin; size_t cbMax; size_t cbStride = _1M; /* Default stride for all controllers. */ switch (aGraphicsControllerType) { case GraphicsControllerType_VBoxVGA: { cbMin = VGA_VRAM_MIN; cbMax = VGA_VRAM_MAX; break; } case GraphicsControllerType_VMSVGA: case GraphicsControllerType_VBoxSVGA: { if (fAccelerate3DEnabled) cbMin = VBOX_SVGA_VRAM_MIN_SIZE_3D; else cbMin = VBOX_SVGA_VRAM_MIN_SIZE; /* We don't want to limit ourselves to VBOX_SVGA_VRAM_MAX_SIZE, * so we use VGA_VRAM_MAX for all controllers. */ cbMax = VGA_VRAM_MAX; break; } case GraphicsControllerType_QemuRamFB: { /* We seem to hardcode 32-bit (4 bytes) as BPP, see RAMFB_BPP in QemuRamfb.c. */ cbMin = 4 /* BPP in bytes */ * 16 * 16; /* Values taken from qemu/hw/display/ramfb.c */ cbMax = 4 /* BPP in bytes */ * 16000 * 12000; /* Values taken from bochs-vbe.h. */ /* Make the maximum value a power of two. */ cbMax = RT_BIT_64(ASMBitLastSetU64(cbMax)); break; } default: return E_INVALIDARG; } /* Sanity. We want all max values to be a power of two. */ AssertMsg(RT_IS_POWER_OF_TWO(cbMax), ("Maximum VRAM value is not a power of two!\n")); /* Convert bytes -> MB, align to stride. */ cbMin = (ULONG)(RT_ALIGN_64(cbMin, cbStride) / _1M); cbMax = (ULONG)(RT_ALIGN_64(cbMax, cbStride) / _1M); cbStride = (ULONG)cbStride / _1M; /* Finally, clamp the values to our schema definitions before returning. */ if (cbMax > SchemaDefs::MaxGuestVRAM) cbMax = SchemaDefs::MaxGuestVRAM; *aMinMB = (ULONG)cbMin; *aMaxMB = (ULONG)cbMax; if (aStrideSizeMB) *aStrideSizeMB = (ULONG)cbStride; return S_OK; } HRESULT PlatformProperties::getSupportedVRAMRange(GraphicsControllerType_T aGraphicsControllerType, BOOL fAccelerate3DEnabled, ULONG *aMinMB, ULONG *aMaxMB, ULONG *aStrideSizeMB) { HRESULT hrc = PlatformProperties::s_getSupportedVRAMRange(aGraphicsControllerType, fAccelerate3DEnabled, aMinMB, aMaxMB, aStrideSizeMB); switch (hrc) { case VBOX_E_NOT_SUPPORTED: return setError(VBOX_E_NOT_SUPPORTED, tr("Selected graphics controller not supported in this version")); case E_INVALIDARG: return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType); default: break; } return S_OK; } HRESULT PlatformProperties::getSupportedGfxFeaturesForType(GraphicsControllerType_T aGraphicsControllerType, std::vector &aSupportedGraphicsFeatures) { int vrc = PlatformProperties::s_getSupportedGraphicsControllerFeatures(mPlatformArchitecture, aGraphicsControllerType, aSupportedGraphicsFeatures); if (RT_SUCCESS(vrc)) return S_OK; return setError(E_INVALIDARG, tr("The graphics controller type (%d) is invalid"), aGraphicsControllerType); } HRESULT PlatformProperties::getSupportedAudioControllerTypes(std::vector &aSupportedAudioControllerTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const AudioControllerType_T aAudioControllerTypes[] = { AudioControllerType_AC97, AudioControllerType_SB16, AudioControllerType_HDA, }; aSupportedAudioControllerTypes.assign(aAudioControllerTypes, aAudioControllerTypes + RT_ELEMENTS(aAudioControllerTypes)); break; } case PlatformArchitecture_ARM: { static const AudioControllerType_T aAudioControllerTypes[] = { AudioControllerType_AC97, AudioControllerType_HDA, }; aSupportedAudioControllerTypes.assign(aAudioControllerTypes, aAudioControllerTypes + RT_ELEMENTS(aAudioControllerTypes)); break; } default: AssertFailedStmt(aSupportedAudioControllerTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedBootDevices(std::vector &aSupportedBootDevices) { /* Note: This function returns the supported boot devices for the given architecture, in the default order, to keep it simple for the caller. */ switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const DeviceType_T aBootDevices[] = { DeviceType_Floppy, DeviceType_DVD, DeviceType_HardDisk, DeviceType_Network }; aSupportedBootDevices.assign(aBootDevices, aBootDevices + RT_ELEMENTS(aBootDevices)); break; } case PlatformArchitecture_ARM: { static const DeviceType_T aBootDevices[] = { DeviceType_DVD, DeviceType_HardDisk /** @todo BUGBUG We need to test network booting via PXE on ARM first! */ }; aSupportedBootDevices.assign(aBootDevices, aBootDevices + RT_ELEMENTS(aBootDevices)); break; } default: AssertFailedStmt(aSupportedBootDevices.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedStorageBuses(std::vector &aSupportedStorageBuses) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const StorageBus_T aStorageBuses[] = { StorageBus_SATA, StorageBus_IDE, StorageBus_SCSI, StorageBus_Floppy, StorageBus_SAS, StorageBus_USB, StorageBus_PCIe, StorageBus_VirtioSCSI, }; aSupportedStorageBuses.assign(aStorageBuses, aStorageBuses + RT_ELEMENTS(aStorageBuses)); break; } case PlatformArchitecture_ARM: { static const StorageBus_T aStorageBuses[] = { StorageBus_SATA, StorageBus_SCSI, StorageBus_SAS, StorageBus_USB, StorageBus_PCIe, StorageBus_VirtioSCSI }; aSupportedStorageBuses.assign(aStorageBuses, aStorageBuses + RT_ELEMENTS(aStorageBuses)); break; } default: AssertFailedStmt(aSupportedStorageBuses.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedStorageControllerTypes(std::vector &aSupportedStorageControllerTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const StorageControllerType_T aStorageControllerTypes[] = { StorageControllerType_IntelAhci, StorageControllerType_PIIX4, StorageControllerType_PIIX3, StorageControllerType_ICH6, StorageControllerType_LsiLogic, StorageControllerType_BusLogic, StorageControllerType_I82078, StorageControllerType_LsiLogicSas, StorageControllerType_USB, StorageControllerType_NVMe, StorageControllerType_VirtioSCSI }; aSupportedStorageControllerTypes.assign(aStorageControllerTypes, aStorageControllerTypes + RT_ELEMENTS(aStorageControllerTypes)); break; } case PlatformArchitecture_ARM: { static const StorageControllerType_T aStorageControllerTypes[] = { StorageControllerType_IntelAhci, StorageControllerType_LsiLogic, StorageControllerType_LsiLogicSas, StorageControllerType_USB, StorageControllerType_NVMe, StorageControllerType_VirtioSCSI }; aSupportedStorageControllerTypes.assign(aStorageControllerTypes, aStorageControllerTypes + RT_ELEMENTS(aStorageControllerTypes)); break; } default: AssertFailedStmt(aSupportedStorageControllerTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedChipsetTypes(std::vector &aSupportedChipsetTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const ChipsetType_T aChipsetTypes[] = { ChipsetType_PIIX3, ChipsetType_ICH9 }; aSupportedChipsetTypes.assign(aChipsetTypes, aChipsetTypes + RT_ELEMENTS(aChipsetTypes)); break; } case PlatformArchitecture_ARM: { static const ChipsetType_T aChipsetTypes[] = { ChipsetType_ARMv8Virtual }; aSupportedChipsetTypes.assign(aChipsetTypes, aChipsetTypes + RT_ELEMENTS(aChipsetTypes)); break; } default: AssertFailedStmt(aSupportedChipsetTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedIommuTypes(std::vector &aSupportedIommuTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const IommuType_T aIommuTypes[] = { IommuType_None, IommuType_Automatic, IommuType_AMD /** @todo Add Intel when it's supported. */ }; aSupportedIommuTypes.assign(aIommuTypes, aIommuTypes + RT_ELEMENTS(aIommuTypes)); break; } case PlatformArchitecture_ARM: { static const IommuType_T aIommuTypes[] = { IommuType_None }; aSupportedIommuTypes.assign(aIommuTypes, aIommuTypes + RT_ELEMENTS(aIommuTypes)); break; } default: AssertFailedStmt(aSupportedIommuTypes.clear()); break; } return S_OK; } HRESULT PlatformProperties::getSupportedTpmTypes(std::vector &aSupportedTpmTypes) { switch (mPlatformArchitecture) { case PlatformArchitecture_x86: { static const TpmType_T aTpmTypes[] = { TpmType_None, TpmType_v1_2, TpmType_v2_0 }; aSupportedTpmTypes.assign(aTpmTypes, aTpmTypes + RT_ELEMENTS(aTpmTypes)); break; } case PlatformArchitecture_ARM: { static const TpmType_T aTpmTypes[] = { TpmType_None, TpmType_v2_0 }; aSupportedTpmTypes.assign(aTpmTypes, aTpmTypes + RT_ELEMENTS(aTpmTypes)); break; } default: AssertFailedStmt(aSupportedTpmTypes.clear()); break; } return S_OK; }