1*621191d7SNuno Das Neves // SPDX-License-Identifier: GPL-2.0-only 2*621191d7SNuno Das Neves /* 3*621191d7SNuno Das Neves * Copyright (c) 2024, Microsoft Corporation. 4*621191d7SNuno Das Neves * 5*621191d7SNuno Das Neves * The main part of the mshv_root module, providing APIs to create 6*621191d7SNuno Das Neves * and manage guest partitions. 7*621191d7SNuno Das Neves * 8*621191d7SNuno Das Neves * Authors: Microsoft Linux virtualization team 9*621191d7SNuno Das Neves */ 10*621191d7SNuno Das Neves 11*621191d7SNuno Das Neves #include <linux/kernel.h> 12*621191d7SNuno Das Neves #include <linux/module.h> 13*621191d7SNuno Das Neves #include <linux/fs.h> 14*621191d7SNuno Das Neves #include <linux/miscdevice.h> 15*621191d7SNuno Das Neves #include <linux/slab.h> 16*621191d7SNuno Das Neves #include <linux/file.h> 17*621191d7SNuno Das Neves #include <linux/anon_inodes.h> 18*621191d7SNuno Das Neves #include <linux/mm.h> 19*621191d7SNuno Das Neves #include <linux/io.h> 20*621191d7SNuno Das Neves #include <linux/cpuhotplug.h> 21*621191d7SNuno Das Neves #include <linux/random.h> 22*621191d7SNuno Das Neves #include <asm/mshyperv.h> 23*621191d7SNuno Das Neves #include <linux/hyperv.h> 24*621191d7SNuno Das Neves #include <linux/notifier.h> 25*621191d7SNuno Das Neves #include <linux/reboot.h> 26*621191d7SNuno Das Neves #include <linux/kexec.h> 27*621191d7SNuno Das Neves #include <linux/page-flags.h> 28*621191d7SNuno Das Neves #include <linux/crash_dump.h> 29*621191d7SNuno Das Neves #include <linux/panic_notifier.h> 30*621191d7SNuno Das Neves #include <linux/vmalloc.h> 31*621191d7SNuno Das Neves 32*621191d7SNuno Das Neves #include "mshv_eventfd.h" 33*621191d7SNuno Das Neves #include "mshv.h" 34*621191d7SNuno Das Neves #include "mshv_root.h" 35*621191d7SNuno Das Neves 36*621191d7SNuno Das Neves MODULE_AUTHOR("Microsoft"); 37*621191d7SNuno Das Neves MODULE_LICENSE("GPL"); 38*621191d7SNuno Das Neves MODULE_DESCRIPTION("Microsoft Hyper-V root partition VMM interface /dev/mshv"); 39*621191d7SNuno Das Neves 40*621191d7SNuno Das Neves /* TODO move this to mshyperv.h when needed outside driver */ 41*621191d7SNuno Das Neves static inline bool hv_parent_partition(void) 42*621191d7SNuno Das Neves { 43*621191d7SNuno Das Neves return hv_root_partition(); 44*621191d7SNuno Das Neves } 45*621191d7SNuno Das Neves 46*621191d7SNuno Das Neves /* TODO move this to another file when debugfs code is added */ 47*621191d7SNuno Das Neves enum hv_stats_vp_counters { /* HV_THREAD_COUNTER */ 48*621191d7SNuno Das Neves #if defined(CONFIG_X86) 49*621191d7SNuno Das Neves VpRootDispatchThreadBlocked = 201, 50*621191d7SNuno Das Neves #elif defined(CONFIG_ARM64) 51*621191d7SNuno Das Neves VpRootDispatchThreadBlocked = 94, 52*621191d7SNuno Das Neves #endif 53*621191d7SNuno Das Neves VpStatsMaxCounter 54*621191d7SNuno Das Neves }; 55*621191d7SNuno Das Neves 56*621191d7SNuno Das Neves struct hv_stats_page { 57*621191d7SNuno Das Neves union { 58*621191d7SNuno Das Neves u64 vp_cntrs[VpStatsMaxCounter]; /* VP counters */ 59*621191d7SNuno Das Neves u8 data[HV_HYP_PAGE_SIZE]; 60*621191d7SNuno Das Neves }; 61*621191d7SNuno Das Neves } __packed; 62*621191d7SNuno Das Neves 63*621191d7SNuno Das Neves struct mshv_root mshv_root; 64*621191d7SNuno Das Neves 65*621191d7SNuno Das Neves enum hv_scheduler_type hv_scheduler_type; 66*621191d7SNuno Das Neves 67*621191d7SNuno Das Neves /* Once we implement the fast extended hypercall ABI they can go away. */ 68*621191d7SNuno Das Neves static void * __percpu *root_scheduler_input; 69*621191d7SNuno Das Neves static void * __percpu *root_scheduler_output; 70*621191d7SNuno Das Neves 71*621191d7SNuno Das Neves static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); 72*621191d7SNuno Das Neves static int mshv_dev_open(struct inode *inode, struct file *filp); 73*621191d7SNuno Das Neves static int mshv_dev_release(struct inode *inode, struct file *filp); 74*621191d7SNuno Das Neves static int mshv_vp_release(struct inode *inode, struct file *filp); 75*621191d7SNuno Das Neves static long mshv_vp_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); 76*621191d7SNuno Das Neves static int mshv_partition_release(struct inode *inode, struct file *filp); 77*621191d7SNuno Das Neves static long mshv_partition_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); 78*621191d7SNuno Das Neves static int mshv_vp_mmap(struct file *file, struct vm_area_struct *vma); 79*621191d7SNuno Das Neves static vm_fault_t mshv_vp_fault(struct vm_fault *vmf); 80*621191d7SNuno Das Neves static int mshv_init_async_handler(struct mshv_partition *partition); 81*621191d7SNuno Das Neves static void mshv_async_hvcall_handler(void *data, u64 *status); 82*621191d7SNuno Das Neves 83*621191d7SNuno Das Neves static const union hv_input_vtl input_vtl_zero; 84*621191d7SNuno Das Neves static const union hv_input_vtl input_vtl_normal = { 85*621191d7SNuno Das Neves .target_vtl = HV_NORMAL_VTL, 86*621191d7SNuno Das Neves .use_target_vtl = 1, 87*621191d7SNuno Das Neves }; 88*621191d7SNuno Das Neves 89*621191d7SNuno Das Neves static const struct vm_operations_struct mshv_vp_vm_ops = { 90*621191d7SNuno Das Neves .fault = mshv_vp_fault, 91*621191d7SNuno Das Neves }; 92*621191d7SNuno Das Neves 93*621191d7SNuno Das Neves static const struct file_operations mshv_vp_fops = { 94*621191d7SNuno Das Neves .owner = THIS_MODULE, 95*621191d7SNuno Das Neves .release = mshv_vp_release, 96*621191d7SNuno Das Neves .unlocked_ioctl = mshv_vp_ioctl, 97*621191d7SNuno Das Neves .llseek = noop_llseek, 98*621191d7SNuno Das Neves .mmap = mshv_vp_mmap, 99*621191d7SNuno Das Neves }; 100*621191d7SNuno Das Neves 101*621191d7SNuno Das Neves static const struct file_operations mshv_partition_fops = { 102*621191d7SNuno Das Neves .owner = THIS_MODULE, 103*621191d7SNuno Das Neves .release = mshv_partition_release, 104*621191d7SNuno Das Neves .unlocked_ioctl = mshv_partition_ioctl, 105*621191d7SNuno Das Neves .llseek = noop_llseek, 106*621191d7SNuno Das Neves }; 107*621191d7SNuno Das Neves 108*621191d7SNuno Das Neves static const struct file_operations mshv_dev_fops = { 109*621191d7SNuno Das Neves .owner = THIS_MODULE, 110*621191d7SNuno Das Neves .open = mshv_dev_open, 111*621191d7SNuno Das Neves .release = mshv_dev_release, 112*621191d7SNuno Das Neves .unlocked_ioctl = mshv_dev_ioctl, 113*621191d7SNuno Das Neves .llseek = noop_llseek, 114*621191d7SNuno Das Neves }; 115*621191d7SNuno Das Neves 116*621191d7SNuno Das Neves static struct miscdevice mshv_dev = { 117*621191d7SNuno Das Neves .minor = MISC_DYNAMIC_MINOR, 118*621191d7SNuno Das Neves .name = "mshv", 119*621191d7SNuno Das Neves .fops = &mshv_dev_fops, 120*621191d7SNuno Das Neves .mode = 0600, 121*621191d7SNuno Das Neves }; 122*621191d7SNuno Das Neves 123*621191d7SNuno Das Neves /* 124*621191d7SNuno Das Neves * Only allow hypercalls that have a u64 partition id as the first member of 125*621191d7SNuno Das Neves * the input structure. 126*621191d7SNuno Das Neves * These are sorted by value. 127*621191d7SNuno Das Neves */ 128*621191d7SNuno Das Neves static u16 mshv_passthru_hvcalls[] = { 129*621191d7SNuno Das Neves HVCALL_GET_PARTITION_PROPERTY, 130*621191d7SNuno Das Neves HVCALL_SET_PARTITION_PROPERTY, 131*621191d7SNuno Das Neves HVCALL_INSTALL_INTERCEPT, 132*621191d7SNuno Das Neves HVCALL_GET_VP_REGISTERS, 133*621191d7SNuno Das Neves HVCALL_SET_VP_REGISTERS, 134*621191d7SNuno Das Neves HVCALL_TRANSLATE_VIRTUAL_ADDRESS, 135*621191d7SNuno Das Neves HVCALL_CLEAR_VIRTUAL_INTERRUPT, 136*621191d7SNuno Das Neves HVCALL_REGISTER_INTERCEPT_RESULT, 137*621191d7SNuno Das Neves HVCALL_ASSERT_VIRTUAL_INTERRUPT, 138*621191d7SNuno Das Neves HVCALL_GET_GPA_PAGES_ACCESS_STATES, 139*621191d7SNuno Das Neves HVCALL_SIGNAL_EVENT_DIRECT, 140*621191d7SNuno Das Neves HVCALL_POST_MESSAGE_DIRECT, 141*621191d7SNuno Das Neves HVCALL_GET_VP_CPUID_VALUES, 142*621191d7SNuno Das Neves }; 143*621191d7SNuno Das Neves 144*621191d7SNuno Das Neves static bool mshv_hvcall_is_async(u16 code) 145*621191d7SNuno Das Neves { 146*621191d7SNuno Das Neves switch (code) { 147*621191d7SNuno Das Neves case HVCALL_SET_PARTITION_PROPERTY: 148*621191d7SNuno Das Neves return true; 149*621191d7SNuno Das Neves default: 150*621191d7SNuno Das Neves break; 151*621191d7SNuno Das Neves } 152*621191d7SNuno Das Neves return false; 153*621191d7SNuno Das Neves } 154*621191d7SNuno Das Neves 155*621191d7SNuno Das Neves static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition, 156*621191d7SNuno Das Neves bool partition_locked, 157*621191d7SNuno Das Neves void __user *user_args) 158*621191d7SNuno Das Neves { 159*621191d7SNuno Das Neves u64 status; 160*621191d7SNuno Das Neves int ret = 0, i; 161*621191d7SNuno Das Neves bool is_async; 162*621191d7SNuno Das Neves struct mshv_root_hvcall args; 163*621191d7SNuno Das Neves struct page *page; 164*621191d7SNuno Das Neves unsigned int pages_order; 165*621191d7SNuno Das Neves void *input_pg = NULL; 166*621191d7SNuno Das Neves void *output_pg = NULL; 167*621191d7SNuno Das Neves 168*621191d7SNuno Das Neves if (copy_from_user(&args, user_args, sizeof(args))) 169*621191d7SNuno Das Neves return -EFAULT; 170*621191d7SNuno Das Neves 171*621191d7SNuno Das Neves if (args.status || !args.in_ptr || args.in_sz < sizeof(u64) || 172*621191d7SNuno Das Neves mshv_field_nonzero(args, rsvd) || args.in_sz > HV_HYP_PAGE_SIZE) 173*621191d7SNuno Das Neves return -EINVAL; 174*621191d7SNuno Das Neves 175*621191d7SNuno Das Neves if (args.out_ptr && (!args.out_sz || args.out_sz > HV_HYP_PAGE_SIZE)) 176*621191d7SNuno Das Neves return -EINVAL; 177*621191d7SNuno Das Neves 178*621191d7SNuno Das Neves for (i = 0; i < ARRAY_SIZE(mshv_passthru_hvcalls); ++i) 179*621191d7SNuno Das Neves if (args.code == mshv_passthru_hvcalls[i]) 180*621191d7SNuno Das Neves break; 181*621191d7SNuno Das Neves 182*621191d7SNuno Das Neves if (i >= ARRAY_SIZE(mshv_passthru_hvcalls)) 183*621191d7SNuno Das Neves return -EINVAL; 184*621191d7SNuno Das Neves 185*621191d7SNuno Das Neves is_async = mshv_hvcall_is_async(args.code); 186*621191d7SNuno Das Neves if (is_async) { 187*621191d7SNuno Das Neves /* async hypercalls can only be called from partition fd */ 188*621191d7SNuno Das Neves if (!partition_locked) 189*621191d7SNuno Das Neves return -EINVAL; 190*621191d7SNuno Das Neves ret = mshv_init_async_handler(partition); 191*621191d7SNuno Das Neves if (ret) 192*621191d7SNuno Das Neves return ret; 193*621191d7SNuno Das Neves } 194*621191d7SNuno Das Neves 195*621191d7SNuno Das Neves pages_order = args.out_ptr ? 1 : 0; 196*621191d7SNuno Das Neves page = alloc_pages(GFP_KERNEL, pages_order); 197*621191d7SNuno Das Neves if (!page) 198*621191d7SNuno Das Neves return -ENOMEM; 199*621191d7SNuno Das Neves input_pg = page_address(page); 200*621191d7SNuno Das Neves 201*621191d7SNuno Das Neves if (args.out_ptr) 202*621191d7SNuno Das Neves output_pg = (char *)input_pg + PAGE_SIZE; 203*621191d7SNuno Das Neves else 204*621191d7SNuno Das Neves output_pg = NULL; 205*621191d7SNuno Das Neves 206*621191d7SNuno Das Neves if (copy_from_user(input_pg, (void __user *)args.in_ptr, 207*621191d7SNuno Das Neves args.in_sz)) { 208*621191d7SNuno Das Neves ret = -EFAULT; 209*621191d7SNuno Das Neves goto free_pages_out; 210*621191d7SNuno Das Neves } 211*621191d7SNuno Das Neves 212*621191d7SNuno Das Neves /* 213*621191d7SNuno Das Neves * NOTE: This only works because all the allowed hypercalls' input 214*621191d7SNuno Das Neves * structs begin with a u64 partition_id field. 215*621191d7SNuno Das Neves */ 216*621191d7SNuno Das Neves *(u64 *)input_pg = partition->pt_id; 217*621191d7SNuno Das Neves 218*621191d7SNuno Das Neves if (args.reps) 219*621191d7SNuno Das Neves status = hv_do_rep_hypercall(args.code, args.reps, 0, 220*621191d7SNuno Das Neves input_pg, output_pg); 221*621191d7SNuno Das Neves else 222*621191d7SNuno Das Neves status = hv_do_hypercall(args.code, input_pg, output_pg); 223*621191d7SNuno Das Neves 224*621191d7SNuno Das Neves if (hv_result(status) == HV_STATUS_CALL_PENDING) { 225*621191d7SNuno Das Neves if (is_async) { 226*621191d7SNuno Das Neves mshv_async_hvcall_handler(partition, &status); 227*621191d7SNuno Das Neves } else { /* Paranoia check. This shouldn't happen! */ 228*621191d7SNuno Das Neves ret = -EBADFD; 229*621191d7SNuno Das Neves goto free_pages_out; 230*621191d7SNuno Das Neves } 231*621191d7SNuno Das Neves } 232*621191d7SNuno Das Neves 233*621191d7SNuno Das Neves if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) { 234*621191d7SNuno Das Neves ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id, 1); 235*621191d7SNuno Das Neves if (!ret) 236*621191d7SNuno Das Neves ret = -EAGAIN; 237*621191d7SNuno Das Neves } else if (!hv_result_success(status)) { 238*621191d7SNuno Das Neves ret = hv_result_to_errno(status); 239*621191d7SNuno Das Neves } 240*621191d7SNuno Das Neves 241*621191d7SNuno Das Neves /* 242*621191d7SNuno Das Neves * Always return the status and output data regardless of result. 243*621191d7SNuno Das Neves * The VMM may need it to determine how to proceed. E.g. the status may 244*621191d7SNuno Das Neves * contain the number of reps completed if a rep hypercall partially 245*621191d7SNuno Das Neves * succeeded. 246*621191d7SNuno Das Neves */ 247*621191d7SNuno Das Neves args.status = hv_result(status); 248*621191d7SNuno Das Neves args.reps = args.reps ? hv_repcomp(status) : 0; 249*621191d7SNuno Das Neves if (copy_to_user(user_args, &args, sizeof(args))) 250*621191d7SNuno Das Neves ret = -EFAULT; 251*621191d7SNuno Das Neves 252*621191d7SNuno Das Neves if (output_pg && 253*621191d7SNuno Das Neves copy_to_user((void __user *)args.out_ptr, output_pg, args.out_sz)) 254*621191d7SNuno Das Neves ret = -EFAULT; 255*621191d7SNuno Das Neves 256*621191d7SNuno Das Neves free_pages_out: 257*621191d7SNuno Das Neves free_pages((unsigned long)input_pg, pages_order); 258*621191d7SNuno Das Neves 259*621191d7SNuno Das Neves return ret; 260*621191d7SNuno Das Neves } 261*621191d7SNuno Das Neves 262*621191d7SNuno Das Neves static inline bool is_ghcb_mapping_available(void) 263*621191d7SNuno Das Neves { 264*621191d7SNuno Das Neves #if IS_ENABLED(CONFIG_X86_64) 265*621191d7SNuno Das Neves return ms_hyperv.ext_features & HV_VP_GHCB_ROOT_MAPPING_AVAILABLE; 266*621191d7SNuno Das Neves #else 267*621191d7SNuno Das Neves return 0; 268*621191d7SNuno Das Neves #endif 269*621191d7SNuno Das Neves } 270*621191d7SNuno Das Neves 271*621191d7SNuno Das Neves static int mshv_get_vp_registers(u32 vp_index, u64 partition_id, u16 count, 272*621191d7SNuno Das Neves struct hv_register_assoc *registers) 273*621191d7SNuno Das Neves { 274*621191d7SNuno Das Neves return hv_call_get_vp_registers(vp_index, partition_id, 275*621191d7SNuno Das Neves count, input_vtl_zero, registers); 276*621191d7SNuno Das Neves } 277*621191d7SNuno Das Neves 278*621191d7SNuno Das Neves static int mshv_set_vp_registers(u32 vp_index, u64 partition_id, u16 count, 279*621191d7SNuno Das Neves struct hv_register_assoc *registers) 280*621191d7SNuno Das Neves { 281*621191d7SNuno Das Neves return hv_call_set_vp_registers(vp_index, partition_id, 282*621191d7SNuno Das Neves count, input_vtl_zero, registers); 283*621191d7SNuno Das Neves } 284*621191d7SNuno Das Neves 285*621191d7SNuno Das Neves /* 286*621191d7SNuno Das Neves * Explicit guest vCPU suspend is asynchronous by nature (as it is requested by 287*621191d7SNuno Das Neves * dom0 vCPU for guest vCPU) and thus it can race with "intercept" suspend, 288*621191d7SNuno Das Neves * done by the hypervisor. 289*621191d7SNuno Das Neves * "Intercept" suspend leads to asynchronous message delivery to dom0 which 290*621191d7SNuno Das Neves * should be awaited to keep the VP loop consistent (i.e. no message pending 291*621191d7SNuno Das Neves * upon VP resume). 292*621191d7SNuno Das Neves * VP intercept suspend can't be done when the VP is explicitly suspended 293*621191d7SNuno Das Neves * already, and thus can be only two possible race scenarios: 294*621191d7SNuno Das Neves * 1. implicit suspend bit set -> explicit suspend bit set -> message sent 295*621191d7SNuno Das Neves * 2. implicit suspend bit set -> message sent -> explicit suspend bit set 296*621191d7SNuno Das Neves * Checking for implicit suspend bit set after explicit suspend request has 297*621191d7SNuno Das Neves * succeeded in either case allows us to reliably identify, if there is a 298*621191d7SNuno Das Neves * message to receive and deliver to VMM. 299*621191d7SNuno Das Neves */ 300*621191d7SNuno Das Neves static int 301*621191d7SNuno Das Neves mshv_suspend_vp(const struct mshv_vp *vp, bool *message_in_flight) 302*621191d7SNuno Das Neves { 303*621191d7SNuno Das Neves struct hv_register_assoc explicit_suspend = { 304*621191d7SNuno Das Neves .name = HV_REGISTER_EXPLICIT_SUSPEND 305*621191d7SNuno Das Neves }; 306*621191d7SNuno Das Neves struct hv_register_assoc intercept_suspend = { 307*621191d7SNuno Das Neves .name = HV_REGISTER_INTERCEPT_SUSPEND 308*621191d7SNuno Das Neves }; 309*621191d7SNuno Das Neves union hv_explicit_suspend_register *es = 310*621191d7SNuno Das Neves &explicit_suspend.value.explicit_suspend; 311*621191d7SNuno Das Neves union hv_intercept_suspend_register *is = 312*621191d7SNuno Das Neves &intercept_suspend.value.intercept_suspend; 313*621191d7SNuno Das Neves int ret; 314*621191d7SNuno Das Neves 315*621191d7SNuno Das Neves es->suspended = 1; 316*621191d7SNuno Das Neves 317*621191d7SNuno Das Neves ret = mshv_set_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 318*621191d7SNuno Das Neves 1, &explicit_suspend); 319*621191d7SNuno Das Neves if (ret) { 320*621191d7SNuno Das Neves vp_err(vp, "Failed to explicitly suspend vCPU\n"); 321*621191d7SNuno Das Neves return ret; 322*621191d7SNuno Das Neves } 323*621191d7SNuno Das Neves 324*621191d7SNuno Das Neves ret = mshv_get_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 325*621191d7SNuno Das Neves 1, &intercept_suspend); 326*621191d7SNuno Das Neves if (ret) { 327*621191d7SNuno Das Neves vp_err(vp, "Failed to get intercept suspend state\n"); 328*621191d7SNuno Das Neves return ret; 329*621191d7SNuno Das Neves } 330*621191d7SNuno Das Neves 331*621191d7SNuno Das Neves *message_in_flight = is->suspended; 332*621191d7SNuno Das Neves 333*621191d7SNuno Das Neves return 0; 334*621191d7SNuno Das Neves } 335*621191d7SNuno Das Neves 336*621191d7SNuno Das Neves /* 337*621191d7SNuno Das Neves * This function is used when VPs are scheduled by the hypervisor's 338*621191d7SNuno Das Neves * scheduler. 339*621191d7SNuno Das Neves * 340*621191d7SNuno Das Neves * Caller has to make sure the registers contain cleared 341*621191d7SNuno Das Neves * HV_REGISTER_INTERCEPT_SUSPEND and HV_REGISTER_EXPLICIT_SUSPEND registers 342*621191d7SNuno Das Neves * exactly in this order (the hypervisor clears them sequentially) to avoid 343*621191d7SNuno Das Neves * potential invalid clearing a newly arrived HV_REGISTER_INTERCEPT_SUSPEND 344*621191d7SNuno Das Neves * after VP is released from HV_REGISTER_EXPLICIT_SUSPEND in case of the 345*621191d7SNuno Das Neves * opposite order. 346*621191d7SNuno Das Neves */ 347*621191d7SNuno Das Neves static long mshv_run_vp_with_hyp_scheduler(struct mshv_vp *vp) 348*621191d7SNuno Das Neves { 349*621191d7SNuno Das Neves long ret; 350*621191d7SNuno Das Neves struct hv_register_assoc suspend_regs[2] = { 351*621191d7SNuno Das Neves { .name = HV_REGISTER_INTERCEPT_SUSPEND }, 352*621191d7SNuno Das Neves { .name = HV_REGISTER_EXPLICIT_SUSPEND } 353*621191d7SNuno Das Neves }; 354*621191d7SNuno Das Neves size_t count = ARRAY_SIZE(suspend_regs); 355*621191d7SNuno Das Neves 356*621191d7SNuno Das Neves /* Resume VP execution */ 357*621191d7SNuno Das Neves ret = mshv_set_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 358*621191d7SNuno Das Neves count, suspend_regs); 359*621191d7SNuno Das Neves if (ret) { 360*621191d7SNuno Das Neves vp_err(vp, "Failed to resume vp execution. %lx\n", ret); 361*621191d7SNuno Das Neves return ret; 362*621191d7SNuno Das Neves } 363*621191d7SNuno Das Neves 364*621191d7SNuno Das Neves ret = wait_event_interruptible(vp->run.vp_suspend_queue, 365*621191d7SNuno Das Neves vp->run.kicked_by_hv == 1); 366*621191d7SNuno Das Neves if (ret) { 367*621191d7SNuno Das Neves bool message_in_flight; 368*621191d7SNuno Das Neves 369*621191d7SNuno Das Neves /* 370*621191d7SNuno Das Neves * Otherwise the waiting was interrupted by a signal: suspend 371*621191d7SNuno Das Neves * the vCPU explicitly and copy message in flight (if any). 372*621191d7SNuno Das Neves */ 373*621191d7SNuno Das Neves ret = mshv_suspend_vp(vp, &message_in_flight); 374*621191d7SNuno Das Neves if (ret) 375*621191d7SNuno Das Neves return ret; 376*621191d7SNuno Das Neves 377*621191d7SNuno Das Neves /* Return if no message in flight */ 378*621191d7SNuno Das Neves if (!message_in_flight) 379*621191d7SNuno Das Neves return -EINTR; 380*621191d7SNuno Das Neves 381*621191d7SNuno Das Neves /* Wait for the message in flight. */ 382*621191d7SNuno Das Neves wait_event(vp->run.vp_suspend_queue, vp->run.kicked_by_hv == 1); 383*621191d7SNuno Das Neves } 384*621191d7SNuno Das Neves 385*621191d7SNuno Das Neves /* 386*621191d7SNuno Das Neves * Reset the flag to make the wait_event call above work 387*621191d7SNuno Das Neves * next time. 388*621191d7SNuno Das Neves */ 389*621191d7SNuno Das Neves vp->run.kicked_by_hv = 0; 390*621191d7SNuno Das Neves 391*621191d7SNuno Das Neves return 0; 392*621191d7SNuno Das Neves } 393*621191d7SNuno Das Neves 394*621191d7SNuno Das Neves static int 395*621191d7SNuno Das Neves mshv_vp_dispatch(struct mshv_vp *vp, u32 flags, 396*621191d7SNuno Das Neves struct hv_output_dispatch_vp *res) 397*621191d7SNuno Das Neves { 398*621191d7SNuno Das Neves struct hv_input_dispatch_vp *input; 399*621191d7SNuno Das Neves struct hv_output_dispatch_vp *output; 400*621191d7SNuno Das Neves u64 status; 401*621191d7SNuno Das Neves 402*621191d7SNuno Das Neves preempt_disable(); 403*621191d7SNuno Das Neves input = *this_cpu_ptr(root_scheduler_input); 404*621191d7SNuno Das Neves output = *this_cpu_ptr(root_scheduler_output); 405*621191d7SNuno Das Neves 406*621191d7SNuno Das Neves memset(input, 0, sizeof(*input)); 407*621191d7SNuno Das Neves memset(output, 0, sizeof(*output)); 408*621191d7SNuno Das Neves 409*621191d7SNuno Das Neves input->partition_id = vp->vp_partition->pt_id; 410*621191d7SNuno Das Neves input->vp_index = vp->vp_index; 411*621191d7SNuno Das Neves input->time_slice = 0; /* Run forever until something happens */ 412*621191d7SNuno Das Neves input->spec_ctrl = 0; /* TODO: set sensible flags */ 413*621191d7SNuno Das Neves input->flags = flags; 414*621191d7SNuno Das Neves 415*621191d7SNuno Das Neves vp->run.flags.root_sched_dispatched = 1; 416*621191d7SNuno Das Neves status = hv_do_hypercall(HVCALL_DISPATCH_VP, input, output); 417*621191d7SNuno Das Neves vp->run.flags.root_sched_dispatched = 0; 418*621191d7SNuno Das Neves 419*621191d7SNuno Das Neves *res = *output; 420*621191d7SNuno Das Neves preempt_enable(); 421*621191d7SNuno Das Neves 422*621191d7SNuno Das Neves if (!hv_result_success(status)) 423*621191d7SNuno Das Neves vp_err(vp, "%s: status %s\n", __func__, 424*621191d7SNuno Das Neves hv_result_to_string(status)); 425*621191d7SNuno Das Neves 426*621191d7SNuno Das Neves return hv_result_to_errno(status); 427*621191d7SNuno Das Neves } 428*621191d7SNuno Das Neves 429*621191d7SNuno Das Neves static int 430*621191d7SNuno Das Neves mshv_vp_clear_explicit_suspend(struct mshv_vp *vp) 431*621191d7SNuno Das Neves { 432*621191d7SNuno Das Neves struct hv_register_assoc explicit_suspend = { 433*621191d7SNuno Das Neves .name = HV_REGISTER_EXPLICIT_SUSPEND, 434*621191d7SNuno Das Neves .value.explicit_suspend.suspended = 0, 435*621191d7SNuno Das Neves }; 436*621191d7SNuno Das Neves int ret; 437*621191d7SNuno Das Neves 438*621191d7SNuno Das Neves ret = mshv_set_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 439*621191d7SNuno Das Neves 1, &explicit_suspend); 440*621191d7SNuno Das Neves 441*621191d7SNuno Das Neves if (ret) 442*621191d7SNuno Das Neves vp_err(vp, "Failed to unsuspend\n"); 443*621191d7SNuno Das Neves 444*621191d7SNuno Das Neves return ret; 445*621191d7SNuno Das Neves } 446*621191d7SNuno Das Neves 447*621191d7SNuno Das Neves #if IS_ENABLED(CONFIG_X86_64) 448*621191d7SNuno Das Neves static u64 mshv_vp_interrupt_pending(struct mshv_vp *vp) 449*621191d7SNuno Das Neves { 450*621191d7SNuno Das Neves if (!vp->vp_register_page) 451*621191d7SNuno Das Neves return 0; 452*621191d7SNuno Das Neves return vp->vp_register_page->interrupt_vectors.as_uint64; 453*621191d7SNuno Das Neves } 454*621191d7SNuno Das Neves #else 455*621191d7SNuno Das Neves static u64 mshv_vp_interrupt_pending(struct mshv_vp *vp) 456*621191d7SNuno Das Neves { 457*621191d7SNuno Das Neves return 0; 458*621191d7SNuno Das Neves } 459*621191d7SNuno Das Neves #endif 460*621191d7SNuno Das Neves 461*621191d7SNuno Das Neves static bool mshv_vp_dispatch_thread_blocked(struct mshv_vp *vp) 462*621191d7SNuno Das Neves { 463*621191d7SNuno Das Neves struct hv_stats_page **stats = vp->vp_stats_pages; 464*621191d7SNuno Das Neves u64 *self_vp_cntrs = stats[HV_STATS_AREA_SELF]->vp_cntrs; 465*621191d7SNuno Das Neves u64 *parent_vp_cntrs = stats[HV_STATS_AREA_PARENT]->vp_cntrs; 466*621191d7SNuno Das Neves 467*621191d7SNuno Das Neves if (self_vp_cntrs[VpRootDispatchThreadBlocked]) 468*621191d7SNuno Das Neves return self_vp_cntrs[VpRootDispatchThreadBlocked]; 469*621191d7SNuno Das Neves return parent_vp_cntrs[VpRootDispatchThreadBlocked]; 470*621191d7SNuno Das Neves } 471*621191d7SNuno Das Neves 472*621191d7SNuno Das Neves static int 473*621191d7SNuno Das Neves mshv_vp_wait_for_hv_kick(struct mshv_vp *vp) 474*621191d7SNuno Das Neves { 475*621191d7SNuno Das Neves int ret; 476*621191d7SNuno Das Neves 477*621191d7SNuno Das Neves ret = wait_event_interruptible(vp->run.vp_suspend_queue, 478*621191d7SNuno Das Neves (vp->run.kicked_by_hv == 1 && 479*621191d7SNuno Das Neves !mshv_vp_dispatch_thread_blocked(vp)) || 480*621191d7SNuno Das Neves mshv_vp_interrupt_pending(vp)); 481*621191d7SNuno Das Neves if (ret) 482*621191d7SNuno Das Neves return -EINTR; 483*621191d7SNuno Das Neves 484*621191d7SNuno Das Neves vp->run.flags.root_sched_blocked = 0; 485*621191d7SNuno Das Neves vp->run.kicked_by_hv = 0; 486*621191d7SNuno Das Neves 487*621191d7SNuno Das Neves return 0; 488*621191d7SNuno Das Neves } 489*621191d7SNuno Das Neves 490*621191d7SNuno Das Neves static int mshv_pre_guest_mode_work(struct mshv_vp *vp) 491*621191d7SNuno Das Neves { 492*621191d7SNuno Das Neves const ulong work_flags = _TIF_NOTIFY_SIGNAL | _TIF_SIGPENDING | 493*621191d7SNuno Das Neves _TIF_NEED_RESCHED | _TIF_NOTIFY_RESUME; 494*621191d7SNuno Das Neves ulong th_flags; 495*621191d7SNuno Das Neves 496*621191d7SNuno Das Neves th_flags = read_thread_flags(); 497*621191d7SNuno Das Neves while (th_flags & work_flags) { 498*621191d7SNuno Das Neves int ret; 499*621191d7SNuno Das Neves 500*621191d7SNuno Das Neves /* nb: following will call schedule */ 501*621191d7SNuno Das Neves ret = mshv_do_pre_guest_mode_work(th_flags); 502*621191d7SNuno Das Neves 503*621191d7SNuno Das Neves if (ret) 504*621191d7SNuno Das Neves return ret; 505*621191d7SNuno Das Neves 506*621191d7SNuno Das Neves th_flags = read_thread_flags(); 507*621191d7SNuno Das Neves } 508*621191d7SNuno Das Neves 509*621191d7SNuno Das Neves return 0; 510*621191d7SNuno Das Neves } 511*621191d7SNuno Das Neves 512*621191d7SNuno Das Neves /* Must be called with interrupts enabled */ 513*621191d7SNuno Das Neves static long mshv_run_vp_with_root_scheduler(struct mshv_vp *vp) 514*621191d7SNuno Das Neves { 515*621191d7SNuno Das Neves long ret; 516*621191d7SNuno Das Neves 517*621191d7SNuno Das Neves if (vp->run.flags.root_sched_blocked) { 518*621191d7SNuno Das Neves /* 519*621191d7SNuno Das Neves * Dispatch state of this VP is blocked. Need to wait 520*621191d7SNuno Das Neves * for the hypervisor to clear the blocked state before 521*621191d7SNuno Das Neves * dispatching it. 522*621191d7SNuno Das Neves */ 523*621191d7SNuno Das Neves ret = mshv_vp_wait_for_hv_kick(vp); 524*621191d7SNuno Das Neves if (ret) 525*621191d7SNuno Das Neves return ret; 526*621191d7SNuno Das Neves } 527*621191d7SNuno Das Neves 528*621191d7SNuno Das Neves do { 529*621191d7SNuno Das Neves u32 flags = 0; 530*621191d7SNuno Das Neves struct hv_output_dispatch_vp output; 531*621191d7SNuno Das Neves 532*621191d7SNuno Das Neves ret = mshv_pre_guest_mode_work(vp); 533*621191d7SNuno Das Neves if (ret) 534*621191d7SNuno Das Neves break; 535*621191d7SNuno Das Neves 536*621191d7SNuno Das Neves if (vp->run.flags.intercept_suspend) 537*621191d7SNuno Das Neves flags |= HV_DISPATCH_VP_FLAG_CLEAR_INTERCEPT_SUSPEND; 538*621191d7SNuno Das Neves 539*621191d7SNuno Das Neves if (mshv_vp_interrupt_pending(vp)) 540*621191d7SNuno Das Neves flags |= HV_DISPATCH_VP_FLAG_SCAN_INTERRUPT_INJECTION; 541*621191d7SNuno Das Neves 542*621191d7SNuno Das Neves ret = mshv_vp_dispatch(vp, flags, &output); 543*621191d7SNuno Das Neves if (ret) 544*621191d7SNuno Das Neves break; 545*621191d7SNuno Das Neves 546*621191d7SNuno Das Neves vp->run.flags.intercept_suspend = 0; 547*621191d7SNuno Das Neves 548*621191d7SNuno Das Neves if (output.dispatch_state == HV_VP_DISPATCH_STATE_BLOCKED) { 549*621191d7SNuno Das Neves if (output.dispatch_event == 550*621191d7SNuno Das Neves HV_VP_DISPATCH_EVENT_SUSPEND) { 551*621191d7SNuno Das Neves /* 552*621191d7SNuno Das Neves * TODO: remove the warning once VP canceling 553*621191d7SNuno Das Neves * is supported 554*621191d7SNuno Das Neves */ 555*621191d7SNuno Das Neves WARN_ONCE(atomic64_read(&vp->run.vp_signaled_count), 556*621191d7SNuno Das Neves "%s: vp#%d: unexpected explicit suspend\n", 557*621191d7SNuno Das Neves __func__, vp->vp_index); 558*621191d7SNuno Das Neves /* 559*621191d7SNuno Das Neves * Need to clear explicit suspend before 560*621191d7SNuno Das Neves * dispatching. 561*621191d7SNuno Das Neves * Explicit suspend is either: 562*621191d7SNuno Das Neves * - set right after the first VP dispatch or 563*621191d7SNuno Das Neves * - set explicitly via hypercall 564*621191d7SNuno Das Neves * Since the latter case is not yet supported, 565*621191d7SNuno Das Neves * simply clear it here. 566*621191d7SNuno Das Neves */ 567*621191d7SNuno Das Neves ret = mshv_vp_clear_explicit_suspend(vp); 568*621191d7SNuno Das Neves if (ret) 569*621191d7SNuno Das Neves break; 570*621191d7SNuno Das Neves 571*621191d7SNuno Das Neves ret = mshv_vp_wait_for_hv_kick(vp); 572*621191d7SNuno Das Neves if (ret) 573*621191d7SNuno Das Neves break; 574*621191d7SNuno Das Neves } else { 575*621191d7SNuno Das Neves vp->run.flags.root_sched_blocked = 1; 576*621191d7SNuno Das Neves ret = mshv_vp_wait_for_hv_kick(vp); 577*621191d7SNuno Das Neves if (ret) 578*621191d7SNuno Das Neves break; 579*621191d7SNuno Das Neves } 580*621191d7SNuno Das Neves } else { 581*621191d7SNuno Das Neves /* HV_VP_DISPATCH_STATE_READY */ 582*621191d7SNuno Das Neves if (output.dispatch_event == 583*621191d7SNuno Das Neves HV_VP_DISPATCH_EVENT_INTERCEPT) 584*621191d7SNuno Das Neves vp->run.flags.intercept_suspend = 1; 585*621191d7SNuno Das Neves } 586*621191d7SNuno Das Neves } while (!vp->run.flags.intercept_suspend); 587*621191d7SNuno Das Neves 588*621191d7SNuno Das Neves return ret; 589*621191d7SNuno Das Neves } 590*621191d7SNuno Das Neves 591*621191d7SNuno Das Neves static_assert(sizeof(struct hv_message) <= MSHV_RUN_VP_BUF_SZ, 592*621191d7SNuno Das Neves "sizeof(struct hv_message) must not exceed MSHV_RUN_VP_BUF_SZ"); 593*621191d7SNuno Das Neves 594*621191d7SNuno Das Neves static long mshv_vp_ioctl_run_vp(struct mshv_vp *vp, void __user *ret_msg) 595*621191d7SNuno Das Neves { 596*621191d7SNuno Das Neves long rc; 597*621191d7SNuno Das Neves 598*621191d7SNuno Das Neves if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) 599*621191d7SNuno Das Neves rc = mshv_run_vp_with_root_scheduler(vp); 600*621191d7SNuno Das Neves else 601*621191d7SNuno Das Neves rc = mshv_run_vp_with_hyp_scheduler(vp); 602*621191d7SNuno Das Neves 603*621191d7SNuno Das Neves if (rc) 604*621191d7SNuno Das Neves return rc; 605*621191d7SNuno Das Neves 606*621191d7SNuno Das Neves if (copy_to_user(ret_msg, vp->vp_intercept_msg_page, 607*621191d7SNuno Das Neves sizeof(struct hv_message))) 608*621191d7SNuno Das Neves rc = -EFAULT; 609*621191d7SNuno Das Neves 610*621191d7SNuno Das Neves return rc; 611*621191d7SNuno Das Neves } 612*621191d7SNuno Das Neves 613*621191d7SNuno Das Neves static int 614*621191d7SNuno Das Neves mshv_vp_ioctl_get_set_state_pfn(struct mshv_vp *vp, 615*621191d7SNuno Das Neves struct hv_vp_state_data state_data, 616*621191d7SNuno Das Neves unsigned long user_pfn, size_t page_count, 617*621191d7SNuno Das Neves bool is_set) 618*621191d7SNuno Das Neves { 619*621191d7SNuno Das Neves int completed, ret = 0; 620*621191d7SNuno Das Neves unsigned long check; 621*621191d7SNuno Das Neves struct page **pages; 622*621191d7SNuno Das Neves 623*621191d7SNuno Das Neves if (page_count > INT_MAX) 624*621191d7SNuno Das Neves return -EINVAL; 625*621191d7SNuno Das Neves /* 626*621191d7SNuno Das Neves * Check the arithmetic for wraparound/overflow. 627*621191d7SNuno Das Neves * The last page address in the buffer is: 628*621191d7SNuno Das Neves * (user_pfn + (page_count - 1)) * PAGE_SIZE 629*621191d7SNuno Das Neves */ 630*621191d7SNuno Das Neves if (check_add_overflow(user_pfn, (page_count - 1), &check)) 631*621191d7SNuno Das Neves return -EOVERFLOW; 632*621191d7SNuno Das Neves if (check_mul_overflow(check, PAGE_SIZE, &check)) 633*621191d7SNuno Das Neves return -EOVERFLOW; 634*621191d7SNuno Das Neves 635*621191d7SNuno Das Neves /* Pin user pages so hypervisor can copy directly to them */ 636*621191d7SNuno Das Neves pages = kcalloc(page_count, sizeof(struct page *), GFP_KERNEL); 637*621191d7SNuno Das Neves if (!pages) 638*621191d7SNuno Das Neves return -ENOMEM; 639*621191d7SNuno Das Neves 640*621191d7SNuno Das Neves for (completed = 0; completed < page_count; completed += ret) { 641*621191d7SNuno Das Neves unsigned long user_addr = (user_pfn + completed) * PAGE_SIZE; 642*621191d7SNuno Das Neves int remaining = page_count - completed; 643*621191d7SNuno Das Neves 644*621191d7SNuno Das Neves ret = pin_user_pages_fast(user_addr, remaining, FOLL_WRITE, 645*621191d7SNuno Das Neves &pages[completed]); 646*621191d7SNuno Das Neves if (ret < 0) { 647*621191d7SNuno Das Neves vp_err(vp, "%s: Failed to pin user pages error %i\n", 648*621191d7SNuno Das Neves __func__, ret); 649*621191d7SNuno Das Neves goto unpin_pages; 650*621191d7SNuno Das Neves } 651*621191d7SNuno Das Neves } 652*621191d7SNuno Das Neves 653*621191d7SNuno Das Neves if (is_set) 654*621191d7SNuno Das Neves ret = hv_call_set_vp_state(vp->vp_index, 655*621191d7SNuno Das Neves vp->vp_partition->pt_id, 656*621191d7SNuno Das Neves state_data, page_count, pages, 657*621191d7SNuno Das Neves 0, NULL); 658*621191d7SNuno Das Neves else 659*621191d7SNuno Das Neves ret = hv_call_get_vp_state(vp->vp_index, 660*621191d7SNuno Das Neves vp->vp_partition->pt_id, 661*621191d7SNuno Das Neves state_data, page_count, pages, 662*621191d7SNuno Das Neves NULL); 663*621191d7SNuno Das Neves 664*621191d7SNuno Das Neves unpin_pages: 665*621191d7SNuno Das Neves unpin_user_pages(pages, completed); 666*621191d7SNuno Das Neves kfree(pages); 667*621191d7SNuno Das Neves return ret; 668*621191d7SNuno Das Neves } 669*621191d7SNuno Das Neves 670*621191d7SNuno Das Neves static long 671*621191d7SNuno Das Neves mshv_vp_ioctl_get_set_state(struct mshv_vp *vp, 672*621191d7SNuno Das Neves struct mshv_get_set_vp_state __user *user_args, 673*621191d7SNuno Das Neves bool is_set) 674*621191d7SNuno Das Neves { 675*621191d7SNuno Das Neves struct mshv_get_set_vp_state args; 676*621191d7SNuno Das Neves long ret = 0; 677*621191d7SNuno Das Neves union hv_output_get_vp_state vp_state; 678*621191d7SNuno Das Neves u32 data_sz; 679*621191d7SNuno Das Neves struct hv_vp_state_data state_data = {}; 680*621191d7SNuno Das Neves 681*621191d7SNuno Das Neves if (copy_from_user(&args, user_args, sizeof(args))) 682*621191d7SNuno Das Neves return -EFAULT; 683*621191d7SNuno Das Neves 684*621191d7SNuno Das Neves if (args.type >= MSHV_VP_STATE_COUNT || mshv_field_nonzero(args, rsvd) || 685*621191d7SNuno Das Neves !args.buf_sz || !PAGE_ALIGNED(args.buf_sz) || 686*621191d7SNuno Das Neves !PAGE_ALIGNED(args.buf_ptr)) 687*621191d7SNuno Das Neves return -EINVAL; 688*621191d7SNuno Das Neves 689*621191d7SNuno Das Neves if (!access_ok((void __user *)args.buf_ptr, args.buf_sz)) 690*621191d7SNuno Das Neves return -EFAULT; 691*621191d7SNuno Das Neves 692*621191d7SNuno Das Neves switch (args.type) { 693*621191d7SNuno Das Neves case MSHV_VP_STATE_LAPIC: 694*621191d7SNuno Das Neves state_data.type = HV_GET_SET_VP_STATE_LAPIC_STATE; 695*621191d7SNuno Das Neves data_sz = HV_HYP_PAGE_SIZE; 696*621191d7SNuno Das Neves break; 697*621191d7SNuno Das Neves case MSHV_VP_STATE_XSAVE: 698*621191d7SNuno Das Neves { 699*621191d7SNuno Das Neves u64 data_sz_64; 700*621191d7SNuno Das Neves 701*621191d7SNuno Das Neves ret = hv_call_get_partition_property(vp->vp_partition->pt_id, 702*621191d7SNuno Das Neves HV_PARTITION_PROPERTY_XSAVE_STATES, 703*621191d7SNuno Das Neves &state_data.xsave.states.as_uint64); 704*621191d7SNuno Das Neves if (ret) 705*621191d7SNuno Das Neves return ret; 706*621191d7SNuno Das Neves 707*621191d7SNuno Das Neves ret = hv_call_get_partition_property(vp->vp_partition->pt_id, 708*621191d7SNuno Das Neves HV_PARTITION_PROPERTY_MAX_XSAVE_DATA_SIZE, 709*621191d7SNuno Das Neves &data_sz_64); 710*621191d7SNuno Das Neves if (ret) 711*621191d7SNuno Das Neves return ret; 712*621191d7SNuno Das Neves 713*621191d7SNuno Das Neves data_sz = (u32)data_sz_64; 714*621191d7SNuno Das Neves state_data.xsave.flags = 0; 715*621191d7SNuno Das Neves /* Always request legacy states */ 716*621191d7SNuno Das Neves state_data.xsave.states.legacy_x87 = 1; 717*621191d7SNuno Das Neves state_data.xsave.states.legacy_sse = 1; 718*621191d7SNuno Das Neves state_data.type = HV_GET_SET_VP_STATE_XSAVE; 719*621191d7SNuno Das Neves break; 720*621191d7SNuno Das Neves } 721*621191d7SNuno Das Neves case MSHV_VP_STATE_SIMP: 722*621191d7SNuno Das Neves state_data.type = HV_GET_SET_VP_STATE_SIM_PAGE; 723*621191d7SNuno Das Neves data_sz = HV_HYP_PAGE_SIZE; 724*621191d7SNuno Das Neves break; 725*621191d7SNuno Das Neves case MSHV_VP_STATE_SIEFP: 726*621191d7SNuno Das Neves state_data.type = HV_GET_SET_VP_STATE_SIEF_PAGE; 727*621191d7SNuno Das Neves data_sz = HV_HYP_PAGE_SIZE; 728*621191d7SNuno Das Neves break; 729*621191d7SNuno Das Neves case MSHV_VP_STATE_SYNTHETIC_TIMERS: 730*621191d7SNuno Das Neves state_data.type = HV_GET_SET_VP_STATE_SYNTHETIC_TIMERS; 731*621191d7SNuno Das Neves data_sz = sizeof(vp_state.synthetic_timers_state); 732*621191d7SNuno Das Neves break; 733*621191d7SNuno Das Neves default: 734*621191d7SNuno Das Neves return -EINVAL; 735*621191d7SNuno Das Neves } 736*621191d7SNuno Das Neves 737*621191d7SNuno Das Neves if (copy_to_user(&user_args->buf_sz, &data_sz, sizeof(user_args->buf_sz))) 738*621191d7SNuno Das Neves return -EFAULT; 739*621191d7SNuno Das Neves 740*621191d7SNuno Das Neves if (data_sz > args.buf_sz) 741*621191d7SNuno Das Neves return -EINVAL; 742*621191d7SNuno Das Neves 743*621191d7SNuno Das Neves /* If the data is transmitted via pfns, delegate to helper */ 744*621191d7SNuno Das Neves if (state_data.type & HV_GET_SET_VP_STATE_TYPE_PFN) { 745*621191d7SNuno Das Neves unsigned long user_pfn = PFN_DOWN(args.buf_ptr); 746*621191d7SNuno Das Neves size_t page_count = PFN_DOWN(args.buf_sz); 747*621191d7SNuno Das Neves 748*621191d7SNuno Das Neves return mshv_vp_ioctl_get_set_state_pfn(vp, state_data, user_pfn, 749*621191d7SNuno Das Neves page_count, is_set); 750*621191d7SNuno Das Neves } 751*621191d7SNuno Das Neves 752*621191d7SNuno Das Neves /* Paranoia check - this shouldn't happen! */ 753*621191d7SNuno Das Neves if (data_sz > sizeof(vp_state)) { 754*621191d7SNuno Das Neves vp_err(vp, "Invalid vp state data size!\n"); 755*621191d7SNuno Das Neves return -EINVAL; 756*621191d7SNuno Das Neves } 757*621191d7SNuno Das Neves 758*621191d7SNuno Das Neves if (is_set) { 759*621191d7SNuno Das Neves if (copy_from_user(&vp_state, (__user void *)args.buf_ptr, data_sz)) 760*621191d7SNuno Das Neves return -EFAULT; 761*621191d7SNuno Das Neves 762*621191d7SNuno Das Neves return hv_call_set_vp_state(vp->vp_index, 763*621191d7SNuno Das Neves vp->vp_partition->pt_id, 764*621191d7SNuno Das Neves state_data, 0, NULL, 765*621191d7SNuno Das Neves sizeof(vp_state), (u8 *)&vp_state); 766*621191d7SNuno Das Neves } 767*621191d7SNuno Das Neves 768*621191d7SNuno Das Neves ret = hv_call_get_vp_state(vp->vp_index, vp->vp_partition->pt_id, 769*621191d7SNuno Das Neves state_data, 0, NULL, &vp_state); 770*621191d7SNuno Das Neves if (ret) 771*621191d7SNuno Das Neves return ret; 772*621191d7SNuno Das Neves 773*621191d7SNuno Das Neves if (copy_to_user((void __user *)args.buf_ptr, &vp_state, data_sz)) 774*621191d7SNuno Das Neves return -EFAULT; 775*621191d7SNuno Das Neves 776*621191d7SNuno Das Neves return 0; 777*621191d7SNuno Das Neves } 778*621191d7SNuno Das Neves 779*621191d7SNuno Das Neves static long 780*621191d7SNuno Das Neves mshv_vp_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) 781*621191d7SNuno Das Neves { 782*621191d7SNuno Das Neves struct mshv_vp *vp = filp->private_data; 783*621191d7SNuno Das Neves long r = -ENOTTY; 784*621191d7SNuno Das Neves 785*621191d7SNuno Das Neves if (mutex_lock_killable(&vp->vp_mutex)) 786*621191d7SNuno Das Neves return -EINTR; 787*621191d7SNuno Das Neves 788*621191d7SNuno Das Neves switch (ioctl) { 789*621191d7SNuno Das Neves case MSHV_RUN_VP: 790*621191d7SNuno Das Neves r = mshv_vp_ioctl_run_vp(vp, (void __user *)arg); 791*621191d7SNuno Das Neves break; 792*621191d7SNuno Das Neves case MSHV_GET_VP_STATE: 793*621191d7SNuno Das Neves r = mshv_vp_ioctl_get_set_state(vp, (void __user *)arg, false); 794*621191d7SNuno Das Neves break; 795*621191d7SNuno Das Neves case MSHV_SET_VP_STATE: 796*621191d7SNuno Das Neves r = mshv_vp_ioctl_get_set_state(vp, (void __user *)arg, true); 797*621191d7SNuno Das Neves break; 798*621191d7SNuno Das Neves case MSHV_ROOT_HVCALL: 799*621191d7SNuno Das Neves r = mshv_ioctl_passthru_hvcall(vp->vp_partition, false, 800*621191d7SNuno Das Neves (void __user *)arg); 801*621191d7SNuno Das Neves break; 802*621191d7SNuno Das Neves default: 803*621191d7SNuno Das Neves vp_warn(vp, "Invalid ioctl: %#x\n", ioctl); 804*621191d7SNuno Das Neves break; 805*621191d7SNuno Das Neves } 806*621191d7SNuno Das Neves mutex_unlock(&vp->vp_mutex); 807*621191d7SNuno Das Neves 808*621191d7SNuno Das Neves return r; 809*621191d7SNuno Das Neves } 810*621191d7SNuno Das Neves 811*621191d7SNuno Das Neves static vm_fault_t mshv_vp_fault(struct vm_fault *vmf) 812*621191d7SNuno Das Neves { 813*621191d7SNuno Das Neves struct mshv_vp *vp = vmf->vma->vm_file->private_data; 814*621191d7SNuno Das Neves 815*621191d7SNuno Das Neves switch (vmf->vma->vm_pgoff) { 816*621191d7SNuno Das Neves case MSHV_VP_MMAP_OFFSET_REGISTERS: 817*621191d7SNuno Das Neves vmf->page = virt_to_page(vp->vp_register_page); 818*621191d7SNuno Das Neves break; 819*621191d7SNuno Das Neves case MSHV_VP_MMAP_OFFSET_INTERCEPT_MESSAGE: 820*621191d7SNuno Das Neves vmf->page = virt_to_page(vp->vp_intercept_msg_page); 821*621191d7SNuno Das Neves break; 822*621191d7SNuno Das Neves case MSHV_VP_MMAP_OFFSET_GHCB: 823*621191d7SNuno Das Neves vmf->page = virt_to_page(vp->vp_ghcb_page); 824*621191d7SNuno Das Neves break; 825*621191d7SNuno Das Neves default: 826*621191d7SNuno Das Neves return VM_FAULT_SIGBUS; 827*621191d7SNuno Das Neves } 828*621191d7SNuno Das Neves 829*621191d7SNuno Das Neves get_page(vmf->page); 830*621191d7SNuno Das Neves 831*621191d7SNuno Das Neves return 0; 832*621191d7SNuno Das Neves } 833*621191d7SNuno Das Neves 834*621191d7SNuno Das Neves static int mshv_vp_mmap(struct file *file, struct vm_area_struct *vma) 835*621191d7SNuno Das Neves { 836*621191d7SNuno Das Neves struct mshv_vp *vp = file->private_data; 837*621191d7SNuno Das Neves 838*621191d7SNuno Das Neves switch (vma->vm_pgoff) { 839*621191d7SNuno Das Neves case MSHV_VP_MMAP_OFFSET_REGISTERS: 840*621191d7SNuno Das Neves if (!vp->vp_register_page) 841*621191d7SNuno Das Neves return -ENODEV; 842*621191d7SNuno Das Neves break; 843*621191d7SNuno Das Neves case MSHV_VP_MMAP_OFFSET_INTERCEPT_MESSAGE: 844*621191d7SNuno Das Neves if (!vp->vp_intercept_msg_page) 845*621191d7SNuno Das Neves return -ENODEV; 846*621191d7SNuno Das Neves break; 847*621191d7SNuno Das Neves case MSHV_VP_MMAP_OFFSET_GHCB: 848*621191d7SNuno Das Neves if (!vp->vp_ghcb_page) 849*621191d7SNuno Das Neves return -ENODEV; 850*621191d7SNuno Das Neves break; 851*621191d7SNuno Das Neves default: 852*621191d7SNuno Das Neves return -EINVAL; 853*621191d7SNuno Das Neves } 854*621191d7SNuno Das Neves 855*621191d7SNuno Das Neves vma->vm_ops = &mshv_vp_vm_ops; 856*621191d7SNuno Das Neves return 0; 857*621191d7SNuno Das Neves } 858*621191d7SNuno Das Neves 859*621191d7SNuno Das Neves static int 860*621191d7SNuno Das Neves mshv_vp_release(struct inode *inode, struct file *filp) 861*621191d7SNuno Das Neves { 862*621191d7SNuno Das Neves struct mshv_vp *vp = filp->private_data; 863*621191d7SNuno Das Neves 864*621191d7SNuno Das Neves /* Rest of VP cleanup happens in destroy_partition() */ 865*621191d7SNuno Das Neves mshv_partition_put(vp->vp_partition); 866*621191d7SNuno Das Neves return 0; 867*621191d7SNuno Das Neves } 868*621191d7SNuno Das Neves 869*621191d7SNuno Das Neves static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index) 870*621191d7SNuno Das Neves { 871*621191d7SNuno Das Neves union hv_stats_object_identity identity = { 872*621191d7SNuno Das Neves .vp.partition_id = partition_id, 873*621191d7SNuno Das Neves .vp.vp_index = vp_index, 874*621191d7SNuno Das Neves }; 875*621191d7SNuno Das Neves 876*621191d7SNuno Das Neves identity.vp.stats_area_type = HV_STATS_AREA_SELF; 877*621191d7SNuno Das Neves hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); 878*621191d7SNuno Das Neves 879*621191d7SNuno Das Neves identity.vp.stats_area_type = HV_STATS_AREA_PARENT; 880*621191d7SNuno Das Neves hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); 881*621191d7SNuno Das Neves } 882*621191d7SNuno Das Neves 883*621191d7SNuno Das Neves static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, 884*621191d7SNuno Das Neves void *stats_pages[]) 885*621191d7SNuno Das Neves { 886*621191d7SNuno Das Neves union hv_stats_object_identity identity = { 887*621191d7SNuno Das Neves .vp.partition_id = partition_id, 888*621191d7SNuno Das Neves .vp.vp_index = vp_index, 889*621191d7SNuno Das Neves }; 890*621191d7SNuno Das Neves int err; 891*621191d7SNuno Das Neves 892*621191d7SNuno Das Neves identity.vp.stats_area_type = HV_STATS_AREA_SELF; 893*621191d7SNuno Das Neves err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, 894*621191d7SNuno Das Neves &stats_pages[HV_STATS_AREA_SELF]); 895*621191d7SNuno Das Neves if (err) 896*621191d7SNuno Das Neves return err; 897*621191d7SNuno Das Neves 898*621191d7SNuno Das Neves identity.vp.stats_area_type = HV_STATS_AREA_PARENT; 899*621191d7SNuno Das Neves err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, 900*621191d7SNuno Das Neves &stats_pages[HV_STATS_AREA_PARENT]); 901*621191d7SNuno Das Neves if (err) 902*621191d7SNuno Das Neves goto unmap_self; 903*621191d7SNuno Das Neves 904*621191d7SNuno Das Neves return 0; 905*621191d7SNuno Das Neves 906*621191d7SNuno Das Neves unmap_self: 907*621191d7SNuno Das Neves identity.vp.stats_area_type = HV_STATS_AREA_SELF; 908*621191d7SNuno Das Neves hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); 909*621191d7SNuno Das Neves return err; 910*621191d7SNuno Das Neves } 911*621191d7SNuno Das Neves 912*621191d7SNuno Das Neves static long 913*621191d7SNuno Das Neves mshv_partition_ioctl_create_vp(struct mshv_partition *partition, 914*621191d7SNuno Das Neves void __user *arg) 915*621191d7SNuno Das Neves { 916*621191d7SNuno Das Neves struct mshv_create_vp args; 917*621191d7SNuno Das Neves struct mshv_vp *vp; 918*621191d7SNuno Das Neves struct page *intercept_message_page, *register_page, *ghcb_page; 919*621191d7SNuno Das Neves void *stats_pages[2]; 920*621191d7SNuno Das Neves long ret; 921*621191d7SNuno Das Neves 922*621191d7SNuno Das Neves if (copy_from_user(&args, arg, sizeof(args))) 923*621191d7SNuno Das Neves return -EFAULT; 924*621191d7SNuno Das Neves 925*621191d7SNuno Das Neves if (args.vp_index >= MSHV_MAX_VPS) 926*621191d7SNuno Das Neves return -EINVAL; 927*621191d7SNuno Das Neves 928*621191d7SNuno Das Neves if (partition->pt_vp_array[args.vp_index]) 929*621191d7SNuno Das Neves return -EEXIST; 930*621191d7SNuno Das Neves 931*621191d7SNuno Das Neves ret = hv_call_create_vp(NUMA_NO_NODE, partition->pt_id, args.vp_index, 932*621191d7SNuno Das Neves 0 /* Only valid for root partition VPs */); 933*621191d7SNuno Das Neves if (ret) 934*621191d7SNuno Das Neves return ret; 935*621191d7SNuno Das Neves 936*621191d7SNuno Das Neves ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index, 937*621191d7SNuno Das Neves HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, 938*621191d7SNuno Das Neves input_vtl_zero, 939*621191d7SNuno Das Neves &intercept_message_page); 940*621191d7SNuno Das Neves if (ret) 941*621191d7SNuno Das Neves goto destroy_vp; 942*621191d7SNuno Das Neves 943*621191d7SNuno Das Neves if (!mshv_partition_encrypted(partition)) { 944*621191d7SNuno Das Neves ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index, 945*621191d7SNuno Das Neves HV_VP_STATE_PAGE_REGISTERS, 946*621191d7SNuno Das Neves input_vtl_zero, 947*621191d7SNuno Das Neves ®ister_page); 948*621191d7SNuno Das Neves if (ret) 949*621191d7SNuno Das Neves goto unmap_intercept_message_page; 950*621191d7SNuno Das Neves } 951*621191d7SNuno Das Neves 952*621191d7SNuno Das Neves if (mshv_partition_encrypted(partition) && 953*621191d7SNuno Das Neves is_ghcb_mapping_available()) { 954*621191d7SNuno Das Neves ret = hv_call_map_vp_state_page(partition->pt_id, args.vp_index, 955*621191d7SNuno Das Neves HV_VP_STATE_PAGE_GHCB, 956*621191d7SNuno Das Neves input_vtl_normal, 957*621191d7SNuno Das Neves &ghcb_page); 958*621191d7SNuno Das Neves if (ret) 959*621191d7SNuno Das Neves goto unmap_register_page; 960*621191d7SNuno Das Neves } 961*621191d7SNuno Das Neves 962*621191d7SNuno Das Neves if (hv_parent_partition()) { 963*621191d7SNuno Das Neves ret = mshv_vp_stats_map(partition->pt_id, args.vp_index, 964*621191d7SNuno Das Neves stats_pages); 965*621191d7SNuno Das Neves if (ret) 966*621191d7SNuno Das Neves goto unmap_ghcb_page; 967*621191d7SNuno Das Neves } 968*621191d7SNuno Das Neves 969*621191d7SNuno Das Neves vp = kzalloc(sizeof(*vp), GFP_KERNEL); 970*621191d7SNuno Das Neves if (!vp) 971*621191d7SNuno Das Neves goto unmap_stats_pages; 972*621191d7SNuno Das Neves 973*621191d7SNuno Das Neves vp->vp_partition = mshv_partition_get(partition); 974*621191d7SNuno Das Neves if (!vp->vp_partition) { 975*621191d7SNuno Das Neves ret = -EBADF; 976*621191d7SNuno Das Neves goto free_vp; 977*621191d7SNuno Das Neves } 978*621191d7SNuno Das Neves 979*621191d7SNuno Das Neves mutex_init(&vp->vp_mutex); 980*621191d7SNuno Das Neves init_waitqueue_head(&vp->run.vp_suspend_queue); 981*621191d7SNuno Das Neves atomic64_set(&vp->run.vp_signaled_count, 0); 982*621191d7SNuno Das Neves 983*621191d7SNuno Das Neves vp->vp_index = args.vp_index; 984*621191d7SNuno Das Neves vp->vp_intercept_msg_page = page_to_virt(intercept_message_page); 985*621191d7SNuno Das Neves if (!mshv_partition_encrypted(partition)) 986*621191d7SNuno Das Neves vp->vp_register_page = page_to_virt(register_page); 987*621191d7SNuno Das Neves 988*621191d7SNuno Das Neves if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) 989*621191d7SNuno Das Neves vp->vp_ghcb_page = page_to_virt(ghcb_page); 990*621191d7SNuno Das Neves 991*621191d7SNuno Das Neves if (hv_parent_partition()) 992*621191d7SNuno Das Neves memcpy(vp->vp_stats_pages, stats_pages, sizeof(stats_pages)); 993*621191d7SNuno Das Neves 994*621191d7SNuno Das Neves /* 995*621191d7SNuno Das Neves * Keep anon_inode_getfd last: it installs fd in the file struct and 996*621191d7SNuno Das Neves * thus makes the state accessible in user space. 997*621191d7SNuno Das Neves */ 998*621191d7SNuno Das Neves ret = anon_inode_getfd("mshv_vp", &mshv_vp_fops, vp, 999*621191d7SNuno Das Neves O_RDWR | O_CLOEXEC); 1000*621191d7SNuno Das Neves if (ret < 0) 1001*621191d7SNuno Das Neves goto put_partition; 1002*621191d7SNuno Das Neves 1003*621191d7SNuno Das Neves /* already exclusive with the partition mutex for all ioctls */ 1004*621191d7SNuno Das Neves partition->pt_vp_count++; 1005*621191d7SNuno Das Neves partition->pt_vp_array[args.vp_index] = vp; 1006*621191d7SNuno Das Neves 1007*621191d7SNuno Das Neves return ret; 1008*621191d7SNuno Das Neves 1009*621191d7SNuno Das Neves put_partition: 1010*621191d7SNuno Das Neves mshv_partition_put(partition); 1011*621191d7SNuno Das Neves free_vp: 1012*621191d7SNuno Das Neves kfree(vp); 1013*621191d7SNuno Das Neves unmap_stats_pages: 1014*621191d7SNuno Das Neves if (hv_parent_partition()) 1015*621191d7SNuno Das Neves mshv_vp_stats_unmap(partition->pt_id, args.vp_index); 1016*621191d7SNuno Das Neves unmap_ghcb_page: 1017*621191d7SNuno Das Neves if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) { 1018*621191d7SNuno Das Neves hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index, 1019*621191d7SNuno Das Neves HV_VP_STATE_PAGE_GHCB, 1020*621191d7SNuno Das Neves input_vtl_normal); 1021*621191d7SNuno Das Neves } 1022*621191d7SNuno Das Neves unmap_register_page: 1023*621191d7SNuno Das Neves if (!mshv_partition_encrypted(partition)) { 1024*621191d7SNuno Das Neves hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index, 1025*621191d7SNuno Das Neves HV_VP_STATE_PAGE_REGISTERS, 1026*621191d7SNuno Das Neves input_vtl_zero); 1027*621191d7SNuno Das Neves } 1028*621191d7SNuno Das Neves unmap_intercept_message_page: 1029*621191d7SNuno Das Neves hv_call_unmap_vp_state_page(partition->pt_id, args.vp_index, 1030*621191d7SNuno Das Neves HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, 1031*621191d7SNuno Das Neves input_vtl_zero); 1032*621191d7SNuno Das Neves destroy_vp: 1033*621191d7SNuno Das Neves hv_call_delete_vp(partition->pt_id, args.vp_index); 1034*621191d7SNuno Das Neves return ret; 1035*621191d7SNuno Das Neves } 1036*621191d7SNuno Das Neves 1037*621191d7SNuno Das Neves static int mshv_init_async_handler(struct mshv_partition *partition) 1038*621191d7SNuno Das Neves { 1039*621191d7SNuno Das Neves if (completion_done(&partition->async_hypercall)) { 1040*621191d7SNuno Das Neves pt_err(partition, 1041*621191d7SNuno Das Neves "Cannot issue async hypercall while another one in progress!\n"); 1042*621191d7SNuno Das Neves return -EPERM; 1043*621191d7SNuno Das Neves } 1044*621191d7SNuno Das Neves 1045*621191d7SNuno Das Neves reinit_completion(&partition->async_hypercall); 1046*621191d7SNuno Das Neves return 0; 1047*621191d7SNuno Das Neves } 1048*621191d7SNuno Das Neves 1049*621191d7SNuno Das Neves static void mshv_async_hvcall_handler(void *data, u64 *status) 1050*621191d7SNuno Das Neves { 1051*621191d7SNuno Das Neves struct mshv_partition *partition = data; 1052*621191d7SNuno Das Neves 1053*621191d7SNuno Das Neves wait_for_completion(&partition->async_hypercall); 1054*621191d7SNuno Das Neves pt_dbg(partition, "Async hypercall completed!\n"); 1055*621191d7SNuno Das Neves 1056*621191d7SNuno Das Neves *status = partition->async_hypercall_status; 1057*621191d7SNuno Das Neves } 1058*621191d7SNuno Das Neves 1059*621191d7SNuno Das Neves static int 1060*621191d7SNuno Das Neves mshv_partition_region_share(struct mshv_mem_region *region) 1061*621191d7SNuno Das Neves { 1062*621191d7SNuno Das Neves u32 flags = HV_MODIFY_SPA_PAGE_HOST_ACCESS_MAKE_SHARED; 1063*621191d7SNuno Das Neves 1064*621191d7SNuno Das Neves if (region->flags.large_pages) 1065*621191d7SNuno Das Neves flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; 1066*621191d7SNuno Das Neves 1067*621191d7SNuno Das Neves return hv_call_modify_spa_host_access(region->partition->pt_id, 1068*621191d7SNuno Das Neves region->pages, region->nr_pages, 1069*621191d7SNuno Das Neves HV_MAP_GPA_READABLE | HV_MAP_GPA_WRITABLE, 1070*621191d7SNuno Das Neves flags, true); 1071*621191d7SNuno Das Neves } 1072*621191d7SNuno Das Neves 1073*621191d7SNuno Das Neves static int 1074*621191d7SNuno Das Neves mshv_partition_region_unshare(struct mshv_mem_region *region) 1075*621191d7SNuno Das Neves { 1076*621191d7SNuno Das Neves u32 flags = HV_MODIFY_SPA_PAGE_HOST_ACCESS_MAKE_EXCLUSIVE; 1077*621191d7SNuno Das Neves 1078*621191d7SNuno Das Neves if (region->flags.large_pages) 1079*621191d7SNuno Das Neves flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; 1080*621191d7SNuno Das Neves 1081*621191d7SNuno Das Neves return hv_call_modify_spa_host_access(region->partition->pt_id, 1082*621191d7SNuno Das Neves region->pages, region->nr_pages, 1083*621191d7SNuno Das Neves 0, 1084*621191d7SNuno Das Neves flags, false); 1085*621191d7SNuno Das Neves } 1086*621191d7SNuno Das Neves 1087*621191d7SNuno Das Neves static int 1088*621191d7SNuno Das Neves mshv_region_remap_pages(struct mshv_mem_region *region, u32 map_flags, 1089*621191d7SNuno Das Neves u64 page_offset, u64 page_count) 1090*621191d7SNuno Das Neves { 1091*621191d7SNuno Das Neves if (page_offset + page_count > region->nr_pages) 1092*621191d7SNuno Das Neves return -EINVAL; 1093*621191d7SNuno Das Neves 1094*621191d7SNuno Das Neves if (region->flags.large_pages) 1095*621191d7SNuno Das Neves map_flags |= HV_MAP_GPA_LARGE_PAGE; 1096*621191d7SNuno Das Neves 1097*621191d7SNuno Das Neves /* ask the hypervisor to map guest ram */ 1098*621191d7SNuno Das Neves return hv_call_map_gpa_pages(region->partition->pt_id, 1099*621191d7SNuno Das Neves region->start_gfn + page_offset, 1100*621191d7SNuno Das Neves page_count, map_flags, 1101*621191d7SNuno Das Neves region->pages + page_offset); 1102*621191d7SNuno Das Neves } 1103*621191d7SNuno Das Neves 1104*621191d7SNuno Das Neves static int 1105*621191d7SNuno Das Neves mshv_region_map(struct mshv_mem_region *region) 1106*621191d7SNuno Das Neves { 1107*621191d7SNuno Das Neves u32 map_flags = region->hv_map_flags; 1108*621191d7SNuno Das Neves 1109*621191d7SNuno Das Neves return mshv_region_remap_pages(region, map_flags, 1110*621191d7SNuno Das Neves 0, region->nr_pages); 1111*621191d7SNuno Das Neves } 1112*621191d7SNuno Das Neves 1113*621191d7SNuno Das Neves static void 1114*621191d7SNuno Das Neves mshv_region_evict_pages(struct mshv_mem_region *region, 1115*621191d7SNuno Das Neves u64 page_offset, u64 page_count) 1116*621191d7SNuno Das Neves { 1117*621191d7SNuno Das Neves if (region->flags.range_pinned) 1118*621191d7SNuno Das Neves unpin_user_pages(region->pages + page_offset, page_count); 1119*621191d7SNuno Das Neves 1120*621191d7SNuno Das Neves memset(region->pages + page_offset, 0, 1121*621191d7SNuno Das Neves page_count * sizeof(struct page *)); 1122*621191d7SNuno Das Neves } 1123*621191d7SNuno Das Neves 1124*621191d7SNuno Das Neves static void 1125*621191d7SNuno Das Neves mshv_region_evict(struct mshv_mem_region *region) 1126*621191d7SNuno Das Neves { 1127*621191d7SNuno Das Neves mshv_region_evict_pages(region, 0, region->nr_pages); 1128*621191d7SNuno Das Neves } 1129*621191d7SNuno Das Neves 1130*621191d7SNuno Das Neves static int 1131*621191d7SNuno Das Neves mshv_region_populate_pages(struct mshv_mem_region *region, 1132*621191d7SNuno Das Neves u64 page_offset, u64 page_count) 1133*621191d7SNuno Das Neves { 1134*621191d7SNuno Das Neves u64 done_count, nr_pages; 1135*621191d7SNuno Das Neves struct page **pages; 1136*621191d7SNuno Das Neves __u64 userspace_addr; 1137*621191d7SNuno Das Neves int ret; 1138*621191d7SNuno Das Neves 1139*621191d7SNuno Das Neves if (page_offset + page_count > region->nr_pages) 1140*621191d7SNuno Das Neves return -EINVAL; 1141*621191d7SNuno Das Neves 1142*621191d7SNuno Das Neves for (done_count = 0; done_count < page_count; done_count += ret) { 1143*621191d7SNuno Das Neves pages = region->pages + page_offset + done_count; 1144*621191d7SNuno Das Neves userspace_addr = region->start_uaddr + 1145*621191d7SNuno Das Neves (page_offset + done_count) * 1146*621191d7SNuno Das Neves HV_HYP_PAGE_SIZE; 1147*621191d7SNuno Das Neves nr_pages = min(page_count - done_count, 1148*621191d7SNuno Das Neves MSHV_PIN_PAGES_BATCH_SIZE); 1149*621191d7SNuno Das Neves 1150*621191d7SNuno Das Neves /* 1151*621191d7SNuno Das Neves * Pinning assuming 4k pages works for large pages too. 1152*621191d7SNuno Das Neves * All page structs within the large page are returned. 1153*621191d7SNuno Das Neves * 1154*621191d7SNuno Das Neves * Pin requests are batched because pin_user_pages_fast 1155*621191d7SNuno Das Neves * with the FOLL_LONGTERM flag does a large temporary 1156*621191d7SNuno Das Neves * allocation of contiguous memory. 1157*621191d7SNuno Das Neves */ 1158*621191d7SNuno Das Neves if (region->flags.range_pinned) 1159*621191d7SNuno Das Neves ret = pin_user_pages_fast(userspace_addr, 1160*621191d7SNuno Das Neves nr_pages, 1161*621191d7SNuno Das Neves FOLL_WRITE | FOLL_LONGTERM, 1162*621191d7SNuno Das Neves pages); 1163*621191d7SNuno Das Neves else 1164*621191d7SNuno Das Neves ret = -EOPNOTSUPP; 1165*621191d7SNuno Das Neves 1166*621191d7SNuno Das Neves if (ret < 0) 1167*621191d7SNuno Das Neves goto release_pages; 1168*621191d7SNuno Das Neves } 1169*621191d7SNuno Das Neves 1170*621191d7SNuno Das Neves if (PageHuge(region->pages[page_offset])) 1171*621191d7SNuno Das Neves region->flags.large_pages = true; 1172*621191d7SNuno Das Neves 1173*621191d7SNuno Das Neves return 0; 1174*621191d7SNuno Das Neves 1175*621191d7SNuno Das Neves release_pages: 1176*621191d7SNuno Das Neves mshv_region_evict_pages(region, page_offset, done_count); 1177*621191d7SNuno Das Neves return ret; 1178*621191d7SNuno Das Neves } 1179*621191d7SNuno Das Neves 1180*621191d7SNuno Das Neves static int 1181*621191d7SNuno Das Neves mshv_region_populate(struct mshv_mem_region *region) 1182*621191d7SNuno Das Neves { 1183*621191d7SNuno Das Neves return mshv_region_populate_pages(region, 0, region->nr_pages); 1184*621191d7SNuno Das Neves } 1185*621191d7SNuno Das Neves 1186*621191d7SNuno Das Neves static struct mshv_mem_region * 1187*621191d7SNuno Das Neves mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn) 1188*621191d7SNuno Das Neves { 1189*621191d7SNuno Das Neves struct mshv_mem_region *region; 1190*621191d7SNuno Das Neves 1191*621191d7SNuno Das Neves hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) { 1192*621191d7SNuno Das Neves if (gfn >= region->start_gfn && 1193*621191d7SNuno Das Neves gfn < region->start_gfn + region->nr_pages) 1194*621191d7SNuno Das Neves return region; 1195*621191d7SNuno Das Neves } 1196*621191d7SNuno Das Neves 1197*621191d7SNuno Das Neves return NULL; 1198*621191d7SNuno Das Neves } 1199*621191d7SNuno Das Neves 1200*621191d7SNuno Das Neves static struct mshv_mem_region * 1201*621191d7SNuno Das Neves mshv_partition_region_by_uaddr(struct mshv_partition *partition, u64 uaddr) 1202*621191d7SNuno Das Neves { 1203*621191d7SNuno Das Neves struct mshv_mem_region *region; 1204*621191d7SNuno Das Neves 1205*621191d7SNuno Das Neves hlist_for_each_entry(region, &partition->pt_mem_regions, hnode) { 1206*621191d7SNuno Das Neves if (uaddr >= region->start_uaddr && 1207*621191d7SNuno Das Neves uaddr < region->start_uaddr + 1208*621191d7SNuno Das Neves (region->nr_pages << HV_HYP_PAGE_SHIFT)) 1209*621191d7SNuno Das Neves return region; 1210*621191d7SNuno Das Neves } 1211*621191d7SNuno Das Neves 1212*621191d7SNuno Das Neves return NULL; 1213*621191d7SNuno Das Neves } 1214*621191d7SNuno Das Neves 1215*621191d7SNuno Das Neves /* 1216*621191d7SNuno Das Neves * NB: caller checks and makes sure mem->size is page aligned 1217*621191d7SNuno Das Neves * Returns: 0 with regionpp updated on success, or -errno 1218*621191d7SNuno Das Neves */ 1219*621191d7SNuno Das Neves static int mshv_partition_create_region(struct mshv_partition *partition, 1220*621191d7SNuno Das Neves struct mshv_user_mem_region *mem, 1221*621191d7SNuno Das Neves struct mshv_mem_region **regionpp, 1222*621191d7SNuno Das Neves bool is_mmio) 1223*621191d7SNuno Das Neves { 1224*621191d7SNuno Das Neves struct mshv_mem_region *region; 1225*621191d7SNuno Das Neves u64 nr_pages = HVPFN_DOWN(mem->size); 1226*621191d7SNuno Das Neves 1227*621191d7SNuno Das Neves /* Reject overlapping regions */ 1228*621191d7SNuno Das Neves if (mshv_partition_region_by_gfn(partition, mem->guest_pfn) || 1229*621191d7SNuno Das Neves mshv_partition_region_by_gfn(partition, mem->guest_pfn + nr_pages - 1) || 1230*621191d7SNuno Das Neves mshv_partition_region_by_uaddr(partition, mem->userspace_addr) || 1231*621191d7SNuno Das Neves mshv_partition_region_by_uaddr(partition, mem->userspace_addr + mem->size - 1)) 1232*621191d7SNuno Das Neves return -EEXIST; 1233*621191d7SNuno Das Neves 1234*621191d7SNuno Das Neves region = vzalloc(sizeof(*region) + sizeof(struct page *) * nr_pages); 1235*621191d7SNuno Das Neves if (!region) 1236*621191d7SNuno Das Neves return -ENOMEM; 1237*621191d7SNuno Das Neves 1238*621191d7SNuno Das Neves region->nr_pages = nr_pages; 1239*621191d7SNuno Das Neves region->start_gfn = mem->guest_pfn; 1240*621191d7SNuno Das Neves region->start_uaddr = mem->userspace_addr; 1241*621191d7SNuno Das Neves region->hv_map_flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_ADJUSTABLE; 1242*621191d7SNuno Das Neves if (mem->flags & BIT(MSHV_SET_MEM_BIT_WRITABLE)) 1243*621191d7SNuno Das Neves region->hv_map_flags |= HV_MAP_GPA_WRITABLE; 1244*621191d7SNuno Das Neves if (mem->flags & BIT(MSHV_SET_MEM_BIT_EXECUTABLE)) 1245*621191d7SNuno Das Neves region->hv_map_flags |= HV_MAP_GPA_EXECUTABLE; 1246*621191d7SNuno Das Neves 1247*621191d7SNuno Das Neves /* Note: large_pages flag populated when we pin the pages */ 1248*621191d7SNuno Das Neves if (!is_mmio) 1249*621191d7SNuno Das Neves region->flags.range_pinned = true; 1250*621191d7SNuno Das Neves 1251*621191d7SNuno Das Neves region->partition = partition; 1252*621191d7SNuno Das Neves 1253*621191d7SNuno Das Neves *regionpp = region; 1254*621191d7SNuno Das Neves 1255*621191d7SNuno Das Neves return 0; 1256*621191d7SNuno Das Neves } 1257*621191d7SNuno Das Neves 1258*621191d7SNuno Das Neves /* 1259*621191d7SNuno Das Neves * Map guest ram. if snp, make sure to release that from the host first 1260*621191d7SNuno Das Neves * Side Effects: In case of failure, pages are unpinned when feasible. 1261*621191d7SNuno Das Neves */ 1262*621191d7SNuno Das Neves static int 1263*621191d7SNuno Das Neves mshv_partition_mem_region_map(struct mshv_mem_region *region) 1264*621191d7SNuno Das Neves { 1265*621191d7SNuno Das Neves struct mshv_partition *partition = region->partition; 1266*621191d7SNuno Das Neves int ret; 1267*621191d7SNuno Das Neves 1268*621191d7SNuno Das Neves ret = mshv_region_populate(region); 1269*621191d7SNuno Das Neves if (ret) { 1270*621191d7SNuno Das Neves pt_err(partition, "Failed to populate memory region: %d\n", 1271*621191d7SNuno Das Neves ret); 1272*621191d7SNuno Das Neves goto err_out; 1273*621191d7SNuno Das Neves } 1274*621191d7SNuno Das Neves 1275*621191d7SNuno Das Neves /* 1276*621191d7SNuno Das Neves * For an SNP partition it is a requirement that for every memory region 1277*621191d7SNuno Das Neves * that we are going to map for this partition we should make sure that 1278*621191d7SNuno Das Neves * host access to that region is released. This is ensured by doing an 1279*621191d7SNuno Das Neves * additional hypercall which will update the SLAT to release host 1280*621191d7SNuno Das Neves * access to guest memory regions. 1281*621191d7SNuno Das Neves */ 1282*621191d7SNuno Das Neves if (mshv_partition_encrypted(partition)) { 1283*621191d7SNuno Das Neves ret = mshv_partition_region_unshare(region); 1284*621191d7SNuno Das Neves if (ret) { 1285*621191d7SNuno Das Neves pt_err(partition, 1286*621191d7SNuno Das Neves "Failed to unshare memory region (guest_pfn: %llu): %d\n", 1287*621191d7SNuno Das Neves region->start_gfn, ret); 1288*621191d7SNuno Das Neves goto evict_region; 1289*621191d7SNuno Das Neves } 1290*621191d7SNuno Das Neves } 1291*621191d7SNuno Das Neves 1292*621191d7SNuno Das Neves ret = mshv_region_map(region); 1293*621191d7SNuno Das Neves if (ret && mshv_partition_encrypted(partition)) { 1294*621191d7SNuno Das Neves int shrc; 1295*621191d7SNuno Das Neves 1296*621191d7SNuno Das Neves shrc = mshv_partition_region_share(region); 1297*621191d7SNuno Das Neves if (!shrc) 1298*621191d7SNuno Das Neves goto evict_region; 1299*621191d7SNuno Das Neves 1300*621191d7SNuno Das Neves pt_err(partition, 1301*621191d7SNuno Das Neves "Failed to share memory region (guest_pfn: %llu): %d\n", 1302*621191d7SNuno Das Neves region->start_gfn, shrc); 1303*621191d7SNuno Das Neves /* 1304*621191d7SNuno Das Neves * Don't unpin if marking shared failed because pages are no 1305*621191d7SNuno Das Neves * longer mapped in the host, ie root, anymore. 1306*621191d7SNuno Das Neves */ 1307*621191d7SNuno Das Neves goto err_out; 1308*621191d7SNuno Das Neves } 1309*621191d7SNuno Das Neves 1310*621191d7SNuno Das Neves return 0; 1311*621191d7SNuno Das Neves 1312*621191d7SNuno Das Neves evict_region: 1313*621191d7SNuno Das Neves mshv_region_evict(region); 1314*621191d7SNuno Das Neves err_out: 1315*621191d7SNuno Das Neves return ret; 1316*621191d7SNuno Das Neves } 1317*621191d7SNuno Das Neves 1318*621191d7SNuno Das Neves /* 1319*621191d7SNuno Das Neves * This maps two things: guest RAM and for pci passthru mmio space. 1320*621191d7SNuno Das Neves * 1321*621191d7SNuno Das Neves * mmio: 1322*621191d7SNuno Das Neves * - vfio overloads vm_pgoff to store the mmio start pfn/spa. 1323*621191d7SNuno Das Neves * - Two things need to happen for mapping mmio range: 1324*621191d7SNuno Das Neves * 1. mapped in the uaddr so VMM can access it. 1325*621191d7SNuno Das Neves * 2. mapped in the hwpt (gfn <-> mmio phys addr) so guest can access it. 1326*621191d7SNuno Das Neves * 1327*621191d7SNuno Das Neves * This function takes care of the second. The first one is managed by vfio, 1328*621191d7SNuno Das Neves * and hence is taken care of via vfio_pci_mmap_fault(). 1329*621191d7SNuno Das Neves */ 1330*621191d7SNuno Das Neves static long 1331*621191d7SNuno Das Neves mshv_map_user_memory(struct mshv_partition *partition, 1332*621191d7SNuno Das Neves struct mshv_user_mem_region mem) 1333*621191d7SNuno Das Neves { 1334*621191d7SNuno Das Neves struct mshv_mem_region *region; 1335*621191d7SNuno Das Neves struct vm_area_struct *vma; 1336*621191d7SNuno Das Neves bool is_mmio; 1337*621191d7SNuno Das Neves ulong mmio_pfn; 1338*621191d7SNuno Das Neves long ret; 1339*621191d7SNuno Das Neves 1340*621191d7SNuno Das Neves if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) || 1341*621191d7SNuno Das Neves !access_ok((const void *)mem.userspace_addr, mem.size)) 1342*621191d7SNuno Das Neves return -EINVAL; 1343*621191d7SNuno Das Neves 1344*621191d7SNuno Das Neves mmap_read_lock(current->mm); 1345*621191d7SNuno Das Neves vma = vma_lookup(current->mm, mem.userspace_addr); 1346*621191d7SNuno Das Neves is_mmio = vma ? !!(vma->vm_flags & (VM_IO | VM_PFNMAP)) : 0; 1347*621191d7SNuno Das Neves mmio_pfn = is_mmio ? vma->vm_pgoff : 0; 1348*621191d7SNuno Das Neves mmap_read_unlock(current->mm); 1349*621191d7SNuno Das Neves 1350*621191d7SNuno Das Neves if (!vma) 1351*621191d7SNuno Das Neves return -EINVAL; 1352*621191d7SNuno Das Neves 1353*621191d7SNuno Das Neves ret = mshv_partition_create_region(partition, &mem, ®ion, 1354*621191d7SNuno Das Neves is_mmio); 1355*621191d7SNuno Das Neves if (ret) 1356*621191d7SNuno Das Neves return ret; 1357*621191d7SNuno Das Neves 1358*621191d7SNuno Das Neves if (is_mmio) 1359*621191d7SNuno Das Neves ret = hv_call_map_mmio_pages(partition->pt_id, mem.guest_pfn, 1360*621191d7SNuno Das Neves mmio_pfn, HVPFN_DOWN(mem.size)); 1361*621191d7SNuno Das Neves else 1362*621191d7SNuno Das Neves ret = mshv_partition_mem_region_map(region); 1363*621191d7SNuno Das Neves 1364*621191d7SNuno Das Neves if (ret) 1365*621191d7SNuno Das Neves goto errout; 1366*621191d7SNuno Das Neves 1367*621191d7SNuno Das Neves /* Install the new region */ 1368*621191d7SNuno Das Neves hlist_add_head(®ion->hnode, &partition->pt_mem_regions); 1369*621191d7SNuno Das Neves 1370*621191d7SNuno Das Neves return 0; 1371*621191d7SNuno Das Neves 1372*621191d7SNuno Das Neves errout: 1373*621191d7SNuno Das Neves vfree(region); 1374*621191d7SNuno Das Neves return ret; 1375*621191d7SNuno Das Neves } 1376*621191d7SNuno Das Neves 1377*621191d7SNuno Das Neves /* Called for unmapping both the guest ram and the mmio space */ 1378*621191d7SNuno Das Neves static long 1379*621191d7SNuno Das Neves mshv_unmap_user_memory(struct mshv_partition *partition, 1380*621191d7SNuno Das Neves struct mshv_user_mem_region mem) 1381*621191d7SNuno Das Neves { 1382*621191d7SNuno Das Neves struct mshv_mem_region *region; 1383*621191d7SNuno Das Neves u32 unmap_flags = 0; 1384*621191d7SNuno Das Neves 1385*621191d7SNuno Das Neves if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP))) 1386*621191d7SNuno Das Neves return -EINVAL; 1387*621191d7SNuno Das Neves 1388*621191d7SNuno Das Neves region = mshv_partition_region_by_gfn(partition, mem.guest_pfn); 1389*621191d7SNuno Das Neves if (!region) 1390*621191d7SNuno Das Neves return -EINVAL; 1391*621191d7SNuno Das Neves 1392*621191d7SNuno Das Neves /* Paranoia check */ 1393*621191d7SNuno Das Neves if (region->start_uaddr != mem.userspace_addr || 1394*621191d7SNuno Das Neves region->start_gfn != mem.guest_pfn || 1395*621191d7SNuno Das Neves region->nr_pages != HVPFN_DOWN(mem.size)) 1396*621191d7SNuno Das Neves return -EINVAL; 1397*621191d7SNuno Das Neves 1398*621191d7SNuno Das Neves hlist_del(®ion->hnode); 1399*621191d7SNuno Das Neves 1400*621191d7SNuno Das Neves if (region->flags.large_pages) 1401*621191d7SNuno Das Neves unmap_flags |= HV_UNMAP_GPA_LARGE_PAGE; 1402*621191d7SNuno Das Neves 1403*621191d7SNuno Das Neves /* ignore unmap failures and continue as process may be exiting */ 1404*621191d7SNuno Das Neves hv_call_unmap_gpa_pages(partition->pt_id, region->start_gfn, 1405*621191d7SNuno Das Neves region->nr_pages, unmap_flags); 1406*621191d7SNuno Das Neves 1407*621191d7SNuno Das Neves mshv_region_evict(region); 1408*621191d7SNuno Das Neves 1409*621191d7SNuno Das Neves vfree(region); 1410*621191d7SNuno Das Neves return 0; 1411*621191d7SNuno Das Neves } 1412*621191d7SNuno Das Neves 1413*621191d7SNuno Das Neves static long 1414*621191d7SNuno Das Neves mshv_partition_ioctl_set_memory(struct mshv_partition *partition, 1415*621191d7SNuno Das Neves struct mshv_user_mem_region __user *user_mem) 1416*621191d7SNuno Das Neves { 1417*621191d7SNuno Das Neves struct mshv_user_mem_region mem; 1418*621191d7SNuno Das Neves 1419*621191d7SNuno Das Neves if (copy_from_user(&mem, user_mem, sizeof(mem))) 1420*621191d7SNuno Das Neves return -EFAULT; 1421*621191d7SNuno Das Neves 1422*621191d7SNuno Das Neves if (!mem.size || 1423*621191d7SNuno Das Neves !PAGE_ALIGNED(mem.size) || 1424*621191d7SNuno Das Neves !PAGE_ALIGNED(mem.userspace_addr) || 1425*621191d7SNuno Das Neves (mem.flags & ~MSHV_SET_MEM_FLAGS_MASK) || 1426*621191d7SNuno Das Neves mshv_field_nonzero(mem, rsvd)) 1427*621191d7SNuno Das Neves return -EINVAL; 1428*621191d7SNuno Das Neves 1429*621191d7SNuno Das Neves if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP)) 1430*621191d7SNuno Das Neves return mshv_unmap_user_memory(partition, mem); 1431*621191d7SNuno Das Neves 1432*621191d7SNuno Das Neves return mshv_map_user_memory(partition, mem); 1433*621191d7SNuno Das Neves } 1434*621191d7SNuno Das Neves 1435*621191d7SNuno Das Neves static long 1436*621191d7SNuno Das Neves mshv_partition_ioctl_ioeventfd(struct mshv_partition *partition, 1437*621191d7SNuno Das Neves void __user *user_args) 1438*621191d7SNuno Das Neves { 1439*621191d7SNuno Das Neves struct mshv_user_ioeventfd args; 1440*621191d7SNuno Das Neves 1441*621191d7SNuno Das Neves if (copy_from_user(&args, user_args, sizeof(args))) 1442*621191d7SNuno Das Neves return -EFAULT; 1443*621191d7SNuno Das Neves 1444*621191d7SNuno Das Neves return mshv_set_unset_ioeventfd(partition, &args); 1445*621191d7SNuno Das Neves } 1446*621191d7SNuno Das Neves 1447*621191d7SNuno Das Neves static long 1448*621191d7SNuno Das Neves mshv_partition_ioctl_irqfd(struct mshv_partition *partition, 1449*621191d7SNuno Das Neves void __user *user_args) 1450*621191d7SNuno Das Neves { 1451*621191d7SNuno Das Neves struct mshv_user_irqfd args; 1452*621191d7SNuno Das Neves 1453*621191d7SNuno Das Neves if (copy_from_user(&args, user_args, sizeof(args))) 1454*621191d7SNuno Das Neves return -EFAULT; 1455*621191d7SNuno Das Neves 1456*621191d7SNuno Das Neves return mshv_set_unset_irqfd(partition, &args); 1457*621191d7SNuno Das Neves } 1458*621191d7SNuno Das Neves 1459*621191d7SNuno Das Neves static long 1460*621191d7SNuno Das Neves mshv_partition_ioctl_get_gpap_access_bitmap(struct mshv_partition *partition, 1461*621191d7SNuno Das Neves void __user *user_args) 1462*621191d7SNuno Das Neves { 1463*621191d7SNuno Das Neves struct mshv_gpap_access_bitmap args; 1464*621191d7SNuno Das Neves union hv_gpa_page_access_state *states; 1465*621191d7SNuno Das Neves long ret, i; 1466*621191d7SNuno Das Neves union hv_gpa_page_access_state_flags hv_flags = {}; 1467*621191d7SNuno Das Neves u8 hv_type_mask; 1468*621191d7SNuno Das Neves ulong bitmap_buf_sz, states_buf_sz; 1469*621191d7SNuno Das Neves int written = 0; 1470*621191d7SNuno Das Neves 1471*621191d7SNuno Das Neves if (copy_from_user(&args, user_args, sizeof(args))) 1472*621191d7SNuno Das Neves return -EFAULT; 1473*621191d7SNuno Das Neves 1474*621191d7SNuno Das Neves if (args.access_type >= MSHV_GPAP_ACCESS_TYPE_COUNT || 1475*621191d7SNuno Das Neves args.access_op >= MSHV_GPAP_ACCESS_OP_COUNT || 1476*621191d7SNuno Das Neves mshv_field_nonzero(args, rsvd) || !args.page_count || 1477*621191d7SNuno Das Neves !args.bitmap_ptr) 1478*621191d7SNuno Das Neves return -EINVAL; 1479*621191d7SNuno Das Neves 1480*621191d7SNuno Das Neves if (check_mul_overflow(args.page_count, sizeof(*states), &states_buf_sz)) 1481*621191d7SNuno Das Neves return -E2BIG; 1482*621191d7SNuno Das Neves 1483*621191d7SNuno Das Neves /* Num bytes needed to store bitmap; one bit per page rounded up */ 1484*621191d7SNuno Das Neves bitmap_buf_sz = DIV_ROUND_UP(args.page_count, 8); 1485*621191d7SNuno Das Neves 1486*621191d7SNuno Das Neves /* Sanity check */ 1487*621191d7SNuno Das Neves if (bitmap_buf_sz > states_buf_sz) 1488*621191d7SNuno Das Neves return -EBADFD; 1489*621191d7SNuno Das Neves 1490*621191d7SNuno Das Neves switch (args.access_type) { 1491*621191d7SNuno Das Neves case MSHV_GPAP_ACCESS_TYPE_ACCESSED: 1492*621191d7SNuno Das Neves hv_type_mask = 1; 1493*621191d7SNuno Das Neves if (args.access_op == MSHV_GPAP_ACCESS_OP_CLEAR) { 1494*621191d7SNuno Das Neves hv_flags.clear_accessed = 1; 1495*621191d7SNuno Das Neves /* not accessed implies not dirty */ 1496*621191d7SNuno Das Neves hv_flags.clear_dirty = 1; 1497*621191d7SNuno Das Neves } else { /* MSHV_GPAP_ACCESS_OP_SET */ 1498*621191d7SNuno Das Neves hv_flags.set_accessed = 1; 1499*621191d7SNuno Das Neves } 1500*621191d7SNuno Das Neves break; 1501*621191d7SNuno Das Neves case MSHV_GPAP_ACCESS_TYPE_DIRTY: 1502*621191d7SNuno Das Neves hv_type_mask = 2; 1503*621191d7SNuno Das Neves if (args.access_op == MSHV_GPAP_ACCESS_OP_CLEAR) { 1504*621191d7SNuno Das Neves hv_flags.clear_dirty = 1; 1505*621191d7SNuno Das Neves } else { /* MSHV_GPAP_ACCESS_OP_SET */ 1506*621191d7SNuno Das Neves hv_flags.set_dirty = 1; 1507*621191d7SNuno Das Neves /* dirty implies accessed */ 1508*621191d7SNuno Das Neves hv_flags.set_accessed = 1; 1509*621191d7SNuno Das Neves } 1510*621191d7SNuno Das Neves break; 1511*621191d7SNuno Das Neves } 1512*621191d7SNuno Das Neves 1513*621191d7SNuno Das Neves states = vzalloc(states_buf_sz); 1514*621191d7SNuno Das Neves if (!states) 1515*621191d7SNuno Das Neves return -ENOMEM; 1516*621191d7SNuno Das Neves 1517*621191d7SNuno Das Neves ret = hv_call_get_gpa_access_states(partition->pt_id, args.page_count, 1518*621191d7SNuno Das Neves args.gpap_base, hv_flags, &written, 1519*621191d7SNuno Das Neves states); 1520*621191d7SNuno Das Neves if (ret) 1521*621191d7SNuno Das Neves goto free_return; 1522*621191d7SNuno Das Neves 1523*621191d7SNuno Das Neves /* 1524*621191d7SNuno Das Neves * Overwrite states buffer with bitmap - the bits in hv_type_mask 1525*621191d7SNuno Das Neves * correspond to bitfields in hv_gpa_page_access_state 1526*621191d7SNuno Das Neves */ 1527*621191d7SNuno Das Neves for (i = 0; i < written; ++i) 1528*621191d7SNuno Das Neves __assign_bit(i, (ulong *)states, 1529*621191d7SNuno Das Neves states[i].as_uint8 & hv_type_mask); 1530*621191d7SNuno Das Neves 1531*621191d7SNuno Das Neves /* zero the unused bits in the last byte(s) of the returned bitmap */ 1532*621191d7SNuno Das Neves for (i = written; i < bitmap_buf_sz * 8; ++i) 1533*621191d7SNuno Das Neves __clear_bit(i, (ulong *)states); 1534*621191d7SNuno Das Neves 1535*621191d7SNuno Das Neves if (copy_to_user((void __user *)args.bitmap_ptr, states, bitmap_buf_sz)) 1536*621191d7SNuno Das Neves ret = -EFAULT; 1537*621191d7SNuno Das Neves 1538*621191d7SNuno Das Neves free_return: 1539*621191d7SNuno Das Neves vfree(states); 1540*621191d7SNuno Das Neves return ret; 1541*621191d7SNuno Das Neves } 1542*621191d7SNuno Das Neves 1543*621191d7SNuno Das Neves static long 1544*621191d7SNuno Das Neves mshv_partition_ioctl_set_msi_routing(struct mshv_partition *partition, 1545*621191d7SNuno Das Neves void __user *user_args) 1546*621191d7SNuno Das Neves { 1547*621191d7SNuno Das Neves struct mshv_user_irq_entry *entries = NULL; 1548*621191d7SNuno Das Neves struct mshv_user_irq_table args; 1549*621191d7SNuno Das Neves long ret; 1550*621191d7SNuno Das Neves 1551*621191d7SNuno Das Neves if (copy_from_user(&args, user_args, sizeof(args))) 1552*621191d7SNuno Das Neves return -EFAULT; 1553*621191d7SNuno Das Neves 1554*621191d7SNuno Das Neves if (args.nr > MSHV_MAX_GUEST_IRQS || 1555*621191d7SNuno Das Neves mshv_field_nonzero(args, rsvd)) 1556*621191d7SNuno Das Neves return -EINVAL; 1557*621191d7SNuno Das Neves 1558*621191d7SNuno Das Neves if (args.nr) { 1559*621191d7SNuno Das Neves struct mshv_user_irq_table __user *urouting = user_args; 1560*621191d7SNuno Das Neves 1561*621191d7SNuno Das Neves entries = vmemdup_user(urouting->entries, 1562*621191d7SNuno Das Neves array_size(sizeof(*entries), 1563*621191d7SNuno Das Neves args.nr)); 1564*621191d7SNuno Das Neves if (IS_ERR(entries)) 1565*621191d7SNuno Das Neves return PTR_ERR(entries); 1566*621191d7SNuno Das Neves } 1567*621191d7SNuno Das Neves ret = mshv_update_routing_table(partition, entries, args.nr); 1568*621191d7SNuno Das Neves kvfree(entries); 1569*621191d7SNuno Das Neves 1570*621191d7SNuno Das Neves return ret; 1571*621191d7SNuno Das Neves } 1572*621191d7SNuno Das Neves 1573*621191d7SNuno Das Neves static long 1574*621191d7SNuno Das Neves mshv_partition_ioctl_initialize(struct mshv_partition *partition) 1575*621191d7SNuno Das Neves { 1576*621191d7SNuno Das Neves long ret; 1577*621191d7SNuno Das Neves 1578*621191d7SNuno Das Neves if (partition->pt_initialized) 1579*621191d7SNuno Das Neves return 0; 1580*621191d7SNuno Das Neves 1581*621191d7SNuno Das Neves ret = hv_call_initialize_partition(partition->pt_id); 1582*621191d7SNuno Das Neves if (ret) 1583*621191d7SNuno Das Neves goto withdraw_mem; 1584*621191d7SNuno Das Neves 1585*621191d7SNuno Das Neves partition->pt_initialized = true; 1586*621191d7SNuno Das Neves 1587*621191d7SNuno Das Neves return 0; 1588*621191d7SNuno Das Neves 1589*621191d7SNuno Das Neves withdraw_mem: 1590*621191d7SNuno Das Neves hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id); 1591*621191d7SNuno Das Neves 1592*621191d7SNuno Das Neves return ret; 1593*621191d7SNuno Das Neves } 1594*621191d7SNuno Das Neves 1595*621191d7SNuno Das Neves static long 1596*621191d7SNuno Das Neves mshv_partition_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) 1597*621191d7SNuno Das Neves { 1598*621191d7SNuno Das Neves struct mshv_partition *partition = filp->private_data; 1599*621191d7SNuno Das Neves long ret; 1600*621191d7SNuno Das Neves void __user *uarg = (void __user *)arg; 1601*621191d7SNuno Das Neves 1602*621191d7SNuno Das Neves if (mutex_lock_killable(&partition->pt_mutex)) 1603*621191d7SNuno Das Neves return -EINTR; 1604*621191d7SNuno Das Neves 1605*621191d7SNuno Das Neves switch (ioctl) { 1606*621191d7SNuno Das Neves case MSHV_INITIALIZE_PARTITION: 1607*621191d7SNuno Das Neves ret = mshv_partition_ioctl_initialize(partition); 1608*621191d7SNuno Das Neves break; 1609*621191d7SNuno Das Neves case MSHV_SET_GUEST_MEMORY: 1610*621191d7SNuno Das Neves ret = mshv_partition_ioctl_set_memory(partition, uarg); 1611*621191d7SNuno Das Neves break; 1612*621191d7SNuno Das Neves case MSHV_CREATE_VP: 1613*621191d7SNuno Das Neves ret = mshv_partition_ioctl_create_vp(partition, uarg); 1614*621191d7SNuno Das Neves break; 1615*621191d7SNuno Das Neves case MSHV_IRQFD: 1616*621191d7SNuno Das Neves ret = mshv_partition_ioctl_irqfd(partition, uarg); 1617*621191d7SNuno Das Neves break; 1618*621191d7SNuno Das Neves case MSHV_IOEVENTFD: 1619*621191d7SNuno Das Neves ret = mshv_partition_ioctl_ioeventfd(partition, uarg); 1620*621191d7SNuno Das Neves break; 1621*621191d7SNuno Das Neves case MSHV_SET_MSI_ROUTING: 1622*621191d7SNuno Das Neves ret = mshv_partition_ioctl_set_msi_routing(partition, uarg); 1623*621191d7SNuno Das Neves break; 1624*621191d7SNuno Das Neves case MSHV_GET_GPAP_ACCESS_BITMAP: 1625*621191d7SNuno Das Neves ret = mshv_partition_ioctl_get_gpap_access_bitmap(partition, 1626*621191d7SNuno Das Neves uarg); 1627*621191d7SNuno Das Neves break; 1628*621191d7SNuno Das Neves case MSHV_ROOT_HVCALL: 1629*621191d7SNuno Das Neves ret = mshv_ioctl_passthru_hvcall(partition, true, uarg); 1630*621191d7SNuno Das Neves break; 1631*621191d7SNuno Das Neves default: 1632*621191d7SNuno Das Neves ret = -ENOTTY; 1633*621191d7SNuno Das Neves } 1634*621191d7SNuno Das Neves 1635*621191d7SNuno Das Neves mutex_unlock(&partition->pt_mutex); 1636*621191d7SNuno Das Neves return ret; 1637*621191d7SNuno Das Neves } 1638*621191d7SNuno Das Neves 1639*621191d7SNuno Das Neves static int 1640*621191d7SNuno Das Neves disable_vp_dispatch(struct mshv_vp *vp) 1641*621191d7SNuno Das Neves { 1642*621191d7SNuno Das Neves int ret; 1643*621191d7SNuno Das Neves struct hv_register_assoc dispatch_suspend = { 1644*621191d7SNuno Das Neves .name = HV_REGISTER_DISPATCH_SUSPEND, 1645*621191d7SNuno Das Neves .value.dispatch_suspend.suspended = 1, 1646*621191d7SNuno Das Neves }; 1647*621191d7SNuno Das Neves 1648*621191d7SNuno Das Neves ret = mshv_set_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 1649*621191d7SNuno Das Neves 1, &dispatch_suspend); 1650*621191d7SNuno Das Neves if (ret) 1651*621191d7SNuno Das Neves vp_err(vp, "failed to suspend\n"); 1652*621191d7SNuno Das Neves 1653*621191d7SNuno Das Neves return ret; 1654*621191d7SNuno Das Neves } 1655*621191d7SNuno Das Neves 1656*621191d7SNuno Das Neves static int 1657*621191d7SNuno Das Neves get_vp_signaled_count(struct mshv_vp *vp, u64 *count) 1658*621191d7SNuno Das Neves { 1659*621191d7SNuno Das Neves int ret; 1660*621191d7SNuno Das Neves struct hv_register_assoc root_signal_count = { 1661*621191d7SNuno Das Neves .name = HV_REGISTER_VP_ROOT_SIGNAL_COUNT, 1662*621191d7SNuno Das Neves }; 1663*621191d7SNuno Das Neves 1664*621191d7SNuno Das Neves ret = mshv_get_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 1665*621191d7SNuno Das Neves 1, &root_signal_count); 1666*621191d7SNuno Das Neves 1667*621191d7SNuno Das Neves if (ret) { 1668*621191d7SNuno Das Neves vp_err(vp, "Failed to get root signal count"); 1669*621191d7SNuno Das Neves *count = 0; 1670*621191d7SNuno Das Neves return ret; 1671*621191d7SNuno Das Neves } 1672*621191d7SNuno Das Neves 1673*621191d7SNuno Das Neves *count = root_signal_count.value.reg64; 1674*621191d7SNuno Das Neves 1675*621191d7SNuno Das Neves return ret; 1676*621191d7SNuno Das Neves } 1677*621191d7SNuno Das Neves 1678*621191d7SNuno Das Neves static void 1679*621191d7SNuno Das Neves drain_vp_signals(struct mshv_vp *vp) 1680*621191d7SNuno Das Neves { 1681*621191d7SNuno Das Neves u64 hv_signal_count; 1682*621191d7SNuno Das Neves u64 vp_signal_count; 1683*621191d7SNuno Das Neves 1684*621191d7SNuno Das Neves get_vp_signaled_count(vp, &hv_signal_count); 1685*621191d7SNuno Das Neves 1686*621191d7SNuno Das Neves vp_signal_count = atomic64_read(&vp->run.vp_signaled_count); 1687*621191d7SNuno Das Neves 1688*621191d7SNuno Das Neves /* 1689*621191d7SNuno Das Neves * There should be at most 1 outstanding notification, but be extra 1690*621191d7SNuno Das Neves * careful anyway. 1691*621191d7SNuno Das Neves */ 1692*621191d7SNuno Das Neves while (hv_signal_count != vp_signal_count) { 1693*621191d7SNuno Das Neves WARN_ON(hv_signal_count - vp_signal_count != 1); 1694*621191d7SNuno Das Neves 1695*621191d7SNuno Das Neves if (wait_event_interruptible(vp->run.vp_suspend_queue, 1696*621191d7SNuno Das Neves vp->run.kicked_by_hv == 1)) 1697*621191d7SNuno Das Neves break; 1698*621191d7SNuno Das Neves vp->run.kicked_by_hv = 0; 1699*621191d7SNuno Das Neves vp_signal_count = atomic64_read(&vp->run.vp_signaled_count); 1700*621191d7SNuno Das Neves } 1701*621191d7SNuno Das Neves } 1702*621191d7SNuno Das Neves 1703*621191d7SNuno Das Neves static void drain_all_vps(const struct mshv_partition *partition) 1704*621191d7SNuno Das Neves { 1705*621191d7SNuno Das Neves int i; 1706*621191d7SNuno Das Neves struct mshv_vp *vp; 1707*621191d7SNuno Das Neves 1708*621191d7SNuno Das Neves /* 1709*621191d7SNuno Das Neves * VPs are reachable from ISR. It is safe to not take the partition 1710*621191d7SNuno Das Neves * lock because nobody else can enter this function and drop the 1711*621191d7SNuno Das Neves * partition from the list. 1712*621191d7SNuno Das Neves */ 1713*621191d7SNuno Das Neves for (i = 0; i < MSHV_MAX_VPS; i++) { 1714*621191d7SNuno Das Neves vp = partition->pt_vp_array[i]; 1715*621191d7SNuno Das Neves if (!vp) 1716*621191d7SNuno Das Neves continue; 1717*621191d7SNuno Das Neves /* 1718*621191d7SNuno Das Neves * Disable dispatching of the VP in the hypervisor. After this 1719*621191d7SNuno Das Neves * the hypervisor guarantees it won't generate any signals for 1720*621191d7SNuno Das Neves * the VP and the hypervisor's VP signal count won't change. 1721*621191d7SNuno Das Neves */ 1722*621191d7SNuno Das Neves disable_vp_dispatch(vp); 1723*621191d7SNuno Das Neves drain_vp_signals(vp); 1724*621191d7SNuno Das Neves } 1725*621191d7SNuno Das Neves } 1726*621191d7SNuno Das Neves 1727*621191d7SNuno Das Neves static void 1728*621191d7SNuno Das Neves remove_partition(struct mshv_partition *partition) 1729*621191d7SNuno Das Neves { 1730*621191d7SNuno Das Neves spin_lock(&mshv_root.pt_ht_lock); 1731*621191d7SNuno Das Neves hlist_del_rcu(&partition->pt_hnode); 1732*621191d7SNuno Das Neves spin_unlock(&mshv_root.pt_ht_lock); 1733*621191d7SNuno Das Neves 1734*621191d7SNuno Das Neves synchronize_rcu(); 1735*621191d7SNuno Das Neves } 1736*621191d7SNuno Das Neves 1737*621191d7SNuno Das Neves /* 1738*621191d7SNuno Das Neves * Tear down a partition and remove it from the list. 1739*621191d7SNuno Das Neves * Partition's refcount must be 0 1740*621191d7SNuno Das Neves */ 1741*621191d7SNuno Das Neves static void destroy_partition(struct mshv_partition *partition) 1742*621191d7SNuno Das Neves { 1743*621191d7SNuno Das Neves struct mshv_vp *vp; 1744*621191d7SNuno Das Neves struct mshv_mem_region *region; 1745*621191d7SNuno Das Neves int i, ret; 1746*621191d7SNuno Das Neves struct hlist_node *n; 1747*621191d7SNuno Das Neves 1748*621191d7SNuno Das Neves if (refcount_read(&partition->pt_ref_count)) { 1749*621191d7SNuno Das Neves pt_err(partition, 1750*621191d7SNuno Das Neves "Attempt to destroy partition but refcount > 0\n"); 1751*621191d7SNuno Das Neves return; 1752*621191d7SNuno Das Neves } 1753*621191d7SNuno Das Neves 1754*621191d7SNuno Das Neves if (partition->pt_initialized) { 1755*621191d7SNuno Das Neves /* 1756*621191d7SNuno Das Neves * We only need to drain signals for root scheduler. This should be 1757*621191d7SNuno Das Neves * done before removing the partition from the partition list. 1758*621191d7SNuno Das Neves */ 1759*621191d7SNuno Das Neves if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) 1760*621191d7SNuno Das Neves drain_all_vps(partition); 1761*621191d7SNuno Das Neves 1762*621191d7SNuno Das Neves /* Remove vps */ 1763*621191d7SNuno Das Neves for (i = 0; i < MSHV_MAX_VPS; ++i) { 1764*621191d7SNuno Das Neves vp = partition->pt_vp_array[i]; 1765*621191d7SNuno Das Neves if (!vp) 1766*621191d7SNuno Das Neves continue; 1767*621191d7SNuno Das Neves 1768*621191d7SNuno Das Neves if (hv_parent_partition()) 1769*621191d7SNuno Das Neves mshv_vp_stats_unmap(partition->pt_id, vp->vp_index); 1770*621191d7SNuno Das Neves 1771*621191d7SNuno Das Neves if (vp->vp_register_page) { 1772*621191d7SNuno Das Neves (void)hv_call_unmap_vp_state_page(partition->pt_id, 1773*621191d7SNuno Das Neves vp->vp_index, 1774*621191d7SNuno Das Neves HV_VP_STATE_PAGE_REGISTERS, 1775*621191d7SNuno Das Neves input_vtl_zero); 1776*621191d7SNuno Das Neves vp->vp_register_page = NULL; 1777*621191d7SNuno Das Neves } 1778*621191d7SNuno Das Neves 1779*621191d7SNuno Das Neves (void)hv_call_unmap_vp_state_page(partition->pt_id, 1780*621191d7SNuno Das Neves vp->vp_index, 1781*621191d7SNuno Das Neves HV_VP_STATE_PAGE_INTERCEPT_MESSAGE, 1782*621191d7SNuno Das Neves input_vtl_zero); 1783*621191d7SNuno Das Neves vp->vp_intercept_msg_page = NULL; 1784*621191d7SNuno Das Neves 1785*621191d7SNuno Das Neves if (vp->vp_ghcb_page) { 1786*621191d7SNuno Das Neves (void)hv_call_unmap_vp_state_page(partition->pt_id, 1787*621191d7SNuno Das Neves vp->vp_index, 1788*621191d7SNuno Das Neves HV_VP_STATE_PAGE_GHCB, 1789*621191d7SNuno Das Neves input_vtl_normal); 1790*621191d7SNuno Das Neves vp->vp_ghcb_page = NULL; 1791*621191d7SNuno Das Neves } 1792*621191d7SNuno Das Neves 1793*621191d7SNuno Das Neves kfree(vp); 1794*621191d7SNuno Das Neves 1795*621191d7SNuno Das Neves partition->pt_vp_array[i] = NULL; 1796*621191d7SNuno Das Neves } 1797*621191d7SNuno Das Neves 1798*621191d7SNuno Das Neves /* Deallocates and unmaps everything including vcpus, GPA mappings etc */ 1799*621191d7SNuno Das Neves hv_call_finalize_partition(partition->pt_id); 1800*621191d7SNuno Das Neves 1801*621191d7SNuno Das Neves partition->pt_initialized = false; 1802*621191d7SNuno Das Neves } 1803*621191d7SNuno Das Neves 1804*621191d7SNuno Das Neves remove_partition(partition); 1805*621191d7SNuno Das Neves 1806*621191d7SNuno Das Neves /* Remove regions, regain access to the memory and unpin the pages */ 1807*621191d7SNuno Das Neves hlist_for_each_entry_safe(region, n, &partition->pt_mem_regions, 1808*621191d7SNuno Das Neves hnode) { 1809*621191d7SNuno Das Neves hlist_del(®ion->hnode); 1810*621191d7SNuno Das Neves 1811*621191d7SNuno Das Neves if (mshv_partition_encrypted(partition)) { 1812*621191d7SNuno Das Neves ret = mshv_partition_region_share(region); 1813*621191d7SNuno Das Neves if (ret) { 1814*621191d7SNuno Das Neves pt_err(partition, 1815*621191d7SNuno Das Neves "Failed to regain access to memory, unpinning user pages will fail and crash the host error: %d\n", 1816*621191d7SNuno Das Neves ret); 1817*621191d7SNuno Das Neves return; 1818*621191d7SNuno Das Neves } 1819*621191d7SNuno Das Neves } 1820*621191d7SNuno Das Neves 1821*621191d7SNuno Das Neves mshv_region_evict(region); 1822*621191d7SNuno Das Neves 1823*621191d7SNuno Das Neves vfree(region); 1824*621191d7SNuno Das Neves } 1825*621191d7SNuno Das Neves 1826*621191d7SNuno Das Neves /* Withdraw and free all pages we deposited */ 1827*621191d7SNuno Das Neves hv_call_withdraw_memory(U64_MAX, NUMA_NO_NODE, partition->pt_id); 1828*621191d7SNuno Das Neves hv_call_delete_partition(partition->pt_id); 1829*621191d7SNuno Das Neves 1830*621191d7SNuno Das Neves mshv_free_routing_table(partition); 1831*621191d7SNuno Das Neves kfree(partition); 1832*621191d7SNuno Das Neves } 1833*621191d7SNuno Das Neves 1834*621191d7SNuno Das Neves struct 1835*621191d7SNuno Das Neves mshv_partition *mshv_partition_get(struct mshv_partition *partition) 1836*621191d7SNuno Das Neves { 1837*621191d7SNuno Das Neves if (refcount_inc_not_zero(&partition->pt_ref_count)) 1838*621191d7SNuno Das Neves return partition; 1839*621191d7SNuno Das Neves return NULL; 1840*621191d7SNuno Das Neves } 1841*621191d7SNuno Das Neves 1842*621191d7SNuno Das Neves struct 1843*621191d7SNuno Das Neves mshv_partition *mshv_partition_find(u64 partition_id) 1844*621191d7SNuno Das Neves __must_hold(RCU) 1845*621191d7SNuno Das Neves { 1846*621191d7SNuno Das Neves struct mshv_partition *p; 1847*621191d7SNuno Das Neves 1848*621191d7SNuno Das Neves hash_for_each_possible_rcu(mshv_root.pt_htable, p, pt_hnode, 1849*621191d7SNuno Das Neves partition_id) 1850*621191d7SNuno Das Neves if (p->pt_id == partition_id) 1851*621191d7SNuno Das Neves return p; 1852*621191d7SNuno Das Neves 1853*621191d7SNuno Das Neves return NULL; 1854*621191d7SNuno Das Neves } 1855*621191d7SNuno Das Neves 1856*621191d7SNuno Das Neves void 1857*621191d7SNuno Das Neves mshv_partition_put(struct mshv_partition *partition) 1858*621191d7SNuno Das Neves { 1859*621191d7SNuno Das Neves if (refcount_dec_and_test(&partition->pt_ref_count)) 1860*621191d7SNuno Das Neves destroy_partition(partition); 1861*621191d7SNuno Das Neves } 1862*621191d7SNuno Das Neves 1863*621191d7SNuno Das Neves static int 1864*621191d7SNuno Das Neves mshv_partition_release(struct inode *inode, struct file *filp) 1865*621191d7SNuno Das Neves { 1866*621191d7SNuno Das Neves struct mshv_partition *partition = filp->private_data; 1867*621191d7SNuno Das Neves 1868*621191d7SNuno Das Neves mshv_eventfd_release(partition); 1869*621191d7SNuno Das Neves 1870*621191d7SNuno Das Neves cleanup_srcu_struct(&partition->pt_irq_srcu); 1871*621191d7SNuno Das Neves 1872*621191d7SNuno Das Neves mshv_partition_put(partition); 1873*621191d7SNuno Das Neves 1874*621191d7SNuno Das Neves return 0; 1875*621191d7SNuno Das Neves } 1876*621191d7SNuno Das Neves 1877*621191d7SNuno Das Neves static int 1878*621191d7SNuno Das Neves add_partition(struct mshv_partition *partition) 1879*621191d7SNuno Das Neves { 1880*621191d7SNuno Das Neves spin_lock(&mshv_root.pt_ht_lock); 1881*621191d7SNuno Das Neves 1882*621191d7SNuno Das Neves hash_add_rcu(mshv_root.pt_htable, &partition->pt_hnode, 1883*621191d7SNuno Das Neves partition->pt_id); 1884*621191d7SNuno Das Neves 1885*621191d7SNuno Das Neves spin_unlock(&mshv_root.pt_ht_lock); 1886*621191d7SNuno Das Neves 1887*621191d7SNuno Das Neves return 0; 1888*621191d7SNuno Das Neves } 1889*621191d7SNuno Das Neves 1890*621191d7SNuno Das Neves static long 1891*621191d7SNuno Das Neves mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev) 1892*621191d7SNuno Das Neves { 1893*621191d7SNuno Das Neves struct mshv_create_partition args; 1894*621191d7SNuno Das Neves u64 creation_flags; 1895*621191d7SNuno Das Neves struct hv_partition_creation_properties creation_properties = {}; 1896*621191d7SNuno Das Neves union hv_partition_isolation_properties isolation_properties = {}; 1897*621191d7SNuno Das Neves struct mshv_partition *partition; 1898*621191d7SNuno Das Neves struct file *file; 1899*621191d7SNuno Das Neves int fd; 1900*621191d7SNuno Das Neves long ret; 1901*621191d7SNuno Das Neves 1902*621191d7SNuno Das Neves if (copy_from_user(&args, user_arg, sizeof(args))) 1903*621191d7SNuno Das Neves return -EFAULT; 1904*621191d7SNuno Das Neves 1905*621191d7SNuno Das Neves if ((args.pt_flags & ~MSHV_PT_FLAGS_MASK) || 1906*621191d7SNuno Das Neves args.pt_isolation >= MSHV_PT_ISOLATION_COUNT) 1907*621191d7SNuno Das Neves return -EINVAL; 1908*621191d7SNuno Das Neves 1909*621191d7SNuno Das Neves /* Only support EXO partitions */ 1910*621191d7SNuno Das Neves creation_flags = HV_PARTITION_CREATION_FLAG_EXO_PARTITION | 1911*621191d7SNuno Das Neves HV_PARTITION_CREATION_FLAG_INTERCEPT_MESSAGE_PAGE_ENABLED; 1912*621191d7SNuno Das Neves 1913*621191d7SNuno Das Neves if (args.pt_flags & BIT(MSHV_PT_BIT_LAPIC)) 1914*621191d7SNuno Das Neves creation_flags |= HV_PARTITION_CREATION_FLAG_LAPIC_ENABLED; 1915*621191d7SNuno Das Neves if (args.pt_flags & BIT(MSHV_PT_BIT_X2APIC)) 1916*621191d7SNuno Das Neves creation_flags |= HV_PARTITION_CREATION_FLAG_X2APIC_CAPABLE; 1917*621191d7SNuno Das Neves if (args.pt_flags & BIT(MSHV_PT_BIT_GPA_SUPER_PAGES)) 1918*621191d7SNuno Das Neves creation_flags |= HV_PARTITION_CREATION_FLAG_GPA_SUPER_PAGES_ENABLED; 1919*621191d7SNuno Das Neves 1920*621191d7SNuno Das Neves switch (args.pt_isolation) { 1921*621191d7SNuno Das Neves case MSHV_PT_ISOLATION_NONE: 1922*621191d7SNuno Das Neves isolation_properties.isolation_type = 1923*621191d7SNuno Das Neves HV_PARTITION_ISOLATION_TYPE_NONE; 1924*621191d7SNuno Das Neves break; 1925*621191d7SNuno Das Neves } 1926*621191d7SNuno Das Neves 1927*621191d7SNuno Das Neves partition = kzalloc(sizeof(*partition), GFP_KERNEL); 1928*621191d7SNuno Das Neves if (!partition) 1929*621191d7SNuno Das Neves return -ENOMEM; 1930*621191d7SNuno Das Neves 1931*621191d7SNuno Das Neves partition->pt_module_dev = module_dev; 1932*621191d7SNuno Das Neves partition->isolation_type = isolation_properties.isolation_type; 1933*621191d7SNuno Das Neves 1934*621191d7SNuno Das Neves refcount_set(&partition->pt_ref_count, 1); 1935*621191d7SNuno Das Neves 1936*621191d7SNuno Das Neves mutex_init(&partition->pt_mutex); 1937*621191d7SNuno Das Neves 1938*621191d7SNuno Das Neves mutex_init(&partition->pt_irq_lock); 1939*621191d7SNuno Das Neves 1940*621191d7SNuno Das Neves init_completion(&partition->async_hypercall); 1941*621191d7SNuno Das Neves 1942*621191d7SNuno Das Neves INIT_HLIST_HEAD(&partition->irq_ack_notifier_list); 1943*621191d7SNuno Das Neves 1944*621191d7SNuno Das Neves INIT_HLIST_HEAD(&partition->pt_devices); 1945*621191d7SNuno Das Neves 1946*621191d7SNuno Das Neves INIT_HLIST_HEAD(&partition->pt_mem_regions); 1947*621191d7SNuno Das Neves 1948*621191d7SNuno Das Neves mshv_eventfd_init(partition); 1949*621191d7SNuno Das Neves 1950*621191d7SNuno Das Neves ret = init_srcu_struct(&partition->pt_irq_srcu); 1951*621191d7SNuno Das Neves if (ret) 1952*621191d7SNuno Das Neves goto free_partition; 1953*621191d7SNuno Das Neves 1954*621191d7SNuno Das Neves ret = hv_call_create_partition(creation_flags, 1955*621191d7SNuno Das Neves creation_properties, 1956*621191d7SNuno Das Neves isolation_properties, 1957*621191d7SNuno Das Neves &partition->pt_id); 1958*621191d7SNuno Das Neves if (ret) 1959*621191d7SNuno Das Neves goto cleanup_irq_srcu; 1960*621191d7SNuno Das Neves 1961*621191d7SNuno Das Neves ret = add_partition(partition); 1962*621191d7SNuno Das Neves if (ret) 1963*621191d7SNuno Das Neves goto delete_partition; 1964*621191d7SNuno Das Neves 1965*621191d7SNuno Das Neves ret = mshv_init_async_handler(partition); 1966*621191d7SNuno Das Neves if (ret) 1967*621191d7SNuno Das Neves goto remove_partition; 1968*621191d7SNuno Das Neves 1969*621191d7SNuno Das Neves fd = get_unused_fd_flags(O_CLOEXEC); 1970*621191d7SNuno Das Neves if (fd < 0) { 1971*621191d7SNuno Das Neves ret = fd; 1972*621191d7SNuno Das Neves goto remove_partition; 1973*621191d7SNuno Das Neves } 1974*621191d7SNuno Das Neves 1975*621191d7SNuno Das Neves file = anon_inode_getfile("mshv_partition", &mshv_partition_fops, 1976*621191d7SNuno Das Neves partition, O_RDWR); 1977*621191d7SNuno Das Neves if (IS_ERR(file)) { 1978*621191d7SNuno Das Neves ret = PTR_ERR(file); 1979*621191d7SNuno Das Neves goto put_fd; 1980*621191d7SNuno Das Neves } 1981*621191d7SNuno Das Neves 1982*621191d7SNuno Das Neves fd_install(fd, file); 1983*621191d7SNuno Das Neves 1984*621191d7SNuno Das Neves return fd; 1985*621191d7SNuno Das Neves 1986*621191d7SNuno Das Neves put_fd: 1987*621191d7SNuno Das Neves put_unused_fd(fd); 1988*621191d7SNuno Das Neves remove_partition: 1989*621191d7SNuno Das Neves remove_partition(partition); 1990*621191d7SNuno Das Neves delete_partition: 1991*621191d7SNuno Das Neves hv_call_delete_partition(partition->pt_id); 1992*621191d7SNuno Das Neves cleanup_irq_srcu: 1993*621191d7SNuno Das Neves cleanup_srcu_struct(&partition->pt_irq_srcu); 1994*621191d7SNuno Das Neves free_partition: 1995*621191d7SNuno Das Neves kfree(partition); 1996*621191d7SNuno Das Neves 1997*621191d7SNuno Das Neves return ret; 1998*621191d7SNuno Das Neves } 1999*621191d7SNuno Das Neves 2000*621191d7SNuno Das Neves static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl, 2001*621191d7SNuno Das Neves unsigned long arg) 2002*621191d7SNuno Das Neves { 2003*621191d7SNuno Das Neves struct miscdevice *misc = filp->private_data; 2004*621191d7SNuno Das Neves 2005*621191d7SNuno Das Neves switch (ioctl) { 2006*621191d7SNuno Das Neves case MSHV_CREATE_PARTITION: 2007*621191d7SNuno Das Neves return mshv_ioctl_create_partition((void __user *)arg, 2008*621191d7SNuno Das Neves misc->this_device); 2009*621191d7SNuno Das Neves } 2010*621191d7SNuno Das Neves 2011*621191d7SNuno Das Neves return -ENOTTY; 2012*621191d7SNuno Das Neves } 2013*621191d7SNuno Das Neves 2014*621191d7SNuno Das Neves static int 2015*621191d7SNuno Das Neves mshv_dev_open(struct inode *inode, struct file *filp) 2016*621191d7SNuno Das Neves { 2017*621191d7SNuno Das Neves return 0; 2018*621191d7SNuno Das Neves } 2019*621191d7SNuno Das Neves 2020*621191d7SNuno Das Neves static int 2021*621191d7SNuno Das Neves mshv_dev_release(struct inode *inode, struct file *filp) 2022*621191d7SNuno Das Neves { 2023*621191d7SNuno Das Neves return 0; 2024*621191d7SNuno Das Neves } 2025*621191d7SNuno Das Neves 2026*621191d7SNuno Das Neves static int mshv_cpuhp_online; 2027*621191d7SNuno Das Neves static int mshv_root_sched_online; 2028*621191d7SNuno Das Neves 2029*621191d7SNuno Das Neves static const char *scheduler_type_to_string(enum hv_scheduler_type type) 2030*621191d7SNuno Das Neves { 2031*621191d7SNuno Das Neves switch (type) { 2032*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_LP: 2033*621191d7SNuno Das Neves return "classic scheduler without SMT"; 2034*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_LP_SMT: 2035*621191d7SNuno Das Neves return "classic scheduler with SMT"; 2036*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_CORE_SMT: 2037*621191d7SNuno Das Neves return "core scheduler"; 2038*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_ROOT: 2039*621191d7SNuno Das Neves return "root scheduler"; 2040*621191d7SNuno Das Neves default: 2041*621191d7SNuno Das Neves return "unknown scheduler"; 2042*621191d7SNuno Das Neves }; 2043*621191d7SNuno Das Neves } 2044*621191d7SNuno Das Neves 2045*621191d7SNuno Das Neves /* TODO move this to hv_common.c when needed outside */ 2046*621191d7SNuno Das Neves static int __init hv_retrieve_scheduler_type(enum hv_scheduler_type *out) 2047*621191d7SNuno Das Neves { 2048*621191d7SNuno Das Neves struct hv_input_get_system_property *input; 2049*621191d7SNuno Das Neves struct hv_output_get_system_property *output; 2050*621191d7SNuno Das Neves unsigned long flags; 2051*621191d7SNuno Das Neves u64 status; 2052*621191d7SNuno Das Neves 2053*621191d7SNuno Das Neves local_irq_save(flags); 2054*621191d7SNuno Das Neves input = *this_cpu_ptr(hyperv_pcpu_input_arg); 2055*621191d7SNuno Das Neves output = *this_cpu_ptr(hyperv_pcpu_output_arg); 2056*621191d7SNuno Das Neves 2057*621191d7SNuno Das Neves memset(input, 0, sizeof(*input)); 2058*621191d7SNuno Das Neves memset(output, 0, sizeof(*output)); 2059*621191d7SNuno Das Neves input->property_id = HV_SYSTEM_PROPERTY_SCHEDULER_TYPE; 2060*621191d7SNuno Das Neves 2061*621191d7SNuno Das Neves status = hv_do_hypercall(HVCALL_GET_SYSTEM_PROPERTY, input, output); 2062*621191d7SNuno Das Neves if (!hv_result_success(status)) { 2063*621191d7SNuno Das Neves local_irq_restore(flags); 2064*621191d7SNuno Das Neves pr_err("%s: %s\n", __func__, hv_result_to_string(status)); 2065*621191d7SNuno Das Neves return hv_result_to_errno(status); 2066*621191d7SNuno Das Neves } 2067*621191d7SNuno Das Neves 2068*621191d7SNuno Das Neves *out = output->scheduler_type; 2069*621191d7SNuno Das Neves local_irq_restore(flags); 2070*621191d7SNuno Das Neves 2071*621191d7SNuno Das Neves return 0; 2072*621191d7SNuno Das Neves } 2073*621191d7SNuno Das Neves 2074*621191d7SNuno Das Neves /* Retrieve and stash the supported scheduler type */ 2075*621191d7SNuno Das Neves static int __init mshv_retrieve_scheduler_type(struct device *dev) 2076*621191d7SNuno Das Neves { 2077*621191d7SNuno Das Neves int ret; 2078*621191d7SNuno Das Neves 2079*621191d7SNuno Das Neves ret = hv_retrieve_scheduler_type(&hv_scheduler_type); 2080*621191d7SNuno Das Neves if (ret) 2081*621191d7SNuno Das Neves return ret; 2082*621191d7SNuno Das Neves 2083*621191d7SNuno Das Neves dev_info(dev, "Hypervisor using %s\n", 2084*621191d7SNuno Das Neves scheduler_type_to_string(hv_scheduler_type)); 2085*621191d7SNuno Das Neves 2086*621191d7SNuno Das Neves switch (hv_scheduler_type) { 2087*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_CORE_SMT: 2088*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_LP_SMT: 2089*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_ROOT: 2090*621191d7SNuno Das Neves case HV_SCHEDULER_TYPE_LP: 2091*621191d7SNuno Das Neves /* Supported scheduler, nothing to do */ 2092*621191d7SNuno Das Neves break; 2093*621191d7SNuno Das Neves default: 2094*621191d7SNuno Das Neves dev_err(dev, "unsupported scheduler 0x%x, bailing.\n", 2095*621191d7SNuno Das Neves hv_scheduler_type); 2096*621191d7SNuno Das Neves return -EOPNOTSUPP; 2097*621191d7SNuno Das Neves } 2098*621191d7SNuno Das Neves 2099*621191d7SNuno Das Neves return 0; 2100*621191d7SNuno Das Neves } 2101*621191d7SNuno Das Neves 2102*621191d7SNuno Das Neves static int mshv_root_scheduler_init(unsigned int cpu) 2103*621191d7SNuno Das Neves { 2104*621191d7SNuno Das Neves void **inputarg, **outputarg, *p; 2105*621191d7SNuno Das Neves 2106*621191d7SNuno Das Neves inputarg = (void **)this_cpu_ptr(root_scheduler_input); 2107*621191d7SNuno Das Neves outputarg = (void **)this_cpu_ptr(root_scheduler_output); 2108*621191d7SNuno Das Neves 2109*621191d7SNuno Das Neves /* Allocate two consecutive pages. One for input, one for output. */ 2110*621191d7SNuno Das Neves p = kmalloc(2 * HV_HYP_PAGE_SIZE, GFP_KERNEL); 2111*621191d7SNuno Das Neves if (!p) 2112*621191d7SNuno Das Neves return -ENOMEM; 2113*621191d7SNuno Das Neves 2114*621191d7SNuno Das Neves *inputarg = p; 2115*621191d7SNuno Das Neves *outputarg = (char *)p + HV_HYP_PAGE_SIZE; 2116*621191d7SNuno Das Neves 2117*621191d7SNuno Das Neves return 0; 2118*621191d7SNuno Das Neves } 2119*621191d7SNuno Das Neves 2120*621191d7SNuno Das Neves static int mshv_root_scheduler_cleanup(unsigned int cpu) 2121*621191d7SNuno Das Neves { 2122*621191d7SNuno Das Neves void *p, **inputarg, **outputarg; 2123*621191d7SNuno Das Neves 2124*621191d7SNuno Das Neves inputarg = (void **)this_cpu_ptr(root_scheduler_input); 2125*621191d7SNuno Das Neves outputarg = (void **)this_cpu_ptr(root_scheduler_output); 2126*621191d7SNuno Das Neves 2127*621191d7SNuno Das Neves p = *inputarg; 2128*621191d7SNuno Das Neves 2129*621191d7SNuno Das Neves *inputarg = NULL; 2130*621191d7SNuno Das Neves *outputarg = NULL; 2131*621191d7SNuno Das Neves 2132*621191d7SNuno Das Neves kfree(p); 2133*621191d7SNuno Das Neves 2134*621191d7SNuno Das Neves return 0; 2135*621191d7SNuno Das Neves } 2136*621191d7SNuno Das Neves 2137*621191d7SNuno Das Neves /* Must be called after retrieving the scheduler type */ 2138*621191d7SNuno Das Neves static int 2139*621191d7SNuno Das Neves root_scheduler_init(struct device *dev) 2140*621191d7SNuno Das Neves { 2141*621191d7SNuno Das Neves int ret; 2142*621191d7SNuno Das Neves 2143*621191d7SNuno Das Neves if (hv_scheduler_type != HV_SCHEDULER_TYPE_ROOT) 2144*621191d7SNuno Das Neves return 0; 2145*621191d7SNuno Das Neves 2146*621191d7SNuno Das Neves root_scheduler_input = alloc_percpu(void *); 2147*621191d7SNuno Das Neves root_scheduler_output = alloc_percpu(void *); 2148*621191d7SNuno Das Neves 2149*621191d7SNuno Das Neves if (!root_scheduler_input || !root_scheduler_output) { 2150*621191d7SNuno Das Neves dev_err(dev, "Failed to allocate root scheduler buffers\n"); 2151*621191d7SNuno Das Neves ret = -ENOMEM; 2152*621191d7SNuno Das Neves goto out; 2153*621191d7SNuno Das Neves } 2154*621191d7SNuno Das Neves 2155*621191d7SNuno Das Neves ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_root_sched", 2156*621191d7SNuno Das Neves mshv_root_scheduler_init, 2157*621191d7SNuno Das Neves mshv_root_scheduler_cleanup); 2158*621191d7SNuno Das Neves 2159*621191d7SNuno Das Neves if (ret < 0) { 2160*621191d7SNuno Das Neves dev_err(dev, "Failed to setup root scheduler state: %i\n", ret); 2161*621191d7SNuno Das Neves goto out; 2162*621191d7SNuno Das Neves } 2163*621191d7SNuno Das Neves 2164*621191d7SNuno Das Neves mshv_root_sched_online = ret; 2165*621191d7SNuno Das Neves 2166*621191d7SNuno Das Neves return 0; 2167*621191d7SNuno Das Neves 2168*621191d7SNuno Das Neves out: 2169*621191d7SNuno Das Neves free_percpu(root_scheduler_input); 2170*621191d7SNuno Das Neves free_percpu(root_scheduler_output); 2171*621191d7SNuno Das Neves return ret; 2172*621191d7SNuno Das Neves } 2173*621191d7SNuno Das Neves 2174*621191d7SNuno Das Neves static void 2175*621191d7SNuno Das Neves root_scheduler_deinit(void) 2176*621191d7SNuno Das Neves { 2177*621191d7SNuno Das Neves if (hv_scheduler_type != HV_SCHEDULER_TYPE_ROOT) 2178*621191d7SNuno Das Neves return; 2179*621191d7SNuno Das Neves 2180*621191d7SNuno Das Neves cpuhp_remove_state(mshv_root_sched_online); 2181*621191d7SNuno Das Neves free_percpu(root_scheduler_input); 2182*621191d7SNuno Das Neves free_percpu(root_scheduler_output); 2183*621191d7SNuno Das Neves } 2184*621191d7SNuno Das Neves 2185*621191d7SNuno Das Neves static int mshv_reboot_notify(struct notifier_block *nb, 2186*621191d7SNuno Das Neves unsigned long code, void *unused) 2187*621191d7SNuno Das Neves { 2188*621191d7SNuno Das Neves cpuhp_remove_state(mshv_cpuhp_online); 2189*621191d7SNuno Das Neves return 0; 2190*621191d7SNuno Das Neves } 2191*621191d7SNuno Das Neves 2192*621191d7SNuno Das Neves struct notifier_block mshv_reboot_nb = { 2193*621191d7SNuno Das Neves .notifier_call = mshv_reboot_notify, 2194*621191d7SNuno Das Neves }; 2195*621191d7SNuno Das Neves 2196*621191d7SNuno Das Neves static void mshv_root_partition_exit(void) 2197*621191d7SNuno Das Neves { 2198*621191d7SNuno Das Neves unregister_reboot_notifier(&mshv_reboot_nb); 2199*621191d7SNuno Das Neves root_scheduler_deinit(); 2200*621191d7SNuno Das Neves } 2201*621191d7SNuno Das Neves 2202*621191d7SNuno Das Neves static int __init mshv_root_partition_init(struct device *dev) 2203*621191d7SNuno Das Neves { 2204*621191d7SNuno Das Neves int err; 2205*621191d7SNuno Das Neves 2206*621191d7SNuno Das Neves if (mshv_retrieve_scheduler_type(dev)) 2207*621191d7SNuno Das Neves return -ENODEV; 2208*621191d7SNuno Das Neves 2209*621191d7SNuno Das Neves err = root_scheduler_init(dev); 2210*621191d7SNuno Das Neves if (err) 2211*621191d7SNuno Das Neves return err; 2212*621191d7SNuno Das Neves 2213*621191d7SNuno Das Neves err = register_reboot_notifier(&mshv_reboot_nb); 2214*621191d7SNuno Das Neves if (err) 2215*621191d7SNuno Das Neves goto root_sched_deinit; 2216*621191d7SNuno Das Neves 2217*621191d7SNuno Das Neves return 0; 2218*621191d7SNuno Das Neves 2219*621191d7SNuno Das Neves root_sched_deinit: 2220*621191d7SNuno Das Neves root_scheduler_deinit(); 2221*621191d7SNuno Das Neves return err; 2222*621191d7SNuno Das Neves } 2223*621191d7SNuno Das Neves 2224*621191d7SNuno Das Neves static int __init mshv_parent_partition_init(void) 2225*621191d7SNuno Das Neves { 2226*621191d7SNuno Das Neves int ret; 2227*621191d7SNuno Das Neves struct device *dev; 2228*621191d7SNuno Das Neves union hv_hypervisor_version_info version_info; 2229*621191d7SNuno Das Neves 2230*621191d7SNuno Das Neves if (!hv_root_partition() || is_kdump_kernel()) 2231*621191d7SNuno Das Neves return -ENODEV; 2232*621191d7SNuno Das Neves 2233*621191d7SNuno Das Neves if (hv_get_hypervisor_version(&version_info)) 2234*621191d7SNuno Das Neves return -ENODEV; 2235*621191d7SNuno Das Neves 2236*621191d7SNuno Das Neves ret = misc_register(&mshv_dev); 2237*621191d7SNuno Das Neves if (ret) 2238*621191d7SNuno Das Neves return ret; 2239*621191d7SNuno Das Neves 2240*621191d7SNuno Das Neves dev = mshv_dev.this_device; 2241*621191d7SNuno Das Neves 2242*621191d7SNuno Das Neves if (version_info.build_number < MSHV_HV_MIN_VERSION || 2243*621191d7SNuno Das Neves version_info.build_number > MSHV_HV_MAX_VERSION) { 2244*621191d7SNuno Das Neves dev_err(dev, "Running on unvalidated Hyper-V version\n"); 2245*621191d7SNuno Das Neves dev_err(dev, "Versions: current: %u min: %u max: %u\n", 2246*621191d7SNuno Das Neves version_info.build_number, MSHV_HV_MIN_VERSION, 2247*621191d7SNuno Das Neves MSHV_HV_MAX_VERSION); 2248*621191d7SNuno Das Neves } 2249*621191d7SNuno Das Neves 2250*621191d7SNuno Das Neves mshv_root.synic_pages = alloc_percpu(struct hv_synic_pages); 2251*621191d7SNuno Das Neves if (!mshv_root.synic_pages) { 2252*621191d7SNuno Das Neves dev_err(dev, "Failed to allocate percpu synic page\n"); 2253*621191d7SNuno Das Neves ret = -ENOMEM; 2254*621191d7SNuno Das Neves goto device_deregister; 2255*621191d7SNuno Das Neves } 2256*621191d7SNuno Das Neves 2257*621191d7SNuno Das Neves ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic", 2258*621191d7SNuno Das Neves mshv_synic_init, 2259*621191d7SNuno Das Neves mshv_synic_cleanup); 2260*621191d7SNuno Das Neves if (ret < 0) { 2261*621191d7SNuno Das Neves dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret); 2262*621191d7SNuno Das Neves goto free_synic_pages; 2263*621191d7SNuno Das Neves } 2264*621191d7SNuno Das Neves 2265*621191d7SNuno Das Neves mshv_cpuhp_online = ret; 2266*621191d7SNuno Das Neves 2267*621191d7SNuno Das Neves ret = mshv_root_partition_init(dev); 2268*621191d7SNuno Das Neves if (ret) 2269*621191d7SNuno Das Neves goto remove_cpu_state; 2270*621191d7SNuno Das Neves 2271*621191d7SNuno Das Neves ret = mshv_irqfd_wq_init(); 2272*621191d7SNuno Das Neves if (ret) 2273*621191d7SNuno Das Neves goto exit_partition; 2274*621191d7SNuno Das Neves 2275*621191d7SNuno Das Neves spin_lock_init(&mshv_root.pt_ht_lock); 2276*621191d7SNuno Das Neves hash_init(mshv_root.pt_htable); 2277*621191d7SNuno Das Neves 2278*621191d7SNuno Das Neves hv_setup_mshv_handler(mshv_isr); 2279*621191d7SNuno Das Neves 2280*621191d7SNuno Das Neves return 0; 2281*621191d7SNuno Das Neves 2282*621191d7SNuno Das Neves exit_partition: 2283*621191d7SNuno Das Neves if (hv_root_partition()) 2284*621191d7SNuno Das Neves mshv_root_partition_exit(); 2285*621191d7SNuno Das Neves remove_cpu_state: 2286*621191d7SNuno Das Neves cpuhp_remove_state(mshv_cpuhp_online); 2287*621191d7SNuno Das Neves free_synic_pages: 2288*621191d7SNuno Das Neves free_percpu(mshv_root.synic_pages); 2289*621191d7SNuno Das Neves device_deregister: 2290*621191d7SNuno Das Neves misc_deregister(&mshv_dev); 2291*621191d7SNuno Das Neves return ret; 2292*621191d7SNuno Das Neves } 2293*621191d7SNuno Das Neves 2294*621191d7SNuno Das Neves static void __exit mshv_parent_partition_exit(void) 2295*621191d7SNuno Das Neves { 2296*621191d7SNuno Das Neves hv_setup_mshv_handler(NULL); 2297*621191d7SNuno Das Neves mshv_port_table_fini(); 2298*621191d7SNuno Das Neves misc_deregister(&mshv_dev); 2299*621191d7SNuno Das Neves mshv_irqfd_wq_cleanup(); 2300*621191d7SNuno Das Neves if (hv_root_partition()) 2301*621191d7SNuno Das Neves mshv_root_partition_exit(); 2302*621191d7SNuno Das Neves cpuhp_remove_state(mshv_cpuhp_online); 2303*621191d7SNuno Das Neves free_percpu(mshv_root.synic_pages); 2304*621191d7SNuno Das Neves } 2305*621191d7SNuno Das Neves 2306*621191d7SNuno Das Neves module_init(mshv_parent_partition_init); 2307*621191d7SNuno Das Neves module_exit(mshv_parent_partition_exit); 2308