From a50802c4115549525b626f464c4432732a1943dc Mon Sep 17 00:00:00 2001 From: Harshad Poshtiwala Date: Thu, 20 Jan 2022 09:43:36 +0000 Subject: [PATCH] KVM_SIGNAL_MSI, Implement ioctl --- shim/include/handle_vm_kvm_signal_msi.h | 9 ++- shim/include/kvm_msi.h | 19 +++++- shim/include/kvm_msi.hpp | 61 +++++++++++++++++++ shim/integration/CMakeLists.txt | 1 + shim/integration/kvm_signal_msi.cpp | 56 +++++++++++++++++ .../shim_platform_interface.hpp | 8 ++- shim/linux/src/entry.c | 23 +++++-- shim/src/handle_vm_kvm_signal_msi.c | 18 +++++- .../src/test_handle_vm_kvm_signal_msi.cpp | 22 ++++++- 9 files changed, 201 insertions(+), 16 deletions(-) create mode 100644 shim/include/kvm_msi.hpp create mode 100644 shim/integration/kvm_signal_msi.cpp diff --git a/shim/include/handle_vm_kvm_signal_msi.h b/shim/include/handle_vm_kvm_signal_msi.h index 39664cef7..618b5021f 100644 --- a/shim/include/handle_vm_kvm_signal_msi.h +++ b/shim/include/handle_vm_kvm_signal_msi.h @@ -29,6 +29,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -40,10 +41,12 @@ extern "C" * @brief Handles the execution of kvm_signal_msi. * * - * @param pmut_ioctl_args the arguments provided by userspace - * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. + * @param pmut_vm the argumento hold vm details of type shim_vm_t + * @param pmut_ioctl_args the arguments provided by userspace + * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ - NODISCARD int64_t handle_vm_kvm_signal_msi(struct kvm_msi *const pmut_ioctl_args) NOEXCEPT; + NODISCARD int64_t handle_vm_kvm_signal_msi( + struct shim_vm_t *const pmut_vm, struct kvm_msi *const pmut_ioctl_args) NOEXCEPT; #ifdef __cplusplus } diff --git a/shim/include/kvm_msi.h b/shim/include/kvm_msi.h index cd987d657..3f3a5e8e0 100644 --- a/shim/include/kvm_msi.h +++ b/shim/include/kvm_msi.h @@ -29,12 +29,18 @@ #include +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif + #ifdef __cplusplus extern "C" { #endif #pragma pack(push, 1) +/** @brief defines the padding size */ +#define PAD_SIZE_MSI ((uint32_t)16) /** * @struct kvm_msi @@ -44,8 +50,17 @@ extern "C" */ struct kvm_msi { - /** @brief replace me with contents from KVM API */ - int32_t dummy; + /** @brief For PCI, this is a BFD identifier in the lower 16 bits. */ + uint32_t address_lo; + /** @brief address_hi bits 31-8 provide bits 31-8 of the destination id. Bits 7-0 of + address_hi must be zero. */ + uint32_t address_hi; + /** @brief a MSI message*/ + uint32_t data; + /** @brief A Flag to indicate valid or invalid data */ + uint32_t flags; + /** @brief TODO */ + uint8_t pad[PAD_SIZE_MSI]; }; #pragma pack(pop) diff --git a/shim/include/kvm_msi.hpp b/shim/include/kvm_msi.hpp new file mode 100644 index 000000000..6512d34b0 --- /dev/null +++ b/shim/include/kvm_msi.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_MSI_HPP +#define KVM_MSI_HPP + +#include +#include +#include + +#pragma pack(push, 1) + +namespace shim +{ + /// @brief defines the size of the padding field + constexpr auto PAD_SIZE_MSI{16_umx}; + /// @struct kvm_msi + /// + /// + /// @brief see /include/uapi/linux/kvm.h in Linux for more details. + /// + struct kvm_msi final + { + /** @brief For PCI, this is a BFD identifier in the lower 16 bits. */ + bsl::uint32 address_lo; + /** @brief address_hi bits 31-8 provide bits 31-8 of the destination id. Bits 7-0 of + address_hi must be zero. */ + bsl::uint32 address_hi; + /** @brief a MSI message*/ + bsl::uint32 data; + /** @brief A Flag to indicate valid or invalid data */ + bsl::uint32 flags; + /** @brief TODO */ + bsl::array pad; + }; +} + +#pragma pack(pop) + +#endif \ No newline at end of file diff --git a/shim/integration/CMakeLists.txt b/shim/integration/CMakeLists.txt index 1527653ab..8e6744cab 100644 --- a/shim/integration/CMakeLists.txt +++ b/shim/integration/CMakeLists.txt @@ -56,3 +56,4 @@ microv_add_shim_integration(kvm_set_irqchip HEADERS) microv_add_shim_integration(kvm_get_lapic HEADERS) microv_add_shim_integration(kvm_set_lapic HEADERS) microv_add_shim_integration(kvm_irqfd HEADERS) +microv_add_shim_integration(kvm_signal_msi HEADERS) diff --git a/shim/integration/kvm_signal_msi.cpp b/shim/integration/kvm_signal_msi.cpp new file mode 100644 index 000000000..5c09e9427 --- /dev/null +++ b/shim/integration/kvm_signal_msi.cpp @@ -0,0 +1,56 @@ +/// @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 + +/// +/// @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)}; + auto const vcpufd{mut_vm.send(shim::KVM_CREATE_VCPU)}; + integration::ioctl_t mut_vcpu{bsl::to_i32(vcpufd)}; + constexpr auto mut_ret{0_i64}; + { + auto const signalmsi{mut_vcpu.send(shim::KVM_SIGNAL_MSI)}; + integration::verify(signalmsi.is_pos()); + integration::verify(signalmsi >= mut_ret.get()); + } + return bsl::exit_success; +} diff --git a/shim/linux/include/platform_interface/shim_platform_interface.hpp b/shim/linux/include/platform_interface/shim_platform_interface.hpp index d190b4b9c..51b5598d0 100644 --- a/shim/linux/include/platform_interface/shim_platform_interface.hpp +++ b/shim/linux/include/platform_interface/shim_platform_interface.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -238,11 +239,14 @@ namespace shim // constexpr bsl::safe_umx KVM_SET_ONE_REG{static_cast(_IOW(SHIMIO.get(), 0xac, struct kvm_one_reg))}; /// @brief defines KVM's KVM_KVMCLOCK_CTRL IOCTL constexpr bsl::safe_umx KVM_KVMCLOCK_CTRL{static_cast(_IO(SHIMIO.get(), 0xad))}; - // /// @brief defines KVM's KVM_SIGNAL_MSI IOCTL - // constexpr bsl::safe_umx KVM_SIGNAL_MSI{static_cast(_IOW(SHIMIO.get(), 0xa5, struct kvm_msi))}; /// @brief defines KVM's KVM_CREATE_PIT2 IOCTL constexpr bsl::safe_umx KVM_CREATE_PIT2{ static_cast(_IOW(SHIMIO.get(), 0x77, struct kvm_pit_config))}; + /// @brief defines KVM's KVM_SIGNAL_MSI IOCTL + constexpr bsl::safe_umx KVM_SIGNAL_MSI{ + static_cast(_IOW(SHIMIO.get(), 0xa5, struct kvm_msi))}; + // /// @brief defines KVM's KVM_CREATE_PIT2 IOCTL + // constexpr bsl::safe_umx KVM_CREATE_PIT2{static_cast(_IOW(SHIMIO.get(), 0x77, struct kvm_pit_config))}; // /// @brief defines KVM's KVM_GET_PIT2 IOCTL // constexpr bsl::safe_umx KVM_GET_PIT2{static_cast(_IOR(SHIMIO.get(), 0x9f, struct kvm_pit_state2))}; // /// @brief defines KVM's KVM_SET_PIT2 IOCTL diff --git a/shim/linux/src/entry.c b/shim/linux/src/entry.c index 464a9978b..ac9ab0384 100644 --- a/shim/linux/src/entry.c +++ b/shim/linux/src/entry.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -807,10 +808,23 @@ dispatch_vm_kvm_set_user_memory_region( } static long -dispatch_vm_kvm_signal_msi(struct kvm_msi *const ioctl_args) +dispatch_vm_kvm_signal_msi( + struct shim_vm_t *const pmut_vm, struct kvm_msi *const pmut_ioctl_args) { - (void)ioctl_args; - return -EINVAL; + struct kvm_msi mut_args; + uint64_t const size = sizeof(mut_args); + + if (platform_copy_from_user(&mut_args, pmut_ioctl_args, size)) { + bferror("platform_copy_from_user failed"); + return -EINVAL; + } + + if (handle_vm_kvm_signal_msi(pmut_vm, &mut_args)) { + bferror("handle_vm_kvm_signal_msi failed"); + return -EINVAL; + } + + return 0; } static long @@ -986,7 +1000,8 @@ dev_unlocked_ioctl_vm( } case KVM_SIGNAL_MSI: { - return dispatch_vm_kvm_signal_msi((struct kvm_msi *)ioctl_args); + return dispatch_vm_kvm_signal_msi( + (struct shim_vm_t *)pmut_mut_vm, (struct kvm_msi *)ioctl_args); } case KVM_UNREGISTER_COALESCED_MMIO: { diff --git a/shim/src/handle_vm_kvm_signal_msi.c b/shim/src/handle_vm_kvm_signal_msi.c index 755a96b10..f30d06c5d 100644 --- a/shim/src/handle_vm_kvm_signal_msi.c +++ b/shim/src/handle_vm_kvm_signal_msi.c @@ -23,21 +23,33 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - +#include +#include #include #include +#include +#include /** * * @brief Handles the execution of kvm_signal_msi. * * + * @param pmut_vm the argumento hold vm details of type shim_vm_t * @param pmut_ioctl_args the arguments provided by userspace * @return SHIM_SUCCESS on success, SHIM_FAILURE on failure. */ NODISCARD int64_t -handle_vm_kvm_signal_msi(struct kvm_msi *const pmut_ioctl_args) NOEXCEPT +handle_vm_kvm_signal_msi( + struct shim_vm_t *const pmut_vm, struct kvm_msi *const pmut_ioctl_args) NOEXCEPT { - (void)pmut_ioctl_args; + platform_expects(NULL != pmut_vm); + platform_expects(NULL != pmut_ioctl_args); + + if (detect_hypervisor()) { + bferror("The shim is not running in a VM. Did you forget to start MicroV?"); + return SHIM_FAILURE; + } + //TODO: Cally the hypercall here after its implementation return SHIM_SUCCESS; } diff --git a/shim/tests/src/test_handle_vm_kvm_signal_msi.cpp b/shim/tests/src/test_handle_vm_kvm_signal_msi.cpp index 381544899..035dbe977 100644 --- a/shim/tests/src/test_handle_vm_kvm_signal_msi.cpp +++ b/shim/tests/src/test_handle_vm_kvm_signal_msi.cpp @@ -23,9 +23,10 @@ /// SOFTWARE. #include "../../include/handle_vm_kvm_signal_msi.h" +#include "shim_vm_t.h" +#include #include -#include #include @@ -43,17 +44,34 @@ namespace shim [[nodiscard]] constexpr auto tests() noexcept -> bsl::exit_code { + init_tests(); bsl::ut_scenario{"description"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { kvm_msi mut_args{}; + shim_vm_t mut_vm{}; bsl::ut_when{} = [&]() noexcept { bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_SUCCESS == handle_vm_kvm_signal_msi(&mut_args)); + bsl::ut_check(SHIM_SUCCESS == handle_vm_kvm_signal_msi(&mut_vm, &mut_args)); }; }; }; }; + bsl::ut_scenario{"hypervisor not detected"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_msi mut_args{}; + shim_vm_t mut_vm{}; + bsl::ut_when{} = [&]() noexcept { + g_mut_hypervisor_detected = false; + bsl::ut_then{} = [&]() noexcept { + bsl::ut_check(SHIM_FAILURE == handle_vm_kvm_signal_msi(&mut_vm, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_hypervisor_detected = true; + }; + }; + }; + }; return bsl::ut_success(); } }