162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/types.h>
362306a36Sopenharmony_ci#include <linux/crash_dump.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <xen/interface/xen.h>
662306a36Sopenharmony_ci#include <xen/hvm.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "mmu.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifdef CONFIG_PROC_VMCORE
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * The kdump kernel has to check whether a pfn of the crashed kernel
1362306a36Sopenharmony_ci * was a ballooned page. vmcore is using this function to decide
1462306a36Sopenharmony_ci * whether to access a pfn of the crashed kernel.
1562306a36Sopenharmony_ci * Returns "false" if the pfn is not backed by a RAM page, the caller may
1662306a36Sopenharmony_ci * handle the pfn special in this case.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_cistatic bool xen_vmcore_pfn_is_ram(struct vmcore_cb *cb, unsigned long pfn)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct xen_hvm_get_mem_type a = {
2162306a36Sopenharmony_ci		.domid = DOMID_SELF,
2262306a36Sopenharmony_ci		.pfn = pfn,
2362306a36Sopenharmony_ci	};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (HYPERVISOR_hvm_op(HVMOP_get_mem_type, &a)) {
2662306a36Sopenharmony_ci		pr_warn_once("Unexpected HVMOP_get_mem_type failure\n");
2762306a36Sopenharmony_ci		return true;
2862306a36Sopenharmony_ci	}
2962306a36Sopenharmony_ci	return a.mem_type != HVMMEM_mmio_dm;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_cistatic struct vmcore_cb xen_vmcore_cb = {
3262306a36Sopenharmony_ci	.pfn_is_ram = xen_vmcore_pfn_is_ram,
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci#endif
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void xen_hvm_exit_mmap(struct mm_struct *mm)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct xen_hvm_pagetable_dying a;
3962306a36Sopenharmony_ci	int rc;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	a.domid = DOMID_SELF;
4262306a36Sopenharmony_ci	a.gpa = __pa(mm->pgd);
4362306a36Sopenharmony_ci	rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a);
4462306a36Sopenharmony_ci	WARN_ON_ONCE(rc < 0);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int is_pagetable_dying_supported(void)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct xen_hvm_pagetable_dying a;
5062306a36Sopenharmony_ci	int rc = 0;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	a.domid = DOMID_SELF;
5362306a36Sopenharmony_ci	a.gpa = 0x00;
5462306a36Sopenharmony_ci	rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a);
5562306a36Sopenharmony_ci	if (rc < 0) {
5662306a36Sopenharmony_ci		printk(KERN_DEBUG "HVMOP_pagetable_dying not supported\n");
5762306a36Sopenharmony_ci		return 0;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci	return 1;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_civoid __init xen_hvm_init_mmu_ops(void)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	if (is_pagetable_dying_supported())
6562306a36Sopenharmony_ci		pv_ops.mmu.exit_mmap = xen_hvm_exit_mmap;
6662306a36Sopenharmony_ci#ifdef CONFIG_PROC_VMCORE
6762306a36Sopenharmony_ci	register_vmcore_cb(&xen_vmcore_cb);
6862306a36Sopenharmony_ci#endif
6962306a36Sopenharmony_ci}
70