From f01d8008ee4263178e1b30c31ede7fff17adb8f5 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Wed, 20 Oct 2021 23:39:21 -0400 Subject: [PATCH 1/3] vmm/integration: Update mv_vs_op_msr_{g,s}et_list --- vmm/integration/mv_vs_op_msr_get_list.cpp | 11 ----------- vmm/integration/mv_vs_op_msr_set_list.cpp | 11 ----------- 2 files changed, 22 deletions(-) diff --git a/vmm/integration/mv_vs_op_msr_get_list.cpp b/vmm/integration/mv_vs_op_msr_get_list.cpp index 5b955f5cd..f8e31b68a 100644 --- a/vmm/integration/mv_vs_op_msr_get_list.cpp +++ b/vmm/integration/mv_vs_op_msr_get_list.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -98,16 +97,6 @@ namespace hypercall mut_ret = mv_vs_op_msr_get_list_impl(hndl.get(), self.get()); integration::verify(mut_ret != MV_STATUS_SUCCESS); - // register invalid - pmut_rdl0->entries.front().reg = to_u64(mv_reg_t::mv_reg_t_invalid).get(); - mut_ret = mv_vs_op_msr_get_list_impl(hndl.get(), self.get()); - integration::verify(mut_ret != MV_STATUS_SUCCESS); - - // register out of range - pmut_rdl0->entries.front().reg = ~to_u64(mv_reg_t::mv_reg_t_invalid).get(); - mut_ret = mv_vs_op_msr_get_list_impl(hndl.get(), self.get()); - integration::verify(mut_ret != MV_STATUS_SUCCESS); - // empty RDL { pmut_rdl0->num_entries = {}; diff --git a/vmm/integration/mv_vs_op_msr_set_list.cpp b/vmm/integration/mv_vs_op_msr_set_list.cpp index 9315e6cdc..0c935606c 100644 --- a/vmm/integration/mv_vs_op_msr_set_list.cpp +++ b/vmm/integration/mv_vs_op_msr_set_list.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -98,16 +97,6 @@ namespace hypercall mut_ret = mv_vs_op_msr_set_list_impl(hndl.get(), self.get()); integration::verify(mut_ret != MV_STATUS_SUCCESS); - // register invalid - pmut_rdl0->entries.front().reg = to_u64(mv_reg_t::mv_reg_t_invalid).get(); - mut_ret = mv_vs_op_msr_set_list_impl(hndl.get(), self.get()); - integration::verify(mut_ret != MV_STATUS_SUCCESS); - - // register out of range - pmut_rdl0->entries.front().reg = ~to_u64(mv_reg_t::mv_reg_t_invalid).get(); - mut_ret = mv_vs_op_msr_set_list_impl(hndl.get(), self.get()); - integration::verify(mut_ret != MV_STATUS_SUCCESS); - // empty RDL { pmut_rdl0->num_entries = {}; From 91c4ab414bc59315cde3078422444bd0cdfd61c8 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Wed, 20 Oct 2021 23:54:35 -0400 Subject: [PATCH 2/3] shim: Remove duplicates in Makefile --- shim/linux/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/shim/linux/Makefile b/shim/linux/Makefile index faa15e3e5..8b95190e1 100644 --- a/shim/linux/Makefile +++ b/shim/linux/Makefile @@ -170,7 +170,6 @@ ifneq ($(KERNELRELEASE),) $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_mp_state_set_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_get_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_get_list_impl.o - $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_pp_op_msr_get_supported_list_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_set_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_msr_set_list_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_fpu_get_all_impl.o @@ -230,7 +229,6 @@ ifneq ($(KERNELRELEASE),) $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_mp_state_set_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_get_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_get_list_impl.o - $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_pp_op_msr_get_supported_list_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_set_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_msr_set_list_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_fpu_get_all_impl.o From 8b1a2cac961d0da8b80a3ee481628ad248899d2f Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Wed, 20 Oct 2021 10:14:56 -0400 Subject: [PATCH 3/3] VMM: Add mv_vs_op_cpuid_{set,get}{_list} support Add support for the following hypercalls: - mv_vs_op_cpuid_get_list - mv_vs_op_cpuid_get - mv_vs_op_cpuid_set_list - mv_vs_op_cpuid_set --- hypercall/include/mv_cdl_t.h | 5 + hypercall/include/mv_constants.h | 8 +- hypercall/include/mv_constants.hpp | 8 +- hypercall/include/mv_cpuid_flag_t.h | 6 +- hypercall/library.cmake | 16 + hypercall/mocks/mv_hypercall.h | 161 ++++++++ .../linux/x64/amd/mv_vs_op_cpuid_get_impl.S | 42 ++ .../x64/amd/mv_vs_op_cpuid_get_list_impl.S | 42 ++ .../linux/x64/amd/mv_vs_op_cpuid_set_impl.S | 42 ++ .../x64/amd/mv_vs_op_cpuid_set_list_impl.S | 42 ++ .../linux/x64/intel/mv_vs_op_cpuid_get_impl.S | 42 ++ .../x64/intel/mv_vs_op_cpuid_get_list_impl.S | 42 ++ .../linux/x64/intel/mv_vs_op_cpuid_set_impl.S | 42 ++ .../x64/intel/mv_vs_op_cpuid_set_list_impl.S | 42 ++ hypercall/src/mv_hypercall.h | 135 +++++++ hypercall/src/mv_hypercall_impl.h | 48 +++ hypercall/src/mv_hypercall_impl.hpp | 48 +++ hypercall/src/mv_hypercall_t.hpp | 137 +++++++ .../windows/x64/amd/mv_vs_op_cpuid_get_impl.S | 42 ++ .../x64/amd/mv_vs_op_cpuid_get_list_impl.S | 42 ++ .../windows/x64/amd/mv_vs_op_cpuid_set_impl.S | 42 ++ .../x64/amd/mv_vs_op_cpuid_set_list_impl.S | 42 ++ .../x64/intel/mv_vs_op_cpuid_get_impl.S | 42 ++ .../x64/intel/mv_vs_op_cpuid_get_list_impl.S | 42 ++ .../x64/intel/mv_vs_op_cpuid_set_impl.S | 42 ++ .../x64/intel/mv_vs_op_cpuid_set_list_impl.S | 42 ++ hypercall/tests/mocks/mv_hypercall.cpp | 104 +++++ shim/linux/Makefile | 8 + vmm/include/x64/cpuid.hpp | 13 +- vmm/integration/CMakeLists.txt | 4 + vmm/integration/mv_vs_op_cpuid_get_list.cpp | 341 ++++++++++++++++ vmm/integration/mv_vs_op_cpuid_set_list.cpp | 341 ++++++++++++++++ vmm/src/dispatch_vmcall_mv_vs_op.hpp | 182 +++++++++ vmm/src/vs_pool_t.hpp | 95 +++++ vmm/src/x64/amd/vs_t.hpp | 45 +++ vmm/src/x64/emulated_cpuid_t.hpp | 367 ++++++++++++++++++ vmm/src/x64/intel/vs_t.hpp | 43 ++ 37 files changed, 2775 insertions(+), 12 deletions(-) create mode 100644 hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_impl.S create mode 100644 hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.S create mode 100644 hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_impl.S create mode 100644 hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_list_impl.S create mode 100644 hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_impl.S create mode 100644 hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_list_impl.S create mode 100644 hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_impl.S create mode 100644 hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_list_impl.S create mode 100644 hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_impl.S create mode 100644 hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_list_impl.S create mode 100644 hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_impl.S create mode 100644 hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_list_impl.S create mode 100644 hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_impl.S create mode 100644 hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_list_impl.S create mode 100644 hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_impl.S create mode 100644 hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_list_impl.S create mode 100644 vmm/integration/mv_vs_op_cpuid_get_list.cpp create mode 100644 vmm/integration/mv_vs_op_cpuid_set_list.cpp diff --git a/hypercall/include/mv_cdl_t.h b/hypercall/include/mv_cdl_t.h index cc0573496..6818c9073 100644 --- a/hypercall/include/mv_cdl_t.h +++ b/hypercall/include/mv_cdl_t.h @@ -37,8 +37,13 @@ extern "C" #pragma pack(push, 1) +#ifdef __cplusplus +/** @brief defines the max number of entires in the CDL */ +#define MV_CDL_MAX_ENTRIES (static_cast(125)) +#else /** @brief defines the max number of entires in the CDL */ #define MV_CDL_MAX_ENTRIES ((uint64_t)125) +#endif /** * diff --git a/hypercall/include/mv_constants.h b/hypercall/include/mv_constants.h index ca167a515..afa47ea26 100644 --- a/hypercall/include/mv_constants.h +++ b/hypercall/include/mv_constants.h @@ -506,10 +506,10 @@ NODISCARD static inline int #define MV_VS_OP_CPUID_GET_IDX_VAL ((uint64_t)0x0000000000000009) /** @brief Defines the index for mv_vs_op_cpuid_set */ #define MV_VS_OP_CPUID_SET_IDX_VAL ((uint64_t)0x000000000000000A) -/** @brief Defines the index for mv_vs_op_cpuid_get_all */ -#define MV_VS_OP_CPUID_GET_ALL_IDX_VAL ((uint64_t)0x000000000000000B) -/** @brief Defines the index for mv_vs_op_cpuid_set_all */ -#define MV_VS_OP_CPUID_SET_ALL_IDX_VAL ((uint64_t)0x000000000000000C) +/** @brief Defines the index for mv_vs_op_cpuid_get_list */ +#define MV_VS_OP_CPUID_GET_LIST_IDX_VAL ((uint64_t)0x000000000000000B) +/** @brief Defines the index for mv_vs_op_cpuid_set_list */ +#define MV_VS_OP_CPUID_SET_LIST_IDX_VAL ((uint64_t)0x000000000000000C) /** @brief Defines the index for mv_vs_op_reg_get */ #define MV_VS_OP_REG_GET_IDX_VAL ((uint64_t)0x000000000000000D) /** @brief Defines the index for mv_vs_op_reg_set */ diff --git a/hypercall/include/mv_constants.hpp b/hypercall/include/mv_constants.hpp index 7bb5cb6be..773b557b6 100644 --- a/hypercall/include/mv_constants.hpp +++ b/hypercall/include/mv_constants.hpp @@ -493,10 +493,10 @@ namespace hypercall constexpr auto MV_VS_OP_CPUID_GET_IDX_VAL{0x0000000000000009_u64}; /// @brief Defines the index for mv_vs_op_cpuid_set constexpr auto MV_VS_OP_CPUID_SET_IDX_VAL{0x000000000000000A_u64}; - /// @brief Defines the index for mv_vs_op_cpuid_get_all - constexpr auto MV_VS_OP_CPUID_GET_ALL_IDX_VAL{0x000000000000000B_u64}; - /// @brief Defines the index for mv_vs_op_cpuid_set_all - constexpr auto MV_VS_OP_CPUID_SET_ALL_IDX_VAL{0x000000000000000C_u64}; + /// @brief Defines the index for mv_vs_op_cpuid_get_list + constexpr auto MV_VS_OP_CPUID_GET_LIST_IDX_VAL{0x000000000000000B_u64}; + /// @brief Defines the index for mv_vs_op_cpuid_set_list + constexpr auto MV_VS_OP_CPUID_SET_LIST_IDX_VAL{0x000000000000000C_u64}; /// @brief Defines the index for mv_vs_op_reg_get constexpr auto MV_VS_OP_REG_GET_IDX_VAL{0x000000000000000D_u64}; /// @brief Defines the index for mv_vs_op_reg_set diff --git a/hypercall/include/mv_cpuid_flag_t.h b/hypercall/include/mv_cpuid_flag_t.h index e08ae0f2f..6e3098f65 100644 --- a/hypercall/include/mv_cpuid_flag_t.h +++ b/hypercall/include/mv_cpuid_flag_t.h @@ -27,6 +27,8 @@ #ifndef MV_CPUID_FLAG_T_H #define MV_CPUID_FLAG_T_H +#include + #ifdef __cplusplus extern "C" { @@ -37,13 +39,13 @@ extern "C" * * @brief Defines CPUID flags */ - enum mv_cpuid_flag : int32_t + enum mv_cpuid_flag_t : int32_t #else /** * * @brief Defines CPUID flags */ -enum mv_cpuid_flag +enum mv_cpuid_flag_t #endif { /** @brief reserved */ diff --git a/hypercall/library.cmake b/hypercall/library.cmake index 8567c2fc4..2000bbc3d 100644 --- a/hypercall/library.cmake +++ b/hypercall/library.cmake @@ -135,6 +135,10 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STRE microv_target_source(hypercall src/windows/x64/amd/mv_vp_op_vmid_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/amd/mv_vp_op_vpid_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_create_vs_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_cpuid_get_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_cpuid_get_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_cpuid_set_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_cpuid_set_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_destroy_vs_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_fpu_get_all_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/amd/mv_vs_op_fpu_set_all_impl.S ${HEADERS}) @@ -177,6 +181,10 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STRE microv_target_source(hypercall src/linux/x64/amd/mv_vp_op_vmid_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/amd/mv_vp_op_vpid_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_create_vs_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_cpuid_get_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_cpuid_set_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_cpuid_set_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_destroy_vs_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_fpu_get_all_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/amd/mv_vs_op_fpu_set_all_impl.S ${HEADERS}) @@ -223,6 +231,10 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STRE microv_target_source(hypercall src/windows/x64/intel/mv_vp_op_vmid_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/intel/mv_vp_op_vpid_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_create_vs_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_cpuid_get_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_cpuid_get_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_cpuid_set_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_cpuid_set_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_destroy_vs_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_fpu_get_all_impl.S ${HEADERS}) microv_target_source(hypercall src/windows/x64/intel/mv_vs_op_fpu_set_all_impl.S ${HEADERS}) @@ -265,6 +277,10 @@ if(HYPERVISOR_TARGET_ARCH STREQUAL "AuthenticAMD" OR HYPERVISOR_TARGET_ARCH STRE microv_target_source(hypercall src/linux/x64/intel/mv_vp_op_vmid_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/intel/mv_vp_op_vpid_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_create_vs_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_cpuid_get_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_cpuid_get_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_cpuid_set_list_impl.S ${HEADERS}) + microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_cpuid_set_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_destroy_vs_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_fpu_get_all_impl.S ${HEADERS}) microv_target_source(hypercall src/linux/x64/intel/mv_vs_op_fpu_set_all_impl.S ${HEADERS}) diff --git a/hypercall/mocks/mv_hypercall.h b/hypercall/mocks/mv_hypercall.h index 1884aea71..38f905f59 100644 --- a/hypercall/mocks/mv_hypercall.h +++ b/hypercall/mocks/mv_hypercall.h @@ -27,6 +27,7 @@ #ifndef MOCKS_MV_HYPERCALL_H #define MOCKS_MV_HYPERCALL_H +#include #include #include #include @@ -738,6 +739,18 @@ extern "C" extern mv_status_t g_mut_mv_vs_op_mp_state_set; /** @brief stores the return value for mv_vs_op_tsc_get_khz */ extern mv_status_t g_mut_mv_vs_op_tsc_get_khz; + /** @brief stores the return value for mv_vs_op_cpuid_get */ + extern mv_status_t g_mut_mv_vs_op_cpuid_get; + /** @brief stores the out value of the shared page for mv_vs_op_cpuid_get */ + extern struct mv_cdl_entry_t g_mut_mv_vs_op_cpuid_get_entry; + /** @brief stores the return value for mv_vs_op_cpuid_set */ + extern mv_status_t g_mut_mv_vs_op_cpuid_set; + /** @brief stores the return value for mv_vs_op_cpuid_get_list */ + extern mv_status_t g_mut_mv_vs_op_cpuid_get_list; + /** @brief stores the out value of the shared page for mv_vs_op_cpuid_get_list */ + extern struct mv_cdl_entry_t g_mut_mv_vs_op_cpuid_get_list_entry; + /** @brief stores the return value for mv_vs_op_cpuid_set_list */ + extern mv_status_t g_mut_mv_vs_op_cpuid_set_list; /** * @@ -1465,6 +1478,154 @@ extern "C" return g_mut_mv_vs_op_tsc_get_khz; } + /** + * + * @brief Given the shared page cast as a single mv_cdl_entry_t, with + * mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested CPUID + * leaf, the same mv_cdl_entry_t is returned in the shared page with + * mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, mv_cdl_entry_t.ecx and + * mv_cdl_entry_t.edx set to the value seen by the VS as if CPUID were + * executed. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to query + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_get(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + struct mv_cdl_entry_t *const pmut_out = (struct mv_cdl_entry_t *const)g_mut_shared_pages[0]; + +#ifdef __cplusplus + bsl::expects(MV_INVALID_HANDLE != hndl); + bsl::expects(hndl > ((uint64_t)0)); + bsl::expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#else + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#endif + + *pmut_out = g_mut_mv_vs_op_cpuid_get_entry; + + return g_mut_mv_vs_op_cpuid_get; + } + + /** + * + * @brief Given the shared page cast as a single mv_cdl_entry_t, with + * mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested CPUID + * leaf, any feature bit in mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, + * mv_cdl_entry_t.ecx and mv_cdl_entry_t.edx set to 0 will disable the + * CPU feature for the requested VS. Any feature bit set to 1 is ignored + * by MicroV (meaning the CPU feature is left unmodified). Any + * non-feature bits are ignored. Note that mv_vs_op_cpuid_set can only be + * used to disabled CPU features. CPU features that are enabled are + * determined by hardware and MicroV's support for this hardware. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to set + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_set(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + +#ifdef __cplusplus + bsl::expects(MV_INVALID_HANDLE != hndl); + bsl::expects(hndl > ((uint64_t)0)); + bsl::expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#else + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#endif + + return g_mut_mv_vs_op_cpuid_set; + } + + /** + * + * @brief Given the shared page cast as a mv_cdl_t, with each entry's + * mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested CPUID + * leaf, the same entries are returned in the shared page with each + * entry's mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, mv_cdl_entry_t.ecx and + * mv_cdl_entry_t.edx set to the value seen by the VS as if CPUID were + * executed. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to query + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_get_list(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + uint64_t mut_i; + +#ifdef __cplusplus + bsl::expects(MV_INVALID_HANDLE != hndl); + bsl::expects(hndl > ((uint64_t)0)); + bsl::expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#else + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#endif + + struct mv_cdl_t *const pmut_out = (struct mv_cdl_t *)g_mut_shared_pages[0]; + +#ifdef __cplusplus + bsl::expects(nullptr != pmut_out); + bsl::expects(pmut_out->num_entries < MV_RDL_MAX_ENTRIES); +#else + platform_expects(NULL != pmut_out); + platform_expects(pmut_out->num_entries < MV_RDL_MAX_ENTRIES); +#endif + + for (mut_i = ((uint64_t)0); mut_i < pmut_out->num_entries; ++mut_i) { + pmut_out->entries[mut_i] = g_mut_mv_vs_op_cpuid_get_list_entry; + } + + return g_mut_mv_vs_op_cpuid_get_list; + } + + /** + * + * @brief This hypercall tells MicroV to set the values of multiple + * requested CPUIDs using a Register Descriptor List (RDL) in the shared + * page. For this ABI, the reg field of each mv_rdl_entry_t refers to + * the index of the CPUID. The val field refers to the value to set the + * requested CPUID in that entry to. This ABI does not use any of the + * reg 0-7 fields in the mv_rdl_t. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to set + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_set_list(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { +#ifdef __cplusplus + bsl::expects(MV_INVALID_HANDLE != hndl); + bsl::expects(hndl > ((uint64_t)0)); + bsl::expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#else + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); +#endif + + return g_mut_mv_vs_op_cpuid_set_list; + } + #ifdef __cplusplus } #endif diff --git a/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_impl.S b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_impl.S new file mode 100644 index 000000000..e1ab2caf9 --- /dev/null +++ b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_impl + .type mv_vs_op_cpuid_get_impl, @function +mv_vs_op_cpuid_get_impl: + + mov rax, 0x764D000000060009 + mov r10, rdi + mov r11, rsi + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_impl, .-mv_vs_op_cpuid_get_impl diff --git a/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.S b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.S new file mode 100644 index 000000000..3460c35d8 --- /dev/null +++ b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_list_impl + .type mv_vs_op_cpuid_get_list_impl, @function +mv_vs_op_cpuid_get_list_impl: + + mov rax, 0x764D00000006000B + mov r10, rdi + mov r11, rsi + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_list_impl, .-mv_vs_op_cpuid_get_list_impl diff --git a/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_impl.S b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_impl.S new file mode 100644 index 000000000..2b6b3e2b9 --- /dev/null +++ b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_impl + .type mv_vs_op_cpuid_set_impl, @function +mv_vs_op_cpuid_set_impl: + + mov rax, 0x764D00000006000A + mov r10, rdi + mov r11, rsi + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_impl, .-mv_vs_op_cpuid_set_impl diff --git a/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_list_impl.S b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_list_impl.S new file mode 100644 index 000000000..b3c53e2ab --- /dev/null +++ b/hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_list_impl + .type mv_vs_op_cpuid_set_list_impl, @function +mv_vs_op_cpuid_set_list_impl: + + mov rax, 0x764D00000006000C + mov r10, rdi + mov r11, rsi + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_list_impl, .-mv_vs_op_cpuid_set_list_impl diff --git a/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_impl.S b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_impl.S new file mode 100644 index 000000000..f1c4d8b11 --- /dev/null +++ b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_impl + .type mv_vs_op_cpuid_get_impl, @function +mv_vs_op_cpuid_get_impl: + + mov rax, 0x764D000000060009 + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_impl, .-mv_vs_op_cpuid_get_impl diff --git a/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_list_impl.S b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_list_impl.S new file mode 100644 index 000000000..bd0b83881 --- /dev/null +++ b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_list_impl + .type mv_vs_op_cpuid_get_list_impl, @function +mv_vs_op_cpuid_get_list_impl: + + mov rax, 0x764D00000006000B + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_list_impl, .-mv_vs_op_cpuid_get_list_impl diff --git a/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_impl.S b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_impl.S new file mode 100644 index 000000000..32892441b --- /dev/null +++ b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_impl + .type mv_vs_op_cpuid_set_impl, @function +mv_vs_op_cpuid_set_impl: + + mov rax, 0x764D00000006000A + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_impl, .-mv_vs_op_cpuid_set_impl diff --git a/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_list_impl.S b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_list_impl.S new file mode 100644 index 000000000..a2a133ed9 --- /dev/null +++ b/hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_list_impl + .type mv_vs_op_cpuid_set_list_impl, @function +mv_vs_op_cpuid_set_list_impl: + + mov rax, 0x764D00000006000C + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_list_impl, .-mv_vs_op_cpuid_set_list_impl diff --git a/hypercall/src/mv_hypercall.h b/hypercall/src/mv_hypercall.h index 40b401f31..fe093f6f4 100644 --- a/hypercall/src/mv_hypercall.h +++ b/hypercall/src/mv_hypercall.h @@ -1397,6 +1397,141 @@ extern "C" return mut_ret; } + /** + * + * @brief Given the shared page cast as a single mv_cdl_entry_t, with + * mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested CPUID + * leaf, the same mv_cdl_entry_t is returned in the shared page with + * mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, mv_cdl_entry_t.ecx and + * mv_cdl_entry_t.edx set to the value seen by the VS as if CPUID were + * executed. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to query + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_get(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + mv_status_t mut_ret; + + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); + + mut_ret = mv_vs_op_cpuid_get_impl(hndl, vsid); + if (mut_ret) { + bferror("mv_vs_op_cpuid_get failed"); + return mut_ret; + } + + return mut_ret; + } + + /** + * + * @brief Given the shared page cast as a single mv_cdl_entry_t, with + * mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested CPUID + * leaf, any feature bit in mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, + * mv_cdl_entry_t.ecx and mv_cdl_entry_t.edx set to 0 will disable the + * CPU feature for the requested VS. Any feature bit set to 1 is ignored + * by MicroV (meaning the CPU feature is left unmodified). Any + * non-feature bits are ignored. Note that mv_vs_op_cpuid_set can only be + * used to disabled CPU features. CPU features that are enabled are + * determined by hardware and MicroV's support for this hardware. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to set + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_set(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + mv_status_t mut_ret; + + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); + + mut_ret = mv_vs_op_cpuid_set_impl(hndl, vsid); + if (mut_ret) { + bferror("mv_vs_op_cpuid_set failed"); + return mut_ret; + } + + return mut_ret; + } + + /** + * + * @brief Given the shared page cast as a mv_cdl_t, with each entry's + * mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested CPUID + * leaf, the same entries are returned in the shared page with each + * entry's mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, mv_cdl_entry_t.ecx and + * mv_cdl_entry_t.edx set to the value seen by the VS as if CPUID were + * executed. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to query + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_get_list(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + mv_status_t mut_ret; + + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); + + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl, vsid); + if (mut_ret) { + bferror("mv_vs_op_cpuid_get_list failed"); + return mut_ret; + } + + return mut_ret; + } + + /** + * + * @brief This hypercall tells MicroV to set the values of multiple + * requested CPUIDs using a Register Descriptor List (RDL) in the shared + * page. For this ABI, the reg field of each mv_rdl_entry_t refers to + * the index of the CPUID. The val field refers to the value to set the + * requested CPUID in that entry to. This ABI does not use any of the + * reg 0-7 fields in the mv_rdl_t. + * + * + * @param hndl Set to the result of mv_handle_op_open_handle + * @param vsid The ID of the VS to set + * @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + * and friends on failure. + */ + NODISCARD static inline mv_status_t + mv_vs_op_cpuid_set_list(uint64_t const hndl, uint16_t const vsid) NOEXCEPT + { + mv_status_t mut_ret; + + platform_expects(MV_INVALID_HANDLE != hndl); + platform_expects(hndl > ((uint64_t)0)); + platform_expects((int32_t)MV_INVALID_ID != (int32_t)vsid); + + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl, vsid); + if (mut_ret) { + bferror("mv_vs_op_cpuid_set_list failed"); + return mut_ret; + } + + return mut_ret; + } + #ifdef __cplusplus } #endif diff --git a/hypercall/src/mv_hypercall_impl.h b/hypercall/src/mv_hypercall_impl.h index 01e4eaf59..e628b5909 100644 --- a/hypercall/src/mv_hypercall_impl.h +++ b/hypercall/src/mv_hypercall_impl.h @@ -572,6 +572,54 @@ extern "C" NODISCARD mv_status_t mv_vs_op_tsc_get_khz_impl( uint64_t const reg0_in, uint16_t const reg1_in, uint64_t *const pmut_reg0_out) NOEXCEPT; + /** + * + * @brief Implements the ABI for mv_vs_op_cpuid_get. + * + * + * @param reg0_in n/a + * @param reg1_in n/a + * @return n/a + */ + NODISCARD mv_status_t + mv_vs_op_cpuid_get_impl(uint64_t const reg0_in, uint16_t const reg1_in) NOEXCEPT; + + /** + * + * @brief Implements the ABI for mv_vs_op_cpuid_set. + * + * + * @param reg0_in n/a + * @param reg1_in n/a + * @return n/a + */ + NODISCARD mv_status_t + mv_vs_op_cpuid_set_impl(uint64_t const reg0_in, uint16_t const reg1_in) NOEXCEPT; + + /** + * + * @brief Implements the ABI for mv_vs_op_cpuid_get_list. + * + * + * @param reg0_in n/a + * @param reg1_in n/a + * @return n/a + */ + NODISCARD mv_status_t + mv_vs_op_cpuid_get_list_impl(uint64_t const reg0_in, uint16_t const reg1_in) NOEXCEPT; + + /** + * + * @brief Implements the ABI for mv_vs_op_cpuid_set_list. + * + * + * @param reg0_in n/a + * @param reg1_in n/a + * @return n/a + */ + NODISCARD mv_status_t + mv_vs_op_cpuid_set_list_impl(uint64_t const reg0_in, uint16_t const reg1_in) NOEXCEPT; + #ifdef __cplusplus } #endif diff --git a/hypercall/src/mv_hypercall_impl.hpp b/hypercall/src/mv_hypercall_impl.hpp index af8cc6671..4ac473742 100644 --- a/hypercall/src/mv_hypercall_impl.hpp +++ b/hypercall/src/mv_hypercall_impl.hpp @@ -571,6 +571,54 @@ namespace hypercall bsl::uint64 const reg0_in, bsl::uint16 const reg1_in, bsl::uint64 *const pmut_reg0_out) noexcept -> mv_status_t::value_type; + + /// + /// @brief Implements the ABI for mv_vs_op_cpuid_get. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @return n/a + /// + extern "C" [[nodiscard]] auto + mv_vs_op_cpuid_get_impl(bsl::uint64 const reg0_in, bsl::uint16 const reg1_in) noexcept + -> mv_status_t::value_type; + + /// + /// @brief Implements the ABI for mv_vs_op_cpuid_set. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @return n/a + /// + extern "C" [[nodiscard]] auto + mv_vs_op_cpuid_set_impl(bsl::uint64 const reg0_in, bsl::uint16 const reg1_in) noexcept + -> mv_status_t::value_type; + + /// + /// @brief Implements the ABI for mv_vs_op_cpuid_get_list. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @return n/a + /// + extern "C" [[nodiscard]] auto + mv_vs_op_cpuid_get_list_impl(bsl::uint64 const reg0_in, bsl::uint16 const reg1_in) noexcept + -> mv_status_t::value_type; + + /// + /// @brief Implements the ABI for mv_vs_op_cpuid_set_list. + /// + /// + /// @param reg0_in n/a + /// @param reg1_in n/a + /// @return n/a + /// + extern "C" [[nodiscard]] auto + mv_vs_op_cpuid_set_list_impl(bsl::uint64 const reg0_in, bsl::uint16 const reg1_in) noexcept + -> mv_status_t::value_type; } #endif diff --git a/hypercall/src/mv_hypercall_t.hpp b/hypercall/src/mv_hypercall_t.hpp index 59e3c34e9..1f48499b3 100644 --- a/hypercall/src/mv_hypercall_t.hpp +++ b/hypercall/src/mv_hypercall_t.hpp @@ -1519,6 +1519,143 @@ namespace hypercall return mut_freq; } + + /// + /// @brief Given the shared page cast as a single mv_cdl_entry_t, with + /// mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested + /// CPUID leaf, the same mv_cdl_entry_t is returned in the shared + /// page with mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, + /// mv_cdl_entry_t.ecx and mv_cdl_entry_t.edx set to the value seen + /// by the VS as if CPUID were executed. + /// + /// + /// @param vsid The ID of the VS to query + /// @return Returns the value read from the MSR + /// + [[nodiscard]] constexpr auto + mv_vs_op_cpuid_get(bsl::safe_u16 const &vsid) noexcept -> bsl::safe_u64 + { + bsl::safe_u64 mut_val{}; + + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(vsid != MV_INVALID_ID); + + mv_status_t const ret{mv_vs_op_cpuid_get_impl(m_hndl.get(), vsid.get())}; + if (bsl::unlikely(ret != MV_STATUS_SUCCESS)) { + bsl::error() << "mv_vs_op_cpuid_get failed with status " // -- + << bsl::hex(ret) // -- + << bsl::endl // -- + << bsl::here(); // -- + + return bsl::safe_u64::failure(); + } + + return mut_val; + } + + /// + /// @brief Given the shared page cast as a single mv_cdl_entry_t, with + /// mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested + /// CPUID leaf, any feature bit in mv_cdl_entry_t.eax, + /// mv_cdl_entry_t.ebx, mv_cdl_entry_t.ecx and mv_cdl_entry_t.edx + /// set to 0 will disable the CPU feature for the requested VS. + /// Any feature bit set to 1 is ignored by MicroV (meaning the CPU + /// feature is left unmodified). Any non-feature bits are ignored. + /// Note that mv_vs_op_cpuid_set can only be used to disabled CPU + /// features. CPU features that are enabled are determined by + /// hardware and MicroV's support for this hardware. + /// + /// + /// @param vsid The ID of the VS to set + /// @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + /// and friends on failure. + /// + [[nodiscard]] constexpr auto + mv_vs_op_cpuid_set(bsl::safe_u16 const &vsid) noexcept -> bsl::errc_type + { + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(vsid != MV_INVALID_ID); + + mv_status_t const ret{mv_vs_op_cpuid_set_impl(m_hndl.get(), vsid.get())}; + if (bsl::unlikely(ret != MV_STATUS_SUCCESS)) { + bsl::error() << "mv_vs_op_cpuid_set failed with status " // -- + << bsl::hex(ret) // -- + << bsl::endl // -- + << bsl::here(); // -- + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Given the shared page cast as a mv_cdl_t, with each entry's + /// mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested + /// CPUID leaf, the same entries are returned in the shared page + /// with each entry's mv_cdl_entry_t.eax, mv_cdl_entry_t.ebx, + /// mv_cdl_entry_t.ecx and mv_cdl_entry_t.edx set to the value seen + /// by the VS as if CPUID were executed. + /// + /// + /// @param vsid The ID of the VS to query + /// @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + /// and friends on failure. + /// + [[nodiscard]] constexpr auto + mv_vs_op_cpuid_get_list(bsl::safe_u16 const &vsid) noexcept -> bsl::errc_type + { + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(vsid != MV_INVALID_ID); + + mv_status_t const ret{mv_vs_op_cpuid_get_list_impl(m_hndl.get(), vsid.get())}; + if (bsl::unlikely(ret != MV_STATUS_SUCCESS)) { + bsl::error() << "mv_vs_op_cpuid_get_list failed with status " // -- + << bsl::hex(ret) // -- + << bsl::endl // -- + << bsl::here(); // -- + + return bsl::errc_failure; + } + + return bsl::errc_success; + } + + /// + /// @brief Given the shared page cast as a mv_cdl_t, with each entry's + /// mv_cdl_entry_t.fun and mv_cdl_entry_t.idx set to the requested + /// CPUID leaf, any feature bit in entry's mv_cdl_entry_t.eax, + /// mv_cdl_entry_t.ebx, mv_cdl_entry_t.ecx and mv_cdl_entry_t.edx + /// set to 0 will disable the CPU feature for the requested VS. Any + /// feature bit set to 1 is ignored by MicroV (meaning the CPU + /// feature is left unmodified). Any non-feature bits are ignored. + /// Note that mv_vs_op_cpuid_set can only be used to disabled CPU + /// features. CPU features that are enabled are determined by + /// hardware and MicroV's support for this hardware. + /// + /// + /// @param vsid The ID of the VS to set + /// @return Returns MV_STATUS_SUCCESS on success, MV_STATUS_FAILURE_UNKNOWN + /// and friends on failure. + /// + [[nodiscard]] constexpr auto + mv_vs_op_cpuid_set_list(bsl::safe_u16 const vsid) noexcept -> bsl::errc_type + { + bsl::expects(vsid.is_valid_and_checked()); + bsl::expects(vsid != MV_INVALID_ID); + + mv_status_t const ret{mv_vs_op_cpuid_set_list_impl(m_hndl.get(), vsid.get())}; + if (bsl::unlikely(ret != MV_STATUS_SUCCESS)) { + bsl::error() << "mv_vs_op_cpuid_set_list failed with status " // -- + << bsl::hex(ret) // -- + << bsl::endl // -- + << bsl::here(); // -- + + return bsl::errc_failure; + } + + return bsl::errc_success; + } }; } diff --git a/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_impl.S b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_impl.S new file mode 100644 index 000000000..727e9308d --- /dev/null +++ b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_impl + .type mv_vs_op_cpuid_get_impl, @function +mv_vs_op_cpuid_get_impl: + + mov rax, 0x764D000000060009 + mov r10, rcx + mov r11, rdx + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_impl, .-mv_vs_op_cpuid_get_impl diff --git a/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_list_impl.S b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_list_impl.S new file mode 100644 index 000000000..cb2172e4b --- /dev/null +++ b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_get_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_list_impl + .type mv_vs_op_cpuid_get_list_impl, @function +mv_vs_op_cpuid_get_list_impl: + + mov rax, 0x764D00000006000B + mov r10, rcx + mov r11, rdx + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_list_impl, .-mv_vs_op_cpuid_get_list_impl diff --git a/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_impl.S b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_impl.S new file mode 100644 index 000000000..0f2e30b09 --- /dev/null +++ b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_impl + .type mv_vs_op_cpuid_set_impl, @function +mv_vs_op_cpuid_set_impl: + + mov rax, 0x764D00000006000A + mov r10, rcx + mov r11, rdx + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_impl, .-mv_vs_op_cpuid_set_impl diff --git a/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_list_impl.S b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_list_impl.S new file mode 100644 index 000000000..3fd175969 --- /dev/null +++ b/hypercall/src/windows/x64/amd/mv_vs_op_cpuid_set_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_list_impl + .type mv_vs_op_cpuid_set_list_impl, @function +mv_vs_op_cpuid_set_list_impl: + + mov rax, 0x764D00000006000C + mov r10, rcx + mov r11, rdx + vmmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_list_impl, .-mv_vs_op_cpuid_set_list_impl diff --git a/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_impl.S b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_impl.S new file mode 100644 index 000000000..f1c4d8b11 --- /dev/null +++ b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_impl + .type mv_vs_op_cpuid_get_impl, @function +mv_vs_op_cpuid_get_impl: + + mov rax, 0x764D000000060009 + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_impl, .-mv_vs_op_cpuid_get_impl diff --git a/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_list_impl.S b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_list_impl.S new file mode 100644 index 000000000..bd0b83881 --- /dev/null +++ b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_get_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_get_list_impl + .type mv_vs_op_cpuid_get_list_impl, @function +mv_vs_op_cpuid_get_list_impl: + + mov rax, 0x764D00000006000B + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_get_list_impl, .-mv_vs_op_cpuid_get_list_impl diff --git a/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_impl.S b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_impl.S new file mode 100644 index 000000000..32892441b --- /dev/null +++ b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_impl + .type mv_vs_op_cpuid_set_impl, @function +mv_vs_op_cpuid_set_impl: + + mov rax, 0x764D00000006000A + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_impl, .-mv_vs_op_cpuid_set_impl diff --git a/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_list_impl.S b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_list_impl.S new file mode 100644 index 000000000..a2a133ed9 --- /dev/null +++ b/hypercall/src/windows/x64/intel/mv_vs_op_cpuid_set_list_impl.S @@ -0,0 +1,42 @@ +/** + * @copyright + * Copyright (C) 2020 Assured Information Security, Inc. + * + * @copyright + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * @copyright + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * @copyright + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + .code64 + .intel_syntax noprefix + + .globl mv_vs_op_cpuid_set_list_impl + .type mv_vs_op_cpuid_set_list_impl, @function +mv_vs_op_cpuid_set_list_impl: + + mov rax, 0x764D00000006000C + mov r10, rdi + mov r11, rsi + vmcall + + ret + int 3 + + .size mv_vs_op_cpuid_set_list_impl, .-mv_vs_op_cpuid_set_list_impl diff --git a/hypercall/tests/mocks/mv_hypercall.cpp b/hypercall/tests/mocks/mv_hypercall.cpp index fe49332a9..926bb29b2 100644 --- a/hypercall/tests/mocks/mv_hypercall.cpp +++ b/hypercall/tests/mocks/mv_hypercall.cpp @@ -24,6 +24,7 @@ #include "../../mocks/mv_hypercall.h" +#include #include #include #include @@ -33,6 +34,7 @@ #include #include +#include #include #include @@ -88,6 +90,12 @@ namespace shim constinit mv_status_t g_mut_mv_vs_op_mp_state_get{}; constinit mv_status_t g_mut_mv_vs_op_mp_state_set{}; constinit mv_status_t g_mut_mv_vs_op_tsc_get_khz{}; + constinit mv_status_t g_mut_mv_vs_op_cpuid_get{}; + constinit mv_cdl_entry_t g_mut_mv_vs_op_cpuid_get_entry{}; + constinit mv_status_t g_mut_mv_vs_op_cpuid_set{}; + constinit mv_status_t g_mut_mv_vs_op_cpuid_get_list{}; + constinit mv_cdl_entry_t g_mut_mv_vs_op_cpuid_get_list_entry{}; + constinit mv_status_t g_mut_mv_vs_op_cpuid_set_list{}; extern bool g_mut_hypervisor_detected; extern bool g_mut_platform_alloc_fails; @@ -644,6 +652,102 @@ namespace shim }; }; + bsl::ut_scenario{"mv_vs_op_cpuid_get"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + constexpr auto hypercall{&mv_vs_op_cpuid_get}; + constexpr auto expected{42_u32}; + mv_cdl_entry_t mut_cdl_entry{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_shared_pages[0] = &mut_cdl_entry; + g_mut_val = bsl::to_u64(expected).get(); + g_mut_mv_vs_op_cpuid_get = bsl::to_u64(expected.get()).get(); + g_mut_mv_vs_op_cpuid_get_entry = { + .fun = expected.get(), + .idx = expected.get(), + .eax = expected.get(), + .ebx = expected.get(), + .ecx = expected.get(), + .edx = expected.get(), + }; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(bsl::to_u64(expected) == hypercall(hndl, {})); + bsl::ut_check(expected == mut_cdl_entry.fun); + bsl::ut_check(expected == mut_cdl_entry.idx); + bsl::ut_check(expected == mut_cdl_entry.eax); + bsl::ut_check(expected == mut_cdl_entry.ebx); + bsl::ut_check(expected == mut_cdl_entry.ecx); + bsl::ut_check(expected == mut_cdl_entry.edx); + }; + }; + }; + }; + + bsl::ut_scenario{"mv_vs_op_cpuid_set"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + constexpr auto hypercall{&mv_vs_op_cpuid_set}; + constexpr auto expected{42_u64}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_cpuid_set = expected.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(expected == hypercall(hndl, {})); + }; + }; + }; + }; + + bsl::ut_scenario{"mv_vs_op_cpuid_get_list"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + constexpr auto hypercall{&mv_vs_op_cpuid_get_list}; + constexpr auto expected{42_u32}; + constexpr struct mv_cdl_entry_t expected_entry + { + .fun = expected.get(), .idx = expected.get(), .eax = expected.get(), + .ebx = expected.get(), .ecx = expected.get(), .edx = expected.get() + }; + mv_cdl_t mut_cdl{}; + bsl::ut_when{} = [&]() noexcept { + mut_cdl.num_entries = bsl::safe_u64::magic_2().get(); + g_mut_shared_pages[0] = &mut_cdl; + g_mut_val = bsl::to_u64(expected).get(); + g_mut_mv_vs_op_cpuid_get_list = bsl::to_u64(expected).get(); + g_mut_mv_vs_op_cpuid_get_list_entry = expected_entry; + bsl::ut_then{} = [&]() noexcept { + auto mut_i{bsl::safe_idx::magic_0()}; + for (; mut_i < bsl::safe_idx::magic_2(); ++mut_i) { + bsl::ut_check(bsl::to_u64(expected) == hypercall(hndl, {})); + bsl::ut_check(expected_entry.fun == mut_cdl.entries[mut_i.get()].fun); + bsl::ut_check(expected_entry.idx == mut_cdl.entries[mut_i.get()].idx); + bsl::ut_check(expected_entry.eax == mut_cdl.entries[mut_i.get()].eax); + bsl::ut_check(expected_entry.ebx == mut_cdl.entries[mut_i.get()].ebx); + bsl::ut_check(expected_entry.ecx == mut_cdl.entries[mut_i.get()].ecx); + bsl::ut_check(expected_entry.edx == mut_cdl.entries[mut_i.get()].edx); + } + ++mut_i; + bsl::ut_check(bsl::to_u64(expected) == hypercall(hndl, {})); + bsl::ut_check(expected_entry.fun != mut_cdl.entries[mut_i.get()].fun); + bsl::ut_check(expected_entry.idx != mut_cdl.entries[mut_i.get()].idx); + bsl::ut_check(expected_entry.eax != mut_cdl.entries[mut_i.get()].eax); + bsl::ut_check(expected_entry.ebx != mut_cdl.entries[mut_i.get()].ebx); + bsl::ut_check(expected_entry.ecx != mut_cdl.entries[mut_i.get()].ecx); + bsl::ut_check(expected_entry.edx != mut_cdl.entries[mut_i.get()].edx); + }; + }; + }; + }; + + bsl::ut_scenario{"mv_vs_op_cpuid_set_list"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + constexpr auto hypercall{&mv_vs_op_cpuid_set_list}; + constexpr auto expected{42_u64}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_cpuid_set_list = expected.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(expected == hypercall(hndl, {})); + }; + }; + }; + }; + return bsl::ut_success(); } } diff --git a/shim/linux/Makefile b/shim/linux/Makefile index 8b95190e1..880f0c59f 100644 --- a/shim/linux/Makefile +++ b/shim/linux/Makefile @@ -163,6 +163,10 @@ ifneq ($(KERNELRELEASE),) $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vp_op_destroy_vp_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vp_op_vmid_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vp_op_vpid_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_list_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_cpuid_set_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_create_vs_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_destroy_vs_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/amd/mv_vs_op_gla_to_gpa_impl.o @@ -222,6 +226,10 @@ ifneq ($(KERNELRELEASE),) $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vp_op_destroy_vp_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vp_op_vmid_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vp_op_vpid_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_list_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_cpuid_get_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_list_impl.o + $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_cpuid_set_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_create_vs_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_destroy_vs_impl.o $(TARGET_MODULE)-objs += ../../hypercall/src/linux/x64/intel/mv_vs_op_gla_to_gpa_impl.o diff --git a/vmm/include/x64/cpuid.hpp b/vmm/include/x64/cpuid.hpp index 873457cfb..d37cf1874 100644 --- a/vmm/include/x64/cpuid.hpp +++ b/vmm/include/x64/cpuid.hpp @@ -30,13 +30,22 @@ namespace microv { + /// @brief the total number of standard CPUID functions supported + constexpr auto CPUID_NUM_STD_FUNCTIONS{5_idx}; + /// @brief the maximum number of standard CPUID indexes supported + constexpr auto CPUID_NUM_STD_INDEXES{1_idx}; /// @brief the vendor-id and largest standard function CPUID constexpr auto CPUID_FN0000_0000{0x00000000_u32}; - /// @brief the feature information CPUID + /// @brief the standard feature information CPUID constexpr auto CPUID_FN0000_0001{0x00000001_u32}; + + /// @brief the total number of extended CPUID functions supported + constexpr auto CPUID_NUM_EXT_FUNCTIONS{5_idx}; + /// @brief the maximum number of extended CPUID indexes supported + constexpr auto CPUID_NUM_EXT_INDEXES{1_idx}; /// @brief the largest extended function CPUID constexpr auto CPUID_FN8000_0000{0x80000000_u32}; - /// @brief the extended feature bits + /// @brief the extended feature information CPUID constexpr auto CPUID_FN8000_0001{0x80000001_u32}; /// @brief the processor brand string constexpr auto CPUID_FN8000_0002{0x80000002_u32}; diff --git a/vmm/integration/CMakeLists.txt b/vmm/integration/CMakeLists.txt index be2efa8af..db95c9f72 100644 --- a/vmm/integration/CMakeLists.txt +++ b/vmm/integration/CMakeLists.txt @@ -48,6 +48,10 @@ microv_add_vmm_integration(mv_vp_op_create_vp HEADERS) microv_add_vmm_integration(mv_vp_op_destroy_vp HEADERS) microv_add_vmm_integration(mv_vp_op_vmid HEADERS) microv_add_vmm_integration(mv_vp_op_vpid HEADERS) +microv_add_vmm_integration(mv_vs_op_cpuid_get_list HEADERS) +#microv_add_vmm_integration(mv_vs_op_cpuid_get HEADERS) +microv_add_vmm_integration(mv_vs_op_cpuid_set_list HEADERS) +#microv_add_vmm_integration(mv_vs_op_cpuid_set HEADERS) microv_add_vmm_integration(mv_vs_op_create_vs HEADERS) microv_add_vmm_integration(mv_vs_op_destroy_vs HEADERS) microv_add_vmm_integration(mv_vs_op_fpu_get_all HEADERS) diff --git a/vmm/integration/mv_vs_op_cpuid_get_list.cpp b/vmm/integration/mv_vs_op_cpuid_get_list.cpp new file mode 100644 index 000000000..be3dcf4d0 --- /dev/null +++ b/vmm/integration/mv_vs_op_cpuid_get_list.cpp @@ -0,0 +1,341 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include + +namespace hypercall +{ + /// @brief the standard feature information CPUID + constexpr auto CPUID_FN0000_0001{0x00000001_u32}; + /// @brief the extended feature information CPUID + constexpr auto CPUID_FN8000_0001{0x80000001_u32}; + + /// + /// @brief Get the CPUID supported list into the shared page + /// + constexpr void + cpuid_get_supported_list() noexcept + { + auto *const pmut_cdl0{to_0()}; + + // Get the list of supported CPUID features + + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + pmut_cdl0->num_entries = (2_u64).get(); + pmut_cdl0->entries.at_if(0_idx)->fun = CPUID_FN0000_0001.get(); + pmut_cdl0->entries.at_if(1_idx)->fun = CPUID_FN8000_0001.get(); + + integration::verify(mut_hvc.mv_pp_op_cpuid_get_supported_list()); + integration::verify(pmut_cdl0->num_entries == bsl::safe_u64::magic_2()); + } + + /// + /// @brief Always returns bsl::exit_success. If a failure occurs, + /// this function will exit early. + /// + /// + /// @return Always returns bsl::exit_success. If a failure occurs, + /// this function will exit early. + /// + [[nodiscard]] constexpr auto + tests() noexcept -> bsl::exit_code + { + mv_status_t mut_ret{}; + + integration::initialize_globals(); + auto *const pmut_cdl0{to_0()}; + auto *const pmut_cdl1{to_1()}; + + // invalid VSID #1 + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), MV_INVALID_ID.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // invalid VSID #2 + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), MV_SELF_ID.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // invalid VSID #3 + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), vsid0.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // invalid VSID #4 + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), vsid1.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // VSID out of range + auto const oor{bsl::to_u16(HYPERVISOR_MAX_VSS + bsl::safe_u64::magic_1()).checked()}; + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), oor.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // VSID not yet created + auto const nyc{bsl::to_u16(HYPERVISOR_MAX_VSS - bsl::safe_u64::magic_1()).checked()}; + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), nyc.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // No shared paged + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), self.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + integration::initialize_shared_pages(); + pmut_cdl0->num_entries = bsl::safe_u64::magic_1().get(); + + // register unsupported + constexpr auto unsupported_cpuid{0xFFFFFFFF_u32}; + pmut_cdl0->entries.front().fun = unsupported_cpuid.get(); + mut_ret = mv_vs_op_cpuid_get_list_impl(hndl.get(), self.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // empty CDL + { + pmut_cdl0->num_entries = {}; + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + integration::verify(!mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // CDL num entries out of range + { + pmut_cdl0->num_entries = + (MV_CDL_MAX_ENTRIES + bsl::safe_u64::magic_1()).checked().get(); + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + integration::verify(!mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // Enable unsupported CPUID features + { + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + cpuid_get_supported_list(); + + auto &mut_entry_fn0000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_0())}; + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.edx != bsl::safe_u32::magic_0()); + auto &mut_entry_fn8000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_1())}; + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.edx != bsl::safe_u32::magic_0()); + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + auto const fn0000_0001_entry_copy{mut_entry_fn0000_0001}; + auto const fn8000_0001_entry_copy{mut_entry_fn8000_0001}; + + // Try to enable all possible features + mut_entry_fn0000_0001.ecx = bsl::safe_u32::max_value().get(); + mut_entry_fn8000_0001.ecx = bsl::safe_u32::max_value().get(); + + integration::verify(mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + mut_entry_fn0000_0001.eax = {}; + mut_entry_fn0000_0001.ebx = {}; + mut_entry_fn0000_0001.ecx = {}; + mut_entry_fn0000_0001.edx = {}; + + mut_entry_fn8000_0001.eax = {}; + mut_entry_fn8000_0001.ebx = {}; + mut_entry_fn8000_0001.ecx = {}; + mut_entry_fn8000_0001.edx = {}; + + // Enabled features should not have changed + integration::verify(mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + integration::verify(mut_entry_fn0000_0001.ecx == fn0000_0001_entry_copy.ecx); + integration::verify(mut_entry_fn8000_0001.ecx == fn8000_0001_entry_copy.ecx); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // Disable CPUID features + { + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + cpuid_get_supported_list(); + + auto &mut_entry_fn0000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_0())}; + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.edx != bsl::safe_u32::magic_0()); + auto &mut_entry_fn8000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_1())}; + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.edx != bsl::safe_u32::magic_0()); + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + // Disable features + mut_entry_fn0000_0001.ecx = bsl::safe_u32::magic_0().get(); + mut_entry_fn8000_0001.ecx = bsl::safe_u32::magic_0().get(); + + integration::verify(mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + mut_entry_fn0000_0001.eax = {}; + mut_entry_fn0000_0001.ebx = {}; + mut_entry_fn0000_0001.ecx = {}; + mut_entry_fn0000_0001.edx = {}; + + mut_entry_fn8000_0001.eax = {}; + mut_entry_fn8000_0001.ebx = {}; + mut_entry_fn8000_0001.ecx = {}; + mut_entry_fn8000_0001.edx = {}; + + // Features should now be disabled + integration::verify(mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + integration::verify(mut_entry_fn0000_0001.ecx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.ecx == bsl::safe_u32::magic_0()); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // CPU affinity test (requires more than one core) + { + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + pmut_cdl0->num_entries = bsl::safe_u64::magic_1().get(); + pmut_cdl0->entries.front().fun = CPUID_FN0000_0001.get(); + pmut_cdl0->entries.front().idx = {}; + pmut_cdl0->entries.front().eax = {}; + pmut_cdl0->entries.front().ebx = {}; + pmut_cdl0->entries.front().ecx = {}; + pmut_cdl0->entries.front().edx = {}; + + pmut_cdl1->num_entries = bsl::safe_u64::magic_1().get(); + pmut_cdl1->entries.front().fun = CPUID_FN0000_0001.get(); + pmut_cdl1->entries.front().idx = {}; + pmut_cdl1->entries.front().eax = {}; + pmut_cdl1->entries.front().ebx = {}; + pmut_cdl1->entries.front().ecx = {}; + pmut_cdl1->entries.front().edx = {}; + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + integration::set_affinity(core0); + integration::verify(mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + integration::set_affinity(core1); + integration::verify(mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + integration::set_affinity(core0); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + return bsl::exit_success; + } +} + +/// +/// @brief Provides the main entry point for this application. +/// +/// +/// @return bsl::exit_success on success, bsl::exit_failure otherwise. +/// +[[nodiscard]] auto +main() noexcept -> bsl::exit_code +{ + bsl::enable_color(); + return hypercall::tests(); +} diff --git a/vmm/integration/mv_vs_op_cpuid_set_list.cpp b/vmm/integration/mv_vs_op_cpuid_set_list.cpp new file mode 100644 index 000000000..2ef8e419a --- /dev/null +++ b/vmm/integration/mv_vs_op_cpuid_set_list.cpp @@ -0,0 +1,341 @@ +/// @copyright +/// Copyright (C) 2020 Assured Information Security, Inc. +/// +/// @copyright +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// @copyright +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// @copyright +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +/// SOFTWARE. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include + +namespace hypercall +{ + /// @brief the standard feature information CPUID + constexpr auto CPUID_FN0000_0001{0x00000001_u32}; + /// @brief the extended feature information CPUID + constexpr auto CPUID_FN8000_0001{0x80000001_u32}; + + /// + /// @brief Get the CPUID supported list into the shared page + /// + constexpr void + cpuid_get_supported_list() noexcept + { + auto *const pmut_cdl0{to_0()}; + + // Get the list of supported CPUID features + + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + pmut_cdl0->num_entries = (2_u64).get(); + pmut_cdl0->entries.at_if(0_idx)->fun = CPUID_FN0000_0001.get(); + pmut_cdl0->entries.at_if(1_idx)->fun = CPUID_FN8000_0001.get(); + + integration::verify(mut_hvc.mv_pp_op_cpuid_get_supported_list()); + integration::verify(pmut_cdl0->num_entries == bsl::safe_u64::magic_2()); + } + + /// + /// @brief Always returns bsl::exit_success. If a failure occurs, + /// this function will exit early. + /// + /// + /// @return Always returns bsl::exit_success. If a failure occurs, + /// this function will exit early. + /// + [[nodiscard]] constexpr auto + tests() noexcept -> bsl::exit_code + { + mv_status_t mut_ret{}; + + integration::initialize_globals(); + auto *const pmut_cdl0{to_0()}; + auto *const pmut_cdl1{to_1()}; + + // invalid VSID #1 + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), MV_INVALID_ID.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // invalid VSID #2 + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), MV_SELF_ID.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // invalid VSID #3 + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), vsid0.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // invalid VSID #4 + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), vsid1.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // VSID out of range + auto const oor{bsl::to_u16(HYPERVISOR_MAX_VSS + bsl::safe_u64::magic_1()).checked()}; + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), oor.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // VSID not yet created + auto const nyc{bsl::to_u16(HYPERVISOR_MAX_VSS - bsl::safe_u64::magic_1()).checked()}; + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), nyc.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // No shared paged + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), self.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + integration::initialize_shared_pages(); + pmut_cdl0->num_entries = bsl::safe_u64::magic_1().get(); + + // register unsupported + constexpr auto unsupported_cpuid{0xFFFFFFFF_u32}; + pmut_cdl0->entries.front().fun = unsupported_cpuid.get(); + mut_ret = mv_vs_op_cpuid_set_list_impl(hndl.get(), self.get()); + integration::verify(mut_ret != MV_STATUS_SUCCESS); + + // empty CDL + { + pmut_cdl0->num_entries = {}; + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + integration::verify(!mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // CDL num entries out of range + { + pmut_cdl0->num_entries = + (MV_CDL_MAX_ENTRIES + bsl::safe_u64::magic_1()).checked().get(); + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + integration::verify(!mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // Enable unsupported CPUID features + { + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + cpuid_get_supported_list(); + + auto &mut_entry_fn0000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_0())}; + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.edx != bsl::safe_u32::magic_0()); + auto &mut_entry_fn8000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_1())}; + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.edx != bsl::safe_u32::magic_0()); + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + auto const fn0000_0001_entry_copy{mut_entry_fn0000_0001}; + auto const fn8000_0001_entry_copy{mut_entry_fn8000_0001}; + + // Try to enable all possible features + mut_entry_fn0000_0001.ecx = bsl::safe_u32::max_value().get(); + mut_entry_fn8000_0001.ecx = bsl::safe_u32::max_value().get(); + + integration::verify(mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + mut_entry_fn0000_0001.eax = {}; + mut_entry_fn0000_0001.ebx = {}; + mut_entry_fn0000_0001.ecx = {}; + mut_entry_fn0000_0001.edx = {}; + + mut_entry_fn8000_0001.eax = {}; + mut_entry_fn8000_0001.ebx = {}; + mut_entry_fn8000_0001.ecx = {}; + mut_entry_fn8000_0001.edx = {}; + + // Enabled features should not have changed + integration::verify(mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + integration::verify(mut_entry_fn0000_0001.ecx == fn0000_0001_entry_copy.ecx); + integration::verify(mut_entry_fn8000_0001.ecx == fn8000_0001_entry_copy.ecx); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // Disable CPUID features + { + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + cpuid_get_supported_list(); + + auto &mut_entry_fn0000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_0())}; + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn0000_0001.edx != bsl::safe_u32::magic_0()); + auto &mut_entry_fn8000_0001{*pmut_cdl0->entries.at_if(bsl::safe_idx::magic_1())}; + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.ecx != bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.edx != bsl::safe_u32::magic_0()); + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + // Disable features + mut_entry_fn0000_0001.ecx = bsl::safe_u32::magic_0().get(); + mut_entry_fn8000_0001.ecx = bsl::safe_u32::magic_0().get(); + + integration::verify(mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + mut_entry_fn0000_0001.eax = {}; + mut_entry_fn0000_0001.ebx = {}; + mut_entry_fn0000_0001.ecx = {}; + mut_entry_fn0000_0001.edx = {}; + + mut_entry_fn8000_0001.eax = {}; + mut_entry_fn8000_0001.ebx = {}; + mut_entry_fn8000_0001.ecx = {}; + mut_entry_fn8000_0001.edx = {}; + + // Features should now be disabled + integration::verify(mut_hvc.mv_vs_op_cpuid_get_list(vsid)); + integration::verify(mut_entry_fn0000_0001.fun == CPUID_FN0000_0001); + integration::verify(mut_entry_fn0000_0001.idx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.fun == CPUID_FN8000_0001); + integration::verify(mut_entry_fn8000_0001.idx == bsl::safe_u32::magic_0()); + + integration::verify(mut_entry_fn0000_0001.ecx == bsl::safe_u32::magic_0()); + integration::verify(mut_entry_fn8000_0001.ecx == bsl::safe_u32::magic_0()); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + // CPU affinity test (requires more than one core) + { + bsl::builtin_memset(pmut_cdl0, '\0', bsl::to_umx(sizeof(*pmut_cdl0))); + + pmut_cdl0->num_entries = bsl::safe_u64::magic_1().get(); + pmut_cdl0->entries.front().fun = CPUID_FN0000_0001.get(); + pmut_cdl0->entries.front().idx = {}; + pmut_cdl0->entries.front().eax = {}; + pmut_cdl0->entries.front().ebx = {}; + pmut_cdl0->entries.front().ecx = {}; + pmut_cdl0->entries.front().edx = {}; + + pmut_cdl1->num_entries = bsl::safe_u64::magic_1().get(); + pmut_cdl1->entries.front().fun = CPUID_FN0000_0001.get(); + pmut_cdl1->entries.front().idx = {}; + pmut_cdl1->entries.front().eax = {}; + pmut_cdl1->entries.front().ebx = {}; + pmut_cdl1->entries.front().ecx = {}; + pmut_cdl1->entries.front().edx = {}; + + auto const vmid{mut_hvc.mv_vm_op_create_vm()}; + auto const vpid{mut_hvc.mv_vp_op_create_vp(vmid)}; + auto const vsid{mut_hvc.mv_vs_op_create_vs(vpid)}; + + integration::verify(vmid.is_valid_and_checked()); + integration::verify(vpid.is_valid_and_checked()); + integration::verify(vsid.is_valid_and_checked()); + + integration::set_affinity(core0); + integration::verify(mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + integration::set_affinity(core1); + integration::verify(mut_hvc.mv_vs_op_cpuid_set_list(vsid)); + integration::set_affinity(core0); + + integration::verify(mut_hvc.mv_vs_op_destroy_vs(vsid)); + integration::verify(mut_hvc.mv_vp_op_destroy_vp(vpid)); + integration::verify(mut_hvc.mv_vm_op_destroy_vm(vmid)); + } + + return bsl::exit_success; + } +} + +/// +/// @brief Provides the main entry point for this application. +/// +/// +/// @return bsl::exit_success on success, bsl::exit_failure otherwise. +/// +[[nodiscard]] auto +main() noexcept -> bsl::exit_code +{ + bsl::enable_color(); + return hypercall::tests(); +} diff --git a/vmm/src/dispatch_vmcall_mv_vs_op.hpp b/vmm/src/dispatch_vmcall_mv_vs_op.hpp index e1f7ecf33..479d48ef0 100644 --- a/vmm/src/dispatch_vmcall_mv_vs_op.hpp +++ b/vmm/src/dispatch_vmcall_mv_vs_op.hpp @@ -790,6 +790,148 @@ namespace microv return vmexit_success_advance_ip_and_run; } + /// + /// @brief Implements the handle_mv_vs_op_cpuid_get hypercall + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param mut_vs_pool the vs_pool_t to use + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + handle_mv_vs_op_cpuid_get(syscall::bf_syscall_t &mut_sys, vs_pool_t &mut_vs_pool) noexcept + -> bsl::errc_type + { + bsl::discard(mut_sys); + bsl::discard(mut_vs_pool); + + bsl::error() << "cpuid_get: Not yet implemented" // -- + << bsl::endl // -- + << bsl::here(); // -- + + return vmexit_failure_advance_ip_and_run; + } + + /// + /// @brief Implements the handle_mv_vs_op_cpuid_set hypercall + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param mut_vs_pool the vs_pool_t to use + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + handle_mv_vs_op_cpuid_set(syscall::bf_syscall_t &mut_sys, vs_pool_t &mut_vs_pool) noexcept + -> bsl::errc_type + { + bsl::discard(mut_sys); + bsl::discard(mut_vs_pool); + + bsl::error() << "cpuid_get: Not yet implemented" // -- + << bsl::endl // -- + << bsl::here(); // -- + + return vmexit_failure_advance_ip_and_run; + } + + /// + /// @brief Implements the handle_mv_vs_op_cpuid_get_list hypercall + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param mut_pp_pool the pp_pool_t to use + /// @param mut_vs_pool the vs_pool_t to use + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + handle_mv_vs_op_cpuid_get_list( + syscall::bf_syscall_t &mut_sys, pp_pool_t &mut_pp_pool, vs_pool_t &mut_vs_pool) noexcept + -> bsl::errc_type + { + bsl::errc_type mut_ret{}; + + auto const vsid{get_allocated_non_self_vsid(mut_sys, get_reg1(mut_sys), mut_vs_pool)}; + if (bsl::unlikely(vsid.is_invalid())) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_INVALID_INPUT_REG1); + return vmexit_failure_advance_ip_and_run; + } + + auto mut_cdl{mut_pp_pool.shared_page(mut_sys)}; + if (bsl::unlikely(mut_cdl.is_invalid())) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_FAILURE_UNKNOWN); + return vmexit_failure_advance_ip_and_run; + } + + bool const cdl_safe{is_cdl_safe(*mut_cdl)}; + if (bsl::unlikely(!cdl_safe)) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_FAILURE_UNKNOWN); + return vmexit_failure_advance_ip_and_run; + } + + mut_ret = mut_vs_pool.cpuid_get_list(mut_sys, vsid, *mut_cdl); + if (bsl::unlikely(!mut_ret)) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_FAILURE_UNKNOWN); + return vmexit_failure_advance_ip_and_run; + } + + return vmexit_success_advance_ip_and_run; + } + + /// + /// @brief Implements the handle_mv_vs_op_cpuid_set_list hypercall + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param mut_pp_pool the pp_pool_t to use + /// @param mut_vs_pool the vs_pool_t to use + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + handle_mv_vs_op_cpuid_set_list( + syscall::bf_syscall_t &mut_sys, pp_pool_t &mut_pp_pool, vs_pool_t &mut_vs_pool) noexcept + -> bsl::errc_type + { + bsl::errc_type mut_ret{}; + + auto const vsid{get_allocated_non_self_vsid(mut_sys, get_reg1(mut_sys), mut_vs_pool)}; + if (bsl::unlikely(vsid.is_invalid())) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_INVALID_INPUT_REG1); + return vmexit_failure_advance_ip_and_run; + } + + auto const cdl{mut_pp_pool.shared_page(mut_sys)}; + if (bsl::unlikely(cdl.is_invalid())) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_FAILURE_UNKNOWN); + return vmexit_failure_advance_ip_and_run; + } + + bool const cdl_safe{is_cdl_safe(*cdl)}; + if (bsl::unlikely(!cdl_safe)) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_FAILURE_UNKNOWN); + return vmexit_failure_advance_ip_and_run; + } + + mut_ret = mut_vs_pool.cpuid_set_list(mut_sys, vsid, *cdl); + if (bsl::unlikely(!mut_ret)) { + bsl::print() << bsl::here(); + set_reg_return(mut_sys, hypercall::MV_STATUS_FAILURE_UNKNOWN); + return vmexit_failure_advance_ip_and_run; + } + + return vmexit_success_advance_ip_and_run; + } + /// /// @brief Dispatches virtual processor state VMCalls. /// @@ -1046,6 +1188,46 @@ namespace microv return ret; } + case hypercall::MV_VS_OP_CPUID_GET_IDX_VAL.get(): { + auto const ret{handle_mv_vs_op_cpuid_get(mut_sys, mut_vs_pool)}; + if (bsl::unlikely(!ret)) { + bsl::print() << bsl::here(); + return ret; + } + + return ret; + } + + case hypercall::MV_VS_OP_CPUID_SET_IDX_VAL.get(): { + auto const ret{handle_mv_vs_op_cpuid_set(mut_sys, mut_vs_pool)}; + if (bsl::unlikely(!ret)) { + bsl::print() << bsl::here(); + return ret; + } + + return ret; + } + + case hypercall::MV_VS_OP_CPUID_GET_LIST_IDX_VAL.get(): { + auto const ret{handle_mv_vs_op_cpuid_get_list(mut_sys, mut_pp_pool, mut_vs_pool)}; + if (bsl::unlikely(!ret)) { + bsl::print() << bsl::here(); + return ret; + } + + return ret; + } + + case hypercall::MV_VS_OP_CPUID_SET_LIST_IDX_VAL.get(): { + auto const ret{handle_mv_vs_op_cpuid_set_list(mut_sys, mut_pp_pool, mut_vs_pool)}; + if (bsl::unlikely(!ret)) { + bsl::print() << bsl::here(); + return ret; + } + + return ret; + } + default: { break; } diff --git a/vmm/src/vs_pool_t.hpp b/vmm/src/vs_pool_t.hpp index 7bce134e6..a19410aa8 100644 --- a/vmm/src/vs_pool_t.hpp +++ b/vmm/src/vs_pool_t.hpp @@ -771,6 +771,101 @@ namespace microv { return this->get_vs(vsid)->tsc_khz_get(); } + + /// + /// @brief Returns the registers of the requested CPUID into + /// the provided CDL entry. + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param vsid the ID of the vs_t to query + /// @param mut_cdl_entry the mv_cdl_entry_t to read the CPUID into + /// @return Returns the value of the requested CPUID + /// + [[nodiscard]] static constexpr auto + cpuid_get( + syscall::bf_syscall_t &mut_sys, + bsl::safe_u16 const &vsid, + hypercall::mv_cdl_entry_t &mut_cdl_entry) noexcept -> bsl::safe_u64 + { + bsl::discard(mut_sys); + bsl::discard(vsid); + bsl::discard(mut_cdl_entry); + + bsl::error() << "cpuid_get: Not yet implemented" // -- + << bsl::endl // -- + << bsl::here(); // -- + + return bsl::safe_u64::failure(); + } + + /// + /// @brief Sets the registers of the requested CPUID given + /// the provided CDL entry. + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param vsid the ID of the vs_t to set + /// @param cdl_entry the mv_cdl_entry_t to set the CPUID from + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] static constexpr auto + cpuid_set( + syscall::bf_syscall_t &mut_sys, + bsl::safe_u16 const &vsid, + hypercall::mv_cdl_entry_t const &cdl_entry) noexcept -> bsl::errc_type + { + bsl::discard(mut_sys); + bsl::discard(vsid); + bsl::discard(cdl_entry); + + bsl::error() << "cpuid_set: Not yet implemented" // -- + << bsl::endl // -- + << bsl::here(); // -- + + return bsl::errc_failure; + } + + /// + /// @brief Returns the registers of the requested CPUIDs from the + /// provided CDL. + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param vsid the ID of the vs_t to query + /// @param mut_cdl the CDL to store the requested CPUID values + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + cpuid_get_list( + syscall::bf_syscall_t &mut_sys, + bsl::safe_u16 const &vsid, + hypercall::mv_cdl_t &mut_cdl) const noexcept -> bsl::errc_type + { + return this->get_vs(vsid)->cpuid_get_list(mut_sys, mut_cdl); + } + + /// + /// @brief Sets the registers of the requested CPUIDs given the + /// provided CDL. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param vsid the ID of the vs_t to set + /// @param cdl the CDL to get the requested CPUID values from + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + cpuid_set_list( + syscall::bf_syscall_t const &sys, + bsl::safe_u16 const &vsid, + hypercall::mv_cdl_t const &cdl) noexcept -> bsl::errc_type + { + return this->get_vs(vsid)->cpuid_set_list(sys, cdl); + } }; } diff --git a/vmm/src/x64/amd/vs_t.hpp b/vmm/src/x64/amd/vs_t.hpp index 561182f71..9132c1217 100644 --- a/vmm/src/x64/amd/vs_t.hpp +++ b/vmm/src/x64/amd/vs_t.hpp @@ -609,6 +609,8 @@ namespace microv this->init_as_16bit_guest(mut_sys); } + this->m_emulated_cpuid.allocate(gs, tls, mut_sys, intrinsic, vsid); + m_assigned_vmid = ~vmid; m_assigned_vpid = ~vpid; m_assigned_ppid = ~ppid; @@ -963,6 +965,49 @@ namespace microv return m_emulated_cpuid.get(mut_sys, intrinsic); } + /// + /// @brief Reads CPUID for this vs_t and returns the results + /// in the provided CDL. + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param mut_cdl the mv_cdl_t to read the CPUID into + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + cpuid_get_list(syscall::bf_syscall_t &mut_sys, hypercall::mv_cdl_t &mut_cdl) const noexcept + -> bsl::errc_type + { + bsl::expects(allocated_status_t::allocated == m_allocated); + bsl::expects(running_status_t::running != m_status); + bsl::expects(mut_sys.bf_tls_ppid() == this->assigned_pp()); + bsl::expects(!mut_sys.is_vs_a_root_vs(this->id())); + + return m_emulated_cpuid.get_list(mut_sys, mut_cdl); + } + + /// + /// @brief Reads CPUID for this vs_t and returns the results + /// in the provided CDL. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param cdl the mv_cdl_t to read the CPUID into + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + cpuid_set_list(syscall::bf_syscall_t const &sys, hypercall::mv_cdl_t const &cdl) noexcept + -> bsl::errc_type + { + bsl::expects(allocated_status_t::allocated == m_allocated); + bsl::expects(running_status_t::running != m_status); + bsl::expects(sys.bf_tls_ppid() == this->assigned_pp()); + + return m_emulated_cpuid.set_list(sys, cdl); + } + /// /// @brief Returns the value of the requested register /// diff --git a/vmm/src/x64/emulated_cpuid_t.hpp b/vmm/src/x64/emulated_cpuid_t.hpp index e2b0fb45a..19e154011 100644 --- a/vmm/src/x64/emulated_cpuid_t.hpp +++ b/vmm/src/x64/emulated_cpuid_t.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,109 @@ namespace microv /// @brief stores the ID of the VS associated with this emulated_cpuid_t bsl::safe_u16 m_assigned_vsid{}; + /// @brief stores the standard CPUID leaves + bsl::array< + bsl::array, + CPUID_NUM_STD_FUNCTIONS.get()> + m_std_leaves{}; + /// @brief stores the extended CPUID leaves + bsl::array< + bsl::array, + CPUID_NUM_EXT_FUNCTIONS.get()> + m_ext_leaves{}; + + /// + /// @brief Sets up a leaf + /// + /// + /// @param fun the CPUID function to use + /// @param idx the CPUID index to use + /// @param eax_mask the mask applied to the EAX register + /// @param eax_enable_mask the enable mask applied to the EAX register + /// @param ebx_mask the mask applied to the EBX register + /// @param ebx_enable_mask the enable mask applied to the EBX register + /// @param ecx_mask the mask applied to the ECX register + /// @param ecx_enable_mask the enable mask applied to the ECX register + /// @param edx_mask the mask applied to the EDX register + /// @param edx_enable_mask the enable mask applied to the EDX register + /// + constexpr void + setup_leaf( + bsl::safe_u32 const &fun, + bsl::safe_u64 const &idx, + bsl::safe_u64 const &eax_mask, + bsl::safe_u64 const &eax_enable_mask, + bsl::safe_u64 const &ebx_mask, + bsl::safe_u64 const &ebx_enable_mask, + bsl::safe_u64 const &ecx_mask, + bsl::safe_u64 const &ecx_enable_mask, + bsl::safe_u64 const &edx_mask, + bsl::safe_u64 const &edx_enable_mask) noexcept + { + auto const idx_i{bsl::to_idx(idx)}; + + hypercall::mv_cdl_entry_t *pmut_mut_entry{}; + + if (fun < CPUID_FN8000_0000) { + auto const fun_i{bsl::to_idx(fun)}; + pmut_mut_entry = m_std_leaves.at_if(fun_i)->at_if(idx_i); + } + else { + auto const fun_i{bsl::to_idx((fun - CPUID_FN8000_0000).checked())}; + pmut_mut_entry = m_ext_leaves.at_if(fun_i)->at_if(idx_i); + } + + auto mut_eax{bsl::to_u64(fun)}; + bsl::safe_u64 mut_ebx{}; + auto mut_ecx{idx}; + bsl::safe_u64 mut_edx{}; + + intrinsic_t::cpuid(mut_eax, mut_ebx, mut_ecx, mut_edx); + + pmut_mut_entry->fun = fun.get(); + pmut_mut_entry->idx = bsl::to_u32_unsafe(idx).get(); + pmut_mut_entry->eax = bsl::to_u32_unsafe(((mut_eax)&eax_mask) | eax_enable_mask).get(); + pmut_mut_entry->ebx = bsl::to_u32_unsafe(((mut_ebx)&ebx_mask) | ebx_enable_mask).get(); + pmut_mut_entry->ecx = bsl::to_u32_unsafe(((mut_ecx)&ecx_mask) | ecx_enable_mask).get(); + pmut_mut_entry->edx = bsl::to_u32_unsafe(((mut_edx)&edx_mask) | edx_enable_mask).get(); + } + + /// + /// @brief Prints a leaf + /// + /// + /// @tparam T The type to query + /// @param output to output to use, e.g. bsl::debug() + /// @param entry the mv_cdl_entry_t to read the CPUID from + /// @param loc the location of the call site + /// + template + static constexpr void + print_leaf( + bsl::out const &output, + hypercall::mv_cdl_entry_t const &entry, + bsl::source_location const &loc = bsl::here()) noexcept + { + constexpr auto upper16{16_u32}; + output << "CPUID leaf Fn" // -- + << bsl::fmt("04x", bsl::to_u16_unsafe(entry.fun >> upper16.get())) // -- + << "_" // -- + << bsl::fmt("04x", bsl::to_u16_unsafe(entry.fun)) // -- + << "h [" // -- + << bsl::fmt("02x", bsl::to_u16_unsafe(entry.idx)) // -- + << "] " // -- + << "[" // -- + << bsl::hex(entry.eax) // -- + << ":" // -- + << bsl::hex(entry.ebx) // -- + << ":" // -- + << bsl::hex(entry.ecx) // -- + << ":" // -- + << bsl::hex(entry.edx) // -- + << "] was requested\n" // -- + << loc; // -- + } + public: /// /// @brief Initializes this emulated_cpuid_t. @@ -105,6 +209,89 @@ namespace microv m_assigned_vsid = {}; } + /// + /// @brief Allocates the emulated_cpuid_t + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vsid the ID of the VS associated with this emulated_cpuid_t + /// + /// + constexpr void + allocate( + gs_t const &gs, + tls_t const &tls, + syscall::bf_syscall_t const &sys, + intrinsic_t const &intrinsic, + bsl::safe_u16 const &vsid) noexcept + { + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + bsl::expects(vsid != syscall::BF_INVALID_ID); + bsl::expects(vsid == this->assigned_vsid()); + + constexpr auto z{0_u64}; + constexpr auto m{bsl::safe_u64::max_value()}; + + // clang-format off + setup_leaf(CPUID_FN0000_0000, z, m, z, m, z, m, z, m, z); + + setup_leaf( + CPUID_FN0000_0001, z, + m, z, + m, z, + CPUID_FN0000_0001_ECX, CPUID_FN0000_0001_ECX_HYPERVISOR_BIT, + CPUID_FN0000_0001_EDX, z); + + setup_leaf(CPUID_FN8000_0000, z, m, z, m, z, m, z, m, z); + + setup_leaf( + CPUID_FN8000_0001, z, + m, z, + z, z, + CPUID_FN8000_0001_ECX, z, + CPUID_FN8000_0001_EDX, z); + + setup_leaf(CPUID_FN8000_0002, z, m, z, m, z, m, z, m, z); + setup_leaf(CPUID_FN8000_0003, z, m, z, m, z, m, z, m, z); + setup_leaf(CPUID_FN8000_0004, z, m, z, m, z, m, z, m, z); + // clang-format on + } + + /// + /// @brief Deallocates the emulated_cpuid_t + /// + /// + /// @param gs the gs_t to use + /// @param tls the tls_t to use + /// @param sys the bf_syscall_t to use + /// @param intrinsic the intrinsic_t to use + /// @param vsid the ID of the VS associated with this emulated_cpuid_t + /// + /// + constexpr void + deallocate( + gs_t const &gs, + tls_t const &tls, + syscall::bf_syscall_t const &sys, + intrinsic_t const &intrinsic, + bsl::safe_u16 const &vsid) const noexcept + { + bsl::discard(gs); + bsl::discard(tls); + bsl::discard(sys); + bsl::discard(intrinsic); + + bsl::expects(vsid != syscall::BF_INVALID_ID); + bsl::expects(vsid == this->assigned_vsid()); + } + /// /// @brief Returns the ID of the PP associated with this /// emulated_cpuid_t @@ -268,6 +455,186 @@ namespace microv bsl::error() << "get not implemented\n" << bsl::here(); return bsl::errc_failure; } + + /// + /// @brief Returns the requested CPUID leaf (mv_cdl_entry_t.fun and + /// mv_cdl_entry_t.idx) into the eax, ebx, ecx, and edx registers of + /// the CDL. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param mut_entry the mv_cdl_entry_t to read the CPUID from + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise. + /// + [[nodiscard]] constexpr auto + get(syscall::bf_syscall_t const &sys, hypercall::mv_cdl_entry_t &mut_entry) const noexcept + -> bsl::errc_type + { + bsl::discard(sys); + + using leaves_type = decltype(m_std_leaves); + leaves_type const *mut_leaves{}; + if (mut_entry.fun < CPUID_FN8000_0000.get()) { + mut_leaves = &m_std_leaves; + } + else { + mut_leaves = &m_ext_leaves; + } + + for (auto const &leaves_idx : *mut_leaves) { + if (leaves_idx.at_if(bsl::safe_idx::magic_0())->fun != mut_entry.fun) { + continue; + } + + for (auto const &leaf : leaves_idx) { + if (leaf.idx != mut_entry.idx) { + continue; + } + + mut_entry.eax = leaf.eax; + mut_entry.ebx = leaf.ebx; + mut_entry.ecx = leaf.ecx; + mut_entry.edx = leaf.edx; + + return bsl::errc_success; + } + } + + print_leaf(bsl::error(), mut_entry); + + return bsl::errc_failure; + } + + /// + /// @brief Sets the requested CPUID leaves with the eax, ebx, ecx, and + /// edx registers given by the CDL. It reducing capabilities is + /// allowed. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param entry the mv_cdl_entry_t to read the CPUID from + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise. + /// + [[nodiscard]] constexpr auto + set(syscall::bf_syscall_t const &sys, hypercall::mv_cdl_entry_t const &entry) noexcept + -> bsl::errc_type + { + bsl::discard(sys); + + auto mut_i{bsl::to_idx(entry.fun)}; + if (mut_i >= bsl::to_idx(CPUID_FN8000_0000)) { + mut_i -= bsl::to_idx(CPUID_FN8000_0000); + } + else { + bsl::touch(); + } + + constexpr auto cpuid_index_0{0_u64}; + constexpr auto upper32{32_u64}; + auto const req{(bsl::to_u64(entry.fun) << upper32) | bsl::to_u64(entry.idx)}; + + switch (req.get()) { + + case ((bsl::to_u64(CPUID_FN0000_0001) << upper32) | cpuid_index_0).get(): { + auto *const pmut_entry{ + m_std_leaves.at_if(mut_i)->at_if(bsl::to_idx(entry.idx))}; + if (entry.eax != bsl::safe_u32::magic_0()) { + break; + } + if (entry.ebx != bsl::safe_u32::magic_0()) { + break; + } + + pmut_entry->ecx &= entry.ecx; + pmut_entry->edx &= entry.edx; + + return bsl::errc_success; + } + + case ((bsl::to_u64(CPUID_FN8000_0001) << upper32) | cpuid_index_0).get(): { + auto *const pmut_entry{ + m_ext_leaves.at_if(mut_i)->at_if(bsl::to_idx(entry.idx))}; + if (entry.eax != bsl::safe_u32::magic_0()) { + break; + } + if (entry.ebx != bsl::safe_u32::magic_0()) { + break; + } + + pmut_entry->ecx &= entry.ecx; + pmut_entry->edx &= entry.edx; + + return bsl::errc_success; + } + + default: { + break; + } + } + + print_leaf(bsl::error(), entry); + + return bsl::errc_failure; + } + + /// + /// @brief Reads the requested CPUID function and index given by the + /// CDL into the eax, ebx, ecx, and edx registers of the CDL. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param mut_cdl the mv_cdl_t to read the CPUID into + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise. + /// + [[nodiscard]] constexpr auto + get_list(syscall::bf_syscall_t const &sys, hypercall::mv_cdl_t &mut_cdl) const noexcept + -> bsl::errc_type + { + bsl::discard(sys); + bsl::discard(mut_cdl); + + for (bsl::safe_idx mut_i{}; mut_i < mut_cdl.num_entries; ++mut_i) { + if (bsl::unlikely(!get(sys, *mut_cdl.entries.at_if(mut_i)))) { + bsl::error() << "get_list failed\n" << bsl::here(); + return bsl::errc_failure; + } + + bsl::touch(); + } + + return bsl::errc_success; + } + + /// + /// @brief Sets the requested CPUID leaves with the eax, ebx, ecx, and + /// edx registers given by the CDL. It reducing capabilities is + /// allowed. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param cdl the mv_cdl_entry_t to read the CPUID into + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise. + /// + [[nodiscard]] constexpr auto + set_list(syscall::bf_syscall_t const &sys, hypercall::mv_cdl_t const &cdl) noexcept + -> bsl::errc_type + { + for (bsl::safe_idx mut_i{}; mut_i < cdl.num_entries; ++mut_i) { + auto const &entry{*cdl.entries.at_if(mut_i)}; + if (bsl::unlikely(!set(sys, entry))) { + bsl::error() << "Set CPUID failed\n" << bsl::here(); + return bsl::errc_failure; + } + + bsl::touch(); + } + + return bsl::errc_success; + } }; } diff --git a/vmm/src/x64/intel/vs_t.hpp b/vmm/src/x64/intel/vs_t.hpp index de37a104d..10356edc5 100644 --- a/vmm/src/x64/intel/vs_t.hpp +++ b/vmm/src/x64/intel/vs_t.hpp @@ -995,6 +995,49 @@ namespace microv return m_emulated_cpuid.get(mut_sys, intrinsic); } + /// + /// @brief Reads CPUID for this vs_t and returns the results + /// in the provided CDL. + /// + /// + /// @param mut_sys the bf_syscall_t to use + /// @param mut_cdl the mv_cdl_t to read the CPUID into + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + cpuid_get_list(syscall::bf_syscall_t &mut_sys, hypercall::mv_cdl_t &mut_cdl) const noexcept + -> bsl::errc_type + { + bsl::expects(allocated_status_t::allocated == m_allocated); + bsl::expects(running_status_t::running != m_status); + bsl::expects(mut_sys.bf_tls_ppid() == this->assigned_pp()); + bsl::expects(!mut_sys.is_vs_a_root_vs(this->id())); + + return m_emulated_cpuid.get_list(mut_sys, mut_cdl); + } + + /// + /// @brief Reads CPUID for this vs_t and returns the results + /// in the provided CDL. + /// + /// + /// @param sys the bf_syscall_t to use + /// @param cdl the mv_cdl_t to read the CPUID into + /// @return Returns bsl::errc_success on success, bsl::errc_failure + /// and friends otherwise + /// + [[nodiscard]] constexpr auto + cpuid_set_list(syscall::bf_syscall_t const &sys, hypercall::mv_cdl_t const &cdl) noexcept + -> bsl::errc_type + { + bsl::expects(allocated_status_t::allocated == m_allocated); + bsl::expects(running_status_t::running != m_status); + bsl::expects(sys.bf_tls_ppid() == this->assigned_pp()); + + return m_emulated_cpuid.set_list(sys, cdl); + } + /// /// @brief Returns the value of the requested register ///