cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nested.c (2909B)


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