Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VMM: Add support for the CPUID hypercalls #85

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions hypercall/include/mv_cdl_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint64_t>(125))
#else
/** @brief defines the max number of entires in the CDL */
#define MV_CDL_MAX_ENTRIES ((uint64_t)125)
#endif

/**
* <!-- description -->
Expand Down
8 changes: 4 additions & 4 deletions hypercall/include/mv_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
8 changes: 4 additions & 4 deletions hypercall/include/mv_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions hypercall/include/mv_cpuid_flag_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#ifndef MV_CPUID_FLAG_T_H
#define MV_CPUID_FLAG_T_H

#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
Expand All @@ -37,13 +39,13 @@ extern "C"
* <!-- description -->
* @brief Defines CPUID flags
*/
enum mv_cpuid_flag : int32_t
enum mv_cpuid_flag_t : int32_t
#else
/**
* <!-- description -->
* @brief Defines CPUID flags
*/
enum mv_cpuid_flag
enum mv_cpuid_flag_t
#endif
{
/** @brief reserved */
Expand Down
16 changes: 16 additions & 0 deletions hypercall/library.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down Expand Up @@ -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})
Expand Down Expand Up @@ -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})
Expand Down Expand Up @@ -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})
Expand Down
161 changes: 161 additions & 0 deletions hypercall/mocks/mv_hypercall.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#ifndef MOCKS_MV_HYPERCALL_H
#define MOCKS_MV_HYPERCALL_H

#include <mv_cdl_t.h>
#include <mv_constants.h>
#include <mv_exit_io_t.h>
#include <mv_exit_reason_t.h>
Expand Down Expand Up @@ -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;

/**
* <!-- description -->
Expand Down Expand Up @@ -1465,6 +1478,154 @@ extern "C"
return g_mut_mv_vs_op_tsc_get_khz;
}

/**
* <!-- description -->
* @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.
*
* <!-- inputs/outputs -->
* @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;
}

/**
* <!-- description -->
* @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.
*
* <!-- inputs/outputs -->
* @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;
}

/**
* <!-- description -->
* @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.
*
* <!-- inputs/outputs -->
* @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;
}

/**
* <!-- description -->
* @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.
*
* <!-- inputs/outputs -->
* @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
Expand Down
42 changes: 42 additions & 0 deletions hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_impl.S
Original file line number Diff line number Diff line change
@@ -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
42 changes: 42 additions & 0 deletions hypercall/src/linux/x64/amd/mv_vs_op_cpuid_get_list_impl.S
Original file line number Diff line number Diff line change
@@ -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
Loading