Skip to content

Commit

Permalink
Merge feature/hyperv-arm64/5.10 (afa4d09)
Browse files Browse the repository at this point in the history
* msft/feature/hyperv-arm64/5.10:
  arm64: hyperv: Do not call hyperv_init if not on Hyper-V
  Hyper-V: ARM64: Always use the Hyper-V hypercall interface
  Drivers: hv: Enable Hyper-V code to be built on ARM64
  arm64: efi: Export screen_info
  arm64: hyperv: Initialize hypervisor on boot
  arm64: hyperv: Add kexec and panic handlers
  arm64: hyperv: Add Hyper-V clocksource/clockevent support
  arm64: hyperv: Add Hyper-V hypercall and register access utilities
  smccc: Add HVC call variant with result registers other than 0 thru 3
  clocksource/drivers/hyper-v: Move handling of STIMER0 interrupts
  clocksource/drivers/hyper-v: Set clocksource rating based on Hyper-V feature
  clocksource/drivers/hyper-v: Handle sched_clock differences inline
  clocksource/drivers/hyper-v: Handle vDSO differences inline
  Drivers: hv: vmbus: Move handling of VMbus interrupts
  Drivers: hv: vmbus: Handle auto EOI quirk inline
  Drivers: hv: vmbus: Move hyperv_report_panic_msg to arch neutral code
  Drivers: hv: Redo Hyper-V synthetic MSR get/set functions
  x86/hyper-v: Move hv_message_type to architecture neutral module
  Drivers: hv: vmbus: Move Hyper-V page allocator to arch neutral code
  • Loading branch information
tyhicks authored and alk3pInjection committed May 21, 2022
2 parents 1947f23 + afa4d09 commit 0604333
Show file tree
Hide file tree
Showing 22 changed files with 1,058 additions and 320 deletions.
3 changes: 3 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -8159,6 +8159,9 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
F: Documentation/ABI/stable/sysfs-bus-vmbus
F: Documentation/ABI/testing/debugfs-hyperv
F: Documentation/networking/device_drivers/ethernet/microsoft/netvsc.rst
F: arch/arm64/hyperv
F: arch/arm64/include/asm/hyperv-tlfs.h
F: arch/arm64/include/asm/mshyperv.h
F: arch/x86/hyperv
F: arch/x86/include/asm/hyperv-tlfs.h
F: arch/x86/include/asm/mshyperv.h
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ obj-y += kernel/ mm/
obj-$(CONFIG_NET) += net/
obj-$(CONFIG_KVM) += kvm/
obj-$(CONFIG_XEN) += xen/
obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/
obj-$(CONFIG_CRYPTO) += crypto/
2 changes: 2 additions & 0 deletions arch/arm64/hyperv/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0
obj-y := hv_core.o mshyperv.o hv_hvc.o
174 changes: 174 additions & 0 deletions arch/arm64/hyperv/hv_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0

/*
* Low level utility routines for interacting with Hyper-V.
*
* Copyright (C) 2021, Microsoft, Inc.
*
* Author : Michael Kelley <mikelley@microsoft.com>
*/

#include <linux/types.h>
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/hyperv.h>
#include <linux/arm-smccc.h>
#include <linux/module.h>
#include <asm-generic/bug.h>
#include <asm/hyperv-tlfs.h>
#include <asm/mshyperv.h>

/*
* hv_do_hypercall- Invoke the specified hypercall
*/
u64 hv_do_hypercall(u64 control, void *input, void *output)
{
u64 input_address;
u64 output_address;

input_address = input ? virt_to_phys(input) : 0;
output_address = output ? virt_to_phys(output) : 0;

return hv_do_hvc(control, input_address, output_address);
}
EXPORT_SYMBOL_GPL(hv_do_hypercall);

/*
* hv_do_fast_hypercall8 -- Invoke the specified hypercall
* with arguments in registers instead of physical memory.
* Avoids the overhead of virt_to_phys for simple hypercalls.
*/
u64 hv_do_fast_hypercall8(u16 code, u64 input)
{
u64 control;

control = (u64)code | HV_HYPERCALL_FAST_BIT;
return hv_do_hvc(control, input);
}
EXPORT_SYMBOL_GPL(hv_do_fast_hypercall8);

union hv_hypercall_status {
u64 as_uint64;
struct {
u16 status;
u16 reserved;
u16 reps_completed; /* Low 12 bits */
u16 reserved2;
};
};

/*
* Set a single VP register to a 64-bit value.
*/
void hv_set_vpreg(u32 msr, u64 value)
{
union hv_hypercall_status status;

status.as_uint64 = hv_do_hvc(
HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
HV_HYPERCALL_REP_COMP_1,
HV_PARTITION_ID_SELF,
HV_VP_INDEX_SELF,
msr,
0,
value,
0);

/*
* Something is fundamentally broken in the hypervisor if
* setting a VP register fails. There's really no way to
* continue as a guest VM, so panic.
*/
BUG_ON(status.status != HV_STATUS_SUCCESS);
}
EXPORT_SYMBOL_GPL(hv_set_vpreg);

/*
* Get the value of a single VP register. One version
* returns just 64 bits and another returns the full 128 bits.
* The two versions are separate to avoid complicating the
* calling sequence for the more frequently used 64 bit version.
*/

void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *result)
{
u64 status;

status = hv_do_hvc_fast_get(
HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
HV_HYPERCALL_REP_COMP_1,
HV_PARTITION_ID_SELF,
HV_VP_INDEX_SELF,
msr,
result);

/*
* Something is fundamentally broken in the hypervisor if
* getting a VP register fails. There's really no way to
* continue as a guest VM, so panic.
*/
BUG_ON((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS);
}
EXPORT_SYMBOL_GPL(hv_get_vpreg_128);

u64 hv_get_vpreg(u32 msr)
{
struct hv_get_vp_registers_output output;

hv_get_vpreg_128(msr, &output);

return output.as64.low;
}
EXPORT_SYMBOL_GPL(hv_get_vpreg);

/*
* hyperv_report_panic - report a panic to Hyper-V. This function uses
* the older version of the Hyper-V interface that admittedly doesn't
* pass enough information to be useful beyond just recording the
* occurrence of a panic. The parallel hv_kmsg_dump() uses the
* new interface that allows reporting 4 Kbytes of data, which is much
* more useful. Hyper-V on ARM64 always supports the newer interface, but
* we retain support for the older version because the sysadmin is allowed
* to disable the newer version via sysctl in case of information security
* concerns about the more verbose version.
*/
void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
{
static bool panic_reported;
u64 guest_id;

/* Don't report a panic to Hyper-V if we're not going to panic */
if (in_die && !panic_on_oops)
return;

/*
* We prefer to report panic on 'die' chain as we have proper
* registers to report, but if we miss it (e.g. on BUG()) we need
* to report it on 'panic'.
*
* Calling code in the 'die' and 'panic' paths ensures that only
* one CPU is running this code, so no atomicity is needed.
*/
if (panic_reported)
return;
panic_reported = true;

guest_id = hv_get_vpreg(HV_REGISTER_GUEST_OSID);

/*
* Hyper-V provides the ability to store only 5 values.
* Pick the passed in error value, the guest_id, and the PC.
* The first two general registers are added arbitrarily.
*/
hv_set_vpreg(HV_REGISTER_CRASH_P0, err);
hv_set_vpreg(HV_REGISTER_CRASH_P1, guest_id);
hv_set_vpreg(HV_REGISTER_CRASH_P2, regs->pc);
hv_set_vpreg(HV_REGISTER_CRASH_P3, regs->regs[0]);
hv_set_vpreg(HV_REGISTER_CRASH_P4, regs->regs[1]);

/*
* Let Hyper-V know there is crash data available
*/
hv_set_vpreg(HV_REGISTER_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
}
EXPORT_SYMBOL_GPL(hyperv_report_panic);
61 changes: 61 additions & 0 deletions arch/arm64/hyperv/hv_hvc.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0 */

/*
* Microsoft Hyper-V hypervisor invocation routines
*
* Copyright (C) 2018, Microsoft, Inc.
*
* Author : Michael Kelley <mikelley@microsoft.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*/

#include <linux/linkage.h>
#include <asm/assembler.h>

.text
/*
* Do the HVC instruction. For Hyper-V the argument is always 1.
* x0 contains the hypercall control value, while additional registers
* vary depending on the hypercall, and whether the hypercall arguments
* are in memory or in registers (a "fast" hypercall per the Hyper-V
* TLFS). When the arguments are in memory x1 is the guest physical
* address of the input arguments, and x2 is the guest physical
* address of the output arguments. When the arguments are in
* registers, the register values depends on the hypercall. Note
* that this version cannot return any values in registers.
*/
SYM_FUNC_START(hv_do_hvc)
hvc #1
ret
SYM_FUNC_END(hv_do_hvc)

/*
* This variant of HVC invocation is for hv_get_vpreg and
* hv_get_vpreg_128. The input parameters are passed in registers
* along with a pointer in x4 to where the output result should
* be stored. The output is returned in x15 and x16. x19 is used as
* scratch space to avoid buildng a stack frame, as Hyper-V does
* not preserve registers x0-x17.
*/
SYM_FUNC_START(hv_do_hvc_fast_get)
/*
* Stash away x19 register so that it can be used as a scratch
* register and pop it at the end.
*/
str x19, [sp, #-16]!
mov x19, x4
hvc #1
str x15,[x19]
str x16,[x19,#8]
ldr x19, [sp], #16
ret
SYM_FUNC_END(hv_do_hvc_fast_get)
Loading

0 comments on commit 0604333

Please sign in to comment.