| // SPDX-License-Identifier: GPL-2.0 |
| |
| /* |
| * Architecture neutral utility routines for interacting with |
| * Hyper-V. This file is specifically for code that must be |
| * built-in to the kernel image when CONFIG_HYPERV is set |
| * (vs. being in a module) because it is called from architecture |
| * specific code under arch/. |
| * |
| * Copyright (C) 2021, Microsoft, Inc. |
| * |
| * Author : Michael Kelley <mikelley@microsoft.com> |
| */ |
| |
| #include <linux/types.h> |
| #include <linux/export.h> |
| #include <linux/bitfield.h> |
| #include <asm/hyperv-tlfs.h> |
| #include <asm/mshyperv.h> |
| |
| |
| /* Bit mask of the extended capability to query: see HV_EXT_CAPABILITY_xxx */ |
| bool hv_query_ext_cap(u64 cap_query) |
| { |
| /* |
| * The address of the 'hv_extended_cap' variable will be used as an |
| * output parameter to the hypercall below and so it should be |
| * compatible with 'virt_to_phys'. Which means, it's address should be |
| * directly mapped. Use 'static' to keep it compatible; stack variables |
| * can be virtually mapped, making them incompatible with |
| * 'virt_to_phys'. |
| * Hypercall input/output addresses should also be 8-byte aligned. |
| */ |
| static u64 hv_extended_cap __aligned(8); |
| static bool hv_extended_cap_queried; |
| u64 status; |
| |
| /* |
| * Querying extended capabilities is an extended hypercall. Check if the |
| * partition supports extended hypercall, first. |
| */ |
| if (!(ms_hyperv.priv_high & HV_ENABLE_EXTENDED_HYPERCALLS)) |
| return false; |
| |
| /* Extended capabilities do not change at runtime. */ |
| if (hv_extended_cap_queried) |
| return hv_extended_cap & cap_query; |
| |
| status = hv_do_hypercall(HV_EXT_CALL_QUERY_CAPABILITIES, NULL, |
| &hv_extended_cap); |
| |
| /* |
| * The query extended capabilities hypercall should not fail under |
| * any normal circumstances. Avoid repeatedly making the hypercall, on |
| * error. |
| */ |
| hv_extended_cap_queried = true; |
| if (!hv_result_success(status)) { |
| pr_err("Hyper-V: Extended query capabilities hypercall failed 0x%llx\n", |
| status); |
| return false; |
| } |
| |
| return hv_extended_cap & cap_query; |
| } |
| EXPORT_SYMBOL_GPL(hv_query_ext_cap); |