^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Hyper-V nested virtualization code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2018, Microsoft, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author : Lan Tianyu <Tianyu.Lan@microsoft.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define pr_fmt(fmt) "Hyper-V: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/hyperv-tlfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/mshyperv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/tlbflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/trace/hyperv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int hyperv_flush_guest_mapping(u64 as)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct hv_guest_mapping_flush **flush_pcpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct hv_guest_mapping_flush *flush;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u64 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int ret = -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) if (!hv_hypercall_pg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) goto fault;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) flush_pcpu = (struct hv_guest_mapping_flush **)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) this_cpu_ptr(hyperv_pcpu_input_arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) flush = *flush_pcpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (unlikely(!flush)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) goto fault;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) flush->address_space = as;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) flush->flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) status = hv_do_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) flush, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (!(status & HV_HYPERCALL_RESULT_MASK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) fault:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) trace_hyperv_nested_flush_guest_mapping(as, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int hyperv_fill_flush_guest_mapping_list(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct hv_guest_mapping_flush_list *flush,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u64 start_gfn, u64 pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u64 cur = start_gfn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u64 additional_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int gpa_n = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * If flush requests exceed max flush count, go back to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * flush tlbs without range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (gpa_n >= HV_MAX_FLUSH_REP_COUNT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) additional_pages = min_t(u64, pages, HV_MAX_FLUSH_PAGES) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) flush->gpa_list[gpa_n].page.additional_pages = additional_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) flush->gpa_list[gpa_n].page.largepage = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) flush->gpa_list[gpa_n].page.basepfn = cur;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) pages -= additional_pages + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) cur += additional_pages + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) gpa_n++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) } while (pages > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return gpa_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) EXPORT_SYMBOL_GPL(hyperv_fill_flush_guest_mapping_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int hyperv_flush_guest_mapping_range(u64 as,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) hyperv_fill_flush_list_func fill_flush_list_func, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct hv_guest_mapping_flush_list **flush_pcpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct hv_guest_mapping_flush_list *flush;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u64 status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int ret = -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int gpa_n = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!hv_hypercall_pg || !fill_flush_list_func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) goto fault;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) flush_pcpu = (struct hv_guest_mapping_flush_list **)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) this_cpu_ptr(hyperv_pcpu_input_arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) flush = *flush_pcpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (unlikely(!flush)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) goto fault;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) flush->address_space = as;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) flush->flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) gpa_n = fill_flush_list_func(flush, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (gpa_n < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) goto fault;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) status = hv_do_rep_hypercall(HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) gpa_n, 0, flush, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (!(status & HV_HYPERCALL_RESULT_MASK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ret = status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) fault:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) trace_hyperv_nested_flush_guest_mapping_range(as, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) EXPORT_SYMBOL_GPL(hyperv_flush_guest_mapping_range);