Commit 1ecccb6a authored by Lu Feifei's avatar Lu Feifei Committed by guzitao
Browse files

sw64: kvm: delete kvm_sw64_ops structure

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I56OLG



--------------------------------

Because the current code cannot be binary compatible with CORE3 and
CORE4, in order to improve the readability of the code, struct
kvm_sw64_ops is deleted, and the same function is implemented as a
different code process under different subarch.

Signed-off-by: default avatarLu Feifei <lufeifei@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent 7f95a300
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -14,11 +14,9 @@
#define SW64_KVM_EXIT_RESTART		17
#define SW64_KVM_EXIT_APT_FAULT		18
#define SW64_KVM_EXIT_FATAL_ERROR	22
#define SW64_KVM_EXIT_MEMHOTPLUG	23
#define SW64_KVM_EXIT_DEBUG		24

#ifdef CONFIG_KVM_MEMHOTPLUG
#define SW64_KVM_EXIT_MEMHOTPLUG	23
#endif

#define kvm_sw64_exception_type	\
	{0, "HOST_INTR" },	\
+12 −22
Original line number Diff line number Diff line
@@ -32,10 +32,12 @@

#ifdef CONFIG_SUBARCH_C3B
#define VPN_BITS	8
#define GUEST_RESET_PC          0xffffffff80011100
#endif

#ifdef CONFIG_SUBARCH_C4
#define VPN_BITS	10
#define GUEST_RESET_PC          0xfff0000000011002
#endif

#define VPN_FIRST_VERSION	(1UL << VPN_BITS)
@@ -79,27 +81,6 @@ struct kvm_arch {
	pgd_t *pgd;
};

struct kvm_sw64_ops {
	unsigned long (*get_new_vpn_context)(struct kvm_vcpu *vcpu, long cpu);
	void (*update_vpn)(struct kvm_vcpu *vcpu, unsigned long vpn);
	int (*init_vm)(struct kvm *kvm);
	void (*destroy_vm)(struct kvm *kvm);
	int (*prepare_memory_region)(struct kvm *kvm, struct kvm_memory_slot *memslot,
			const struct kvm_userspace_memory_region *mem, enum kvm_mr_change change);
	void (*mmu_enable_log_dirty_pt_masked)(struct kvm *kvm, struct kvm_memory_slot *slot,
			gfn_t gfn_offset, unsigned long mask);
	void (*commit_memory_region)(struct kvm *kvm, const struct kvm_userspace_memory_region *mem,
			const struct kvm_memory_slot *old, const struct kvm_memory_slot *new,
			enum kvm_mr_change change);
	void (*flush_shadow_memslot)(struct kvm *kvm, struct kvm_memory_slot *slot);
	void (*flush_shadow_all)(struct kvm *kvm);
	int (*vcpu_reset)(struct kvm_vcpu *vcpu);
	int (*vcpu_run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
	void (*vcpu_free)(struct kvm_vcpu *vcpu);
	long (*get_vcb)(struct file *filp, unsigned long arg);
	long (*set_vcb)(struct file *filp, unsigned long arg);
};

#define KVM_NR_MEM_OBJS		40

/*
@@ -230,5 +211,14 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu);

int kvm_sw64_perf_init(void);
int kvm_sw64_perf_teardown(void);

void kvm_flush_tlb_all(void);
void kvm_sw64_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn);
int kvm_sw64_init_vm(struct kvm *kvm);
void kvm_sw64_destroy_vm(struct kvm *kvm);
int kvm_sw64_vcpu_reset(struct kvm_vcpu *vcpu);
long kvm_sw64_set_vcb(struct file *filp, unsigned long arg);
long kvm_sw64_get_vcb(struct file *filp, unsigned long arg);

void update_aptp(unsigned long);
void vcpu_set_numa_affinity(struct kvm_vcpu *vcpu);
#endif /* _ASM_SW64_KVM_HOST_H */
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ config KVM

config KVM_MEMHOTPLUG
	bool "Memory hotplug support for guest"
	depends on KVM && MEMORY_HOTPLUG
	depends on KVM && MEMORY_HOTPLUG && SUBARCH_C3B
	help
	  Provides memory hotplug support for SW64 guest.

+63 −157
Original line number Diff line number Diff line
@@ -56,43 +56,58 @@ static void bind_vcpu_exit(void) { }

#endif

#define GUEST_RESET_PC		0xffffffff80011100

static unsigned long longtime_offset;

#ifdef CONFIG_KVM_MEMHOTPLUG
static u64 get_vpcr_memhp(u64 seg_base, u64 vpn)
static unsigned long get_vpcr(struct kvm_vcpu *vcpu, u64 vpn)
{
	return seg_base | ((vpn & VPN_MASK) << 44);
	unsigned long base;

	base = virt_to_phys(vcpu->kvm->arch.seg_pgd);
	return base | ((vpn & VPN_MASK) << 44);
}
#else
static u64 get_vpcr(u64 hpa_base, u64 mem_size, u64 vpn)
static unsigned long get_vpcr(struct kvm_vcpu *vcpu, u64 vpn)
{
	return (hpa_base >> 23) | ((mem_size >> 23) << 16)
		| ((vpn & VPN_MASK) << 44);
	unsigned long base, size;

	base = vcpu->kvm->arch.host_phys_addr;
	size = vcpu->kvm->arch.size;
	return (base >> 23) | ((size >> 23) << 16) | ((vpn & VPN_MASK) << 44);
}
#endif

static unsigned long core3_get_new_vpn_context(struct kvm_vcpu *vcpu, long cpu)
void vcpu_set_numa_affinity(struct kvm_vcpu *vcpu)
{
	unsigned long vpn = last_vpn(cpu);
	unsigned long next = vpn + 1;
	if (vcpu->arch.vcb.vpcr == 0) {
		vcpu->arch.vcb.vpcr = get_vpcr(vcpu, 0);
#ifndef CONFIG_KVM_MEMHOTPLUG
		if (unlikely(bind_vcpu_enabled)) {
			int nid;
			unsigned long end;

	if ((vpn & VPN_MASK) >= VPN_MASK) {
		tbia();
		next = (vpn & ~VPN_MASK) + VPN_FIRST_VERSION + 1; /* bypass 0 */
			end = vcpu->kvm->arch.host_phys_addr + vcpu->kvm->arch.size;
			nid = pfn_to_nid(PHYS_PFN(vcpu->kvm->arch.host_phys_addr));
			if (pfn_to_nid(PHYS_PFN(end)) == nid)
				set_cpus_allowed_ptr(vcpu->arch.tsk, cpumask_of_node(nid));
		}
#endif
		vcpu->arch.vcb.upcr = 0x7;
	}
	last_vpn(cpu) = next;
	return next;
}

static void core3_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn)
void kvm_flush_tlb_all(void)
{
	tbia();
}

void kvm_sw64_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn)
{
	vcpu->arch.vcb.vpcr = ((vcpu->arch.vcb.vpcr) & (~(VPN_MASK << 44))) | (vpn << 44);
	vcpu->arch.vcb.dtb_vpcr = ((vcpu->arch.vcb.dtb_vpcr) & (~(VPN_MASK << VPN_SHIFT))) | (vpn << VPN_SHIFT);
}

int kvm_core3_init_vm(struct kvm *kvm)
int kvm_sw64_init_vm(struct kvm *kvm)
{
#ifdef CONFIG_KVM_MEMHOTPLUG
	unsigned long *seg_pgd;
@@ -111,7 +126,7 @@ int kvm_core3_init_vm(struct kvm *kvm)
	return 0;
}

void kvm_core3_destroy_vm(struct kvm *kvm)
void kvm_sw64_destroy_vm(struct kvm *kvm)
{
	int i;
 #ifdef CONFIG_KVM_MEMHOTPLUG
@@ -150,7 +165,7 @@ static void setup_segment_table(struct kvm *kvm,
}
#endif

int kvm_core3_prepare_memory_region(struct kvm *kvm,
int kvm_arch_prepare_memory_region(struct kvm *kvm,
		struct kvm_memory_slot *memslot,
		const struct kvm_userspace_memory_region *mem,
		enum kvm_mr_change change)
@@ -259,9 +274,9 @@ void kvm_mark_migration(struct kvm *kvm, int mark)
	kvm_flush_remote_tlbs(kvm);
}

void kvm_core3_commit_memory_region(struct kvm *kvm,
void kvm_arch_commit_memory_region(struct kvm *kvm,
		const struct kvm_userspace_memory_region *mem,
		const struct kvm_memory_slot *old,
		struct kvm_memory_slot *old,
		const struct kvm_memory_slot *new,
		enum kvm_mr_change change)
{
@@ -284,7 +299,7 @@ void kvm_core3_commit_memory_region(struct kvm *kvm,
		kvm_mark_migration(kvm, 1);
}

int kvm_core3_vcpu_reset(struct kvm_vcpu *vcpu)
int kvm_sw64_vcpu_reset(struct kvm_vcpu *vcpu)
{
	unsigned long addr = vcpu->kvm->arch.host_phys_addr;

@@ -301,124 +316,7 @@ int kvm_core3_vcpu_reset(struct kvm_vcpu *vcpu)
	return 0;
}

/*
 * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
 * proper exit to userspace.
 */
int kvm_core3_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
	int ret;
	struct vcpucb *vcb = &(vcpu->arch.vcb);
	struct hcall_args hargs;
	int irq;
	bool more;
	sigset_t sigsaved;

	/* Set guest vcb */
	/* vpn will update later when vcpu is running */
	if (vcpu->arch.vcb.vpcr == 0) {
#ifndef CONFIG_KVM_MEMHOTPLUG
		vcpu->arch.vcb.vpcr
			= get_vpcr(vcpu->kvm->arch.host_phys_addr, vcpu->kvm->arch.size, 0);
		if (unlikely(bind_vcpu_enabled)) {
			int nid;
			unsigned long end;

			end = vcpu->kvm->arch.host_phys_addr + vcpu->kvm->arch.size;
			nid = pfn_to_nid(PHYS_PFN(vcpu->kvm->arch.host_phys_addr));
			if (pfn_to_nid(PHYS_PFN(end)) == nid)
				set_cpus_allowed_ptr(vcpu->arch.tsk, cpumask_of_node(nid));
		}
#else /* !CONFIG_KVM_MEMHOTPLUG */
		unsigned long seg_base = virt_to_phys(vcpu->kvm->arch.seg_pgd);

		vcpu->arch.vcb.vpcr = get_vpcr_memhp(seg_base, 0);
#endif /* CONFIG_KVM_MEMHOTPLUG */
		vcpu->arch.vcb.upcr = 0x7;
	}

#ifdef CONFIG_PERF_EVENTS
	vcpu_load(vcpu);
#endif
	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);

	if (run->exit_reason == KVM_EXIT_MMIO)
		kvm_handle_mmio_return(vcpu, run);

	run->exit_reason = KVM_EXIT_UNKNOWN;
	ret = 1;
	while (ret > 0) {
		/* Check conditions before entering the guest */
		cond_resched();

		preempt_disable();
		local_irq_disable();

		if (signal_pending(current)) {
			ret = -EINTR;
			run->exit_reason = KVM_EXIT_INTR;
			vcpu->stat.signal_exits++;
		}

		if (ret <= 0) {
			local_irq_enable();
			preempt_enable();
			continue;
		}

		memset(&hargs, 0, sizeof(hargs));

		clear_vcpu_irq(vcpu);

		if (vcpu->arch.restart == 1) {
			/* handle reset vCPU */
			vcpu->arch.regs.pc = GUEST_RESET_PC;
			vcpu->arch.restart = 0;
		}

		irq = interrupt_pending(vcpu, &more);
		if (irq < SWVM_IRQS)
			try_deliver_interrupt(vcpu, irq, more);

		vcpu->arch.halted = 0;

		sw64_kvm_switch_vpn(vcpu);
		check_vcpu_requests(vcpu);
		guest_enter_irqoff();

		/* Enter the guest */
		trace_kvm_sw64_entry(vcpu->vcpu_id, vcpu->arch.regs.pc);
		vcpu->mode = IN_GUEST_MODE;

		ret = __sw64_vcpu_run(__pa(vcb), &(vcpu->arch.regs), &hargs);

		/* Back from guest */
		vcpu->mode = OUTSIDE_GUEST_MODE;

		vcpu->stat.exits++;
		local_irq_enable();
		guest_exit_irqoff();

		trace_kvm_sw64_exit(ret, vcpu->arch.regs.pc);

		preempt_enable();

		/* ret = 0 indicate interrupt in guest mode, ret > 0 indicate hcall */
		ret = handle_exit(vcpu, run, ret, &hargs);
		update_vcpu_stat_time(&vcpu->stat);
	}

	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &sigsaved, NULL);

#ifdef CONFIG_PERF_EVENTS
	vcpu_put(vcpu);
#endif
	return ret;
}

static long kvm_core3_get_vcb(struct file *filp, unsigned long arg)
long kvm_sw64_get_vcb(struct file *filp, unsigned long arg)
{
	struct kvm_vcpu *vcpu = filp->private_data;

@@ -435,7 +333,7 @@ static long kvm_core3_get_vcb(struct file *filp, unsigned long arg)
	return 0;
}

static long kvm_core3_set_vcb(struct file *filp, unsigned long arg)
long kvm_sw64_set_vcb(struct file *filp, unsigned long arg)
{
	unsigned long result;
	struct kvm_vcpu *vcpu = filp->private_data;
@@ -446,9 +344,7 @@ static long kvm_core3_set_vcb(struct file *filp, unsigned long arg)

	if (vcpu->arch.vcb.migration_mark) {
		/* updated vpcr needed by destination vm */
		vcpu->arch.vcb.vpcr
			= get_vpcr(vcpu->kvm->arch.host_phys_addr, vcpu->kvm->arch.size, 0);

		vcpu->arch.vcb.vpcr = get_vpcr(vcpu, 0);
		/* synchronize the longtime of source and destination */
		if (vcpu->arch.vcb.soft_cid == 0) {
			result = sw64_io_read(0, LONG_TIME);
@@ -488,18 +384,28 @@ void vcpu_mem_hotplug(struct kvm_vcpu *vcpu, unsigned long start_addr)
}
#endif

static struct kvm_sw64_ops core3_sw64_ops __ro_after_init = {
	.get_new_vpn_context = core3_get_new_vpn_context,
	.update_vpn = core3_update_vpn,
	.init_vm = kvm_core3_init_vm,
	.destroy_vm = kvm_core3_destroy_vm,
	.prepare_memory_region = kvm_core3_prepare_memory_region,
	.commit_memory_region = kvm_core3_commit_memory_region,
	.vcpu_reset = kvm_core3_vcpu_reset,
	.vcpu_run = kvm_core3_vcpu_ioctl_run,
	.get_vcb = kvm_core3_get_vcb,
	.set_vcb = kvm_core3_set_vcb,
};
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
}

void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
		struct kvm_memory_slot *slot, gfn_t gfn_offset,
		unsigned long mask)
{
}

void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
				   struct kvm_memory_slot *slot)
{
}

void kvm_arch_flush_shadow_all(struct kvm *kvm)
{
}

void update_aptp(unsigned long pgd)
{
}

static int __init kvm_core3_init(void)
{
@@ -514,7 +420,7 @@ static int __init kvm_core3_init(void)
	for (i = 0; i < NR_CPUS; i++)
		last_vpn(i) = VPN_FIRST_VERSION;

	ret = kvm_init(&core3_sw64_ops, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);

	if (likely(!ret))
		return 0;
+27 −137
Original line number Diff line number Diff line
@@ -21,34 +21,31 @@

#include "../kernel/pci_impl.h"

#define GUEST_RESET_PC		0xfff0000000011002
static unsigned long shtclock_offset;

static unsigned long core4_get_new_vpn_context(struct kvm_vcpu *vcpu, long cpu)
void update_aptp(unsigned long pgd)
{
	unsigned long vpn = last_vpn(cpu);
	unsigned long next = vpn + 1;

	if ((vpn & VPN_MASK) >= VPN_MASK) {
		tbivpn(-1, 0, 0);
		next = (vpn & ~VPN_MASK) + VPN_FIRST_VERSION + 1; /* bypass 0 */
	}
	last_vpn(cpu) = next;
	return next;
	imemb();
	write_csr_imb(pgd, CSR_APTP);
}

static void core4_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn)
void kvm_sw64_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn)
{
	vcpu->arch.vcb.vpcr = vpn << 44;
	vcpu->arch.vcb.dtb_vpcr = vpn;
}

int kvm_core4_init_vm(struct kvm *kvm)
void kvm_flush_tlb_all(void)
{
	tbivpn(-1, 0, 0);
}

int kvm_sw64_init_vm(struct kvm *kvm)
{
	return kvm_alloc_addtional_stage_pgd(kvm);
}

void kvm_core4_destroy_vm(struct kvm *kvm)
void kvm_sw64_destroy_vm(struct kvm *kvm)
{
	int i;

@@ -61,7 +58,7 @@ void kvm_core4_destroy_vm(struct kvm *kvm)
	atomic_set(&kvm->online_vcpus, 0);
}

int kvm_core4_vcpu_reset(struct kvm_vcpu *vcpu)
int kvm_sw64_vcpu_reset(struct kvm_vcpu *vcpu)
{
	if (vcpu->arch.has_run_once)
		apt_unmap_vm(vcpu->kvm);
@@ -76,112 +73,7 @@ int kvm_core4_vcpu_reset(struct kvm_vcpu *vcpu)
	return 0;
}

/*
 * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
 * proper exit to userspace.
 */
int kvm_core4_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
	int ret;
	struct vcpucb *vcb = &(vcpu->arch.vcb);
	struct hcall_args hargs;
	int irq;
	bool more;
	sigset_t sigsaved;

#ifdef CONFIG_PERF_EVENTS
	vcpu_load(vcpu);
#endif
	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);

	if (run->exit_reason == KVM_EXIT_MMIO)
		kvm_handle_mmio_return(vcpu, run);

	run->exit_reason = KVM_EXIT_UNKNOWN;
	ret = 1;
	while (ret > 0) {
		/*
		 * Check conditions before entering the guest
		 */
		cond_resched();

		preempt_disable();
		local_irq_disable();

		if (signal_pending(current)) {
			ret = -EINTR;
			run->exit_reason = KVM_EXIT_INTR;
			vcpu->stat.signal_exits++;
		}

		if (ret <= 0) {
			local_irq_enable();
			preempt_enable();
			continue;
		}

		memset(&hargs, 0, sizeof(hargs));

		clear_vcpu_irq(vcpu);

		if (vcpu->arch.restart == 1) {
			/* handle reset vCPU */
			vcpu->arch.regs.pc = GUEST_RESET_PC;
			vcpu->arch.restart = 0;
		}

		irq = interrupt_pending(vcpu, &more);
		if (irq < SWVM_IRQS)
			try_deliver_interrupt(vcpu, irq, more);

		vcpu->arch.halted = 0;

		sw64_kvm_switch_vpn(vcpu);
		check_vcpu_requests(vcpu);
		guest_enter_irqoff();

		/* update aptp before the guest runs */
		imemb();
		write_csr_imb((unsigned long)vcpu->kvm->arch.pgd, CSR_APTP);

		/* Enter the guest */
		trace_kvm_sw64_entry(vcpu->vcpu_id, vcpu->arch.regs.pc);
		vcpu->mode = IN_GUEST_MODE;

		ret = __sw64_vcpu_run(__pa(vcb), &(vcpu->arch.regs), &hargs);

		/* Back from guest */
		vcpu->mode = OUTSIDE_GUEST_MODE;

		vcpu->stat.exits++;
		local_irq_enable();
		guest_exit_irqoff();

		trace_kvm_sw64_exit(ret, vcpu->arch.regs.pc);

		preempt_enable();

		/* ret = 0 indicate interrupt in guest mode, ret > 0 indicate hcall */
		ret = handle_exit(vcpu, run, ret, &hargs);
		update_vcpu_stat_time(&vcpu->stat);
	}

	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &sigsaved, NULL);

#ifdef CONFIG_PERF_EVENTS
	vcpu_put(vcpu);
#endif
	return ret;
}

static void kvm_core4_vcpu_free(struct kvm_vcpu *vcpu)
{
	kvm_mmu_free_memory_caches(vcpu);
}

static long kvm_core4_get_vcb(struct file *filp, unsigned long arg)
long kvm_sw64_get_vcb(struct file *filp, unsigned long arg)
{
	struct kvm_vcpu *vcpu = filp->private_data;

@@ -194,7 +86,7 @@ static long kvm_core4_get_vcb(struct file *filp, unsigned long arg)
	return 0;
}

static long kvm_core4_set_vcb(struct file *filp, unsigned long arg)
long kvm_sw64_set_vcb(struct file *filp, unsigned long arg)
{
	struct kvm_vcpu *vcpu = filp->private_data;
	struct vcpucb *kvm_vcb;
@@ -213,20 +105,18 @@ static long kvm_core4_set_vcb(struct file *filp, unsigned long arg)
	return 0;
}

static struct kvm_sw64_ops core4_sw64_ops __ro_after_init = {
	.get_new_vpn_context = core4_get_new_vpn_context,
	.update_vpn = core4_update_vpn,
	.init_vm = kvm_core4_init_vm,
	.destroy_vm = kvm_core4_destroy_vm,
	.commit_memory_region = kvm_core4_commit_memory_region,
	.flush_shadow_memslot = kvm_core4_flush_shadow_memslot,
	.flush_shadow_all = kvm_core4_flush_shadow_all,
	.vcpu_reset = kvm_core4_vcpu_reset,
	.vcpu_run = kvm_core4_vcpu_ioctl_run,
	.vcpu_free = kvm_core4_vcpu_free,
	.get_vcb = kvm_core4_get_vcb,
	.set_vcb = kvm_core4_set_vcb,
};
int kvm_arch_prepare_memory_region(struct kvm *kvm,
		struct kvm_memory_slot *memslot,
		const struct kvm_userspace_memory_region *mem,
		enum kvm_mr_change change)
{
	return 0;
}

void vcpu_set_numa_affinity(struct kvm_vcpu *vcpu)
{
	return;
}

static int __init kvm_core4_init(void)
{
@@ -235,7 +125,7 @@ static int __init kvm_core4_init(void)
	for (i = 0; i < NR_CPUS; i++)
		last_vpn(i) = VPN_FIRST_VERSION;

	ret = kvm_init(&core4_sw64_ops, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);

	if (ret)
		return ret;
Loading