Skip to content

Commit 99cdc6c

Browse files
committed
RISC-V: Add initial skeletal KVM support
This patch adds initial skeletal KVM RISC-V support which has: 1. A simple implementation of arch specific VM functions except kvm_vm_ioctl_get_dirty_log() which will implemeted in-future as part of stage2 page loging. 2. Stubs of required arch specific VCPU functions except kvm_arch_vcpu_ioctl_run() which is semi-complete and extended by subsequent patches. 3. Stubs for required arch specific stage2 MMU functions. Signed-off-by: Anup Patel <[email protected]> Acked-by: Paolo Bonzini <[email protected]> Reviewed-by: Paolo Bonzini <[email protected]> Reviewed-by: Alexander Graf <[email protected]> Acked-by: Palmer Dabbelt <[email protected]>
1 parent 3f2401f commit 99cdc6c

File tree

12 files changed

+805
-0
lines changed

12 files changed

+805
-0
lines changed

arch/riscv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,4 +562,5 @@ source "kernel/power/Kconfig"
562562

563563
endmenu
564564

565+
source "arch/riscv/kvm/Kconfig"
565566
source "drivers/firmware/Kconfig"

arch/riscv/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ endif
100100
head-y := arch/riscv/kernel/head.o
101101

102102
core-$(CONFIG_RISCV_ERRATA_ALTERNATIVE) += arch/riscv/errata/
103+
core-$(CONFIG_KVM) += arch/riscv/kvm/
103104

104105
libs-y += arch/riscv/lib/
105106
libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a

arch/riscv/include/asm/kvm_host.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
4+
*
5+
* Authors:
6+
* Anup Patel <[email protected]>
7+
*/
8+
9+
#ifndef __RISCV_KVM_HOST_H__
10+
#define __RISCV_KVM_HOST_H__
11+
12+
#include <linux/types.h>
13+
#include <linux/kvm.h>
14+
#include <linux/kvm_types.h>
15+
16+
#ifdef CONFIG_64BIT
17+
#define KVM_MAX_VCPUS (1U << 16)
18+
#else
19+
#define KVM_MAX_VCPUS (1U << 9)
20+
#endif
21+
22+
#define KVM_HALT_POLL_NS_DEFAULT 500000
23+
24+
#define KVM_VCPU_MAX_FEATURES 0
25+
26+
#define KVM_REQ_SLEEP \
27+
KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
28+
#define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(1)
29+
30+
struct kvm_vm_stat {
31+
struct kvm_vm_stat_generic generic;
32+
};
33+
34+
struct kvm_vcpu_stat {
35+
struct kvm_vcpu_stat_generic generic;
36+
u64 ecall_exit_stat;
37+
u64 wfi_exit_stat;
38+
u64 mmio_exit_user;
39+
u64 mmio_exit_kernel;
40+
u64 exits;
41+
};
42+
43+
struct kvm_arch_memory_slot {
44+
};
45+
46+
struct kvm_arch {
47+
/* stage2 page table */
48+
pgd_t *pgd;
49+
phys_addr_t pgd_phys;
50+
};
51+
52+
struct kvm_cpu_trap {
53+
unsigned long sepc;
54+
unsigned long scause;
55+
unsigned long stval;
56+
unsigned long htval;
57+
unsigned long htinst;
58+
};
59+
60+
struct kvm_vcpu_arch {
61+
/* Don't run the VCPU (blocked) */
62+
bool pause;
63+
64+
/* SRCU lock index for in-kernel run loop */
65+
int srcu_idx;
66+
};
67+
68+
static inline void kvm_arch_hardware_unsetup(void) {}
69+
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
70+
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
71+
static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
72+
73+
void kvm_riscv_stage2_flush_cache(struct kvm_vcpu *vcpu);
74+
int kvm_riscv_stage2_alloc_pgd(struct kvm *kvm);
75+
void kvm_riscv_stage2_free_pgd(struct kvm *kvm);
76+
void kvm_riscv_stage2_update_hgatp(struct kvm_vcpu *vcpu);
77+
78+
int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
79+
int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
80+
struct kvm_cpu_trap *trap);
81+
82+
static inline void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch) {}
83+
84+
#endif /* __RISCV_KVM_HOST_H__ */

arch/riscv/include/asm/kvm_types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_RISCV_KVM_TYPES_H
3+
#define _ASM_RISCV_KVM_TYPES_H
4+
5+
#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
6+
7+
#endif /* _ASM_RISCV_KVM_TYPES_H */

arch/riscv/include/uapi/asm/kvm.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
/*
3+
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
4+
*
5+
* Authors:
6+
* Anup Patel <[email protected]>
7+
*/
8+
9+
#ifndef __LINUX_KVM_RISCV_H
10+
#define __LINUX_KVM_RISCV_H
11+
12+
#ifndef __ASSEMBLY__
13+
14+
#include <linux/types.h>
15+
#include <asm/ptrace.h>
16+
17+
#define __KVM_HAVE_READONLY_MEM
18+
19+
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
20+
21+
/* for KVM_GET_REGS and KVM_SET_REGS */
22+
struct kvm_regs {
23+
};
24+
25+
/* for KVM_GET_FPU and KVM_SET_FPU */
26+
struct kvm_fpu {
27+
};
28+
29+
/* KVM Debug exit structure */
30+
struct kvm_debug_exit_arch {
31+
};
32+
33+
/* for KVM_SET_GUEST_DEBUG */
34+
struct kvm_guest_debug_arch {
35+
};
36+
37+
/* definition of registers in kvm_run */
38+
struct kvm_sync_regs {
39+
};
40+
41+
/* dummy definition */
42+
struct kvm_sregs {
43+
};
44+
45+
#endif
46+
47+
#endif /* __LINUX_KVM_RISCV_H */

arch/riscv/kvm/Kconfig

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# KVM configuration
4+
#
5+
6+
source "virt/kvm/Kconfig"
7+
8+
menuconfig VIRTUALIZATION
9+
bool "Virtualization"
10+
help
11+
Say Y here to get to see options for using your Linux host to run
12+
other operating systems inside virtual machines (guests).
13+
This option alone does not add any kernel code.
14+
15+
If you say N, all options in this submenu will be skipped and
16+
disabled.
17+
18+
if VIRTUALIZATION
19+
20+
config KVM
21+
tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)"
22+
depends on RISCV_SBI && MMU
23+
select PREEMPT_NOTIFIERS
24+
select ANON_INODES
25+
select KVM_MMIO
26+
select HAVE_KVM_VCPU_ASYNC_IOCTL
27+
select SRCU
28+
help
29+
Support hosting virtualized guest machines.
30+
31+
If unsure, say N.
32+
33+
endif # VIRTUALIZATION

arch/riscv/kvm/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# Makefile for RISC-V KVM support
4+
#
5+
6+
ccflags-y += -I $(srctree)/$(src)
7+
8+
KVM := ../../../virt/kvm
9+
10+
obj-$(CONFIG_KVM) += kvm.o
11+
12+
kvm-y += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/binary_stats.o \
13+
main.o vm.o mmu.o vcpu.o vcpu_exit.o

arch/riscv/kvm/main.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
4+
*
5+
* Authors:
6+
* Anup Patel <[email protected]>
7+
*/
8+
9+
#include <linux/errno.h>
10+
#include <linux/err.h>
11+
#include <linux/module.h>
12+
#include <linux/kvm_host.h>
13+
#include <asm/csr.h>
14+
#include <asm/hwcap.h>
15+
#include <asm/sbi.h>
16+
17+
long kvm_arch_dev_ioctl(struct file *filp,
18+
unsigned int ioctl, unsigned long arg)
19+
{
20+
return -EINVAL;
21+
}
22+
23+
int kvm_arch_check_processor_compat(void *opaque)
24+
{
25+
return 0;
26+
}
27+
28+
int kvm_arch_hardware_setup(void *opaque)
29+
{
30+
return 0;
31+
}
32+
33+
int kvm_arch_hardware_enable(void)
34+
{
35+
unsigned long hideleg, hedeleg;
36+
37+
hedeleg = 0;
38+
hedeleg |= (1UL << EXC_INST_MISALIGNED);
39+
hedeleg |= (1UL << EXC_BREAKPOINT);
40+
hedeleg |= (1UL << EXC_SYSCALL);
41+
hedeleg |= (1UL << EXC_INST_PAGE_FAULT);
42+
hedeleg |= (1UL << EXC_LOAD_PAGE_FAULT);
43+
hedeleg |= (1UL << EXC_STORE_PAGE_FAULT);
44+
csr_write(CSR_HEDELEG, hedeleg);
45+
46+
hideleg = 0;
47+
hideleg |= (1UL << IRQ_VS_SOFT);
48+
hideleg |= (1UL << IRQ_VS_TIMER);
49+
hideleg |= (1UL << IRQ_VS_EXT);
50+
csr_write(CSR_HIDELEG, hideleg);
51+
52+
csr_write(CSR_HCOUNTEREN, -1UL);
53+
54+
csr_write(CSR_HVIP, 0);
55+
56+
return 0;
57+
}
58+
59+
void kvm_arch_hardware_disable(void)
60+
{
61+
csr_write(CSR_HEDELEG, 0);
62+
csr_write(CSR_HIDELEG, 0);
63+
}
64+
65+
int kvm_arch_init(void *opaque)
66+
{
67+
if (!riscv_isa_extension_available(NULL, h)) {
68+
kvm_info("hypervisor extension not available\n");
69+
return -ENODEV;
70+
}
71+
72+
if (sbi_spec_is_0_1()) {
73+
kvm_info("require SBI v0.2 or higher\n");
74+
return -ENODEV;
75+
}
76+
77+
if (sbi_probe_extension(SBI_EXT_RFENCE) <= 0) {
78+
kvm_info("require SBI RFENCE extension\n");
79+
return -ENODEV;
80+
}
81+
82+
kvm_info("hypervisor extension available\n");
83+
84+
return 0;
85+
}
86+
87+
void kvm_arch_exit(void)
88+
{
89+
}
90+
91+
static int riscv_kvm_init(void)
92+
{
93+
return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
94+
}
95+
module_init(riscv_kvm_init);

arch/riscv/kvm/mmu.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
4+
*
5+
* Authors:
6+
* Anup Patel <[email protected]>
7+
*/
8+
9+
#include <linux/bitops.h>
10+
#include <linux/errno.h>
11+
#include <linux/err.h>
12+
#include <linux/hugetlb.h>
13+
#include <linux/module.h>
14+
#include <linux/uaccess.h>
15+
#include <linux/vmalloc.h>
16+
#include <linux/kvm_host.h>
17+
#include <linux/sched/signal.h>
18+
#include <asm/page.h>
19+
#include <asm/pgtable.h>
20+
21+
void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
22+
{
23+
}
24+
25+
void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free)
26+
{
27+
}
28+
29+
void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen)
30+
{
31+
}
32+
33+
void kvm_arch_flush_shadow_all(struct kvm *kvm)
34+
{
35+
/* TODO: */
36+
}
37+
38+
void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
39+
struct kvm_memory_slot *slot)
40+
{
41+
}
42+
43+
void kvm_arch_commit_memory_region(struct kvm *kvm,
44+
const struct kvm_userspace_memory_region *mem,
45+
struct kvm_memory_slot *old,
46+
const struct kvm_memory_slot *new,
47+
enum kvm_mr_change change)
48+
{
49+
/* TODO: */
50+
}
51+
52+
int kvm_arch_prepare_memory_region(struct kvm *kvm,
53+
struct kvm_memory_slot *memslot,
54+
const struct kvm_userspace_memory_region *mem,
55+
enum kvm_mr_change change)
56+
{
57+
/* TODO: */
58+
return 0;
59+
}
60+
61+
void kvm_riscv_stage2_flush_cache(struct kvm_vcpu *vcpu)
62+
{
63+
/* TODO: */
64+
}
65+
66+
int kvm_riscv_stage2_alloc_pgd(struct kvm *kvm)
67+
{
68+
/* TODO: */
69+
return 0;
70+
}
71+
72+
void kvm_riscv_stage2_free_pgd(struct kvm *kvm)
73+
{
74+
/* TODO: */
75+
}
76+
77+
void kvm_riscv_stage2_update_hgatp(struct kvm_vcpu *vcpu)
78+
{
79+
/* TODO: */
80+
}

0 commit comments

Comments
 (0)