Commit 09a48172 authored by Mao Minkai's avatar Mao Minkai Committed by guzitao
Browse files

sw64: add KVM support

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



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

Add KVM support for SW64.

Signed-off-by: default avatarMao Minkai <maominkai@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent 7544a86e
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_HCALL_H
#define _ASM_SW64_HCALL_H

#define HMC_hcall	0x32
/* HCALL must > 0 */
enum HCALL_TYPE {
	HCALL_HALT		= 10,
	HCALL_NOTIFY		= 11,
	HCALL_SHUTDOWN		= 12,
	HCALL_SET_CLOCKEVENT	= 13,
	HCALL_IVI		= 14,   /* interrupt between virtual cpu */
	HCALL_TBI		= 15,   /* tlb flush for virtual cpu */
	HCALL_STOP		= 16,   /* indicate virtual cpu stopped */
	HCALL_RESTART		= 17,	/* indicate virtual cpu restarted */
	HCALL_MSI		= 18,   /* guest request msi intr */
	HCALL_MSIX		= 19,	/* guest request msix intr */
	HCALL_SWNET		= 20,   /* guest request swnet service */
	HCALL_SWNET_IRQ		= 21,   /* guest request swnet intr */
	HCALL_FATAL_ERROR	= 22,   /* guest fatal error, issued by hmcode */
	HCALL_MEMHOTPLUG	= 23,   /* guest memory hotplug event */
	NR_HCALL
};

static inline unsigned long hcall(unsigned long hcall, unsigned long arg0,
				  unsigned long arg1, unsigned long arg2)
{
	register unsigned long __r0 __asm__("$0");
	register unsigned long __r16 __asm__("$16") = hcall;
	register unsigned long __r17 __asm__("$17") = arg0;
	register unsigned long __r18 __asm__("$18") = arg1;
	register unsigned long __r19 __asm__("$19") = arg2;
	__asm__ __volatile__(
		"sys_call %5 "
		: "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r19), "=r"(__r0)
		: "i"(HMC_hcall), "0"(__r16), "1"(__r17), "2"(__r18), "3"(__r19)
		: "$1", "$22", "$23", "$24", "$25");
	return __r0;
}

#endif /* _ASM_SW64_HCALL_H */
+38 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_KVM_ASM_H
#define _ASM_SW64_KVM_ASM_H

#define SW64_KVM_EXIT_HOST_INTR		0
#define SW64_KVM_EXIT_IO		1
#define SW64_KVM_MIGRATION_SET_DIRTY    2
#define SW64_KVM_MIGRATION_SET_DIRTY_HM 3
#define SW64_KVM_EXIT_HALT		10
#define SW64_KVM_EXIT_SHUTDOWN		12
#define SW64_KVM_EXIT_TIMER		13
#define SW64_KVM_EXIT_IPI		14
#define SW64_KVM_EXIT_STOP		16
#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


#define kvm_sw64_exception_type	\
	{0, "HOST_INTR" },	\
	{1, "IO" },		\
	{10, "HALT" },		\
	{12, "SHUTDOWN" },	\
	{13, "TIMER" },		\
	{14, "IPI" },		\
	{16, "STOP" },		\
	{17, "RESTART" },	\
	{18, "APT_FAULT" },	\
	{22, "FATAL_ERROR" },	\
	{23, "MEMHOTPLUG" },	\
	{24, "DEBUG" }


#include <asm/csr.h>

#endif /* _ASM_SW64_KVM_ASM_H */
+11 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_KVM_CMA_H
#define _ASM_SW64_KVM_CMA_H

#include <linux/cma.h>

extern int __init kvm_cma_declare_contiguous(phys_addr_t base,
			phys_addr_t size, phys_addr_t limit,
			phys_addr_t alignment, unsigned int order_per_bit,
			const char *name, struct cma **res_cma);
#endif /* _ASM_SW64_KVM_CMA_H */
+46 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_KVM_EMULATE_H
#define _ASM_SW64_KVM_EMULATE_H

#include <linux/kvm_host.h>
#include <asm/kvm_asm.h>

#define R(x)	((size_t) &((struct kvm_regs *)0)->x)

static int reg_offsets[32] = {
	R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),
	R(r9), R(r10), R(r11), R(r12), R(r13), R(r14), R(r15),
	R(r16), R(r17), R(r18),
	R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),
	R(r27), R(r28), R(gp),
	0, 0,
};


static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
				unsigned long val)
{
	void *regs_ptr = (void *)&vcpu->arch.regs;

	regs_ptr += reg_offsets[reg_num];
	*(unsigned long *)regs_ptr = val;
}

static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu, u8 reg_num)
{
	void *regs_ptr = (void *)&vcpu->arch.regs;

	if (reg_num == 31)
		return 0;
	regs_ptr += reg_offsets[reg_num];
	return *(unsigned long *)regs_ptr;
}

void sw64_decode(struct kvm_vcpu *vcpu, unsigned int insn,
		 struct kvm_run *run);

unsigned int interrupt_pending(struct kvm_vcpu *vcpu, bool *more);
void clear_vcpu_irq(struct kvm_vcpu *vcpu);
void inject_vcpu_irq(struct kvm_vcpu *vcpu, unsigned int irq);
void try_deliver_interrupt(struct kvm_vcpu *vcpu, unsigned int irq, bool more);
#endif /* _ASM_SW64_KVM_EMULATE_H */
+225 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SW64_KVM_HOST_H
#define _ASM_SW64_KVM_HOST_H

#include <linux/types.h>
#include <linux/hardirq.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/bug.h>
#include <linux/mm.h>
#include <linux/mmu_notifier.h>
#include <linux/preempt.h>
#include <linux/msi.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <linux/ratelimit.h>
#include <linux/err.h>
#include <linux/bitmap.h>
#include <linux/compiler.h>
#include <asm/signal.h>
#include <asm/vcpu.h>

#include <generated/autoconf.h>
#include <asm/ptrace.h>

#include <asm/kvm_mmio.h>

#define last_vpn(cpu)	(cpu_data[cpu].last_vpn)

#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)
#define VPN_MASK		((1UL << VPN_BITS) - 1)
#define VPN_SHIFT		(64 - VPN_BITS)

#define KVM_MAX_VCPUS 64
#define KVM_INTERNAL_MEM_SLOTS	(KVM_MEM_SLOTS_NUM - 512)

#define KVM_HALT_POLL_NS_DEFAULT 0
#define KVM_IRQCHIP_NUM_PINS     256
/* KVM Hugepage definitions for sw64 */
#define KVM_NR_PAGE_SIZES   3
#define KVM_HPAGE_GFN_SHIFT(x)  (((x) - 1) * 9)
#define KVM_HPAGE_SHIFT(x)  (PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x))
#define KVM_HPAGE_SIZE(x)   (1UL << KVM_HPAGE_SHIFT(x))
#define KVM_HPAGE_MASK(x)   (~(KVM_HPAGE_SIZE(x) - 1))
#define KVM_PAGES_PER_HPAGE(x)  (KVM_HPAGE_SIZE(x) / PAGE_SIZE)

/*
 * The architecture supports 48-bit GPA as input to the addtional stage translations.
 */
#define KVM_PHYS_SHIFT	(48)
#define KVM_PHYS_SIZE	(_AC(1, ULL) << KVM_PHYS_SHIFT)
#define KVM_PHYS_MASK	(KVM_PHYS_SIZE - _AC(1, ULL))

struct kvm_arch_memory_slot {
	unsigned long host_phys_addr;
	bool valid;
};

struct kvm_arch {
	unsigned long host_phys_addr;
	unsigned long size;

	/* segment table */
	unsigned long *seg_pgd;

	struct swvm_mem mem;
	/* Addtional stage page table*/
	pgd_t *pgd;
};

#define KVM_NR_MEM_OBJS		40

/*
 * We don't want allocation failures within the mmu code, so we preallocate
 * enough memory for a single page fault in a cache.
 */
struct kvm_mmu_memory_cache {
	int nobjs;
	void *objects[KVM_NR_MEM_OBJS];
};

struct kvm_vcpu_arch {
	struct kvm_regs regs __aligned(32);
	struct vcpucb vcb;
	struct task_struct *tsk;
	unsigned int pcpu_id; /* current running pcpu id */

	/* Virtual clock device */
	struct hrtimer hrt;
	unsigned long timer_next_event;
	unsigned long vtimer_freq;

	int first_run;
	int halted;
	int stopped;
	int restart;

	/* Pending virtual interrupts */
	DECLARE_BITMAP(irqs_pending, SWVM_IRQS);
	unsigned long vpnc[NR_CPUS];

	/* Detect first run of a vcpu */
	bool has_run_once;

	/* WAIT executed */
	int wait;

	/* vcpu power-off state */
	bool power_off;

	/* Don't run the guest (internal implementation need) */
	bool pause;

	struct kvm_decode mmio_decode;

	/* Cache some mmu pages needed inside spinlock regions */
	struct kvm_mmu_memory_cache mmu_page_cache;

	/* guest live migration */
	unsigned long migration_mark;
	unsigned long shtclock;
};

struct vmem_info {
	unsigned long start;
	size_t size;
	atomic_t refcnt;
};

struct kvm_vm_stat {
	struct kvm_vm_stat_generic generic;
};

struct kvm_vcpu_stat {
	struct kvm_vcpu_stat_generic generic;
	u64 pid;
	u64 exits;
	u64 io_exits;
	u64 mmio_exits;
	u64 migration_set_dirty;
	u64 shutdown_exits;
	u64 restart_exits;
	u64 stop_exits;
	u64 ipi_exits;
	u64 timer_exits;
	u64 debug_exits;
#ifdef CONFIG_KVM_MEMHOTPLUG
	u64 memhotplug_exits;
#endif
	u64 fatal_error_exits;
	u64 halt_exits;
	u64 halt_successful_poll;
	u64 halt_attempted_poll;
	u64 halt_wakeup;
	u64 halt_poll_success_ns;
	u64 halt_poll_fail_ns;
	u64 halt_poll_invalid;
	u64 signal_exits;
	u64 steal;
	u64 st_max;
	u64 utime;
	u64 stime;
	u64 gtime;
};

#ifdef CONFIG_KVM_MEMHOTPLUG
void vcpu_mem_hotplug(struct kvm_vcpu *vcpu, unsigned long start_addr);
#endif
#ifdef CONFIG_SUBARCH_C4
#define KVM_ARCH_WANT_MMU_NOTIFIER
#endif
int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end, bool blockable);
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);

void update_vcpu_stat_time(struct kvm_vcpu_stat *vcpu_stat);
void check_vcpu_requests(struct kvm_vcpu *vcpu);
void sw64_kvm_switch_vpn(struct kvm_vcpu *vcpu);
int vmem_init(void);
void vmem_exit(void);
int __sw64_vcpu_run(unsigned long vcb_pa, struct kvm_regs *regs,
		struct hcall_args *args);
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
		int exception_index, struct hcall_args *hargs);
void vcpu_send_ipi(struct kvm_vcpu *vcpu, int target_vcpuid, int type);
static inline void kvm_arch_hardware_disable(void) {}
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
static inline void kvm_arch_free_memslot(struct kvm *kvm,
		struct kvm_memory_slot *slot) {}
static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}

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 pgd);
void vcpu_set_numa_affinity(struct kvm_vcpu *vcpu);
#endif /* _ASM_SW64_KVM_HOST_H */
Loading