From f5c88b47173258bd10bd9e56707be8fd43555edf Mon Sep 17 00:00:00 2001 From: Harshad Poshtiwala Date: Mon, 24 Jan 2022 09:39:35 +0000 Subject: [PATCH] KVM_IRQFD, Implement Ioctl --- shim/include/handle_vm_kvm_irqfd.h | 5 +- shim/include/kvm_irqfd.h | 21 ++++++- shim/include/kvm_irqfd.hpp | 60 +++++++++++++++++++ shim/integration/CMakeLists.txt | 1 + shim/integration/kvm_irqfd.cpp | 56 +++++++++++++++++ .../shim_platform_interface.hpp | 6 +- shim/linux/src/entry.c | 24 ++++++-- shim/src/handle_vm_kvm_irqfd.c | 18 +++++- shim/tests/src/test_handle_vm_kvm_irqfd.cpp | 23 ++++++- 9 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 shim/include/kvm_irqfd.hpp create mode 100644 shim/integration/kvm_irqfd.cpp diff --git a/shim/include/handle_vm_kvm_irqfd.h b/shim/include/handle_vm_kvm_irqfd.h index 517412acc..7d7cb4444 100644 --- a/shim/include/handle_vm_kvm_irqfd.h +++ b/shim/include/handle_vm_kvm_irqfd.h @@ -29,6 +29,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -40,10 +41,12 @@ extern "C" * @brief Handles the execution of kvm_irqfd. * * + * @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_irqfd(struct kvm_irqfd *const pmut_ioctl_args) NOEXCEPT; + NODISCARD int64_t handle_vm_kvm_irqfd( + struct shim_vm_t *const pmut_vm, struct kvm_irqfd *const pmut_ioctl_args) NOEXCEPT; #ifdef __cplusplus } diff --git a/shim/include/kvm_irqfd.h b/shim/include/kvm_irqfd.h index 867972547..84e9dc765 100644 --- a/shim/include/kvm_irqfd.h +++ b/shim/include/kvm_irqfd.h @@ -29,6 +29,10 @@ #include +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif + #ifdef __cplusplus extern "C" { @@ -36,16 +40,27 @@ extern "C" #pragma pack(push, 1) +/** @brief defines the padding size */ +#define PAD_SIZE_IRQFD ((uint32_t)16) + /** * @struct kvm_irqfd * * - * @brief see /include/uapi/linux/kvm.h in Linux for more details. + * @brief Allows setting an eventfd to directly trigger a guest interrupt.. */ struct kvm_irqfd { - /** @brief replace me with contents from KVM API */ - int32_t dummy; + /** @brief specifies the file descriptor to use as the eventfd */ + uint32_t fd; + /** @brief specifies the irqchip pin toggled by this event*/ + uint32_t gsi; + /** @brief The flag is used to remove irqfd */ + uint32_t flags; + /** @brief Additional eventfd the user must pass when KVM_IRQFD_FLAG_RESAMPLE is set */ + uint32_t resamplefd; + /** @brief TODO*/ + uint8_t pad[PAD_SIZE_IRQFD]; }; #pragma pack(pop) diff --git a/shim/include/kvm_irqfd.hpp b/shim/include/kvm_irqfd.hpp new file mode 100644 index 000000000..646a6e275 --- /dev/null +++ b/shim/include/kvm_irqfd.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_IRQFD_HPP +#define KVM_IRQFD_HPP + +#include +#include +#include + +#pragma pack(push, 1) + +namespace shim +{ + /// @brief defines the size of the padding field + constexpr auto PAD_SIZE_IRQFD{16_umx}; + /// @struct kvm_irqfd + /// + /// + /// @brief Allows setting an eventfd to directly trigger a guest interrupt. + /// + struct kvm_irqfd final + { + /** @brief specifies the file descriptor to use as the eventfd */ + bsl::uint32 fd; + /** @brief specifies the irqchip pin toggled by this event*/ + bsl::uint32 gsi; + /** @brief The flag is used to remove irqfd */ + bsl::uint32 flags; + /** @brief Additional eventfd the user must pass when KVM_IRQFD_FLAG_RESAMPLE is set */ + bsl::uint32 resamplefd; + /** @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 9bcad1da4..1527653ab 100644 --- a/shim/integration/CMakeLists.txt +++ b/shim/integration/CMakeLists.txt @@ -55,3 +55,4 @@ microv_add_shim_integration(kvm_get_irqchip HEADERS) 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) diff --git a/shim/integration/kvm_irqfd.cpp b/shim/integration/kvm_irqfd.cpp new file mode 100644 index 000000000..eaf2159d0 --- /dev/null +++ b/shim/integration/kvm_irqfd.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 irqfd{mut_vcpu.send(shim::KVM_IRQFD)}; + integration::verify(irqfd.is_pos()); + integration::verify(irqfd >= 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 54e3edff8..d190b4b9c 100644 --- a/shim/linux/include/platform_interface/shim_platform_interface.hpp +++ b/shim/linux/include/platform_interface/shim_platform_interface.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -246,8 +247,9 @@ namespace shim // 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 // constexpr bsl::safe_umx KVM_SET_PIT2{static_cast(_IOW(SHIMIO.get(), 0xa0, struct kvm_pit_state2))}; - // /// @brief defines KVM's KVM_IRQFD IOCTL - // constexpr bsl::safe_umx KVM_IRQFD{static_cast(_IOW(SHIMIO.get(), 0x76, struct kvm_irqfd))}; + /// @brief defines KVM's KVM_IRQFD IOCTL + constexpr bsl::safe_umx KVM_IRQFD{ + static_cast(_IOW(SHIMIO.get(), 0x76, struct kvm_irqfd))}; // /// @brief defines KVM's KVM_CREATE_DEVICE IOCTL // constexpr bsl::safe_umx KVM_CREATE_DEVICE{static_cast(_IOWR(SHIMIO.get(), 0xe0, struct kvm_create_device))}; // /// @brief defines KVM's KVM_GET_DEVICE_ATTR IOCTL diff --git a/shim/linux/src/entry.c b/shim/linux/src/entry.c index d86ed7607..464a9978b 100644 --- a/shim/linux/src/entry.c +++ b/shim/linux/src/entry.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -661,10 +662,23 @@ dispatch_vm_kvm_irq_line(struct kvm_irq_level *const ioctl_args) } static long -dispatch_vm_kvm_irqfd(struct kvm_irqfd *const ioctl_args) +dispatch_vm_kvm_irqfd( + struct shim_vm_t *const pmut_vm, struct kvm_irqfd *const pmut_ioctl_args) { - (void)ioctl_args; - return -EINVAL; + struct kvm_irqfd 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_irqfd(pmut_vm, &mut_args)) { + bferror("handle_vm_kvm_irqfd failed"); + return -EINVAL; + } + + return 0; } static long @@ -903,7 +917,9 @@ dev_unlocked_ioctl_vm( } case KVM_IRQFD: { - return dispatch_vm_kvm_irqfd((struct kvm_irqfd *)ioctl_args); + return dispatch_vm_kvm_irqfd( + (struct shim_vm_t *)pmut_mut_vm, + (struct kvm_irqfd *)ioctl_args); } case KVM_REGISTER_COALESCED_MMIO: { diff --git a/shim/src/handle_vm_kvm_irqfd.c b/shim/src/handle_vm_kvm_irqfd.c index 3c26c3d9c..00d1dcddd 100644 --- a/shim/src/handle_vm_kvm_irqfd.c +++ b/shim/src/handle_vm_kvm_irqfd.c @@ -24,20 +24,34 @@ * SOFTWARE. */ +#include +#include #include #include +#include +#include /** * * @brief Handles the execution of kvm_irqfd. * * + * @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_irqfd(struct kvm_irqfd *const pmut_ioctl_args) NOEXCEPT +handle_vm_kvm_irqfd( + struct shim_vm_t *const pmut_vm, struct kvm_irqfd *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_irqfd.cpp b/shim/tests/src/test_handle_vm_kvm_irqfd.cpp index cb90e11f9..f75c7a07c 100644 --- a/shim/tests/src/test_handle_vm_kvm_irqfd.cpp +++ b/shim/tests/src/test_handle_vm_kvm_irqfd.cpp @@ -23,9 +23,10 @@ /// SOFTWARE. #include "../../include/handle_vm_kvm_irqfd.h" +#include "shim_vm_t.h" +#include #include -#include #include @@ -43,12 +44,30 @@ namespace shim [[nodiscard]] constexpr auto tests() noexcept -> bsl::exit_code { + init_tests(); bsl::ut_scenario{"description"} = []() noexcept { bsl::ut_given{} = [&]() noexcept { kvm_irqfd mut_args{}; + shim_vm_t mut_vm{}; bsl::ut_when{} = [&]() noexcept { bsl::ut_then{} = [&]() noexcept { - bsl::ut_check(SHIM_SUCCESS == handle_vm_kvm_irqfd(&mut_args)); + bsl::ut_check(SHIM_SUCCESS == handle_vm_kvm_irqfd(&mut_vm, &mut_args)); + }; + }; + }; + }; + + bsl::ut_scenario{"hypervisor not detected"} = []() noexcept { + bsl::ut_given{} = [&]() noexcept { + kvm_irqfd 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_irqfd(&mut_vm, &mut_args)); + }; + bsl::ut_cleanup{} = [&]() noexcept { + g_mut_hypervisor_detected = true; }; }; };