mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
Merge tag 'hyperv-fixes-signed-20260319' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull Hyper-V fixes from Wei Liu: - Fix ARM64 MSHV support (Anirudh Rayabharam) - Fix MSHV driver memory handling issues (Stanislav Kinsburskii) - Update maintainers for Hyper-V DRM driver (Saurabh Sengar) - Misc clean up in MSHV crashdump code (Ard Biesheuvel, Uros Bizjak) - Minor improvements to MSHV code (Mukesh R, Wei Liu) - Revert not yet released MSHV scrub partition hypercall (Wei Liu) * tag 'hyperv-fixes-signed-20260319' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: mshv: Fix error handling in mshv_region_pin MAINTAINERS: Update maintainers for Hyper-V DRM driver mshv: Fix use-after-free in mshv_map_user_memory error path mshv: pass struct mshv_user_mem_region by reference x86/hyperv: Use any general-purpose register when saving %cr2 and %cr8 x86/hyperv: Use current_stack_pointer to avoid asm() in hv_hvcrash_ctxt_save() x86/hyperv: Save segment registers directly to memory in hv_hvcrash_ctxt_save() x86/hyperv: Use __naked attribute to fix stackless C function Revert "mshv: expose the scrub partition hypercall" mshv: add arm64 support for doorbell & intercept SINTs mshv: refactor synic init and cleanup x86/hyperv: print out reserved vectors in hexadecimal
This commit is contained in:
@@ -7998,7 +7998,9 @@ F: Documentation/devicetree/bindings/display/himax,hx8357.yaml
|
||||
F: drivers/gpu/drm/tiny/hx8357d.c
|
||||
|
||||
DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE
|
||||
M: Deepak Rawat <drawat.floss@gmail.com>
|
||||
M: Dexuan Cui <decui@microsoft.com>
|
||||
M: Long Li <longli@microsoft.com>
|
||||
M: Saurabh Sengar <ssengar@linux.microsoft.com>
|
||||
L: linux-hyperv@vger.kernel.org
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Maintained
|
||||
|
||||
@@ -107,14 +107,12 @@ static void __noreturn hv_panic_timeout_reboot(void)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
/* This cannot be inlined as it needs stack */
|
||||
static noinline __noclone void hv_crash_restore_tss(void)
|
||||
static void hv_crash_restore_tss(void)
|
||||
{
|
||||
load_TR_desc();
|
||||
}
|
||||
|
||||
/* This cannot be inlined as it needs stack */
|
||||
static noinline void hv_crash_clear_kernpt(void)
|
||||
static void hv_crash_clear_kernpt(void)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
p4d_t *p4d;
|
||||
@@ -125,50 +123,9 @@ static noinline void hv_crash_clear_kernpt(void)
|
||||
native_p4d_clear(p4d);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the C entry point from the asm glue code after the disable hypercall.
|
||||
* We enter here in IA32-e long mode, ie, full 64bit mode running on kernel
|
||||
* page tables with our below 4G page identity mapped, but using a temporary
|
||||
* GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not
|
||||
* available. We restore kernel GDT, and rest of the context, and continue
|
||||
* to kexec.
|
||||
*/
|
||||
static asmlinkage void __noreturn hv_crash_c_entry(void)
|
||||
|
||||
static void __noreturn hv_crash_handle(void)
|
||||
{
|
||||
struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
|
||||
|
||||
/* first thing, restore kernel gdt */
|
||||
native_load_gdt(&ctxt->gdtr);
|
||||
|
||||
asm volatile("movw %%ax, %%ss" : : "a"(ctxt->ss));
|
||||
asm volatile("movq %0, %%rsp" : : "m"(ctxt->rsp));
|
||||
|
||||
asm volatile("movw %%ax, %%ds" : : "a"(ctxt->ds));
|
||||
asm volatile("movw %%ax, %%es" : : "a"(ctxt->es));
|
||||
asm volatile("movw %%ax, %%fs" : : "a"(ctxt->fs));
|
||||
asm volatile("movw %%ax, %%gs" : : "a"(ctxt->gs));
|
||||
|
||||
native_wrmsrq(MSR_IA32_CR_PAT, ctxt->pat);
|
||||
asm volatile("movq %0, %%cr0" : : "r"(ctxt->cr0));
|
||||
|
||||
asm volatile("movq %0, %%cr8" : : "r"(ctxt->cr8));
|
||||
asm volatile("movq %0, %%cr4" : : "r"(ctxt->cr4));
|
||||
asm volatile("movq %0, %%cr2" : : "r"(ctxt->cr4));
|
||||
|
||||
native_load_idt(&ctxt->idtr);
|
||||
native_wrmsrq(MSR_GS_BASE, ctxt->gsbase);
|
||||
native_wrmsrq(MSR_EFER, ctxt->efer);
|
||||
|
||||
/* restore the original kernel CS now via far return */
|
||||
asm volatile("movzwq %0, %%rax\n\t"
|
||||
"pushq %%rax\n\t"
|
||||
"pushq $1f\n\t"
|
||||
"lretq\n\t"
|
||||
"1:nop\n\t" : : "m"(ctxt->cs) : "rax");
|
||||
|
||||
/* We are in asmlinkage without stack frame, hence make C function
|
||||
* calls which will buy stack frames.
|
||||
*/
|
||||
hv_crash_restore_tss();
|
||||
hv_crash_clear_kernpt();
|
||||
|
||||
@@ -177,7 +134,54 @@ static asmlinkage void __noreturn hv_crash_c_entry(void)
|
||||
|
||||
hv_panic_timeout_reboot();
|
||||
}
|
||||
/* Tell gcc we are using lretq long jump in the above function intentionally */
|
||||
|
||||
/*
|
||||
* __naked functions do not permit function calls, not even to __always_inline
|
||||
* functions that only contain asm() blocks themselves. So use a macro instead.
|
||||
*/
|
||||
#define hv_wrmsr(msr, val) \
|
||||
asm volatile("wrmsr" :: "c"(msr), "a"((u32)val), "d"((u32)(val >> 32)) : "memory")
|
||||
|
||||
/*
|
||||
* This is the C entry point from the asm glue code after the disable hypercall.
|
||||
* We enter here in IA32-e long mode, ie, full 64bit mode running on kernel
|
||||
* page tables with our below 4G page identity mapped, but using a temporary
|
||||
* GDT. ds/fs/gs/es are null. ss is not usable. bp is null. stack is not
|
||||
* available. We restore kernel GDT, and rest of the context, and continue
|
||||
* to kexec.
|
||||
*/
|
||||
static void __naked hv_crash_c_entry(void)
|
||||
{
|
||||
/* first thing, restore kernel gdt */
|
||||
asm volatile("lgdt %0" : : "m" (hv_crash_ctxt.gdtr));
|
||||
|
||||
asm volatile("movw %0, %%ss\n\t"
|
||||
"movq %1, %%rsp"
|
||||
:: "m"(hv_crash_ctxt.ss), "m"(hv_crash_ctxt.rsp));
|
||||
|
||||
asm volatile("movw %0, %%ds" : : "m"(hv_crash_ctxt.ds));
|
||||
asm volatile("movw %0, %%es" : : "m"(hv_crash_ctxt.es));
|
||||
asm volatile("movw %0, %%fs" : : "m"(hv_crash_ctxt.fs));
|
||||
asm volatile("movw %0, %%gs" : : "m"(hv_crash_ctxt.gs));
|
||||
|
||||
hv_wrmsr(MSR_IA32_CR_PAT, hv_crash_ctxt.pat);
|
||||
asm volatile("movq %0, %%cr0" : : "r"(hv_crash_ctxt.cr0));
|
||||
|
||||
asm volatile("movq %0, %%cr8" : : "r"(hv_crash_ctxt.cr8));
|
||||
asm volatile("movq %0, %%cr4" : : "r"(hv_crash_ctxt.cr4));
|
||||
asm volatile("movq %0, %%cr2" : : "r"(hv_crash_ctxt.cr2));
|
||||
|
||||
asm volatile("lidt %0" : : "m" (hv_crash_ctxt.idtr));
|
||||
hv_wrmsr(MSR_GS_BASE, hv_crash_ctxt.gsbase);
|
||||
hv_wrmsr(MSR_EFER, hv_crash_ctxt.efer);
|
||||
|
||||
/* restore the original kernel CS now via far return */
|
||||
asm volatile("pushq %q0\n\t"
|
||||
"pushq %q1\n\t"
|
||||
"lretq"
|
||||
:: "r"(hv_crash_ctxt.cs), "r"(hv_crash_handle));
|
||||
}
|
||||
/* Tell objtool we are using lretq long jump in the above function intentionally */
|
||||
STACK_FRAME_NON_STANDARD(hv_crash_c_entry);
|
||||
|
||||
static void hv_mark_tss_not_busy(void)
|
||||
@@ -195,20 +199,20 @@ static void hv_hvcrash_ctxt_save(void)
|
||||
{
|
||||
struct hv_crash_ctxt *ctxt = &hv_crash_ctxt;
|
||||
|
||||
asm volatile("movq %%rsp,%0" : "=m"(ctxt->rsp));
|
||||
ctxt->rsp = current_stack_pointer;
|
||||
|
||||
ctxt->cr0 = native_read_cr0();
|
||||
ctxt->cr4 = native_read_cr4();
|
||||
|
||||
asm volatile("movq %%cr2, %0" : "=a"(ctxt->cr2));
|
||||
asm volatile("movq %%cr8, %0" : "=a"(ctxt->cr8));
|
||||
asm volatile("movq %%cr2, %0" : "=r"(ctxt->cr2));
|
||||
asm volatile("movq %%cr8, %0" : "=r"(ctxt->cr8));
|
||||
|
||||
asm volatile("movl %%cs, %%eax" : "=a"(ctxt->cs));
|
||||
asm volatile("movl %%ss, %%eax" : "=a"(ctxt->ss));
|
||||
asm volatile("movl %%ds, %%eax" : "=a"(ctxt->ds));
|
||||
asm volatile("movl %%es, %%eax" : "=a"(ctxt->es));
|
||||
asm volatile("movl %%fs, %%eax" : "=a"(ctxt->fs));
|
||||
asm volatile("movl %%gs, %%eax" : "=a"(ctxt->gs));
|
||||
asm volatile("movw %%cs, %0" : "=m"(ctxt->cs));
|
||||
asm volatile("movw %%ss, %0" : "=m"(ctxt->ss));
|
||||
asm volatile("movw %%ds, %0" : "=m"(ctxt->ds));
|
||||
asm volatile("movw %%es, %0" : "=m"(ctxt->es));
|
||||
asm volatile("movw %%fs, %0" : "=m"(ctxt->fs));
|
||||
asm volatile("movw %%gs, %0" : "=m"(ctxt->gs));
|
||||
|
||||
native_store_gdt(&ctxt->gdtr);
|
||||
store_idt(&ctxt->idtr);
|
||||
|
||||
@@ -496,8 +496,9 @@ static void hv_reserve_irq_vectors(void)
|
||||
test_and_set_bit(HYPERV_DBG_FASTFAIL_VECTOR, system_vectors))
|
||||
BUG();
|
||||
|
||||
pr_info("Hyper-V: reserve vectors: %d %d %d\n", HYPERV_DBG_ASSERT_VECTOR,
|
||||
HYPERV_DBG_SERVICE_VECTOR, HYPERV_DBG_FASTFAIL_VECTOR);
|
||||
pr_info("Hyper-V: reserve vectors: 0x%x 0x%x 0x%x\n",
|
||||
HYPERV_DBG_ASSERT_VECTOR, HYPERV_DBG_SERVICE_VECTOR,
|
||||
HYPERV_DBG_FASTFAIL_VECTOR);
|
||||
}
|
||||
|
||||
static void __init ms_hyperv_init_platform(void)
|
||||
|
||||
@@ -314,15 +314,17 @@ int mshv_region_pin(struct mshv_mem_region *region)
|
||||
ret = pin_user_pages_fast(userspace_addr, nr_pages,
|
||||
FOLL_WRITE | FOLL_LONGTERM,
|
||||
pages);
|
||||
if (ret < 0)
|
||||
if (ret != nr_pages)
|
||||
goto release_pages;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
release_pages:
|
||||
if (ret > 0)
|
||||
done_count += ret;
|
||||
mshv_region_invalidate_pages(region, 0, done_count);
|
||||
return ret;
|
||||
return ret < 0 ? ret : -ENOMEM;
|
||||
}
|
||||
|
||||
static int mshv_region_chunk_unmap(struct mshv_mem_region *region,
|
||||
|
||||
@@ -190,7 +190,6 @@ struct hv_synic_pages {
|
||||
};
|
||||
|
||||
struct mshv_root {
|
||||
struct hv_synic_pages __percpu *synic_pages;
|
||||
spinlock_t pt_ht_lock;
|
||||
DECLARE_HASHTABLE(pt_htable, MSHV_PARTITIONS_HASH_BITS);
|
||||
struct hv_partition_property_vmm_capabilities vmm_caps;
|
||||
@@ -249,8 +248,8 @@ int mshv_register_doorbell(u64 partition_id, doorbell_cb_t doorbell_cb,
|
||||
void mshv_unregister_doorbell(u64 partition_id, int doorbell_portid);
|
||||
|
||||
void mshv_isr(void);
|
||||
int mshv_synic_init(unsigned int cpu);
|
||||
int mshv_synic_cleanup(unsigned int cpu);
|
||||
int mshv_synic_init(struct device *dev);
|
||||
void mshv_synic_exit(void);
|
||||
|
||||
static inline bool mshv_partition_encrypted(struct mshv_partition *partition)
|
||||
{
|
||||
|
||||
@@ -120,7 +120,6 @@ static u16 mshv_passthru_hvcalls[] = {
|
||||
HVCALL_SET_VP_REGISTERS,
|
||||
HVCALL_TRANSLATE_VIRTUAL_ADDRESS,
|
||||
HVCALL_CLEAR_VIRTUAL_INTERRUPT,
|
||||
HVCALL_SCRUB_PARTITION,
|
||||
HVCALL_REGISTER_INTERCEPT_RESULT,
|
||||
HVCALL_ASSERT_VIRTUAL_INTERRUPT,
|
||||
HVCALL_GET_GPA_PAGES_ACCESS_STATES,
|
||||
@@ -1289,7 +1288,7 @@ err_out:
|
||||
*/
|
||||
static long
|
||||
mshv_map_user_memory(struct mshv_partition *partition,
|
||||
struct mshv_user_mem_region mem)
|
||||
struct mshv_user_mem_region *mem)
|
||||
{
|
||||
struct mshv_mem_region *region;
|
||||
struct vm_area_struct *vma;
|
||||
@@ -1297,12 +1296,12 @@ mshv_map_user_memory(struct mshv_partition *partition,
|
||||
ulong mmio_pfn;
|
||||
long ret;
|
||||
|
||||
if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
|
||||
!access_ok((const void __user *)mem.userspace_addr, mem.size))
|
||||
if (mem->flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
|
||||
!access_ok((const void __user *)mem->userspace_addr, mem->size))
|
||||
return -EINVAL;
|
||||
|
||||
mmap_read_lock(current->mm);
|
||||
vma = vma_lookup(current->mm, mem.userspace_addr);
|
||||
vma = vma_lookup(current->mm, mem->userspace_addr);
|
||||
is_mmio = vma ? !!(vma->vm_flags & (VM_IO | VM_PFNMAP)) : 0;
|
||||
mmio_pfn = is_mmio ? vma->vm_pgoff : 0;
|
||||
mmap_read_unlock(current->mm);
|
||||
@@ -1310,7 +1309,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
|
||||
if (!vma)
|
||||
return -EINVAL;
|
||||
|
||||
ret = mshv_partition_create_region(partition, &mem, ®ion,
|
||||
ret = mshv_partition_create_region(partition, mem, ®ion,
|
||||
is_mmio);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1348,32 +1347,32 @@ mshv_map_user_memory(struct mshv_partition *partition,
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
vfree(region);
|
||||
mshv_region_put(region);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Called for unmapping both the guest ram and the mmio space */
|
||||
static long
|
||||
mshv_unmap_user_memory(struct mshv_partition *partition,
|
||||
struct mshv_user_mem_region mem)
|
||||
struct mshv_user_mem_region *mem)
|
||||
{
|
||||
struct mshv_mem_region *region;
|
||||
|
||||
if (!(mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
|
||||
if (!(mem->flags & BIT(MSHV_SET_MEM_BIT_UNMAP)))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&partition->pt_mem_regions_lock);
|
||||
|
||||
region = mshv_partition_region_by_gfn(partition, mem.guest_pfn);
|
||||
region = mshv_partition_region_by_gfn(partition, mem->guest_pfn);
|
||||
if (!region) {
|
||||
spin_unlock(&partition->pt_mem_regions_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Paranoia check */
|
||||
if (region->start_uaddr != mem.userspace_addr ||
|
||||
region->start_gfn != mem.guest_pfn ||
|
||||
region->nr_pages != HVPFN_DOWN(mem.size)) {
|
||||
if (region->start_uaddr != mem->userspace_addr ||
|
||||
region->start_gfn != mem->guest_pfn ||
|
||||
region->nr_pages != HVPFN_DOWN(mem->size)) {
|
||||
spin_unlock(&partition->pt_mem_regions_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1404,9 +1403,9 @@ mshv_partition_ioctl_set_memory(struct mshv_partition *partition,
|
||||
return -EINVAL;
|
||||
|
||||
if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP))
|
||||
return mshv_unmap_user_memory(partition, mem);
|
||||
return mshv_unmap_user_memory(partition, &mem);
|
||||
|
||||
return mshv_map_user_memory(partition, mem);
|
||||
return mshv_map_user_memory(partition, &mem);
|
||||
}
|
||||
|
||||
static long
|
||||
@@ -2064,7 +2063,6 @@ mshv_dev_release(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mshv_cpuhp_online;
|
||||
static int mshv_root_sched_online;
|
||||
|
||||
static const char *scheduler_type_to_string(enum hv_scheduler_type type)
|
||||
@@ -2249,27 +2247,6 @@ root_scheduler_deinit(void)
|
||||
free_percpu(root_scheduler_output);
|
||||
}
|
||||
|
||||
static int mshv_reboot_notify(struct notifier_block *nb,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
cpuhp_remove_state(mshv_cpuhp_online);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct notifier_block mshv_reboot_nb = {
|
||||
.notifier_call = mshv_reboot_notify,
|
||||
};
|
||||
|
||||
static void mshv_root_partition_exit(void)
|
||||
{
|
||||
unregister_reboot_notifier(&mshv_reboot_nb);
|
||||
}
|
||||
|
||||
static int __init mshv_root_partition_init(struct device *dev)
|
||||
{
|
||||
return register_reboot_notifier(&mshv_reboot_nb);
|
||||
}
|
||||
|
||||
static int __init mshv_init_vmm_caps(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
@@ -2314,39 +2291,21 @@ static int __init mshv_parent_partition_init(void)
|
||||
MSHV_HV_MAX_VERSION);
|
||||
}
|
||||
|
||||
mshv_root.synic_pages = alloc_percpu(struct hv_synic_pages);
|
||||
if (!mshv_root.synic_pages) {
|
||||
dev_err(dev, "Failed to allocate percpu synic page\n");
|
||||
ret = -ENOMEM;
|
||||
ret = mshv_synic_init(dev);
|
||||
if (ret)
|
||||
goto device_deregister;
|
||||
}
|
||||
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
|
||||
mshv_synic_init,
|
||||
mshv_synic_cleanup);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
|
||||
goto free_synic_pages;
|
||||
}
|
||||
|
||||
mshv_cpuhp_online = ret;
|
||||
|
||||
ret = mshv_init_vmm_caps(dev);
|
||||
if (ret)
|
||||
goto remove_cpu_state;
|
||||
goto synic_cleanup;
|
||||
|
||||
ret = mshv_retrieve_scheduler_type(dev);
|
||||
if (ret)
|
||||
goto remove_cpu_state;
|
||||
|
||||
if (hv_root_partition())
|
||||
ret = mshv_root_partition_init(dev);
|
||||
if (ret)
|
||||
goto remove_cpu_state;
|
||||
goto synic_cleanup;
|
||||
|
||||
ret = root_scheduler_init(dev);
|
||||
if (ret)
|
||||
goto exit_partition;
|
||||
goto synic_cleanup;
|
||||
|
||||
ret = mshv_debugfs_init();
|
||||
if (ret)
|
||||
@@ -2367,13 +2326,8 @@ exit_debugfs:
|
||||
mshv_debugfs_exit();
|
||||
deinit_root_scheduler:
|
||||
root_scheduler_deinit();
|
||||
exit_partition:
|
||||
if (hv_root_partition())
|
||||
mshv_root_partition_exit();
|
||||
remove_cpu_state:
|
||||
cpuhp_remove_state(mshv_cpuhp_online);
|
||||
free_synic_pages:
|
||||
free_percpu(mshv_root.synic_pages);
|
||||
synic_cleanup:
|
||||
mshv_synic_exit();
|
||||
device_deregister:
|
||||
misc_deregister(&mshv_dev);
|
||||
return ret;
|
||||
@@ -2387,10 +2341,7 @@ static void __exit mshv_parent_partition_exit(void)
|
||||
misc_deregister(&mshv_dev);
|
||||
mshv_irqfd_wq_cleanup();
|
||||
root_scheduler_deinit();
|
||||
if (hv_root_partition())
|
||||
mshv_root_partition_exit();
|
||||
cpuhp_remove_state(mshv_cpuhp_online);
|
||||
free_percpu(mshv_root.synic_pages);
|
||||
mshv_synic_exit();
|
||||
}
|
||||
|
||||
module_init(mshv_parent_partition_init);
|
||||
|
||||
@@ -10,13 +10,22 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/mshyperv.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "mshv_eventfd.h"
|
||||
#include "mshv.h"
|
||||
|
||||
static int synic_cpuhp_online;
|
||||
static struct hv_synic_pages __percpu *synic_pages;
|
||||
static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */
|
||||
static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */
|
||||
|
||||
static u32 synic_event_ring_get_queued_port(u32 sint_index)
|
||||
{
|
||||
struct hv_synic_event_ring_page **event_ring_page;
|
||||
@@ -26,7 +35,7 @@ static u32 synic_event_ring_get_queued_port(u32 sint_index)
|
||||
u32 message;
|
||||
u8 tail;
|
||||
|
||||
spages = this_cpu_ptr(mshv_root.synic_pages);
|
||||
spages = this_cpu_ptr(synic_pages);
|
||||
event_ring_page = &spages->synic_event_ring_page;
|
||||
synic_eventring_tail = (u8 **)this_cpu_ptr(hv_synic_eventring_tail);
|
||||
|
||||
@@ -393,7 +402,7 @@ unlock_out:
|
||||
|
||||
void mshv_isr(void)
|
||||
{
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
|
||||
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
|
||||
struct hv_message *msg;
|
||||
bool handled;
|
||||
@@ -437,25 +446,21 @@ void mshv_isr(void)
|
||||
if (msg->header.message_flags.msg_pending)
|
||||
hv_set_non_nested_msr(HV_MSR_EOM, 0);
|
||||
|
||||
#ifdef HYPERVISOR_CALLBACK_VECTOR
|
||||
add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR);
|
||||
#endif
|
||||
add_interrupt_randomness(mshv_sint_vector);
|
||||
} else {
|
||||
pr_warn_once("%s: unknown message type 0x%x\n", __func__,
|
||||
msg->header.message_type);
|
||||
}
|
||||
}
|
||||
|
||||
int mshv_synic_init(unsigned int cpu)
|
||||
static int mshv_synic_cpu_init(unsigned int cpu)
|
||||
{
|
||||
union hv_synic_simp simp;
|
||||
union hv_synic_siefp siefp;
|
||||
union hv_synic_sirbp sirbp;
|
||||
#ifdef HYPERVISOR_CALLBACK_VECTOR
|
||||
union hv_synic_sint sint;
|
||||
#endif
|
||||
union hv_synic_scontrol sctrl;
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
|
||||
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
|
||||
struct hv_synic_event_flags_page **event_flags_page =
|
||||
&spages->synic_event_flags_page;
|
||||
@@ -496,10 +501,12 @@ int mshv_synic_init(unsigned int cpu)
|
||||
|
||||
hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64);
|
||||
|
||||
#ifdef HYPERVISOR_CALLBACK_VECTOR
|
||||
if (mshv_sint_irq != -1)
|
||||
enable_percpu_irq(mshv_sint_irq, 0);
|
||||
|
||||
/* Enable intercepts */
|
||||
sint.as_uint64 = 0;
|
||||
sint.vector = HYPERVISOR_CALLBACK_VECTOR;
|
||||
sint.vector = mshv_sint_vector;
|
||||
sint.masked = false;
|
||||
sint.auto_eoi = hv_recommend_using_aeoi();
|
||||
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX,
|
||||
@@ -507,13 +514,12 @@ int mshv_synic_init(unsigned int cpu)
|
||||
|
||||
/* Doorbell SINT */
|
||||
sint.as_uint64 = 0;
|
||||
sint.vector = HYPERVISOR_CALLBACK_VECTOR;
|
||||
sint.vector = mshv_sint_vector;
|
||||
sint.masked = false;
|
||||
sint.as_intercept = 1;
|
||||
sint.auto_eoi = hv_recommend_using_aeoi();
|
||||
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
|
||||
sint.as_uint64);
|
||||
#endif
|
||||
|
||||
/* Enable global synic bit */
|
||||
sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL);
|
||||
@@ -542,14 +548,14 @@ cleanup:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int mshv_synic_cleanup(unsigned int cpu)
|
||||
static int mshv_synic_cpu_exit(unsigned int cpu)
|
||||
{
|
||||
union hv_synic_sint sint;
|
||||
union hv_synic_simp simp;
|
||||
union hv_synic_siefp siefp;
|
||||
union hv_synic_sirbp sirbp;
|
||||
union hv_synic_scontrol sctrl;
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(mshv_root.synic_pages);
|
||||
struct hv_synic_pages *spages = this_cpu_ptr(synic_pages);
|
||||
struct hv_message_page **msg_page = &spages->hyp_synic_message_page;
|
||||
struct hv_synic_event_flags_page **event_flags_page =
|
||||
&spages->synic_event_flags_page;
|
||||
@@ -568,6 +574,9 @@ int mshv_synic_cleanup(unsigned int cpu)
|
||||
hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX,
|
||||
sint.as_uint64);
|
||||
|
||||
if (mshv_sint_irq != -1)
|
||||
disable_percpu_irq(mshv_sint_irq);
|
||||
|
||||
/* Disable Synic's event ring page */
|
||||
sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP);
|
||||
sirbp.sirbp_enabled = false;
|
||||
@@ -663,3 +672,152 @@ mshv_unregister_doorbell(u64 partition_id, int doorbell_portid)
|
||||
|
||||
mshv_portid_free(doorbell_portid);
|
||||
}
|
||||
|
||||
static int mshv_synic_reboot_notify(struct notifier_block *nb,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
if (!hv_root_partition())
|
||||
return 0;
|
||||
|
||||
cpuhp_remove_state(synic_cpuhp_online);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block mshv_synic_reboot_nb = {
|
||||
.notifier_call = mshv_synic_reboot_notify,
|
||||
};
|
||||
|
||||
#ifndef HYPERVISOR_CALLBACK_VECTOR
|
||||
static DEFINE_PER_CPU(long, mshv_evt);
|
||||
|
||||
static irqreturn_t mshv_percpu_isr(int irq, void *dev_id)
|
||||
{
|
||||
mshv_isr();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static int __init mshv_acpi_setup_sint_irq(void)
|
||||
{
|
||||
return acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE,
|
||||
ACPI_ACTIVE_HIGH);
|
||||
}
|
||||
|
||||
static void mshv_acpi_cleanup_sint_irq(void)
|
||||
{
|
||||
acpi_unregister_gsi(mshv_sint_vector);
|
||||
}
|
||||
#else
|
||||
static int __init mshv_acpi_setup_sint_irq(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void mshv_acpi_cleanup_sint_irq(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init mshv_sint_vector_setup(void)
|
||||
{
|
||||
int ret;
|
||||
struct hv_register_assoc reg = {
|
||||
.name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID,
|
||||
};
|
||||
union hv_input_vtl input_vtl = { 0 };
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
|
||||
1, input_vtl, ®);
|
||||
if (ret || !reg.value.reg64)
|
||||
return -ENODEV;
|
||||
|
||||
mshv_sint_vector = reg.value.reg64;
|
||||
ret = mshv_acpi_setup_sint_irq();
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to setup IRQ for MSHV SINT vector %d: %d\n",
|
||||
mshv_sint_vector, ret);
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
mshv_sint_irq = ret;
|
||||
|
||||
ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV",
|
||||
&mshv_evt);
|
||||
if (ret)
|
||||
goto out_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
out_unregister:
|
||||
mshv_acpi_cleanup_sint_irq();
|
||||
out_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mshv_sint_vector_cleanup(void)
|
||||
{
|
||||
free_percpu_irq(mshv_sint_irq, &mshv_evt);
|
||||
mshv_acpi_cleanup_sint_irq();
|
||||
}
|
||||
#else /* !HYPERVISOR_CALLBACK_VECTOR */
|
||||
static int __init mshv_sint_vector_setup(void)
|
||||
{
|
||||
mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mshv_sint_vector_cleanup(void)
|
||||
{
|
||||
}
|
||||
#endif /* HYPERVISOR_CALLBACK_VECTOR */
|
||||
|
||||
int __init mshv_synic_init(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = mshv_sint_vector_setup();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
synic_pages = alloc_percpu(struct hv_synic_pages);
|
||||
if (!synic_pages) {
|
||||
dev_err(dev, "Failed to allocate percpu synic page\n");
|
||||
ret = -ENOMEM;
|
||||
goto sint_vector_cleanup;
|
||||
}
|
||||
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic",
|
||||
mshv_synic_cpu_init,
|
||||
mshv_synic_cpu_exit);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to setup cpu hotplug state: %i\n", ret);
|
||||
goto free_synic_pages;
|
||||
}
|
||||
|
||||
synic_cpuhp_online = ret;
|
||||
|
||||
ret = register_reboot_notifier(&mshv_synic_reboot_nb);
|
||||
if (ret)
|
||||
goto remove_cpuhp_state;
|
||||
|
||||
return 0;
|
||||
|
||||
remove_cpuhp_state:
|
||||
cpuhp_remove_state(synic_cpuhp_online);
|
||||
free_synic_pages:
|
||||
free_percpu(synic_pages);
|
||||
sint_vector_cleanup:
|
||||
mshv_sint_vector_cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mshv_synic_exit(void)
|
||||
{
|
||||
unregister_reboot_notifier(&mshv_synic_reboot_nb);
|
||||
cpuhp_remove_state(synic_cpuhp_online);
|
||||
free_percpu(synic_pages);
|
||||
mshv_sint_vector_cleanup();
|
||||
}
|
||||
|
||||
@@ -477,7 +477,6 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
|
||||
#define HVCALL_NOTIFY_PARTITION_EVENT 0x0087
|
||||
#define HVCALL_ENTER_SLEEP_STATE 0x0084
|
||||
#define HVCALL_NOTIFY_PORT_RING_EMPTY 0x008b
|
||||
#define HVCALL_SCRUB_PARTITION 0x008d
|
||||
#define HVCALL_REGISTER_INTERCEPT_RESULT 0x0091
|
||||
#define HVCALL_ASSERT_VIRTUAL_INTERRUPT 0x0094
|
||||
#define HVCALL_CREATE_PORT 0x0095
|
||||
@@ -1121,6 +1120,8 @@ enum hv_register_name {
|
||||
HV_X64_REGISTER_MSR_MTRR_FIX4KF8000 = 0x0008007A,
|
||||
|
||||
HV_X64_REGISTER_REG_PAGE = 0x0009001C,
|
||||
#elif defined(CONFIG_ARM64)
|
||||
HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID = 0x00070001,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user