diff --git a/hypercall/include/mv_cpuid_flag_t.h b/hypercall/include/mv_cpuid_flag_t.h index e08ae0f2f..809b3a1ae 100644 --- a/hypercall/include/mv_cpuid_flag_t.h +++ b/hypercall/include/mv_cpuid_flag_t.h @@ -37,13 +37,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/include/mv_rdl_t.h b/hypercall/include/mv_rdl_t.h index fe70cebb9..3aebe4021 100644 --- a/hypercall/include/mv_rdl_t.h +++ b/hypercall/include/mv_rdl_t.h @@ -30,6 +30,10 @@ #include // IWYU pragma: export #include +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif + #ifdef __cplusplus extern "C" { diff --git a/hypercall/mocks/mv_hypercall.h b/hypercall/mocks/mv_hypercall.h index 1884aea71..5786383ed 100644 --- a/hypercall/mocks/mv_hypercall.h +++ b/hypercall/mocks/mv_hypercall.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -246,6 +247,8 @@ extern "C" NODISCARD static inline mv_status_t mv_pp_op_cpuid_get_supported_list(uint64_t const hndl) NOEXCEPT { + uint64_t mut_i; + struct mv_cdl_entry_t mut_cdl_entry; #ifdef __cplusplus bsl::expects(MV_INVALID_HANDLE != hndl); bsl::expects(hndl > ((uint64_t)0)); @@ -253,7 +256,30 @@ extern "C" platform_expects(MV_INVALID_HANDLE != hndl); platform_expects(hndl > ((uint64_t)0)); #endif + struct mv_cdl_t *const pmut_cdl = (struct mv_cdl_t *)g_mut_shared_pages[0]; +#ifdef __cplusplus + bsl::expects(nullptr != pmut_cdl); + bsl::expects(pmut_cdl->num_entries < MV_CDL_MAX_ENTRIES); +#else + platform_expects(NULL != pmut_cdl); + platform_expects(pmut_cdl->num_entries < MV_CDL_MAX_ENTRIES); +#endif + if (MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES == g_mut_mv_pp_op_msr_get_supported_list) { + pmut_cdl->num_entries = GARBAGE; + return MV_STATUS_SUCCESS; + } + + pmut_cdl->num_entries = g_mut_val; + for (mut_i = ((uint64_t)0); mut_i < pmut_cdl->num_entries; ++mut_i) { + mut_cdl_entry.fun = ((uint32_t)g_mut_val); + mut_cdl_entry.idx = ((uint32_t)g_mut_val); + mut_cdl_entry.eax = ((uint32_t)g_mut_val); + mut_cdl_entry.ebx = ((uint32_t)g_mut_val); + mut_cdl_entry.ecx = ((uint32_t)g_mut_val); + mut_cdl_entry.edx = ((uint32_t)g_mut_val); + pmut_cdl->entries[mut_i] = mut_cdl_entry; + } return g_mut_mv_pp_op_cpuid_get_supported_list; } diff --git a/hypercall/tests/mocks/mv_hypercall.cpp b/hypercall/tests/mocks/mv_hypercall.cpp index fe49332a9..023916ae2 100644 --- a/hypercall/tests/mocks/mv_hypercall.cpp +++ b/hypercall/tests/mocks/mv_hypercall.cpp @@ -194,7 +194,10 @@ namespace shim bsl::ut_given{} = [&]() noexcept { constexpr auto hypercall{&mv_pp_op_cpuid_get_supported_list}; constexpr auto expected{42_u64}; + 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_mv_pp_op_cpuid_get_supported_list = expected.get(); bsl::ut_then{} = [&]() noexcept { bsl::ut_check(expected == hypercall(hndl)); diff --git a/shim/include/handle_system_kvm_get_msrs.h b/shim/include/handle_system_kvm_get_msrs.h index 94d5ad2cc..7c53278b0 100644 --- a/shim/include/handle_system_kvm_get_msrs.h +++ b/shim/include/handle_system_kvm_get_msrs.h @@ -40,10 +40,10 @@ extern "C" * @brief Handles the execution of kvm_check_extension. * * - * @param pmut_ioctl_args the arguments provided by userspace + * @param pmut_userargs the arguments provided by userspace * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ - NODISCARD int64_t handle_system_kvm_get_msrs(struct kvm_msrs *const pmut_ioctl_args) NOEXCEPT; + NODISCARD int64_t handle_system_kvm_get_msrs(struct kvm_msrs *const pmut_userargs) NOEXCEPT; #ifdef __cplusplus } diff --git a/shim/include/handle_vcpu_kvm_get_msrs.h b/shim/include/handle_vcpu_kvm_get_msrs.h index f0df091c9..04f8ed8e9 100644 --- a/shim/include/handle_vcpu_kvm_get_msrs.h +++ b/shim/include/handle_vcpu_kvm_get_msrs.h @@ -29,6 +29,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -40,10 +41,12 @@ extern "C" * @brief Handles the execution of kvm_get_msrs. * * - * @param pmut_ioctl_args the arguments provided by userspace + * @param vcpu to get vsid to pass to hypercall + * @param pmut_args the arguments provided by userspace * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ - NODISCARD int64_t handle_vcpu_kvm_get_msrs(struct kvm_msrs *const pmut_ioctl_args) NOEXCEPT; + NODISCARD int64_t handle_vcpu_kvm_get_msrs( + struct shim_vcpu_t const *const vcpu, struct kvm_msrs *const pmut_args) NOEXCEPT; #ifdef __cplusplus } diff --git a/shim/include/handle_vcpu_kvm_set_msrs.h b/shim/include/handle_vcpu_kvm_set_msrs.h index 9bc49c0b7..374732537 100644 --- a/shim/include/handle_vcpu_kvm_set_msrs.h +++ b/shim/include/handle_vcpu_kvm_set_msrs.h @@ -29,6 +29,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -40,10 +41,12 @@ extern "C" * @brief Handles the execution of kvm_set_msrs. * * - * @param pmut_ioctl_args the arguments provided by userspace + * @param vcpu arguments received from private data + * @param args the arguments provided by userspace * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ - NODISCARD int64_t handle_vcpu_kvm_set_msrs(struct kvm_msrs *const pmut_ioctl_args) NOEXCEPT; + NODISCARD int64_t handle_vcpu_kvm_set_msrs( + struct shim_vcpu_t const *const vcpu, struct kvm_msrs const *const args) NOEXCEPT; #ifdef __cplusplus } diff --git a/shim/include/handle_vm_kvm_set_user_memory_region.h b/shim/include/handle_vm_kvm_set_user_memory_region.h index aae722c3b..4d501e20f 100644 --- a/shim/include/handle_vm_kvm_set_user_memory_region.h +++ b/shim/include/handle_vm_kvm_set_user_memory_region.h @@ -35,11 +35,6 @@ extern "C" { #endif -/** @brief TBD */ -#define KVM_MEM_LOG_DIRTY_PAGES (((uint64_t)1) << ((uint64_t)0)) -/** @brief allows a slot to be read-only */ -#define KVM_MEM_READONLY (((uint64_t)1) << ((uint64_t)1)) - /** * * @brief Handles the execution of kvm_set_user_memory_region. diff --git a/shim/include/kvm_clock_data.h b/shim/include/kvm_clock_data.h index 39ecec2d3..f4a23907e 100644 --- a/shim/include/kvm_clock_data.h +++ b/shim/include/kvm_clock_data.h @@ -34,6 +34,8 @@ extern "C" { #endif +#define KVM_CLOCK_TSC_STABLE 2 + #pragma pack(push, 1) /** @@ -44,8 +46,14 @@ extern "C" */ struct kvm_clock_data { - /** @brief replace me with contents from KVM API */ - int32_t dummy; + /** @brief value of the clock */ + uint64_t clock; + + /** @brief clock flags */ + uint32_t flags; + + /** @brief unused padding for alignment */ + uint32_t pad[9]; }; #pragma pack(pop) diff --git a/shim/include/kvm_clock_data.hpp b/shim/include/kvm_clock_data.hpp new file mode 100644 index 000000000..76c87a862 --- /dev/null +++ b/shim/include/kvm_clock_data.hpp @@ -0,0 +1,60 @@ +/** + * @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. + */ + +#ifndef KVM_CLOCK_DATA_HPP +#define KVM_CLOCK_DATA_HPP + +#include +#include +#include + +constexpr auto CLOCK_TSC_STABLE{2_u32}; +constexpr auto PADDING{9_u32}; + +namespace shim +{ +#pragma pack(push, 1) + + /** + * @struct kvm_clock_data + * + * + * @brief see /include/uapi/linux/kvm.h in Linux for more details. + */ + struct kvm_clock_data + { + /** @brief value of the clock data */ + bsl::uint64 clock; + /** @brief clock flags */ + bsl::uint32 flags; + /** @brief CPUID entries */ + bsl::array pad; + }; +} + +#pragma pack(pop) + +#endif diff --git a/shim/include/kvm_cpuid2.h b/shim/include/kvm_cpuid2.h index aa74d264b..84a323ca0 100644 --- a/shim/include/kvm_cpuid2.h +++ b/shim/include/kvm_cpuid2.h @@ -27,6 +27,7 @@ #ifndef KVM_CPUID2_H #define KVM_CPUID2_H +#include #include #ifdef __cplusplus @@ -34,6 +35,8 @@ extern "C" { #endif +#define CPUID2_MAX_ENTRIES 40 + #pragma pack(push, 1) /** @@ -44,8 +47,12 @@ extern "C" */ struct kvm_cpuid2 { - /** @brief replace me with contents from KVM API */ - int32_t dummy; + /** @brief number of entries */ + uint32_t nent; + /** @brief padding for alignment */ + uint32_t padding; + /** @brief CPUID entries */ + struct kvm_cpuid_entry2 entries[CPUID2_MAX_ENTRIES]; }; #pragma pack(pop) diff --git a/shim/include/kvm_cpuid2.hpp b/shim/include/kvm_cpuid2.hpp new file mode 100644 index 000000000..134a4bfc1 --- /dev/null +++ b/shim/include/kvm_cpuid2.hpp @@ -0,0 +1,61 @@ +/** + * @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. + */ + +#ifndef KVM_CPUID2_HPP +#define KVM_CPUID2_HPP + +#include + +#include +#include +#include + +constexpr auto CPUID2_MAX_ENTRIES{40_u32}; + +namespace shim +{ +#pragma pack(push, 1) + + /** + * @struct kvm_cpuid2 + * + * + * @brief see /include/uapi/linux/kvm.h in Linux for more details. + */ + struct kvm_cpuid2 + { + /** @brief number of entries */ + bsl::uint32 nent; + /** @brief padding for alignment */ + bsl::uint32 padding; + /** @brief CPUID entries */ + bsl::array entries; + }; +} + +#pragma pack(pop) + +#endif diff --git a/shim/include/kvm_cpuid_entry2.h b/shim/include/kvm_cpuid_entry2.h new file mode 100644 index 000000000..4efdcab9c --- /dev/null +++ b/shim/include/kvm_cpuid_entry2.h @@ -0,0 +1,84 @@ +/** + * @copyright + * Copyright (C) 2021 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. + */ + +#ifndef KVM_CPUID_ENTRY2_H +#define KVM_CPUID_ENTRY2_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0) +#define KVM_CPUID_FLAG_STATEFUL_FUNC (1 << 1) +#define KVM_CPUID_FLAG_STATE_READ_NEXT (1 << 2) + +#pragma pack(push, 1) + + /** + * @struct kvm_cpuid_entry2 + * + * + * @brief see /include/uapi/linux/kvm.h in Linux for more details. + */ + struct kvm_cpuid_entry2 + { + /** @brief the eax value used to obtain the entry */ + uint32_t function; + /** @brief the ecx value used to obtain the entry (for entries that are affected by ecx) */ + uint32_t index; + /** @brief an OR of zero or more of the following: + * KVM_CPUID_FLAG_SIGNIFCANT_INDEX: if the index field is valid + * KVM_CPUID_FLAG_STATEFUL_FUNC: if cpuid for this function + * returns different values for successive invocations; there will + * be several entries with the same function, all with this flag + * set + * KVM_CPUID_FLAG_STATE_READ_NEXT: for + * KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry if the + * first entry to be read by a cpu + */ + uint32_t flags; + /** @brief the eax value returned by the cpuid instruction for this function/index combination */ + uint32_t eax; + /** @brief the ebx value returned by the cpuid instruction for this function/index combination */ + uint32_t ebx; + /** @brief the ecx value returned by the cpuid instruction for this function/index combination */ + uint32_t ecx; + /** @brief the edx value returned by the cpuid instruction for this function/index combination */ + uint32_t edx; + /** @brief padding for alignment */ + uint32_t padding[3]; + }; + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/shim/include/kvm_cpuid_entry2.hpp b/shim/include/kvm_cpuid_entry2.hpp new file mode 100644 index 000000000..ffb44040c --- /dev/null +++ b/shim/include/kvm_cpuid_entry2.hpp @@ -0,0 +1,80 @@ +/** + * @copyright + * Copyright (C) 2021 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. + */ + +#ifndef KVM_CPUID_ENTRY2_HPP +#define KVM_CPUID_ENTRY2_HPP + +#include +#include +#include + +namespace shim +{ + constexpr auto KVM_CPUID_FLAG_SIGNIFCANT_INDEX{0x1_u32}; + constexpr auto KVM_CPUID_FLAG_STATEFUL_FUNC{0x10_u32}; + constexpr auto KVM_CPUID_FLAG_STATE_READ_NEXT{0x100_u32}; + +#pragma pack(push, 1) + + /** + * @struct kvm_cpuid_entry2 + * + * + * @brief see /include/uapi/linux/kvm.h in Linux for more details. + */ + struct kvm_cpuid_entry2 + { + /** @brief the eax value used to obtain the entry */ + bsl::uint32 function; + /** @breif the ecx value used to obtain the entry (for entries that are affected by ecx) */ + bsl::uint32 index; + /** @brief an OR of zero or more of the following: + * KVM_CPUID_FLAG_SIGNIFCANT_INDEX: if the index field is valid + * KVM_CPUID_FLAG_STATEFUL_FUNC: if cpuid for this function + * returns different values for successive invocations; there will + * be several entries with the same function, all with this flag + * set + * KVM_CPUID_FLAG_STATE_READ_NEXT: for + * KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry if the + * first entry to be read by a cpu + */ + bsl::uint32 flags; + /** @brief the eax value returned by the cpuid instruction for this function/index combination */ + bsl::uint32 eax; + /** @brief the ebx value returned by the cpuid instruction for this function/index combination */ + bsl::uint32 ebx; + /** @brief the ecx value returned by the cpuid instruction for this function/index combination */ + bsl::uint32 ecx; + /** @brief the edx value returned by the cpuid instruction for this function/index combination */ + bsl::uint32 edx; + /** @brief padding for alignment */ + bsl::array padding; + }; +} + +#pragma pack(pop) + +#endif diff --git a/shim/include/kvm_msr_entry.h b/shim/include/kvm_msr_entry.h new file mode 100644 index 000000000..b5db31b74 --- /dev/null +++ b/shim/include/kvm_msr_entry.h @@ -0,0 +1,61 @@ +/** + * @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. + */ + +#ifndef KVM_MSR_ENTRY_H +#define KVM_MSR_ENTRY_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#pragma pack(push, 1) + + /** + * @struct kvm_msr_entry + * + * + * @brief see /include/uapi/linux/kvm.h in Linux for more details. + */ + struct kvm_msr_entry + { + /** @brief defines index for msr entries */ + uint32_t index; + /** @brief defines reserved for msr entries */ + uint32_t reserved; + /** @brief defines data for msr entries*/ + uint64_t data; + }; + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/shim/include/kvm_msr_entry.hpp b/shim/include/kvm_msr_entry.hpp new file mode 100644 index 000000000..38bdc7591 --- /dev/null +++ b/shim/include/kvm_msr_entry.hpp @@ -0,0 +1,53 @@ +/// @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. + +#ifndef KVM_MSR_ENTRY_HPP +#define KVM_MSR_ENTRY_HPP + +#include + +#pragma pack(push, 1) + +namespace shim +{ + /// @struct kvm_msr_entry + /// + /// + /// @brief see /include/uapi/linux/kvm.h in Linux for more details. + /// + struct kvm_msr_entry final + { + /** @brief defines index for msr entries */ + bsl::uint32 index; + /** @brief defines reserved for msr entries */ + bsl::uint32 reserved; + /** @brief defines data for msr entries*/ + bsl::uint64 data; + }; + +} + +#pragma pack(pop) + +#endif diff --git a/shim/include/kvm_msr_list.h b/shim/include/kvm_msr_list.h index 60ce5b87a..668eed1be 100644 --- a/shim/include/kvm_msr_list.h +++ b/shim/include/kvm_msr_list.h @@ -34,6 +34,8 @@ extern "C" { #endif +#define MSR_LIST_MAX_INDICES 128 + #pragma pack(push, 1) /** @@ -48,7 +50,7 @@ extern "C" uint32_t nmsrs; /** @brief array containing the indices of supported MSRs */ - uint32_t *indices; + uint32_t indices[MSR_LIST_MAX_INDICES]; }; #pragma pack(pop) diff --git a/shim/include/kvm_msr_list.hpp b/shim/include/kvm_msr_list.hpp index 421f7589a..9895a9677 100644 --- a/shim/include/kvm_msr_list.hpp +++ b/shim/include/kvm_msr_list.hpp @@ -27,7 +27,11 @@ #ifndef KVM_MSR_LIST_HPP #define KVM_MSR_LIST_HPP -#include +#include +#include +#include + +constexpr auto MSR_LIST_MAX_INDICES{128_u32}; namespace shim { @@ -45,7 +49,7 @@ namespace shim bsl::uint32 nmsrs; /** @brief array containing the indices of supported MSRs */ - bsl::uint32 *indices; + bsl::array indices; }; } diff --git a/shim/include/kvm_msrs.h b/shim/include/kvm_msrs.h index 308c8b86b..bf7743235 100644 --- a/shim/include/kvm_msrs.h +++ b/shim/include/kvm_msrs.h @@ -27,8 +27,14 @@ #ifndef KVM_MSRS_H #define KVM_MSRS_H +#include +#include #include +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif + #ifdef __cplusplus extern "C" { @@ -44,8 +50,12 @@ extern "C" */ struct kvm_msrs { - /** @brief replace me with contents from KVM API */ - int32_t dummy; + /** @brief number of msrs in entries */ + uint32_t nmsrs; + /** @brief number of pad in entries */ + uint32_t pad; + /** @brief defines array of entries*/ + struct kvm_msr_entry entries[MV_RDL_MAX_ENTRIES]; }; #pragma pack(pop) diff --git a/shim/include/kvm_msrs.hpp b/shim/include/kvm_msrs.hpp new file mode 100644 index 000000000..99862c277 --- /dev/null +++ b/shim/include/kvm_msrs.hpp @@ -0,0 +1,60 @@ +/// @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. + +#ifndef KVM_MSRS_HPP +#define KVM_MSRS_HPP + +#include + +#include +#include +#include + +#pragma pack(push, 1) + +namespace shim +{ + /// @brief defines the max number of entires in the RDL + constexpr auto MV_RDL_MAX_ENTRIES{250_u64}; + + /// @struct kvm_msrs + /// + /// + /// @brief see /include/uapi/linux/kvm.h in Linux for more details. + /// + struct kvm_msrs final + { + /** @brief number of msrs in entries */ + bsl::uint32 nmsrs; + /** @brief number of pad in entries */ + bsl::uint32 pad; + /// @brief stores each entry in the RDL + bsl::array entries; + }; + +} + +#pragma pack(pop) + +#endif diff --git a/shim/include/kvm_userspace_memory_region.h b/shim/include/kvm_userspace_memory_region.h index 2a29a446b..f4da48e6c 100644 --- a/shim/include/kvm_userspace_memory_region.h +++ b/shim/include/kvm_userspace_memory_region.h @@ -36,6 +36,9 @@ extern "C" #pragma pack(push, 1) +#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) +#define KVM_MEM_READONLY (1UL << 1) + /** * @struct kvm_userspace_memory_region * diff --git a/shim/integration/CMakeLists.txt b/shim/integration/CMakeLists.txt index 3433c3c6c..59e37ac8b 100644 --- a/shim/integration/CMakeLists.txt +++ b/shim/integration/CMakeLists.txt @@ -37,6 +37,8 @@ microv_add_shim_integration(kvm_set_regs HEADERS) microv_add_shim_integration(kvm_set_sregs HEADERS) microv_add_shim_integration(kvm_set_user_memory_region HEADERS) microv_add_shim_integration(kvm_get_api_version HEADERS) +microv_add_shim_integration(kvm_get_clock HEADERS) +microv_add_shim_integration(kvm_set_clock HEADERS) microv_add_shim_integration(kvm_set_fpu HEADERS) microv_add_shim_integration(kvm_get_fpu HEADERS) microv_add_shim_integration(kvm_set_tss_addr HEADERS) @@ -46,3 +48,6 @@ microv_add_shim_integration(kvm_get_mp_state HEADERS) microv_add_shim_integration(kvm_set_mp_state HEADERS) microv_add_shim_integration(kvm_get_tsc_khz HEADERS) microv_add_shim_integration(kvm_get_msr_index_list HEADERS) +microv_add_shim_integration(kvm_get_msrs HEADERS) +microv_add_shim_integration(kvm_set_msrs HEADERS) +microv_add_shim_integration(kvm_get_supported_cpuid HEADERS) diff --git a/shim/integration/kvm_get_clock.cpp b/shim/integration/kvm_get_clock.cpp new file mode 100644 index 000000000..87ceccc73 --- /dev/null +++ b/shim/integration/kvm_get_clock.cpp @@ -0,0 +1,55 @@ +/// @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 + +/// +/// @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(); + integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME}; + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + + shim::kvm_clock_data mut_clock_data; + integration::verify(mut_vm.write(shim::KVM_GET_CLOCK, &mut_clock_data).is_zero()); + + bsl::print() << " clock: " << bsl::hex(mut_clock_data.clock) << bsl::endl; + + return bsl::exit_success; +} diff --git a/shim/integration/kvm_get_msr_index_list.cpp b/shim/integration/kvm_get_msr_index_list.cpp index 723167779..eb086ac00 100644 --- a/shim/integration/kvm_get_msr_index_list.cpp +++ b/shim/integration/kvm_get_msr_index_list.cpp @@ -51,21 +51,20 @@ main() noexcept -> bsl::exit_code bsl::enable_color(); integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME}; - bsl::array mut_msr_indices{}; - // nmsrs is too big + // nmsrs is too small { - mut_msr_list.nmsrs = HYPERVISOR_PAGE_SIZE.get(); - mut_msr_list.nmsrs++; - mut_msr_list.indices = mut_msr_indices.front_if(); + mut_msr_list.nmsrs = bsl::safe_u32::magic_0().get(); integration::verify( mut_system_ctl.write(shim::KVM_GET_MSR_INDEX_LIST, &mut_msr_list).is_neg()); + + auto mut_nmsrs{bsl::to_u32(mut_msr_list.nmsrs)}; + integration::verify(mut_nmsrs > bsl::safe_u32::magic_0()); } { mut_msr_list.nmsrs = init_nmsrs.get(); - mut_msr_list.indices = mut_msr_indices.front_if(); integration::verify( mut_system_ctl.write(shim::KVM_GET_MSR_INDEX_LIST, &mut_msr_list).is_zero()); @@ -82,13 +81,13 @@ main() noexcept -> bsl::exit_code auto mut_nmsrs{bsl::to_idx(mut_msr_list.nmsrs)}; for (bsl::safe_idx mut_i{}; mut_i < mut_nmsrs; ++mut_i) { - if (star_val == mut_msr_list.indices[mut_i.get()]) { + if (star_val == *mut_msr_list.indices.at_if(mut_i)) { mut_found_star = true; } - else if (pat_val == mut_msr_list.indices[mut_i.get()]) { + else if (pat_val == *mut_msr_list.indices.at_if(mut_i)) { mut_found_pat = true; } - else if (apic_base_val == mut_msr_list.indices[mut_i.get()]) { + else if (apic_base_val == *mut_msr_list.indices.at_if(mut_i)) { mut_found_apic_base = true; } } @@ -100,6 +99,8 @@ main() noexcept -> bsl::exit_code // Try a bunch of times { + mut_msr_list.nmsrs = init_nmsrs.get(); + constexpr auto num_loops{0x1000_umx}; for (bsl::safe_idx mut_i{}; mut_i < num_loops; ++mut_i) { integration::verify( diff --git a/shim/integration/kvm_get_msrs.cpp b/shim/integration/kvm_get_msrs.cpp new file mode 100644 index 000000000..064df9221 --- /dev/null +++ b/shim/integration/kvm_get_msrs.cpp @@ -0,0 +1,110 @@ +/// @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 +#include + +namespace +{ + /// @brief defines the number of MSRS we expect + constexpr auto EXPECTED_NMSRS{0x01_u32}; + /// @brief defines the PAD we expect + constexpr auto EXPECTED_PAD{0x00_u32}; + /// @brief defines the size for entries in RDL + constexpr auto MYSIZE_ENTRIES{1_u64}; + /// @brief defines the register index we expect + constexpr auto EXPECTED_INDEX{0x00_u32}; + /// @brief defines the register data we expect + constexpr auto EXPECTED_DATA{0x42_u64}; +} + +/// +/// @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 +{ + shim::kvm_msrs mut_msrs{}; + + mut_msrs.nmsrs = EXPECTED_NMSRS.get(); + mut_msrs.pad = EXPECTED_PAD.get(); + + for (bsl::safe_idx mut_i{}; mut_i < MYSIZE_ENTRIES.get(); ++mut_i) { + mut_msrs.entries.at_if(mut_i)->index = EXPECTED_INDEX.get(); + mut_msrs.entries.at_if(mut_i)->data = EXPECTED_DATA.get(); + } + + bsl::enable_color(); + integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME}; + + /// Verify that get/set works + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + + auto const vcpufd{mut_vm.send(shim::KVM_CREATE_VCPU)}; + integration::ioctl_t mut_vcpu{bsl::to_i32(vcpufd)}; + + integration::verify(mut_vcpu.write(shim::KVM_SET_MSRS, &mut_msrs).is_zero()); + mut_msrs = {}; + auto const ret{bsl::to_u32(mut_vcpu.read(shim::KVM_GET_MSRS, &mut_msrs))}; + + integration::verify(ret == EXPECTED_NMSRS.get()); + integration::verify(EXPECTED_NMSRS == mut_msrs.nmsrs); + integration::verify(EXPECTED_PAD == mut_msrs.pad); + for (bsl::safe_idx mut_i{}; mut_i < MYSIZE_ENTRIES.get(); ++mut_i) { + mut_msrs.entries.at_if(mut_i)->index = EXPECTED_INDEX.get(); + mut_msrs.entries.at_if(mut_i)->data = EXPECTED_DATA.get(); + } + } + // Try a bunch of times + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + + auto const vcpufd{mut_vm.send(shim::KVM_CREATE_VCPU)}; + integration::ioctl_t mut_vcpu{bsl::to_i32(vcpufd)}; + + constexpr auto num_loops{0x1000_umx}; + for (bsl::safe_idx mut_i{}; mut_i < num_loops; ++mut_i) { + auto const ret{bsl::to_u32(mut_vcpu.read(shim::KVM_GET_MSRS, &mut_msrs))}; + integration::verify(ret == EXPECTED_NMSRS.get()); + } + } + + return bsl::exit_success; +} diff --git a/shim/integration/kvm_get_supported_cpuid.cpp b/shim/integration/kvm_get_supported_cpuid.cpp new file mode 100644 index 000000000..92fba2b2d --- /dev/null +++ b/shim/integration/kvm_get_supported_cpuid.cpp @@ -0,0 +1,95 @@ +/// @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 +#include + +/// +/// @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 +{ + constexpr auto init_nent{0x20_u32}; + constexpr auto cpuid_fn0000_0001{0x00000001_u32}; + shim::kvm_cpuid2 mut_cpuid2{}; + + bsl::enable_color(); + integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME}; + + { + mut_cpuid2.nent = init_nent.get(); + + integration::verify( + mut_system_ctl.write(shim::KVM_GET_SUPPORTED_CPUID, &mut_cpuid2).is_zero()); + + auto nent{bsl::to_u32(mut_cpuid2.nent)}; + integration::verify(nent > bsl::safe_u32::magic_0()); + } + + // Valid registers should be present + { + // Fn0000_0001h[0][EDX][ 5]: RDMSR and WRMSR support + bool found_rdmsr_support{}; + constexpr auto rdmsr_bit{0x20_u32}; + constexpr shim::kvm_cpuid_entry2 rdmsr_support{ + .function = cpuid_fn0000_0001.get(), .index = 0U, .edx = rdmsr_bit.get()}; + auto mut_nent{bsl::to_idx(mut_cpuid2.nent)}; + shim::kvm_cpuid_entry2 mut_entry{}; + + for (bsl::safe_idx mut_i{}; mut_i < mut_nent; ++mut_i) { + mut_entry = *mut_cpuid2.entries.at_if(mut_i); + if ((mut_entry.function == rdmsr_support.function) && // NOLINT + (mut_entry.index == rdmsr_support.index) && // NOLINT + ((mut_entry.edx & rdmsr_support.edx) == rdmsr_support.edx)) { // NOLINT + found_rdmsr_support = true; + } + } + integration::verify(found_rdmsr_support); + } + + // Try a bunch of times + { + constexpr auto num_loops{0x1000_umx}; + for (bsl::safe_idx mut_i{}; mut_i < num_loops; ++mut_i) { + integration::verify( + mut_system_ctl.write(shim::KVM_GET_SUPPORTED_CPUID, &mut_cpuid2).is_zero()); + } + } + + return bsl::exit_success; +} diff --git a/shim/integration/kvm_set_clock.cpp b/shim/integration/kvm_set_clock.cpp new file mode 100644 index 000000000..0534ece2d --- /dev/null +++ b/shim/integration/kvm_set_clock.cpp @@ -0,0 +1,55 @@ +/// @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 + +/// +/// @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(); + integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME}; + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + + shim::kvm_clock_data mut_clock_data; + mut_clock_data.clock = 0xfeedbeef; + mut_clock_data.flags = 2; + integration::verify(mut_vm.write(shim::KVM_SET_CLOCK, &mut_clock_data).is_zero()); + + return bsl::exit_success; +} diff --git a/shim/integration/kvm_set_msrs.cpp b/shim/integration/kvm_set_msrs.cpp new file mode 100644 index 000000000..eb11427a3 --- /dev/null +++ b/shim/integration/kvm_set_msrs.cpp @@ -0,0 +1,110 @@ +/// @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 +#include + +namespace +{ + /// @brief defines the number of MSRS we expect + constexpr auto EXPECTED_NMSRS{0x01_u32}; + /// @brief defines the PAD we expect + constexpr auto EXPECTED_PAD{0x00_u32}; + /// @brief defines the size for entries in RDL + constexpr auto MYSIZE_ENTRIES{1_u64}; + /// @brief defines the register index we expect + constexpr auto EXPECTED_INDEX{0x00_u32}; + /// @brief defines the register data we expect + constexpr auto EXPECTED_DATA{0x42_u64}; +} + +/// +/// @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 +{ + shim::kvm_msrs mut_msrs{}; + + mut_msrs.nmsrs = EXPECTED_NMSRS.get(); + mut_msrs.pad = EXPECTED_PAD.get(); + + for (bsl::safe_idx mut_i{}; mut_i < MYSIZE_ENTRIES.get(); ++mut_i) { + mut_msrs.entries.at_if(mut_i)->index = EXPECTED_INDEX.get(); + mut_msrs.entries.at_if(mut_i)->data = EXPECTED_DATA.get(); + } + + bsl::enable_color(); + integration::ioctl_t mut_system_ctl{shim::DEVICE_NAME}; + + /// Verify that get/set works + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + + auto const vcpufd{mut_vm.send(shim::KVM_CREATE_VCPU)}; + integration::ioctl_t mut_vcpu{bsl::to_i32(vcpufd)}; + + integration::verify(mut_vcpu.write(shim::KVM_SET_MSRS, &mut_msrs).is_zero()); + mut_msrs = {}; + auto const ret{bsl::to_u32(mut_vcpu.read(shim::KVM_GET_MSRS, &mut_msrs))}; + + integration::verify(ret == EXPECTED_NMSRS.get()); + integration::verify(EXPECTED_NMSRS == mut_msrs.nmsrs); + integration::verify(EXPECTED_PAD == mut_msrs.pad); + for (bsl::safe_idx mut_i{}; mut_i < MYSIZE_ENTRIES.get(); ++mut_i) { + mut_msrs.entries.at_if(mut_i)->index = EXPECTED_INDEX.get(); + mut_msrs.entries.at_if(mut_i)->data = EXPECTED_DATA.get(); + } + } + + // Try a bunch of times + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + + auto const vcpufd{mut_vm.send(shim::KVM_CREATE_VCPU)}; + integration::ioctl_t mut_vcpu{bsl::to_i32(vcpufd)}; + + constexpr auto num_loops{0x1000_umx}; + for (bsl::safe_idx mut_i{}; mut_i < num_loops; ++mut_i) { + integration::verify(mut_vcpu.write(shim::KVM_SET_MSRS, &mut_msrs).is_zero()); + } + } + + return bsl::exit_success; +} diff --git a/shim/integration/kvm_set_user_memory_region.cpp b/shim/integration/kvm_set_user_memory_region.cpp index b6954c9d9..d8f61311d 100644 --- a/shim/integration/kvm_set_user_memory_region.cpp +++ b/shim/integration/kvm_set_user_memory_region.cpp @@ -201,6 +201,84 @@ main() noexcept -> bsl::exit_code mut_vm.close(); } + // non-canonical address below the canonical boundary + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + constexpr auto non_canonical_address{0xFFFF7FFFFFFFFFFF_u64}; + shim::kvm_userspace_memory_region mut_region{}; + mut_region.slot = {}; + mut_region.flags = {}; + mut_region.guest_phys_addr = {}; + mut_region.memory_size = vm_image.size().get(); + mut_region.userspace_addr = reinterpret_cast(non_canonical_address.get()); + + auto const ret{mut_vm.write(shim::KVM_SET_USER_MEMORY_REGION, &mut_region)}; + integration::verify(ret.is_neg()); + + mut_vm.close(); + } + + // non-canonical address above the canonical boundary + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + constexpr auto non_canonical_address{0x0008000000000000_u64}; + shim::kvm_userspace_memory_region mut_region{}; + mut_region.slot = {}; + mut_region.flags = {}; + mut_region.guest_phys_addr = {}; + mut_region.memory_size = vm_image.size().get(); + mut_region.userspace_addr = reinterpret_cast(non_canonical_address.get()); + + auto const ret{mut_vm.write(shim::KVM_SET_USER_MEMORY_REGION, &mut_region)}; + integration::verify(ret.is_neg()); + + mut_vm.close(); + } + + // canonical address on the higher canonical boundary + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + constexpr auto non_canonical_address{0xFFFF800000000000_u64}; + shim::kvm_userspace_memory_region mut_region{}; + mut_region.slot = {}; + mut_region.flags = {}; + mut_region.guest_phys_addr = {}; + mut_region.memory_size = vm_image.size().get(); + mut_region.userspace_addr = reinterpret_cast(non_canonical_address.get()); + + auto const ret{mut_vm.write(shim::KVM_SET_USER_MEMORY_REGION, &mut_region)}; + // This fails on platform_virt_to_phys, but none of the error paths distinguish + // between error type. This test should verify ret.is_zero(). Might have to add + // flags for the shim to short circuit. + integration::verify(ret.is_neg()); + + mut_vm.close(); + } + + // canonical address on the lower canonical boundary + { + auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; + integration::ioctl_t mut_vm{bsl::to_i32(vmfd)}; + constexpr auto non_canonical_address{0x0007FFFFFFFFFFFF_u64}; + shim::kvm_userspace_memory_region mut_region{}; + mut_region.slot = {}; + mut_region.flags = {}; + mut_region.guest_phys_addr = {}; + mut_region.memory_size = vm_image.size().get(); + mut_region.userspace_addr = reinterpret_cast(non_canonical_address.get()); + + auto const ret{mut_vm.write(shim::KVM_SET_USER_MEMORY_REGION, &mut_region)}; + // This fails on platform_virt_to_phys, but none of the error paths distinguish + // between error type. This test should verify ret.is_zero(). Might have to add + // flags for the shim to short circuit. + integration::verify(ret.is_neg()); + + mut_vm.close(); + } + // The shim has a limited number of slots { auto const vmfd{mut_system_ctl.send(shim::KVM_CREATE_VM)}; diff --git a/shim/linux/include/platform_interface/shim_platform_interface.h b/shim/linux/include/platform_interface/shim_platform_interface.h index 03e73db7b..15a78ed6b 100644 --- a/shim/linux/include/platform_interface/shim_platform_interface.h +++ b/shim/linux/include/platform_interface/shim_platform_interface.h @@ -78,12 +78,16 @@ /** @brief defines the /dev name of the shim */ #define SHIM_DEVICE_NAME "/dev/microv_shim" +#define _IOWR_LIST(type, nr, size, sub_size) \ + _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size) - sizeof(sub_size)) + /** @brief defines KVM's KVM_GET_API_VERSION IOCTL */ #define KVM_GET_API_VERSION _IO(SHIMIO, 0x00) /** @brief defines KVM's KVM_CREATE_VM IOCTL */ #define KVM_CREATE_VM _IO(SHIMIO, 0x01) /** @brief defines KVM's KVM_GET_MSR_INDEX_LIST IOCTL */ -#define KVM_GET_MSR_INDEX_LIST _IOWR(SHIMIO, 0x02, struct kvm_msr_list) +#define KVM_GET_MSR_INDEX_LIST \ + _IOWR_LIST(SHIMIO, 0x02, struct kvm_msr_list, uint32_t[MSR_LIST_MAX_INDICES]) /** @brief defines KVM's KVM_GET_MSR_FEATURE_INDEX_LIST IOCTL */ #define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(SHIMIO, 0x0a, struct kvm_msr_list) /** @brief defines KVM's KVM_CHECK_EXTENSION IOCTL */ @@ -109,8 +113,11 @@ /** @brief defines KVM's KVM_INTERRUPT IOCTL */ #define KVM_INTERRUPT _IOW(SHIMIO, 0x86, struct kvm_interrupt) /** @brief defines KVM's KVM_GET_MSRS IOCTL */ -#define KVM_GET_MSRS _IOWR(SHIMIO, 0x88, struct kvm_msrs) +#define KVM_GET_MSRS \ + _IOWR_LIST(SHIMIO, 0x88, struct kvm_msrs, struct kvm_msr_entry[MV_RDL_MAX_ENTRIES]) +//#define KVM_GET_MSRS _IOWR(SHIMIO, 0x88, struct kvm_msrs) /** @brief defines KVM's KVM_SET_MSRS IOCTL */ +//#define KVM_SET_MSRS _IOWR_LIST(SHIMIO, 0x89, struct kvm_msrs, struct kvm_msr_entry[MV_RDL_MAX_ENTRIES]) #define KVM_SET_MSRS _IOW(SHIMIO, 0x89, struct kvm_msrs) /** @brief defines KVM's KVM_SET_CPUID IOCTL */ #define KVM_SET_CPUID _IOW(SHIMIO, 0x8a, struct kvm_cpuid) @@ -169,7 +176,7 @@ /** @brief defines KVM's KVM_SET_XCRS IOCTL */ #define KVM_SET_XCRS _IOW(SHIMIO, 0xa7, struct kvm_xcrs) /** @brief defines KVM's KVM_GET_SUPPORTED_CPUID IOCTL */ -#define KVM_GET_SUPPORTED_CPUID _IOWR(SHIMIO, 0x05, struct kvm_cpuid2) +#define KVM_GET_SUPPORTED_CPUID _IOWR_LIST(SHIMIO, 0x05, struct kvm_cpuid2, struct kvm_cpuid_entry2[CPUID2_MAX_ENTRIES]) /** @brief defines KVM's KVM_SET_GSI_ROUTING IOCTL */ #define KVM_SET_GSI_ROUTING _IOW(SHIMIO, 0x6a, struct kvm_irq_routing) /** @brief defines KVM's KVM_GET_TSC_KHZ IOCTL */ diff --git a/shim/linux/include/platform_interface/shim_platform_interface.hpp b/shim/linux/include/platform_interface/shim_platform_interface.hpp index 74321c259..c0e7aa821 100644 --- a/shim/linux/include/platform_interface/shim_platform_interface.hpp +++ b/shim/linux/include/platform_interface/shim_platform_interface.hpp @@ -28,9 +28,13 @@ #define SHIM_PLATFORM_INTERFACE_HPP #include +#include +#include #include #include +#include #include +#include #include #include #include @@ -43,7 +47,6 @@ // #include // #include // #include -// #include // #include // #include // #include @@ -78,6 +81,16 @@ // #include // #include // #include +/** + * @brief Hack for defining ioctl commands that require structs + * with zero-length arrays. This is usually for ioctls that return + * a list. + * + * It is just like _IOWR, except it subtracts the size of a pointer + * from the size of the struct passed. + */ +#define _IOWR_LIST(type, nr, size, sub_size) \ + _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size) - sizeof(sub_size)) namespace shim { @@ -94,8 +107,8 @@ namespace shim /// @brief defines KVM's KVM_CREATE_VM IOCTL constexpr bsl::safe_umx KVM_CREATE_VM{static_cast(_IO(SHIMIO.get(), 0x01))}; /// @brief defines KVM's KVM_GET_MSR_INDEX_LIST IOCTL - constexpr bsl::safe_umx KVM_GET_MSR_INDEX_LIST{ - static_cast(_IOWR(SHIMIO.get(), 0x02, struct kvm_msr_list))}; + constexpr bsl::safe_umx KVM_GET_MSR_INDEX_LIST{static_cast( + _IOWR_LIST(SHIMIO.get(), 0x02, struct kvm_msr_list, uint32_t[MSR_LIST_MAX_INDICES.get()]))}; // /// @brief defines KVM's KVM_GET_MSR_FEATURE_INDEX_LIST IOCTL // constexpr bsl::safe_umx KVM_GET_MSR_FEATURE_INDEX_LIST{static_cast(_IOWR(SHIMIO.get(), 0x0a, struct kvm_msr_list))}; /// @brief defines KVM's KVM_CHECK_EXTENSION IOCTL @@ -125,10 +138,12 @@ namespace shim // constexpr bsl::safe_umx KVM_TRANSLATE{static_cast(_IOWR(SHIMIO.get(), 0x85, struct kvm_translation))}; // /// @brief defines KVM's KVM_INTERRUPT IOCTL // constexpr bsl::safe_umx KVM_INTERRUPT{static_cast(_IOW(SHIMIO.get(), 0x86, struct kvm_interrupt))}; - // /// @brief defines KVM's KVM_GET_MSRS IOCTL - // constexpr bsl::safe_umx KVM_GET_MSRS{static_cast(_IOWR(SHIMIO.get(), 0x88, struct kvm_msrs))}; - // /// @brief defines KVM's KVM_SET_MSRS IOCTL - // constexpr bsl::safe_umx KVM_SET_MSRS{static_cast(_IOW(SHIMIO.get(), 0x89, struct kvm_msrs))}; + /// @brief defines KVM's KVM_GET_MSRS IOCTL + constexpr bsl::safe_umx KVM_GET_MSRS{static_cast(_IOWR_LIST( + SHIMIO.get(), 0x88, struct kvm_msrs, struct kvm_msr_entry[MV_RDL_MAX_ENTRIES.get()]))}; + /// @brief defines KVM's KVM_SET_MSRS IOCTL + constexpr bsl::safe_umx KVM_SET_MSRS{ + static_cast(_IOW(SHIMIO.get(), 0x89, struct kvm_msrs))}; // /// @brief defines KVM's KVM_SET_CPUID IOCTL // constexpr bsl::safe_umx KVM_SET_CPUID{static_cast(_IOW(SHIMIO.get(), 0x8a, struct kvm_cpuid))}; // /// @brief defines KVM's KVM_GET_CPUID2 IOCTL @@ -153,10 +168,10 @@ namespace shim // constexpr bsl::safe_umx KVM_SET_IRQCHIP{static_cast(_IOR(SHIMIO.get(), 0x63, struct kvm_irqchip))}; // /// @brief defines KVM's KVM_XEN_HVM_CONFIG IOCTL // constexpr bsl::safe_umx KVM_XEN_HVM_CONFIG{static_cast(_IOW(SHIMIO.get(), 0x7a, struct kvm_xen_hvm_config))}; - // /// @brief defines KVM's KVM_GET_CLOCK IOCTL - // constexpr bsl::safe_umx KVM_GET_CLOCK{static_cast(_IOR(SHIMIO.get(), 0x7c, struct kvm_clock_data))}; - // /// @brief defines KVM's KVM_SET_CLOCK IOCTL - // constexpr bsl::safe_umx KVM_SET_CLOCK{static_cast(_IOW(SHIMIO.get(), 0x7b, struct kvm_clock_data))}; + /// @brief defines KVM's KVM_GET_CLOCK IOCTL + constexpr bsl::safe_umx KVM_GET_CLOCK{static_cast(_IOR(SHIMIO.get(), 0x7c, struct kvm_clock_data))}; + /// @brief defines KVM's KVM_SET_CLOCK IOCTL + constexpr bsl::safe_umx KVM_SET_CLOCK{static_cast(_IOW(SHIMIO.get(), 0x7b, struct kvm_clock_data))}; // /// @brief defines KVM's KVM_GET_VCPU_EVENTS IOCTL // constexpr bsl::safe_umx KVM_GET_VCPU_EVENTS{static_cast(_IOR(SHIMIO.get(), 0x9f, struct kvm_vcpu_events))}; // /// @brief defines KVM's KVM_SET_VCPU_EVENTS IOCTL @@ -191,8 +206,9 @@ namespace shim // constexpr bsl::safe_umx KVM_GET_XCRS{static_cast(_IOR(SHIMIO.get(), 0xa6, struct kvm_xcrs))}; // /// @brief defines KVM's KVM_SET_XCRS IOCTL // constexpr bsl::safe_umx KVM_SET_XCRS{static_cast(_IOW(SHIMIO.get(), 0xa7, struct kvm_xcrs))}; - // /// @brief defines KVM's KVM_GET_SUPPORTED_CPUID IOCTL - // constexpr bsl::safe_umx KVM_GET_SUPPORTED_CPUID{static_cast(_IOWR(SHIMIO.get(), 0x05, struct kvm_cpuid2))}; + /// @brief defines KVM's KVM_GET_SUPPORTED_CPUID IOCTL + constexpr bsl::safe_umx KVM_GET_SUPPORTED_CPUID{ + static_cast(_IOWR_LIST(SHIMIO.get(), 0x05, struct kvm_cpuid2, struct kvm_cpuid_entry2[CPUID2_MAX_ENTRIES.get()]))}; // /// @brief defines KVM's KVM_SET_GSI_ROUTING IOCTL // constexpr bsl::safe_umx KVM_SET_GSI_ROUTING{static_cast(_IOW(SHIMIO.get(), 0x6a, struct kvm_irq_routing))}; /// @brief defines KVM's KVM_GET_TSC_KHZ IOCTL diff --git a/shim/linux/include/types.h b/shim/linux/include/types.h index ea5b19990..92fc2dd4f 100644 --- a/shim/linux/include/types.h +++ b/shim/linux/include/types.h @@ -50,4 +50,9 @@ */ #define SHIM_INTERRUPTED ((int64_t)-EINTR) +/** + * @brief Returned by a shim function when a provided data structure + * is not large enough to hold the return data. + */ +#define SHIM_2BIG ((int64_t)-E2BIG) #endif diff --git a/shim/linux/src/entry.c b/shim/linux/src/entry.c index a848e23b2..afe1a2bd2 100644 --- a/shim/linux/src/entry.c +++ b/shim/linux/src/entry.c @@ -32,20 +32,26 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -230,57 +236,46 @@ dispatch_system_kvm_get_msr_feature_index_list( static long dispatch_system_kvm_get_msr_index_list( - struct kvm_msr_list __user *const user_args) + struct kvm_msr_list __user *const pmut_user_args) { struct kvm_msr_list mut_args; - uint32_t __user *pmut_mut_user_indices; int64_t mut_ret; - uint64_t mut_alloc_size; - if (platform_copy_from_user(&mut_args, user_args, sizeof(mut_args))) { + if (platform_copy_from_user(&mut_args, pmut_user_args, sizeof(mut_args))) { bferror("platform_copy_from_user failed"); return -EINVAL; } - mut_alloc_size = mut_args.nmsrs * sizeof(*mut_args.indices); - if (mut_alloc_size > HYPERVISOR_PAGE_SIZE) { - bferror("requested nmsrs too big"); + if (mut_args.nmsrs > MSR_LIST_MAX_INDICES) { + bferror("caller nmsrs exceeds MSR_LIST_MAX_INDICES"); return -ENOMEM; } - pmut_mut_user_indices = mut_args.indices; - mut_args.indices = vzalloc(mut_alloc_size); + mut_ret = handle_system_kvm_get_msr_index_list(&mut_args); + if (SHIM_2BIG == mut_ret) { + if (platform_copy_to_user( + pmut_user_args, &mut_args, sizeof(mut_args.nmsrs))) { + bferror("platform_copy_to_user nmsrs failed"); + return -EINVAL; + } - if (NULL == mut_args.indices) { - bferror("vzalloc failed"); - return -ENOMEM; + return -E2BIG; } - - mut_ret = -EINVAL; - if (handle_system_kvm_get_msr_index_list(&mut_args)) { + else if (mut_ret) { bferror("handle_system_kvm_get_msr_index_list failed"); - goto out; - } - - if (platform_copy_to_user(user_args, &mut_args, sizeof(mut_args.nmsrs))) { - bferror("platform_copy_to_user nmsrs failed"); - goto out; + return -EINVAL; } if (platform_copy_to_user( - pmut_mut_user_indices, - mut_args.indices, - mut_args.nmsrs * sizeof(*mut_args.indices))) { + pmut_user_args, + &mut_args, + sizeof(mut_args.nmsrs) + + mut_args.nmsrs * sizeof(*mut_args.indices))) { bferror("platform_copy_to_user indices failed"); - goto out; + return -EINVAL; } - mut_ret = 0; -out: - if (mut_args.indices) - vfree(mut_args.indices); - - return mut_ret; + return 0; } static long @@ -291,10 +286,47 @@ dispatch_system_kvm_get_msrs(struct kvm_msrs *const ioctl_args) } static long -dispatch_system_kvm_get_supported_cpuid(struct kvm_cpuid2 *const ioctl_args) +dispatch_system_kvm_get_supported_cpuid( + struct kvm_cpuid2 __user *const pmut_user_args) { - (void)ioctl_args; - return -EINVAL; + struct kvm_cpuid2 mut_args; + int64_t mut_ret; + + if (platform_copy_from_user(&mut_args, pmut_user_args, sizeof(mut_args))) { + bferror("platform_copy_from_user failed"); + return -EINVAL; + } + + if (mut_args.nent > CPUID2_MAX_ENTRIES) { + bferror("caller nent exceeds CPUID2_MAX_ENTRIES"); + return -ENOMEM; + } + + mut_ret = handle_system_kvm_get_supported_cpuid(&mut_args); + if (SHIM_2BIG == mut_ret) { + if (platform_copy_to_user( + pmut_user_args, &mut_args, sizeof(mut_args.nent))) { + bferror("platform_copy_to_user nent failed"); + return -EINVAL; + } + + return -E2BIG; + } + else if (mut_ret) { + bferror("handle_system_kvm_get_msr_index_list failed"); + return -EINVAL; + } + + if (platform_copy_to_user( + pmut_user_args, + &mut_args, + sizeof(mut_args.nent) + + mut_args.nent * sizeof(*mut_args.entries))) { + bferror("platform_copy_to_user failed"); + return -EINVAL; + } + + return 0; } static long @@ -500,8 +532,19 @@ dispatch_vm_kvm_create_vcpu(struct shim_vm_t *const pmut_vm) static long dispatch_vm_kvm_get_clock(struct kvm_clock_data *const ioctl_args) { - (void)ioctl_args; - return -EINVAL; + struct kvm_clock_data mut_args; + + if (handle_vm_kvm_get_clock(&mut_args)) { + bferror("handle_vm_kvm_get_clock failed"); + return -EINVAL; + } + + if (platform_copy_to_user(ioctl_args, &mut_args, sizeof(*ioctl_args))) { + bferror("platform_copy_from_user failed"); + return -EINVAL; + } + + return 0; } static long @@ -597,8 +640,19 @@ dispatch_vm_kvm_set_boot_cpu_id(void) static long dispatch_vm_kvm_set_clock(struct kvm_clock_data *const ioctl_args) { - (void)ioctl_args; - return -EINVAL; + struct kvm_clock_data mut_args; + + if (platform_copy_from_user(&mut_args, ioctl_args, sizeof(*ioctl_args))) { + bferror("platform_copy_from_user failed"); + return -EINVAL; + } + + if (handle_vm_kvm_set_clock(&mut_args)) { + bferror("handle_vm_kvm_get_clock failed"); + return -EINVAL; + } + + return 0; } static long @@ -951,10 +1005,23 @@ dispatch_vcpu_kvm_get_mp_state( } static long -dispatch_vcpu_kvm_get_msrs(struct kvm_msrs *const ioctl_args) +dispatch_vcpu_kvm_get_msrs( + struct shim_vcpu_t const *const vcpu, struct kvm_msrs *const user_args) { - (void)ioctl_args; - return -EINVAL; + struct kvm_msrs mut_args; + uint64_t const size = sizeof(mut_args); + + if (handle_vcpu_kvm_get_msrs(vcpu, &mut_args)) { + bferror("handle_vcpu_kvm_get_msrs failed"); + return -EINVAL; + } + + if (platform_copy_to_user(user_args, &mut_args, size)) { + bferror("platform_copy_to_user failed"); + return -EINVAL; + } + + return (long)mut_args.nmsrs; } static long @@ -1155,10 +1222,29 @@ dispatch_vcpu_kvm_set_mp_state( } static long -dispatch_vcpu_kvm_set_msrs(struct kvm_msrs *const ioctl_args) +dispatch_vcpu_kvm_set_msrs( + struct shim_vcpu_t const *const vcpu, struct kvm_msrs *const user_args) { - (void)ioctl_args; - return -EINVAL; + + struct kvm_msrs mut_args; + uint64_t const size = sizeof(mut_args); + + if (NULL == user_args) { + bferror("user_args are null"); + return -EINVAL; + } + + if (platform_copy_from_user(&mut_args, user_args, size)) { + bferror("platform_copy_from_user failed"); + return -EINVAL; + } + + if (handle_vcpu_kvm_set_msrs(vcpu, &mut_args)) { + bferror("handle_vcpu_kvm_set_msrs failed"); + return -EINVAL; + } + + return 0; } static long @@ -1266,7 +1352,7 @@ static long dispatch_vcpu_kvm_x86_set_mce(struct kvm_x86_mce *const ioctl_args) { (void)ioctl_args; - return -EINVAL; + return -EINVAL; } static long @@ -1314,7 +1400,8 @@ dev_unlocked_ioctl_vcpu( } case KVM_GET_MSRS: { - return dispatch_vcpu_kvm_get_msrs((struct kvm_msrs *)ioctl_args); + return dispatch_vcpu_kvm_get_msrs( + pmut_mut_vcpu, (struct kvm_msrs *)ioctl_args); } case KVM_GET_NESTED_STATE: { @@ -1390,7 +1477,6 @@ dev_unlocked_ioctl_vcpu( } case KVM_SET_FPU: { - bferror("in KVM_set_fpu"); return dispatch_vcpu_kvm_set_fpu( pmut_mut_vcpu, (struct kvm_fpu *)ioctl_args); } @@ -1411,7 +1497,8 @@ dev_unlocked_ioctl_vcpu( } case KVM_SET_MSRS: { - return dispatch_vcpu_kvm_set_msrs((struct kvm_msrs *)ioctl_args); + return dispatch_vcpu_kvm_set_msrs( + pmut_mut_vcpu, (struct kvm_msrs *)ioctl_args); } case KVM_SET_NESTED_STATE: { diff --git a/shim/src/handle_system_kvm_get_msr_index_list.c b/shim/src/handle_system_kvm_get_msr_index_list.c index 00df95a34..0b156a87c 100644 --- a/shim/src/handle_system_kvm_get_msr_index_list.c +++ b/shim/src/handle_system_kvm_get_msr_index_list.c @@ -41,11 +41,14 @@ * * * @param pmut_ioctl_args the arguments provided by userspace - * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. + * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure, and SHIM_2BIG when + * the number of MSRs is greater than what was set in nmsrs. When SHIM_2BIG is + * returned, the correct number of MSRs is set in the nmsrs field. */ NODISCARD int64_t handle_system_kvm_get_msr_index_list(struct kvm_msr_list *const pmut_ioctl_args) NOEXCEPT { + int64_t mut_ret; int64_t mut_i; uint32_t mut_nmsrs = ((uint32_t)0); @@ -57,11 +60,6 @@ handle_system_kvm_get_msr_index_list(struct kvm_msr_list *const pmut_ioctl_args) return SHIM_FAILURE; } - if (NULL == pmut_ioctl_args->indices) { - bferror("indices not allocated"); - return SHIM_FAILURE; - } - platform_expects(MV_INVALID_HANDLE != g_mut_hndl); do { @@ -78,18 +76,29 @@ handle_system_kvm_get_msr_index_list(struct kvm_msr_list *const pmut_ioctl_args) return SHIM_FAILURE; } + /** + * If the provided buffer is not large enough to fit all the MSRs, we still + * need to calculate the total number, and set the nmsrs field correctly. + */ if (pmut_rdl->num_entries + ((uint64_t)mut_nmsrs) > ((uint64_t)pmut_ioctl_args->nmsrs)) { - bferror("number of MSRs is larger than kvm_msr_list indices"); - return SHIM_FAILURE; + mut_nmsrs += pmut_rdl->num_entries; } - - for (mut_i = ((int64_t)0); mut_i < ((int64_t)pmut_rdl->num_entries); ++mut_i) { - pmut_ioctl_args->indices[mut_nmsrs] = ((uint32_t)pmut_rdl->entries[mut_i].reg); - ++mut_nmsrs; + else { + for (mut_i = ((int64_t)0); mut_i < ((int64_t)pmut_rdl->num_entries); ++mut_i) { + pmut_ioctl_args->indices[mut_nmsrs] = ((uint32_t)pmut_rdl->entries[mut_i].reg); + ++mut_nmsrs; + } } } while (((uint64_t)0) != pmut_rdl->reg1); + if (mut_nmsrs > pmut_ioctl_args->nmsrs) { + mut_ret = SHIM_2BIG; + } + else { + mut_ret = SHIM_SUCCESS; + } + pmut_ioctl_args->nmsrs = mut_nmsrs; - return SHIM_SUCCESS; + return mut_ret; } diff --git a/shim/src/handle_system_kvm_get_supported_cpuid.c b/shim/src/handle_system_kvm_get_supported_cpuid.c index e5c945d2c..16bde371c 100644 --- a/shim/src/handle_system_kvm_get_supported_cpuid.c +++ b/shim/src/handle_system_kvm_get_supported_cpuid.c @@ -24,8 +24,17 @@ * SOFTWARE. */ +#include +#include +#include #include +#include +#include +#include +#include #include +#include +#include /** * @@ -33,11 +42,90 @@ * * * @param pmut_ioctl_args the arguments provided by userspace - * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. + * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure, and SHIM_2BIG when + * the number of CPUID entries is greater than what was set in nent. When SHIM_2BIG is + * returned, the correct number of CPUID entries is set in the nent field. */ NODISCARD int64_t handle_system_kvm_get_supported_cpuid(struct kvm_cpuid2 *const pmut_ioctl_args) NOEXCEPT { - (void)pmut_ioctl_args; + uint32_t const init_fun = ((uint32_t)0x00000000); + uint32_t const init_xfun = ((uint32_t)0x80000000); + uint32_t mut_fun = init_fun; + uint32_t mut_xfun = init_xfun; + uint32_t mut_fun_max; + uint32_t mut_xfun_max; + uint64_t mut_i; + struct mv_cdl_entry_t mut_cdl_entry; + + struct mv_cdl_t *const pmut_cdl = (struct mv_cdl_t *)shared_page_for_current_pp(); + platform_expects(NULL != pmut_cdl); + + if (detect_hypervisor()) { + bferror("The shim is not running in a VM. Did you forget to start MicroV?"); + return SHIM_FAILURE; + } + + if (!pmut_ioctl_args->entries) { + bferror("entries array not allocated"); + return SHIM_FAILURE; + } + + /* Start by getting the largest function and largest extended function */ + pmut_cdl->num_entries = ((uint64_t)2); + pmut_cdl->entries[0].fun = mut_fun; + pmut_cdl->entries[1].fun = mut_xfun; + + platform_expects(MV_INVALID_HANDLE != g_mut_hndl); + if (mv_pp_op_cpuid_get_supported_list(g_mut_hndl)) { + bferror("mv_pp_op_cpuid_get_supported_list failed"); + return SHIM_FAILURE; + } + + /* Calculate the new num_entries */ + mut_fun_max = pmut_cdl->entries[0].eax; + mut_xfun_max = pmut_cdl->entries[1].eax; + pmut_cdl->num_entries = ((uint64_t)(mut_fun_max + mut_xfun_max - init_xfun)); + + if (pmut_cdl->num_entries >= MV_CDL_MAX_ENTRIES) { + bferror("num_entries exceeds MV_CDL_MAX_ENTRIES"); + return SHIM_FAILURE; + } + + if (pmut_cdl->num_entries > ((uint64_t)pmut_ioctl_args->nent)) { + bferror("CDL entries is larger than kvm_cpuid2 entries"); + pmut_ioctl_args->nent = ((uint32_t)pmut_cdl->num_entries); + return SHIM_2BIG; + } + + mut_i = ((uint64_t)0); + for (; mut_fun < mut_fun_max; ++mut_fun) { + pmut_cdl->entries[mut_i].fun = mut_fun; + ++mut_i; + } + + for (; mut_xfun < mut_xfun_max; ++mut_xfun) { + pmut_cdl->entries[mut_i].fun = mut_xfun; + ++mut_i; + } + + platform_expects(MV_INVALID_HANDLE != g_mut_hndl); + if (mv_pp_op_cpuid_get_supported_list(g_mut_hndl)) { + bferror("mv_pp_op_cpuid_get_supported_list failed"); + return SHIM_FAILURE; + } + + for (mut_i = ((uint64_t)0); mut_i < ((uint64_t)pmut_cdl->num_entries); ++mut_i) { + mut_cdl_entry = pmut_cdl->entries[mut_i]; + pmut_ioctl_args->entries[mut_i].function = mut_cdl_entry.fun; + pmut_ioctl_args->entries[mut_i].index = mut_cdl_entry.idx; + pmut_ioctl_args->entries[mut_i].flags = mut_cdl_entry.flags; + pmut_ioctl_args->entries[mut_i].eax = mut_cdl_entry.eax; + pmut_ioctl_args->entries[mut_i].ebx = mut_cdl_entry.ebx; + pmut_ioctl_args->entries[mut_i].ecx = mut_cdl_entry.ecx; + pmut_ioctl_args->entries[mut_i].edx = mut_cdl_entry.edx; + } + pmut_ioctl_args->nent = ((uint32_t)pmut_cdl->num_entries); + return SHIM_SUCCESS; } diff --git a/shim/src/handle_vcpu_kvm_get_msrs.c b/shim/src/handle_vcpu_kvm_get_msrs.c index 3e9b2d298..4b63a6155 100644 --- a/shim/src/handle_vcpu_kvm_get_msrs.c +++ b/shim/src/handle_vcpu_kvm_get_msrs.c @@ -24,20 +24,63 @@ * SOFTWARE. */ +#include +#include +#include +#include #include +#include +#include +#include #include - +#include +#include +#include /** * * @brief Handles the execution of kvm_get_msrs. * * - * @param pmut_ioctl_args the arguments provided by userspace + * @param vcpu arguments received from private data + * @param pmut_args the arguments provided by userspace * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ NODISCARD int64_t -handle_vcpu_kvm_get_msrs(struct kvm_msrs *const pmut_ioctl_args) NOEXCEPT +handle_vcpu_kvm_get_msrs( + struct shim_vcpu_t const *const vcpu, struct kvm_msrs *const pmut_args) NOEXCEPT { - (void)pmut_ioctl_args; + uint64_t mut_i; + platform_expects(MV_INVALID_HANDLE != g_mut_hndl); + platform_expects(NULL != vcpu); + platform_expects(NULL != pmut_args); + + if (detect_hypervisor()) { + bferror("The shim is not running in a VM. Did you forget to start MicorV?"); + return SHIM_FAILURE; + } + + struct mv_rdl_t *const pmut_rdl = (struct mv_rdl_t *)shared_page_for_current_pp(); + platform_expects(NULL != pmut_rdl); + + pmut_rdl->num_entries = (uint64_t)pmut_args->nmsrs; + + for (mut_i = ((uint64_t)0); mut_i < pmut_rdl->num_entries; ++mut_i) { + pmut_rdl->entries[mut_i].reg = (uint64_t)pmut_args->entries[mut_i].index; + } + + if (mv_vs_op_msr_get_list(g_mut_hndl, vcpu->vsid)) { + bferror("mv_vs_op_msr_get_list failed"); + return SHIM_FAILURE; + } + + if (pmut_rdl->num_entries != (uint64_t)pmut_args->nmsrs) { + bferror("The RDL's num_entries is no longer valid"); + return SHIM_FAILURE; + } + + for (mut_i = ((uint64_t)0); mut_i < pmut_rdl->num_entries; ++mut_i) { + pmut_args->entries[mut_i].data = pmut_rdl->entries[mut_i].val; + } + return SHIM_SUCCESS; } diff --git a/shim/src/handle_vcpu_kvm_set_msrs.c b/shim/src/handle_vcpu_kvm_set_msrs.c index 6f2bc0380..e719c5fea 100644 --- a/shim/src/handle_vcpu_kvm_set_msrs.c +++ b/shim/src/handle_vcpu_kvm_set_msrs.c @@ -23,21 +23,56 @@ * 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 +#include +#include /** * * @brief Handles the execution of kvm_set_msrs. * * - * @param pmut_ioctl_args the arguments provided by userspace + * @param args the arguments provided by userspace + * @param vcpu arguments received from private data * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ NODISCARD int64_t -handle_vcpu_kvm_set_msrs(struct kvm_msrs *const pmut_ioctl_args) NOEXCEPT +handle_vcpu_kvm_set_msrs( + struct shim_vcpu_t const *const vcpu, struct kvm_msrs const *const args) NOEXCEPT { - (void)pmut_ioctl_args; + uint64_t mut_i; + platform_expects(MV_INVALID_HANDLE != g_mut_hndl); + platform_expects(NULL != vcpu); + platform_expects(NULL != args); + + if (detect_hypervisor()) { + bferror("The shim is not running in a VM. Did you forget to start MicroV?"); + return SHIM_FAILURE; + } + + struct mv_rdl_t *const pmut_rdl = (struct mv_rdl_t *)shared_page_for_current_pp(); + platform_expects(NULL != pmut_rdl); + + pmut_rdl->num_entries = (uint64_t)args->nmsrs; + + for (mut_i = ((uint64_t)0); mut_i < pmut_rdl->num_entries; ++mut_i) { + pmut_rdl->entries[mut_i].reg = (uint64_t)args->entries[mut_i].index; + pmut_rdl->entries[mut_i].val = args->entries[mut_i].data; + } + + if (mv_vs_op_msr_set_list(g_mut_hndl, vcpu->vsid)) { + bferror("mv_vs_op_msr_set_list failed"); + return SHIM_FAILURE; + } + return SHIM_SUCCESS; } diff --git a/shim/src/handle_vm_kvm_get_clock.c b/shim/src/handle_vm_kvm_get_clock.c index 283e64da2..f3b1364ab 100644 --- a/shim/src/handle_vm_kvm_get_clock.c +++ b/shim/src/handle_vm_kvm_get_clock.c @@ -25,6 +25,7 @@ */ #include +#include #include /** @@ -38,6 +39,10 @@ NODISCARD int64_t handle_vm_kvm_get_clock(struct kvm_clock_data *const pmut_ioctl_args) NOEXCEPT { - (void)pmut_ioctl_args; + platform_expects(NULL != pmut_ioctl_args); + + pmut_ioctl_args->clock = 0xDEADBEEF; + pmut_ioctl_args->flags = 0; + return SHIM_SUCCESS; } diff --git a/shim/src/handle_vm_kvm_set_clock.c b/shim/src/handle_vm_kvm_set_clock.c index 894b0c4c4..a8665a5cd 100644 --- a/shim/src/handle_vm_kvm_set_clock.c +++ b/shim/src/handle_vm_kvm_set_clock.c @@ -24,8 +24,10 @@ * SOFTWARE. */ +#include #include #include +#include /** * @@ -38,6 +40,9 @@ NODISCARD int64_t handle_vm_kvm_set_clock(struct kvm_clock_data *const pmut_ioctl_args) NOEXCEPT { - (void)pmut_ioctl_args; + platform_expects(NULL != pmut_ioctl_args); + + bferror_x64("clock value: ", pmut_ioctl_args->clock); + return SHIM_SUCCESS; } diff --git a/shim/src/handle_vm_kvm_set_user_memory_region.c b/shim/src/handle_vm_kvm_set_user_memory_region.c index b96fcbf11..bdf525212 100644 --- a/shim/src/handle_vm_kvm_set_user_memory_region.c +++ b/shim/src/handle_vm_kvm_set_user_memory_region.c @@ -70,6 +70,30 @@ get_slot_as(uint32_t const slot) NOEXCEPT return slot & as_mask; } +/** + * + * @brief Translates KVM_MEM_* flags to MV_MAP_FLAG* flags + * + * + * @param flags KVM memory flag in the set_user_memory_region + * @return Returns the microv equivalent flag for the kvm flag + */ +NODISCARD static inline uint64_t +kvm_to_mv_page_flags(uint32_t const flags) NOEXCEPT +{ + uint64_t mut_flags = ((uint64_t)0); + if (flags & ((uint32_t)KVM_MEM_READONLY)) { + // Anticipate that we'll have to provide RE access here + // in reality + mut_flags |= MV_MAP_FLAG_READ_ACCESS; + } + else { + mv_touch(); + } + + return mut_flags; +} + /** * * @brief Handles the execution of kvm_set_user_memory_region. @@ -83,6 +107,8 @@ NODISCARD int64_t handle_vm_kvm_set_user_memory_region( struct kvm_userspace_memory_region const *const args, struct shim_vm_t *const pmut_vm) NOEXCEPT { + uint64_t const high_canonical_boundary = ((uint64_t)0xFFFF800000000000ULL); + uint64_t const low_canonical_boundary = ((uint64_t)0x00007FFFFFFFFFFFULL); struct mv_mdl_t *pmut_mut_mdl; int64_t mut_i; @@ -92,6 +118,7 @@ handle_vm_kvm_set_user_memory_region( uint32_t mut_slot_as; uint64_t mut_dst; uint64_t mut_src; + uint64_t const flags = kvm_to_mv_page_flags(args->flags); platform_expects(NULL != args); platform_expects(NULL != pmut_vm); @@ -124,7 +151,7 @@ handle_vm_kvm_set_user_memory_region( } if (((uint64_t)0) == args->memory_size) { - bferror("deleting an existing slot is currently not implemeneted"); + bferror("deleting an existing slot is currently not implemented"); return SHIM_FAILURE; } @@ -148,18 +175,26 @@ handle_vm_kvm_set_user_memory_region( return SHIM_FAILURE; } - /// TODO: - /// - Check to make sure that the userspace address that was provided - /// is canonical. Otherwise MicroV will get mad. - /// + if (high_canonical_boundary < args->userspace_addr) { + if (low_canonical_boundary <= args->userspace_addr) { + mv_touch(); + } + else { + bferror("args->userspace_addr is not a canonical address"); + return SHIM_FAILURE; + } + } + else { + mv_touch(); + } - /// TODO: - /// - Check to make sure that the provided flags are supported by MicroV - /// and then construct the MicroV flags as required. - /// + // Don't support KVM_MEM_LOG_DIRTY_PAGES right now + if (args->flags & ~((uint32_t)KVM_MEM_READONLY)) { + return SHIM_FAILURE; + } /// TODO: - /// - Check to make sure that non of the slots overlap. This is not + /// - Check to make sure that none of the slots overlap. This is not /// allowed by the KVM API, and even if it were, MicroV would get /// mad as it doesn't allow this either. /// @@ -231,15 +266,9 @@ handle_vm_kvm_set_user_memory_region( pmut_mut_mdl->entries[pmut_mut_mdl->num_entries].dst = dst; pmut_mut_mdl->entries[pmut_mut_mdl->num_entries].src = src; pmut_mut_mdl->entries[pmut_mut_mdl->num_entries].bytes = HYPERVISOR_PAGE_SIZE; + pmut_mut_mdl->entries[pmut_mut_mdl->num_entries].flags = flags; ++pmut_mut_mdl->num_entries; - /// TODO: - /// - Need to add support for memory flags. Right now, MicroV ignores - /// the flags field and always sets the memory to RWE. This needs - /// to be fixed, and then we will need to translate the KVM flags - /// to MicroV flags here and send them up properly. - /// - /// TODO: /// - Right now MicroV assumes that every entry is 4k in size. /// Instead, it should be modified to handle any page aligned diff --git a/shim/tests/include/types.h b/shim/tests/include/types.h index 138613e9c..128331921 100644 --- a/shim/tests/include/types.h +++ b/shim/tests/include/types.h @@ -49,4 +49,10 @@ */ #define SHIM_INTERRUPTED ((int64_t)-2) +/** + * @brief Returned by a shim function when a provided data structure + * is not large enough to hold the return data. + */ +#define SHIM_2BIG ((int64_t)-3) + #endif diff --git a/shim/tests/src/test_handle_system_kvm_get_msr_index_list.cpp b/shim/tests/src/test_handle_system_kvm_get_msr_index_list.cpp index cffb43e2c..bdbea6f4d 100644 --- a/shim/tests/src/test_handle_system_kvm_get_msr_index_list.cpp +++ b/shim/tests/src/test_handle_system_kvm_get_msr_index_list.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -36,7 +35,6 @@ namespace shim { constexpr auto VAL64{42_u64}; constexpr auto INIT_NMSRS{0x10_u32}; - bsl::array g_mut_msr_indices{}; /// /// @brief Used to execute the actual checks. We put the checks in this @@ -57,7 +55,6 @@ namespace shim bsl::ut_given{} = [&]() noexcept { kvm_msr_list mut_args{}; bsl::ut_when{} = [&]() noexcept { - mut_args.indices = g_mut_msr_indices.front_if(); mut_args.nmsrs = INIT_NMSRS.get(); g_mut_val = bsl::safe_u64::magic_2().get(); bsl::ut_then{} = [&]() noexcept { @@ -71,7 +68,6 @@ namespace shim bsl::ut_given{} = [&]() noexcept { kvm_msr_list mut_args{}; bsl::ut_when{} = [&]() noexcept { - mut_args.indices = g_mut_msr_indices.front_if(); mut_args.nmsrs = INIT_NMSRS.get(); g_mut_val = bsl::safe_u64::magic_2().get(); g_mut_mv_pp_op_msr_get_supported_list = MV_STATUS_FAILURE_SET_RDL_REG1; @@ -86,25 +82,12 @@ namespace shim }; }; - bsl::ut_scenario{"indices not allocated"} = []() noexcept { - bsl::ut_given{} = [&]() noexcept { - kvm_msr_list mut_args{}; - bsl::ut_when{} = [&]() noexcept { - mut_args.nmsrs = INIT_NMSRS.get(); - bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); - }; - }; - }; - }; - bsl::ut_scenario{"hypervisor not detected"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { kvm_msr_list mut_args{}; bsl::ut_when{} = [&]() noexcept { g_mut_hypervisor_detected = false; mut_args.nmsrs = INIT_NMSRS.get(); - mut_args.indices = g_mut_msr_indices.front_if(); bsl::ut_then{} = [&]() noexcept { bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); }; @@ -115,25 +98,12 @@ namespace shim }; }; - bsl::ut_scenario{"indices too small"} = []() noexcept { - bsl::ut_given{} = [&]() noexcept { - kvm_msr_list mut_args{}; - bsl::ut_when{} = [&]() noexcept { - mut_args.nmsrs = bsl::safe_u32::magic_0().get(); - bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); - }; - }; - }; - }; - bsl::ut_scenario{"mv_pp_op_msr_get_supported_list corrupts num_entries"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { kvm_msr_list mut_args{}; bsl::ut_when{} = [&]() noexcept { g_mut_mv_pp_op_msr_get_supported_list = MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES; mut_args.nmsrs = INIT_NMSRS.get(); - mut_args.indices = g_mut_msr_indices.front_if(); bsl::ut_then{} = [&]() noexcept { bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); }; @@ -150,7 +120,6 @@ namespace shim bsl::ut_when{} = [&]() noexcept { g_mut_mv_pp_op_msr_get_supported_list = VAL64.get(); mut_args.nmsrs = INIT_NMSRS.get(); - mut_args.indices = g_mut_msr_indices.front_if(); bsl::ut_then{} = [&]() noexcept { bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); }; @@ -166,10 +135,9 @@ namespace shim kvm_msr_list mut_args{}; bsl::ut_when{} = [&]() noexcept { mut_args.nmsrs = INIT_NMSRS.get(); - mut_args.indices = g_mut_msr_indices.front_if(); g_mut_val = VAL64.get(); bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); + bsl::ut_check(SHIM_2BIG == handle(&mut_args)); }; bsl::ut_cleanup{} = [&]() noexcept { g_mut_val = {}; diff --git a/shim/tests/src/test_handle_system_kvm_get_supported_cpuid.cpp b/shim/tests/src/test_handle_system_kvm_get_supported_cpuid.cpp index 8d668a7df..bb7fd52e9 100644 --- a/shim/tests/src/test_handle_system_kvm_get_supported_cpuid.cpp +++ b/shim/tests/src/test_handle_system_kvm_get_supported_cpuid.cpp @@ -24,13 +24,19 @@ #include "../../include/handle_system_kvm_get_supported_cpuid.h" +#include #include #include +#include +#include +#include #include namespace shim { + constexpr auto VAL64{42_u64}; + constexpr auto INIT_NENT{0x20_u32}; /// /// @brief Used to execute the actual checks. We put the checks in this /// function so that we can validate the tests both at compile-time @@ -43,19 +49,110 @@ namespace shim [[nodiscard]] constexpr auto tests() noexcept -> bsl::exit_code { - bsl::ut_scenario{"description"} = []() noexcept { + constexpr auto handle{&handle_system_kvm_get_supported_cpuid}; + init_tests(); + + bsl::ut_scenario{"success"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_cpuid2 mut_args{}; + bsl::ut_when{} = [&]() noexcept { + mut_args.nent = INIT_NENT.get(); + g_mut_val = bsl::safe_u64::magic_2().get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_SUCCESS == handle(&mut_args)); + }; + }; + }; + }; + + bsl::ut_scenario{"entries not allocated"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_cpuid2 mut_args{}; + bsl::ut_when{} = [&]() noexcept { + mut_args.nent = INIT_NENT.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); + }; + }; + }; + }; + + bsl::ut_scenario{"hypervisor not detected"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_cpuid2 mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_hypervisor_detected = false; + mut_args.nent = INIT_NENT.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_hypervisor_detected = true; + }; + }; + }; + }; + + bsl::ut_scenario{"entries too small"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { kvm_cpuid2 mut_args{}; bsl::ut_when{} = [&]() noexcept { + mut_args.nent = bsl::safe_u32::magic_0().get(); bsl::ut_then{} = [&]() noexcept { - bsl::ut_check( - SHIM_SUCCESS == handle_system_kvm_get_supported_cpuid(&mut_args)); + bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); }; }; }; }; - return bsl::ut_success(); + bsl::ut_scenario{"mv_pp_op_cpuid_get_supported_list corrupts num_entries"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_cpuid2 mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_pp_op_cpuid_get_supported_list = MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES; + mut_args.nent = INIT_NENT.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_pp_op_cpuid_get_supported_list = {}; + }; + }; + }; + }; + + bsl::ut_scenario{"mv_pp_op_cpuid_get_supported_list fails"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_cpuid2 mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_pp_op_cpuid_get_supported_list = VAL64.get(); + mut_args.nent = INIT_NENT.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_pp_op_cpuid_get_supported_list = {}; + }; + }; + }; + }; + + bsl::ut_scenario{"number of MSRs is larger than kvm_cpuid2 entries"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_cpuid2 mut_args{}; + bsl::ut_when{} = [&]() noexcept { + mut_args.nent = INIT_NENT.get(); + g_mut_val = VAL64.get(); + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_2BIG == handle(&mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_val = {}; + }; + }; + }; + }; + return fini_tests(); } } diff --git a/shim/tests/src/test_handle_vcpu_kvm_get_msrs.cpp b/shim/tests/src/test_handle_vcpu_kvm_get_msrs.cpp index 6b9fca788..6b2107682 100644 --- a/shim/tests/src/test_handle_vcpu_kvm_get_msrs.cpp +++ b/shim/tests/src/test_handle_vcpu_kvm_get_msrs.cpp @@ -24,13 +24,18 @@ #include "../../include/handle_vcpu_kvm_get_msrs.h" +#include #include -#include +#include +#include +#include #include namespace shim { + constexpr auto VAL32{2_u32}; + /// /// @brief Used to execute the actual checks. We put the checks in this /// function so that we can validate the tests both at compile-time @@ -43,18 +48,97 @@ namespace shim [[nodiscard]] constexpr auto tests() noexcept -> bsl::exit_code { - bsl::ut_scenario{"description"} = []() noexcept { + init_tests(); + constexpr auto handle{&handle_vcpu_kvm_get_msrs}; + + bsl::ut_scenario{"success"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; kvm_msrs mut_args{}; bsl::ut_when{} = [&]() noexcept { + mut_args.nmsrs = VAL32.get(); bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_SUCCESS == handle_vcpu_kvm_get_msrs(&mut_args)); + bsl::ut_check(SHIM_SUCCESS == handle(&vcpu, &mut_args)); }; }; }; }; - - return bsl::ut_success(); + bsl::ut_scenario{"hypervisor not detected"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_hypervisor_detected = false; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_hypervisor_detected = true; + }; + }; + }; + }; + bsl::ut_scenario{"mv_vs_op_msr_get_list fails"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = MV_STATUS_FAILURE_UNKNOWN; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = {}; + }; + }; + }; + }; + bsl::ut_scenario{"mv_vs_op_msr_get_list adds 0 register"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = MV_STATUS_FAILURE_INC_NUM_ENTRIES; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = {}; + }; + }; + }; + }; + bsl::ut_scenario{"mv_vs_op_msr_get_list adds unknown"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = MV_STATUS_FAILURE_ADD_UNKNOWN; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = {}; + }; + }; + }; + }; + bsl::ut_scenario{"g_mut_mv_vs_op_msr_get_list corrupts num_entries"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = MV_STATUS_FAILURE_CORRUPT_NUM_ENTRIES; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_vs_op_msr_get_list = {}; + }; + }; + }; + }; + return fini_tests(); } } diff --git a/shim/tests/src/test_handle_vcpu_kvm_set_msrs.cpp b/shim/tests/src/test_handle_vcpu_kvm_set_msrs.cpp index 25e08be69..44e084acd 100644 --- a/shim/tests/src/test_handle_vcpu_kvm_set_msrs.cpp +++ b/shim/tests/src/test_handle_vcpu_kvm_set_msrs.cpp @@ -24,13 +24,18 @@ #include "../../include/handle_vcpu_kvm_set_msrs.h" +#include #include -#include +#include +#include +#include #include namespace shim { + constexpr auto VAL32{2_u32}; + /// /// @brief Used to execute the actual checks. We put the checks in this /// function so that we can validate the tests both at compile-time @@ -43,18 +48,52 @@ namespace shim [[nodiscard]] constexpr auto tests() noexcept -> bsl::exit_code { - bsl::ut_scenario{"description"} = []() noexcept { + init_tests(); + constexpr auto handle{&handle_vcpu_kvm_set_msrs}; + + bsl::ut_scenario{"success"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; kvm_msrs mut_args{}; bsl::ut_when{} = [&]() noexcept { + mut_args.nmsrs = VAL32.get(); bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_SUCCESS == handle_vcpu_kvm_set_msrs(&mut_args)); + bsl::ut_check(SHIM_SUCCESS == handle(&vcpu, &mut_args)); }; }; }; }; - - return bsl::ut_success(); + bsl::ut_scenario{"hypervisor not detected"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_hypervisor_detected = false; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_hypervisor_detected = true; + }; + }; + }; + }; + bsl::ut_scenario{"mv_vs_op_msr_set_list fails"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + shim_vcpu_t const vcpu{}; + kvm_msrs mut_args{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_mv_vs_op_msr_set_list = MV_STATUS_FAILURE_UNKNOWN; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle(&vcpu, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_mv_vs_op_msr_set_list = {}; + }; + }; + }; + }; + return fini_tests(); } } diff --git a/vmm/src/x64/emulated_mmio_t.hpp b/vmm/src/x64/emulated_mmio_t.hpp index 4025aa44c..5126a0670 100644 --- a/vmm/src/x64/emulated_mmio_t.hpp +++ b/vmm/src/x64/emulated_mmio_t.hpp @@ -247,7 +247,7 @@ namespace microv auto const gpa{bsl::to_u64(entry->dst)}; auto const spa{this->gpa_to_spa(mut_sys, bsl::to_u64(entry->src))}; - + auto const flags{bsl::to_u64(entry->flags)}; /// TODO: /// - Add support for entries that have a size greater than /// 4k. For now we only support 4k pages. @@ -258,8 +258,7 @@ namespace microv /// because guest software will not attempt to undo a /// failed map operation. /// - auto const ret{ - m_slpt.map(tls, mut_page_pool, gpa, spa, MAP_PAGE_RWE, false, mut_sys)}; + auto const ret{m_slpt.map(tls, mut_page_pool, gpa, spa, flags, false, mut_sys)}; if (bsl::unlikely(ret == bsl::errc_already_exists)) { bsl::error() << "mdl entry " // -- diff --git a/vmm/src/x64/intel/dispatch_vmexit_io.hpp b/vmm/src/x64/intel/dispatch_vmexit_io.hpp index fdaa2dd4e..d04bcd11b 100644 --- a/vmm/src/x64/intel/dispatch_vmexit_io.hpp +++ b/vmm/src/x64/intel/dispatch_vmexit_io.hpp @@ -73,11 +73,6 @@ namespace microv vs_pool_t &mut_vs_pool, bsl::safe_u16 const &vsid) noexcept -> bsl::errc_type { - /// TODO: - /// - Need to properly handle string instructions (INS/OUTS) - /// - Need to properly handle IN instructions - /// - bsl::expects(!mut_sys.is_the_active_vm_the_root_vm()); bsl::discard(gs); @@ -131,8 +126,7 @@ namespace microv mut_exit_io->type = hypercall::MV_EXIT_IO_OUT.get(); } else { - bsl::error() << "MV_EXIT_IO_IN not implemented\n" << bsl::here(); - return bsl::errc_failure; + mut_exit_io->type = hypercall::MV_EXIT_IO_IN.get(); } constexpr auto bytes1{0_u64};