2023-09-15 01:50:51

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 00/29] Add KVM LoongArch support

This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
assisted virtualization. With cpu virtualization, there are separate
hw-supported user mode and kernel mode in guest mode. With memory
virtualization, there are two-level hw mmu table for guest mode and host
mode. Also there is separate hw cpu timer with consant frequency in
guest mode, so that vm can migrate between hosts with different freq.
Currently, we are able to boot LoongArch Linux Guests.

Few key aspects of KVM LoongArch added by this series are:
1. Enable kvm hardware function when kvm module is loaded.
2. Implement VM and vcpu related ioctl interface such as vcpu create,
vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
get general registers one by one.
3. Hardware access about MMU, timer and csr are emulated in kernel.
4. Hardwares such as mmio and iocsr device are emulated in user space
such as APIC, IPI, pci devices etc.

The running environment of LoongArch virt machine:
1. Cross tools for building kernel and uefi:
https://github.com/loongson/build-tools
2. This series is based on the linux source code:
https://github.com/loongson/linux-loongarch-kvm
Build command:
git checkout kvm-loongarch
make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
3. QEMU hypervisor with LoongArch supported:
https://github.com/loongson/qemu
Build command:
git checkout kvm-loongarch
./configure --target-list="loongarch64-softmmu" --enable-kvm
make
4. Uefi bios of LoongArch virt machine:
Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
5. you can also access the binary files we have already build:
https://github.com/yangxiaojuan-loongson/qemu-binary
The command to boot loongarch virt machine:
$ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
-smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
-serial stdio -monitor telnet:localhost:4495,server,nowait \
-append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
--nographic

Changes for v21:
1. Remove unnecessary prefix '_' in some kvm function names.
2. Replace check_vmid with check_vpid, and move the functions
to main.c.
3. Re-order the file names and config names by alphabetical
in KVM makefile and Kconfig.
4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
ioctl functions.

changes for v20:
1. Remove the binary code of virtualization instructions in
insn_def.h and csr_ops.S and directly use the default csrrd,
csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
already supported them to compile the KVM. This can make our
LoongArch KVM codes more maintainable and easier.

changes for v19:
1. Use the common interface xfer_to_guest_mode_handle_work to
Check conditions before entering the guest.
2. Add vcpu dirty ring support.

changes for v18:
1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
the stable_ktime_saved variable to expire.
2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.

changes for v17:
1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
binutils that support LVZ assemble instruction.
2. Change kvm mmu related functions, such as rename level2_ptw_pgd
to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
handling.
3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
when injecting IRQ.
4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
kvm_arch.online_vcpus and kvm_arch.is_migrating,
5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
since NR/NX bit is not set in kvm page fault handling.

Changes for v16:
1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
exit to avoid memory leak problem.
2. Simplify some assemble codes in switch.S which are necessary to be
replaced with pseudo-instructions. And any other instructions do not need
to be replaced anymore.
3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
guest regs instructions when vcpu world switch.
4. It is more secure to disable irq when flush guest tlb by gpa, so replace
preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.

Changes for v15:
1. Re-order some macros and variables in LoongArch kvm headers, put them
together which have the same meaning.
2. Make some function definitions in one line, as it is not needed to split
them.
3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.

Changes for v14:
1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
loongarch/kvm/main.c, as it is not useful.
2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
as it is used by virt/kvm.
3. Fix the LoongArch KVM source link in MAINTAINERS.
4. Improve LoongArch KVM documentation, such as add comment for
LoongArch kvm_regs.

Changes for v13:
1. Remove patch-28 "Implement probe virtualization when cpu init", as the
virtualization information about FPU,PMP,LSX in guest.options,options_dyn
is not used and the gcfg reg value can be read in kvm_hardware_enable, so
remove the previous cpu_probe_lvz function.
2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
FPU cap is enable by default, and do not support any other caps now.
3. Simplify the jirl instruction with jr when without return addr,
simplify case HW0 ... HW7 statment in interrupt.c
4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
and remove 'cpu' parameter in kvm_check_vmid function, as it can get
cpu number by itself.

Changes for v12:
1. Improve the gcsr write/read/xchg interface to avoid the previous
instruction statment like parse_r and make the code easy understanding,
they are implemented in asm/insn-def.h and the instructions consistent
of "opcode" "rj" "rd" "simm14" arguments.
2. Fix the maintainers list of LoongArch KVM.

Changes for v11:
1. Add maintainers for LoongArch KVM.

Changes for v10:
1. Fix grammatical problems in LoongArch documentation.
2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
vcpu put and vcpu load, so we remove it.

Changes for v9:
1. Apply the new defined interrupt number macros in loongarch.h to kvm,
such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
previous unused macros.
2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
to make them more standard.

Changes for v8:
1. Adjust the cpu_data.guest.options structure, add the ases flag into
it, and remove the previous guest.ases. We do this to keep consistent
with host cpu_data.options structure.
2. Remove the "#include <asm/kvm_host.h>" in some files which also
include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
the asm/kvm_host.h.
3. Fix some unstandard spelling and grammar errors in comments, and
improve a little code format to make it easier and standard.

Changes for v7:
1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
kernel test robot. The report link is:
https://lore.kernel.org/oe-kbuild-all/[email protected]/
2. Fix loongarch kvm trace related compiling problems.

Changes for v6:
1. Fix the Documentation/virt/kvm/api.rst compile warning about
loongarch parts.

Changes for v5:
1. Implement get/set mp_state ioctl interface, and only the
KVM_MP_STATE_RUNNABLE state is supported now, and other states
will be completed in the future. The state is also used when vcpu
run idle instruction, if vcpu state is changed to RUNNABLE, the
vcpu will have the possibility to be woken up.
2. Supplement kvm document about loongarch-specific part, such as add
api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
etc.
3. Improve the kvm_switch_to_guest function in switch.S, remove the
previous tmp,tmp1 arguments and replace it with t0,t1 reg.

Changes for v4:
1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
unchanged during process context switch, so we need not to update it
every time. We can do this only if the soft csr is different form hardware.
That is to say all of csrs should update after vcpu enter guest, as for
set_csr_ioctl, we have written soft csr to keep consistent with hardware.
2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
SW, we use software to emulate it, and others return false.
3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
We have splited hw gcsr into three parts, so we can calculate the code offset
by gcsrid and jump here to run the gcsrwr instruction. We use this function to
make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
4. Improve kvm mmu functions, such as flush page table and make clean page table
interface.

Changes for v3:
1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
because a vpid will never be recycled if a vCPU migrates from physical CPU A
to B and back to A.
2. Make some constant variables in kvm_context to global such as vpid_mask,
guest_eentry, enter_guest, etc.
3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
kvm_trace_gspr, etc.
4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
so we move it to a new function kvm_pre_enter_guest.
5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
and "<= 0" for resume host.
6. Fcsr and fpu registers are saved/restored together.

Changes for v2:
1. Seprate the original patch-01 and patch-03 into small patches, and the
patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
etc.
2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
and we use the common KVM_{GET,SET}_ONE_REG to access register.
3. Use BIT(x) to replace the "1 << n_bits" statement.

Tianrui Zhao (29):
LoongArch: KVM: Add kvm related header files
LoongArch: KVM: Implement kvm module related interface
LoongArch: KVM: Implement kvm hardware enable, disable interface
LoongArch: KVM: Implement VM related functions
LoongArch: KVM: Add vcpu related header files
LoongArch: KVM: Implement vcpu create and destroy interface
LoongArch: KVM: Implement vcpu run interface
LoongArch: KVM: Implement vcpu handle exit interface
LoongArch: KVM: Implement vcpu get, vcpu set registers
LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
LoongArch: KVM: Implement fpu related operations for vcpu
LoongArch: KVM: Implement vcpu interrupt operations
LoongArch: KVM: Implement misc vcpu related interfaces
LoongArch: KVM: Implement vcpu load and vcpu put operations
LoongArch: KVM: Implement vcpu status description
LoongArch: KVM: Implement virtual machine tlb operations
LoongArch: KVM: Implement vcpu timer operations
LoongArch: KVM: Implement kvm mmu operations
LoongArch: KVM: Implement handle csr exception
LoongArch: KVM: Implement handle iocsr exception
LoongArch: KVM: Implement handle idle exception
LoongArch: KVM: Implement handle gspr exception
LoongArch: KVM: Implement handle mmio exception
LoongArch: KVM: Implement handle fpu exception
LoongArch: KVM: Implement kvm exception vector
LoongArch: KVM: Implement vcpu world switch
LoongArch: KVM: Enable kvm config and add the makefile
LoongArch: KVM: Supplement kvm document about LoongArch-specific part
LoongArch: KVM: Add maintainers for LoongArch KVM

Documentation/virt/kvm/api.rst | 70 +-
MAINTAINERS | 12 +
arch/loongarch/Kbuild | 1 +
arch/loongarch/Kconfig | 3 +
arch/loongarch/configs/loongson3_defconfig | 2 +
arch/loongarch/include/asm/inst.h | 16 +
arch/loongarch/include/asm/kvm_csr.h | 221 +++++
arch/loongarch/include/asm/kvm_host.h | 245 ++++++
arch/loongarch/include/asm/kvm_mmu.h | 138 +++
arch/loongarch/include/asm/kvm_types.h | 11 +
arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
arch/loongarch/include/asm/loongarch.h | 19 +-
arch/loongarch/include/uapi/asm/kvm.h | 108 +++
arch/loongarch/kernel/asm-offsets.c | 32 +
arch/loongarch/kvm/Kconfig | 45 +
arch/loongarch/kvm/Makefile | 20 +
arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
arch/loongarch/kvm/interrupt.c | 185 ++++
arch/loongarch/kvm/main.c | 429 ++++++++++
arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
arch/loongarch/kvm/switch.S | 255 ++++++
arch/loongarch/kvm/timer.c | 200 +++++
arch/loongarch/kvm/tlb.c | 34 +
arch/loongarch/kvm/trace.h | 166 ++++
arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
arch/loongarch/kvm/vm.c | 92 ++
include/uapi/linux/kvm.h | 9 +
27 files changed, 4979 insertions(+), 14 deletions(-)
create mode 100644 arch/loongarch/include/asm/kvm_csr.h
create mode 100644 arch/loongarch/include/asm/kvm_host.h
create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
create mode 100644 arch/loongarch/include/asm/kvm_types.h
create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
create mode 100644 arch/loongarch/kvm/Kconfig
create mode 100644 arch/loongarch/kvm/Makefile
create mode 100644 arch/loongarch/kvm/exit.c
create mode 100644 arch/loongarch/kvm/interrupt.c
create mode 100644 arch/loongarch/kvm/main.c
create mode 100644 arch/loongarch/kvm/mmu.c
create mode 100644 arch/loongarch/kvm/switch.S
create mode 100644 arch/loongarch/kvm/timer.c
create mode 100644 arch/loongarch/kvm/tlb.c
create mode 100644 arch/loongarch/kvm/trace.h
create mode 100644 arch/loongarch/kvm/vcpu.c
create mode 100644 arch/loongarch/kvm/vm.c

--
2.39.1


2023-09-15 01:50:53

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 10/29] LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface

Implement LoongArch vcpu KVM_ENABLE_CAP ioctl interface.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 1cc53f56d0..6b1b2a058b 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -215,6 +215,16 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
return 0;
}

+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+ struct kvm_enable_cap *cap)
+{
+ /*
+ * FPU is enable by default, do not support any other caps,
+ * and later we will support such as LSX cap.
+ */
+ return -EINVAL;
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -249,6 +259,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_get_reg(vcpu, &reg);
break;
}
+ case KVM_ENABLE_CAP: {
+ struct kvm_enable_cap cap;
+
+ r = -EFAULT;
+ if (copy_from_user(&cap, argp, sizeof(cap)))
+ break;
+ r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+ break;
+ }
default:
r = -ENOIOCTLCMD;
break;
--
2.39.1

2023-09-15 01:50:59

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 13/29] LoongArch: KVM: Implement misc vcpu related interfaces

Implement some misc vcpu relaterd interfaces, such as vcpu runnable,
vcpu should kick, vcpu dump regs, etc.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 105 ++++++++++++++++++++++++++++++++++++++
1 file changed, 105 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 191d9f5517..42383f8648 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -13,6 +13,111 @@
#define CREATE_TRACE_POINTS
#include "trace.h"

+int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
+{
+ return !!(vcpu->arch.irq_pending) &&
+ vcpu->arch.mp_state.mp_state == KVM_MP_STATE_RUNNABLE;
+}
+
+int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
+}
+
+bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+
+vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+{
+ return VM_FAULT_SIGBUS;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ return -EINVAL;
+}
+
+int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return kvm_pending_timer(vcpu) ||
+ kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT) &
+ (1 << INT_TI);
+}
+
+int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ kvm_debug("vCPU Register Dump:\n");
+ kvm_debug("\tpc = 0x%08lx\n", vcpu->arch.pc);
+ kvm_debug("\texceptions: %08lx\n", vcpu->arch.irq_pending);
+
+ for (i = 0; i < 32; i += 4) {
+ kvm_debug("\tgpr%02d: %08lx %08lx %08lx %08lx\n", i,
+ vcpu->arch.gprs[i],
+ vcpu->arch.gprs[i + 1],
+ vcpu->arch.gprs[i + 2], vcpu->arch.gprs[i + 3]);
+ }
+
+ kvm_debug("\tCRMOD: 0x%08lx, exst: 0x%08lx\n",
+ kvm_read_hw_gcsr(LOONGARCH_CSR_CRMD),
+ kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT));
+
+ kvm_debug("\tERA: 0x%08lx\n", kvm_read_hw_gcsr(LOONGARCH_CSR_ERA));
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ *mp_state = vcpu->arch.mp_state;
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
+ struct kvm_mp_state *mp_state)
+{
+ int ret = 0;
+
+ switch (mp_state->mp_state) {
+ case KVM_MP_STATE_RUNNABLE:
+ vcpu->arch.mp_state = *mp_state;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug *dbg)
+{
+ return -EINVAL;
+}
+
+/**
+ * kvm_migrate_count() - Migrate timer.
+ * @vcpu: Virtual CPU.
+ *
+ * Migrate hrtimer to the current CPU by cancelling and restarting it
+ * if it was running prior to being cancelled.
+ *
+ * Must be called when the vCPU is migrated to a different CPU to ensure that
+ * timer expiry during guest execution interrupts the guest and causes the
+ * interrupt to be delivered in a timely manner.
+ */
+static void kvm_migrate_count(struct kvm_vcpu *vcpu)
+{
+ if (hrtimer_cancel(&vcpu->arch.swtimer))
+ hrtimer_restart(&vcpu->arch.swtimer);
+}
+
int kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v)
{
unsigned long val;
--
2.39.1

2023-09-15 01:52:08

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 07/29] LoongArch: KVM: Implement vcpu run interface

Implement vcpu run interface, handling mmio, iocsr reading fault
and deliver interrupt, lose fpu before vcpu enter guest.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 131 ++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index e6efa0f185..a510082e9b 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -18,6 +18,92 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
return 0;
}

+/*
+ * kvm_check_requests - check and handle pending vCPU requests
+ *
+ * Return: RESUME_GUEST if we should enter the guest
+ * RESUME_HOST if we should exit to userspace
+ */
+static int kvm_check_requests(struct kvm_vcpu *vcpu)
+{
+ if (!kvm_request_pending(vcpu))
+ return RESUME_GUEST;
+
+ if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
+ /* Drop vpid for this vCPU */
+ vcpu->arch.vpid = 0;
+
+ if (kvm_dirty_ring_check_request(vcpu))
+ return RESUME_HOST;
+
+ return RESUME_GUEST;
+}
+
+/*
+ * Check and handle pending signal and vCPU requests etc
+ * Run with irq enabled and preempt enabled
+ *
+ * Return: RESUME_GUEST if we should enter the guest
+ * RESUME_HOST if we should exit to userspace
+ * < 0 if we should exit to userspace, where the return value
+ * indicates an error
+ */
+static int kvm_enter_guest_check(struct kvm_vcpu *vcpu)
+{
+ int ret;
+
+ /*
+ * Check conditions before entering the guest
+ */
+ ret = xfer_to_guest_mode_handle_work(vcpu);
+ if (ret < 0)
+ return ret;
+
+ ret = kvm_check_requests(vcpu);
+ return ret;
+}
+
+/*
+ * called with irq enabled
+ *
+ * Return: RESUME_GUEST if we should enter the guest, and irq disabled
+ * Others if we should exit to userspace
+ */
+static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
+{
+ int ret;
+
+ do {
+ ret = kvm_enter_guest_check(vcpu);
+ if (ret != RESUME_GUEST)
+ break;
+
+ /*
+ * handle vcpu timer, interrupts, check requests and
+ * check vmid before vcpu enter guest
+ */
+ local_irq_disable();
+ kvm_acquire_timer(vcpu);
+ kvm_deliver_intr(vcpu);
+ kvm_deliver_exception(vcpu);
+ /* make sure the vcpu mode has been written */
+ smp_store_mb(vcpu->mode, IN_GUEST_MODE);
+ kvm_check_vpid(vcpu);
+ vcpu->arch.host_eentry = csr_read64(LOONGARCH_CSR_EENTRY);
+ /* clear KVM_LARCH_CSR as csr will change when enter guest */
+ vcpu->arch.aux_inuse &= ~KVM_LARCH_CSR;
+
+ if (kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending()) {
+ /* make sure the vcpu mode has been written */
+ smp_store_mb(vcpu->mode, OUTSIDE_GUEST_MODE);
+ local_irq_enable();
+ ret = -EAGAIN;
+ }
+ } while (ret != RESUME_GUEST);
+
+ return ret;
+}
+
int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
{
unsigned long timer_hz;
@@ -85,3 +171,48 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
context->last_vcpu = NULL;
}
}
+
+int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+{
+ int r = -EINTR;
+ struct kvm_run *run = vcpu->run;
+
+ if (vcpu->mmio_needed) {
+ if (!vcpu->mmio_is_write)
+ kvm_complete_mmio_read(vcpu, run);
+ vcpu->mmio_needed = 0;
+ }
+
+ if (run->exit_reason == KVM_EXIT_LOONGARCH_IOCSR) {
+ if (!run->iocsr_io.is_write)
+ kvm_complete_iocsr_read(vcpu, run);
+ }
+
+ if (run->immediate_exit)
+ return r;
+
+ /* clear exit_reason */
+ run->exit_reason = KVM_EXIT_UNKNOWN;
+ lose_fpu(1);
+ vcpu_load(vcpu);
+ kvm_sigset_activate(vcpu);
+ r = kvm_pre_enter_guest(vcpu);
+ if (r != RESUME_GUEST)
+ goto out;
+
+ guest_timing_enter_irqoff();
+ guest_state_enter_irqoff();
+ trace_kvm_enter(vcpu);
+ r = kvm_loongarch_ops->enter_guest(run, vcpu);
+
+ trace_kvm_out(vcpu);
+ /*
+ * guest exit is already recorded at kvm_handle_exit
+ * return val must not be RESUME_GUEST
+ */
+ local_irq_enable();
+out:
+ kvm_sigset_deactivate(vcpu);
+ vcpu_put(vcpu);
+ return r;
+}
--
2.39.1

2023-09-15 01:53:24

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 28/29] LoongArch: KVM: Supplement kvm document about LoongArch-specific part

Supplement kvm document about LoongArch-specific part, such as add
api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
etc.

Reviewed-by: Huacai Chen <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
Documentation/virt/kvm/api.rst | 70 +++++++++++++++++++++++++++++-----
1 file changed, 61 insertions(+), 9 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 21a7578142..2be69d9f30 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -416,6 +416,13 @@ Reads the general purpose registers from the vcpu.
__u64 pc;
};

+ /* LoongArch */
+ struct kvm_regs {
+ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+ unsigned long gpr[32];
+ unsigned long pc;
+ };
+

4.12 KVM_SET_REGS
-----------------
@@ -506,7 +513,7 @@ translation mode.
------------------

:Capability: basic
-:Architectures: x86, ppc, mips, riscv
+:Architectures: x86, ppc, mips, riscv, loongarch
:Type: vcpu ioctl
:Parameters: struct kvm_interrupt (in)
:Returns: 0 on success, negative on failure.
@@ -592,6 +599,14 @@ b) KVM_INTERRUPT_UNSET

This is an asynchronous vcpu ioctl and can be invoked from any thread.

+LOONGARCH:
+^^^^^^^^^^
+
+Queues an external interrupt to be injected into the virtual CPU. A negative
+interrupt number dequeues the interrupt.
+
+This is an asynchronous vcpu ioctl and can be invoked from any thread.
+

4.17 KVM_DEBUG_GUEST
--------------------
@@ -737,7 +752,7 @@ signal mask.
----------------

:Capability: basic
-:Architectures: x86
+:Architectures: x86, loongarch
:Type: vcpu ioctl
:Parameters: struct kvm_fpu (out)
:Returns: 0 on success, -1 on error
@@ -746,7 +761,7 @@ Reads the floating point state from the vcpu.

::

- /* for KVM_GET_FPU and KVM_SET_FPU */
+ /* x86: for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
__u8 fpr[8][16];
__u16 fcw;
@@ -761,12 +776,21 @@ Reads the floating point state from the vcpu.
__u32 pad2;
};

+ /* LoongArch: for KVM_GET_FPU and KVM_SET_FPU */
+ struct kvm_fpu {
+ __u32 fcsr;
+ __u64 fcc;
+ struct kvm_fpureg {
+ __u64 val64[4];
+ }fpr[32];
+ };
+

4.23 KVM_SET_FPU
----------------

:Capability: basic
-:Architectures: x86
+:Architectures: x86, loongarch
:Type: vcpu ioctl
:Parameters: struct kvm_fpu (in)
:Returns: 0 on success, -1 on error
@@ -775,7 +799,7 @@ Writes the floating point state to the vcpu.

::

- /* for KVM_GET_FPU and KVM_SET_FPU */
+ /* x86: for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
__u8 fpr[8][16];
__u16 fcw;
@@ -790,6 +814,15 @@ Writes the floating point state to the vcpu.
__u32 pad2;
};

+ /* LoongArch: for KVM_GET_FPU and KVM_SET_FPU */
+ struct kvm_fpu {
+ __u32 fcsr;
+ __u64 fcc;
+ struct kvm_fpureg {
+ __u64 val64[4];
+ }fpr[32];
+ };
+

4.24 KVM_CREATE_IRQCHIP
-----------------------
@@ -1387,7 +1420,7 @@ documentation when it pops into existence).
-------------------

:Capability: KVM_CAP_ENABLE_CAP
-:Architectures: mips, ppc, s390, x86
+:Architectures: mips, ppc, s390, x86, loongarch
:Type: vcpu ioctl
:Parameters: struct kvm_enable_cap (in)
:Returns: 0 on success; -1 on error
@@ -1442,7 +1475,7 @@ for vm-wide capabilities.
---------------------

:Capability: KVM_CAP_MP_STATE
-:Architectures: x86, s390, arm64, riscv
+:Architectures: x86, s390, arm64, riscv, loongarch
:Type: vcpu ioctl
:Parameters: struct kvm_mp_state (out)
:Returns: 0 on success; -1 on error
@@ -1460,7 +1493,7 @@ Possible values are:

========================== ===============================================
KVM_MP_STATE_RUNNABLE the vcpu is currently running
- [x86,arm64,riscv]
+ [x86,arm64,riscv,loongarch]
KVM_MP_STATE_UNINITIALIZED the vcpu is an application processor (AP)
which has not yet received an INIT signal [x86]
KVM_MP_STATE_INIT_RECEIVED the vcpu has received an INIT signal, and is
@@ -1516,11 +1549,14 @@ For riscv:
The only states that are valid are KVM_MP_STATE_STOPPED and
KVM_MP_STATE_RUNNABLE which reflect if the vcpu is paused or not.

+On LoongArch, only the KVM_MP_STATE_RUNNABLE state is used to reflect
+whether the vcpu is runnable.
+
4.39 KVM_SET_MP_STATE
---------------------

:Capability: KVM_CAP_MP_STATE
-:Architectures: x86, s390, arm64, riscv
+:Architectures: x86, s390, arm64, riscv, loongarch
:Type: vcpu ioctl
:Parameters: struct kvm_mp_state (in)
:Returns: 0 on success; -1 on error
@@ -1538,6 +1574,9 @@ For arm64/riscv:
The only states that are valid are KVM_MP_STATE_STOPPED and
KVM_MP_STATE_RUNNABLE which reflect if the vcpu should be paused or not.

+On LoongArch, only the KVM_MP_STATE_RUNNABLE state is used to reflect
+whether the vcpu is runnable.
+
4.40 KVM_SET_IDENTITY_MAP_ADDR
------------------------------

@@ -2841,6 +2880,19 @@ Following are the RISC-V D-extension registers:
0x8020 0000 0600 0020 fcsr Floating point control and status register
======================= ========= =============================================

+LoongArch registers are mapped using the lower 32 bits. The upper 16 bits of
+that is the register group type.
+
+LoongArch csr registers are used to control guest cpu or get status of guest
+cpu, and they have the following id bit patterns::
+
+ 0x9030 0000 0001 00 <reg:5> <sel:3> (64-bit)
+
+LoongArch KVM control registers are used to implement some new defined functions
+such as set vcpu counter or reset vcpu, and they have the following id bit patterns::
+
+ 0x9030 0000 0002 <reg:16>
+

4.69 KVM_GET_ONE_REG
--------------------
--
2.39.1

2023-09-15 01:53:41

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 20/29] LoongArch: KVM: Implement handle iocsr exception

Implement kvm handle vcpu iocsr exception, setting the iocsr info into
vcpu_run and return to user space to handle it.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/include/asm/inst.h | 16 ++++++
arch/loongarch/kvm/exit.c | 92 +++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index 71e1ed4165..008a88ead6 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -65,6 +65,14 @@ enum reg2_op {
revbd_op = 0x0f,
revh2w_op = 0x10,
revhd_op = 0x11,
+ iocsrrdb_op = 0x19200,
+ iocsrrdh_op = 0x19201,
+ iocsrrdw_op = 0x19202,
+ iocsrrdd_op = 0x19203,
+ iocsrwrb_op = 0x19204,
+ iocsrwrh_op = 0x19205,
+ iocsrwrw_op = 0x19206,
+ iocsrwrd_op = 0x19207,
};

enum reg2i5_op {
@@ -318,6 +326,13 @@ struct reg2bstrd_format {
unsigned int opcode : 10;
};

+struct reg2csr_format {
+ unsigned int rd : 5;
+ unsigned int rj : 5;
+ unsigned int csr : 14;
+ unsigned int opcode : 8;
+};
+
struct reg3_format {
unsigned int rd : 5;
unsigned int rj : 5;
@@ -346,6 +361,7 @@ union loongarch_instruction {
struct reg2i14_format reg2i14_format;
struct reg2i16_format reg2i16_format;
struct reg2bstrd_format reg2bstrd_format;
+ struct reg2csr_format reg2csr_format;
struct reg3_format reg3_format;
struct reg3sa2_format reg3sa2_format;
};
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index f77175351b..1a83eb9afe 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -107,3 +107,95 @@ static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)

return EMULATE_DONE;
}
+
+int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+ u32 rd, rj, opcode;
+ u32 addr;
+ unsigned long val;
+ int ret;
+
+ /*
+ * Each IOCSR with different opcode
+ */
+ rd = inst.reg2_format.rd;
+ rj = inst.reg2_format.rj;
+ opcode = inst.reg2_format.opcode;
+ addr = vcpu->arch.gprs[rj];
+ ret = EMULATE_DO_IOCSR;
+ run->iocsr_io.phys_addr = addr;
+ run->iocsr_io.is_write = 0;
+
+ /* LoongArch is Little endian */
+ switch (opcode) {
+ case iocsrrdb_op:
+ run->iocsr_io.len = 1;
+ break;
+ case iocsrrdh_op:
+ run->iocsr_io.len = 2;
+ break;
+ case iocsrrdw_op:
+ run->iocsr_io.len = 4;
+ break;
+ case iocsrrdd_op:
+ run->iocsr_io.len = 8;
+ break;
+ case iocsrwrb_op:
+ run->iocsr_io.len = 1;
+ run->iocsr_io.is_write = 1;
+ break;
+ case iocsrwrh_op:
+ run->iocsr_io.len = 2;
+ run->iocsr_io.is_write = 1;
+ break;
+ case iocsrwrw_op:
+ run->iocsr_io.len = 4;
+ run->iocsr_io.is_write = 1;
+ break;
+ case iocsrwrd_op:
+ run->iocsr_io.len = 8;
+ run->iocsr_io.is_write = 1;
+ break;
+ default:
+ ret = EMULATE_FAIL;
+ break;
+ }
+
+ if (ret == EMULATE_DO_IOCSR) {
+ if (run->iocsr_io.is_write) {
+ val = vcpu->arch.gprs[rd];
+ memcpy(run->iocsr_io.data, &val, run->iocsr_io.len);
+ }
+ vcpu->arch.io_gpr = rd;
+ }
+
+ return ret;
+}
+
+int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
+ enum emulation_result er = EMULATE_DONE;
+
+ switch (run->iocsr_io.len) {
+ case 8:
+ *gpr = *(s64 *)run->iocsr_io.data;
+ break;
+ case 4:
+ *gpr = *(int *)run->iocsr_io.data;
+ break;
+ case 2:
+ *gpr = *(short *)run->iocsr_io.data;
+ break;
+ case 1:
+ *gpr = *(char *) run->iocsr_io.data;
+ break;
+ default:
+ kvm_err("Bad IOCSR length: %d,addr is 0x%lx",
+ run->iocsr_io.len, vcpu->arch.badv);
+ er = EMULATE_FAIL;
+ break;
+ }
+
+ return er;
+}
--
2.39.1

2023-09-15 01:53:48

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 25/29] LoongArch: KVM: Implement kvm exception vector

Implement kvm exception vector, using _kvm_fault_tables array to save
the handle function pointer and it is used when vcpu handle exit.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/exit.c | 45 +++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index a91811918d..6ceeddf581 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -664,3 +664,48 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
kvm_own_fpu(vcpu);
return RESUME_GUEST;
}
+
+/*
+ * Loongarch KVM callback handling for not implemented guest exiting
+ */
+static int kvm_fault_ni(struct kvm_vcpu *vcpu)
+{
+ unsigned long estat, badv;
+ unsigned int exccode, inst;
+
+ /*
+ * Fetch the instruction.
+ */
+ badv = vcpu->arch.badv;
+ estat = vcpu->arch.host_estat;
+ exccode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
+ inst = vcpu->arch.badi;
+ kvm_err("Exccode: %d PC=%#lx inst=0x%08x BadVaddr=%#lx estat=%#lx\n",
+ exccode, vcpu->arch.pc, inst, badv, read_gcsr_estat());
+ kvm_arch_vcpu_dump_regs(vcpu);
+ kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+ return RESUME_GUEST;
+}
+
+static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = {
+ [EXCCODE_TLBL] = kvm_handle_read_fault,
+ [EXCCODE_TLBI] = kvm_handle_read_fault,
+ [EXCCODE_TLBS] = kvm_handle_write_fault,
+ [EXCCODE_TLBM] = kvm_handle_write_fault,
+ [EXCCODE_FPDIS] = kvm_handle_fpu_disabled,
+ [EXCCODE_GSPR] = kvm_handle_gspr,
+};
+
+void kvm_init_fault(void)
+{
+ int i;
+
+ for (i = 0; i < EXCCODE_INT_START; i++)
+ if (!kvm_fault_tables[i])
+ kvm_fault_tables[i] = kvm_fault_ni;
+}
+
+int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault)
+{
+ return kvm_fault_tables[fault](vcpu);
+}
--
2.39.1

2023-09-15 01:53:53

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 27/29] LoongArch: KVM: Enable kvm config and add the makefile

Enable LoongArch kvm config and add the makefile to support build kvm
module.

Reviewed-by: Bibo Mao <[email protected]>
Reported-by: kernel test robot <[email protected]>
Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/Kbuild | 1 +
arch/loongarch/Kconfig | 3 ++
arch/loongarch/configs/loongson3_defconfig | 2 +
arch/loongarch/kvm/Kconfig | 45 ++++++++++++++++++++++
arch/loongarch/kvm/Makefile | 20 ++++++++++
5 files changed, 71 insertions(+)
create mode 100644 arch/loongarch/kvm/Kconfig
create mode 100644 arch/loongarch/kvm/Makefile

diff --git a/arch/loongarch/Kbuild b/arch/loongarch/Kbuild
index b01f5cdb27..9679c798c2 100644
--- a/arch/loongarch/Kbuild
+++ b/arch/loongarch/Kbuild
@@ -2,6 +2,7 @@ obj-y += kernel/
obj-y += mm/
obj-y += net/
obj-y += vdso/
+obj-$(CONFIG_KVM) += kvm/

# for cleaning
subdir- += boot
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index e14396a2dd..0abb1f12eb 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -129,6 +129,7 @@ config LOONGARCH
select HAVE_KPROBES
select HAVE_KPROBES_ON_FTRACE
select HAVE_KRETPROBES
+ select HAVE_KVM
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI
select HAVE_PCI
@@ -676,3 +677,5 @@ source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig"

endmenu
+
+source "arch/loongarch/kvm/Kconfig"
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig
index a3b52aaa83..2a8edebcc5 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson3_defconfig
@@ -67,11 +67,13 @@ CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
CONFIG_EFI_CAPSULE_LOADER=m
CONFIG_EFI_TEST=m
CONFIG_JUMP_LABEL=y
+CONFIG_KVM=m
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_VIRTUALIZATION=y
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_BSD_DISKLABEL=y
diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig
new file mode 100644
index 0000000000..b517785c50
--- /dev/null
+++ b/arch/loongarch/kvm/Kconfig
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ help
+ Say Y here to get to see options for using your Linux host to run
+ other operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+if VIRTUALIZATION
+
+config AS_HAS_LVZ_EXTENSION
+ def_bool $(as-instr,hvcl 0)
+
+config KVM
+ tristate "Kernel-based Virtual Machine (KVM) support"
+ depends on AS_HAS_LVZ_EXTENSION
+ depends on HAVE_KVM
+ select ANON_INODES
+ select HAVE_KVM_DIRTY_RING_ACQ_REL
+ select HAVE_KVM_EVENTFD
+ select HAVE_KVM_VCPU_ASYNC_IOCTL
+ select KVM_GENERIC_DIRTYLOG_READ_PROTECT
+ select KVM_GENERIC_HARDWARE_ENABLING
+ select KVM_MMIO
+ select KVM_XFER_TO_GUEST_WORK
+ select MMU_NOTIFIER
+ select PREEMPT_NOTIFIERS
+ select SRCU
+ help
+ Support hosting virtualized guest machines using
+ hardware virtualization extensions. You will need
+ a processor equipped with virtualization extensions.
+
+ If unsure, say N.
+
+endif # VIRTUALIZATION
diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile
new file mode 100644
index 0000000000..77e9ba2b7a
--- /dev/null
+++ b/arch/loongarch/kvm/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for LoongArch KVM support
+#
+
+ccflags-y += -I $(srctree)/$(src)
+
+include $(srctree)/virt/kvm/Makefile.kvm
+
+obj-$(CONFIG_KVM) += kvm.o
+
+kvm-y += exit.o
+kvm-y += interrupt.o
+kvm-y += main.o
+kvm-y += mmu.o
+kvm-y += switch.o
+kvm-y += timer.o
+kvm-y += tlb.o
+kvm-y += vcpu.o
+kvm-y += vm.o
--
2.39.1

2023-09-15 01:54:05

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 24/29] LoongArch: KVM: Implement handle fpu exception

Implement handle fpu exception, using kvm_own_fpu to enable fpu for
guest.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/exit.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index 004b91055a..a91811918d 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -638,3 +638,29 @@ static int kvm_handle_read_fault(struct kvm_vcpu *vcpu)
{
return kvm_handle_mmu_fault(vcpu, false);
}
+
+/**
+ * kvm_handle_fpu_disabled() - Guest used fpu however it is disabled at host
+ * @vcpu: Virtual CPU context.
+ *
+ * Handle when the guest attempts to use fpu which hasn't been allowed
+ * by the root context.
+ */
+static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
+{
+ struct kvm_run *run = vcpu->run;
+
+ /*
+ * If guest FPU not present, the FPU operation should have been
+ * treated as a reserved instruction!
+ * If FPU already in use, we shouldn't get this at all.
+ */
+ if (WARN_ON(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) {
+ kvm_err("%s internal error\n", __func__);
+ run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ return RESUME_HOST;
+ }
+
+ kvm_own_fpu(vcpu);
+ return RESUME_GUEST;
+}
--
2.39.1

2023-09-15 01:54:18

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files

Add LoongArch KVM related header files, including kvm.h,
kvm_host.h, kvm_types.h. All of those are about LoongArch
virtualization features and kvm interfaces.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
arch/loongarch/include/asm/kvm_types.h | 11 ++
arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
include/uapi/linux/kvm.h | 9 +
4 files changed, 373 insertions(+)
create mode 100644 arch/loongarch/include/asm/kvm_host.h
create mode 100644 arch/loongarch/include/asm/kvm_types.h
create mode 100644 arch/loongarch/include/uapi/asm/kvm.h

diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
new file mode 100644
index 0000000000..00e0c1876b
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_HOST_H__
+#define __ASM_LOONGARCH_KVM_HOST_H__
+
+#include <linux/cpumask.h>
+#include <linux/mutex.h>
+#include <linux/hrtimer.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/kvm.h>
+#include <linux/kvm_types.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+
+#include <asm/inst.h>
+#include <asm/kvm_mmu.h>
+#include <asm/loongarch.h>
+
+/* Loongarch KVM register ids */
+#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
+#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
+
+#define KVM_MAX_VCPUS 256
+#define KVM_MAX_CPUCFG_REGS 21
+/* memory slots that does not exposed to userspace */
+#define KVM_PRIVATE_MEM_SLOTS 0
+
+#define KVM_HALT_POLL_NS_DEFAULT 500000
+
+struct kvm_vm_stat {
+ struct kvm_vm_stat_generic generic;
+ u64 pages;
+ u64 hugepages;
+};
+
+struct kvm_vcpu_stat {
+ struct kvm_vcpu_stat_generic generic;
+ u64 idle_exits;
+ u64 signal_exits;
+ u64 int_exits;
+ u64 cpucfg_exits;
+};
+
+struct kvm_arch_memory_slot {
+};
+
+struct kvm_context {
+ unsigned long vpid_cache;
+ struct kvm_vcpu *last_vcpu;
+};
+
+struct kvm_world_switch {
+ int (*guest_eentry)(void);
+ int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+ unsigned long page_order;
+};
+
+#define MAX_PGTABLE_LEVELS 4
+struct kvm_arch {
+ /* Guest physical mm */
+ kvm_pte_t *pgd;
+ unsigned long gpa_size;
+ unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
+ unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
+ unsigned int root_level;
+
+ s64 time_offset;
+ struct kvm_context __percpu *vmcs;
+};
+
+#define CSR_MAX_NUMS 0x800
+
+struct loongarch_csrs {
+ unsigned long csrs[CSR_MAX_NUMS];
+};
+
+/* Resume Flags */
+#define RESUME_HOST 0
+#define RESUME_GUEST 1
+
+enum emulation_result {
+ EMULATE_DONE, /* no further processing */
+ EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
+ EMULATE_FAIL, /* can't emulate this instruction */
+ EMULATE_EXCEPT, /* A guest exception has been generated */
+ EMULATE_DO_IOCSR, /* handle IOCSR request */
+};
+
+#define KVM_LARCH_FPU (0x1 << 0)
+#define KVM_LARCH_CSR (0x1 << 1)
+#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
+
+struct kvm_vcpu_arch {
+ /*
+ * Switch pointer-to-function type to unsigned long
+ * for loading the value into register directly.
+ */
+ unsigned long host_eentry;
+ unsigned long guest_eentry;
+
+ /* Pointers stored here for easy accessing from assembly code */
+ int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
+
+ /* Host registers preserved across guest mode execution */
+ unsigned long host_sp;
+ unsigned long host_tp;
+ unsigned long host_pgd;
+
+ /* Host CSRs are used when handling exits from guest */
+ unsigned long badi;
+ unsigned long badv;
+ unsigned long host_ecfg;
+ unsigned long host_estat;
+ unsigned long host_percpu;
+
+ /* GPRs */
+ unsigned long gprs[32];
+ unsigned long pc;
+
+ /* Which auxiliary state is loaded (KVM_LARCH_*) */
+ unsigned int aux_inuse;
+ /* FPU state */
+ struct loongarch_fpu fpu FPU_ALIGN;
+
+ /* CSR state */
+ struct loongarch_csrs *csr;
+
+ /* GPR used as IO source/target */
+ u32 io_gpr;
+
+ struct hrtimer swtimer;
+ /* KVM register to control count timer */
+ u32 count_ctl;
+
+ /* Bitmask of intr that are pending */
+ unsigned long irq_pending;
+ /* Bitmask of pending intr to be cleared */
+ unsigned long irq_clear;
+
+ /* Bitmask of exceptions that are pending */
+ unsigned long exception_pending;
+ unsigned int subcode;
+
+ /* Cache for pages needed inside spinlock regions */
+ struct kvm_mmu_memory_cache mmu_page_cache;
+
+ /* vcpu's vpid */
+ u64 vpid;
+
+ /* Frequency of stable timer in Hz */
+ u64 timer_mhz;
+ ktime_t expire;
+
+ u64 core_ext_ioisr[4];
+
+ /* Last CPU the vCPU state was loaded on */
+ int last_sched_cpu;
+ /* mp state */
+ struct kvm_mp_state mp_state;
+ /* cpucfg */
+ u32 cpucfg[KVM_MAX_CPUCFG_REGS];
+};
+
+static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
+{
+ return csr->csrs[reg];
+}
+
+static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
+{
+ csr->csrs[reg] = val;
+}
+
+/* Helpers */
+static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
+{
+ return cpu_has_fpu;
+}
+
+void kvm_init_fault(void);
+
+/* Debug: dump vcpu state */
+int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
+
+/* MMU handling */
+int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
+void kvm_flush_tlb_all(void);
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+int kvm_unmap_hva_range(struct kvm *kvm,
+ unsigned long start, unsigned long end, bool blockable);
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
+
+static inline void update_pc(struct kvm_vcpu_arch *arch)
+{
+ arch->pc += 4;
+}
+
+/**
+ * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
+ * @vcpu: Virtual CPU.
+ *
+ * Returns: Whether the TLBL exception was likely due to an instruction
+ * fetch fault rather than a data load fault.
+ */
+static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
+{
+ return arch->pc == arch->badv;
+}
+
+/* Misc */
+static inline void kvm_arch_hardware_unsetup(void) {}
+static inline void kvm_arch_sync_events(struct kvm *kvm) {}
+static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
+static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
+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) {}
+static inline void kvm_arch_free_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *slot) {}
+void kvm_check_vpid(struct kvm_vcpu *vcpu);
+enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
+int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
+void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
+ const struct kvm_memory_slot *memslot);
+void kvm_init_vmcs(struct kvm *kvm);
+void kvm_vector_entry(void);
+int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
+extern const unsigned long kvm_vector_size;
+extern const unsigned long kvm_enter_guest_size;
+extern unsigned long vpid_mask;
+extern struct kvm_world_switch *kvm_loongarch_ops;
+
+#define SW_GCSR (1 << 0)
+#define HW_GCSR (1 << 1)
+#define INVALID_GCSR (1 << 2)
+int get_gcsr_flag(int csr);
+extern void set_hw_gcsr(int csr_id, unsigned long val);
+#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
new file mode 100644
index 0000000000..2fe1d4bdff
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_types.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef _ASM_LOONGARCH_KVM_TYPES_H
+#define _ASM_LOONGARCH_KVM_TYPES_H
+
+#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
+
+#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
new file mode 100644
index 0000000000..fafda487d6
--- /dev/null
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __UAPI_ASM_LOONGARCH_KVM_H
+#define __UAPI_ASM_LOONGARCH_KVM_H
+
+#include <linux/types.h>
+
+/*
+ * KVM Loongarch specific structures and definitions.
+ *
+ * Some parts derived from the x86 version of this file.
+ */
+
+#define __KVM_HAVE_READONLY_MEM
+
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+#define KVM_DIRTY_LOG_PAGE_OFFSET 64
+
+/*
+ * for KVM_GET_REGS and KVM_SET_REGS
+ */
+struct kvm_regs {
+ /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
+ __u64 gpr[32];
+ __u64 pc;
+};
+
+/*
+ * for KVM_GET_FPU and KVM_SET_FPU
+ */
+struct kvm_fpu {
+ __u32 fcsr;
+ __u64 fcc; /* 8x8 */
+ struct kvm_fpureg {
+ __u64 val64[4];
+ } fpr[32];
+};
+
+/*
+ * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
+ * registers. The id field is broken down as follows:
+ *
+ * bits[63..52] - As per linux/kvm.h
+ * bits[51..32] - Must be zero.
+ * bits[31..16] - Register set.
+ *
+ * Register set = 0: GP registers from kvm_regs (see definitions below).
+ *
+ * Register set = 1: CSR registers.
+ *
+ * Register set = 2: KVM specific registers (see definitions below).
+ *
+ * Register set = 3: FPU / SIMD registers (see definitions below).
+ *
+ * Other sets registers may be added in the future. Each set would
+ * have its own identifier in bits[31..16].
+ */
+
+#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
+#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
+#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
+#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
+#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
+#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
+#define KVM_CSR_IDX_MASK 0x7fff
+#define KVM_CPUCFG_IDX_MASK 0x7fff
+
+/*
+ * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
+ */
+
+#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
+#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
+
+#define LOONGARCH_REG_SHIFT 3
+#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
+#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
+#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
+
+struct kvm_debug_exit_arch {
+};
+
+/* for KVM_SET_GUEST_DEBUG */
+struct kvm_guest_debug_arch {
+};
+
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
+/* dummy definition */
+struct kvm_sregs {
+};
+
+struct kvm_iocsr_entry {
+ __u32 addr;
+ __u32 pad;
+ __u64 data;
+};
+
+#define KVM_NR_IRQCHIPS 1
+#define KVM_IRQCHIP_NUM_PINS 64
+#define KVM_MAX_CORES 256
+
+#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 13065dd961..863f84619a 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -264,6 +264,7 @@ struct kvm_xen_exit {
#define KVM_EXIT_RISCV_SBI 35
#define KVM_EXIT_RISCV_CSR 36
#define KVM_EXIT_NOTIFY 37
+#define KVM_EXIT_LOONGARCH_IOCSR 38

/* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
@@ -336,6 +337,13 @@ struct kvm_run {
__u32 len;
__u8 is_write;
} mmio;
+ /* KVM_EXIT_LOONGARCH_IOCSR */
+ struct {
+ __u64 phys_addr;
+ __u8 data[8];
+ __u32 len;
+ __u8 is_write;
+ } iocsr_io;
/* KVM_EXIT_HYPERCALL */
struct {
__u64 nr;
@@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
#define KVM_REG_ARM64 0x6000000000000000ULL
#define KVM_REG_MIPS 0x7000000000000000ULL
#define KVM_REG_RISCV 0x8000000000000000ULL
+#define KVM_REG_LOONGARCH 0x9000000000000000ULL

#define KVM_REG_SIZE_SHIFT 52
#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
--
2.39.1

2023-09-15 01:54:21

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 03/29] LoongArch: KVM: Implement kvm hardware enable, disable interface

Implement kvm hardware enable, disable interface, setting
the guest config register to enable virtualization features
when called the interface.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/main.c | 62 +++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)

diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
index 0deb9273d8..fdbea0bc65 100644
--- a/arch/loongarch/kvm/main.c
+++ b/arch/loongarch/kvm/main.c
@@ -255,6 +255,68 @@ void kvm_check_vpid(struct kvm_vcpu *vcpu)
change_csr_gstat(vpid_mask << CSR_GSTAT_GID_SHIFT, vpid);
}

+void kvm_init_vmcs(struct kvm *kvm)
+{
+ kvm->arch.vmcs = vmcs;
+}
+
+long kvm_arch_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+int kvm_arch_hardware_enable(void)
+{
+ unsigned long env, gcfg = 0;
+
+ env = read_csr_gcfg();
+ /* First init gtlbc, gcfg, gstat, gintc. All guest use the same config */
+ clear_csr_gtlbc(CSR_GTLBC_USETGID | CSR_GTLBC_TOTI);
+ write_csr_gcfg(0);
+ write_csr_gstat(0);
+ write_csr_gintc(0);
+
+ /*
+ * Enable virtualization features granting guest direct control of
+ * certain features:
+ * GCI=2: Trap on init or unimplement cache instruction.
+ * TORU=0: Trap on Root Unimplement.
+ * CACTRL=1: Root control cache.
+ * TOP=0: Trap on Previlege.
+ * TOE=0: Trap on Exception.
+ * TIT=0: Trap on Timer.
+ */
+ if (env & CSR_GCFG_GCIP_ALL)
+ gcfg |= CSR_GCFG_GCI_SECURE;
+ if (env & CSR_GCFG_MATC_ROOT)
+ gcfg |= CSR_GCFG_MATC_ROOT;
+
+ gcfg |= CSR_GCFG_TIT;
+ write_csr_gcfg(gcfg);
+
+ kvm_flush_tlb_all();
+
+ /* Enable using TGID */
+ set_csr_gtlbc(CSR_GTLBC_USETGID);
+ kvm_debug("gtlbc:%lx gintc:%lx gstat:%lx gcfg:%lx",
+ read_csr_gtlbc(), read_csr_gintc(),
+ read_csr_gstat(), read_csr_gcfg());
+
+ return 0;
+}
+
+void kvm_arch_hardware_disable(void)
+{
+ clear_csr_gtlbc(CSR_GTLBC_USETGID | CSR_GTLBC_TOTI);
+ write_csr_gcfg(0);
+ write_csr_gstat(0);
+ write_csr_gintc(0);
+
+ /* Flush any remaining guest TLB entries */
+ kvm_flush_tlb_all();
+}
+
static int kvm_loongarch_env_init(void)
{
struct kvm_context *context;
--
2.39.1

2023-09-15 01:54:23

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 06/29] LoongArch: KVM: Implement vcpu create and destroy interface

Implement vcpu create and destroy interface, saving some info
into vcpu arch structure such as vcpu exception entrance, vcpu
enter guest pointer, etc. Init vcpu timer and set address
translation mode when vcpu create.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 87 +++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 arch/loongarch/kvm/vcpu.c

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
new file mode 100644
index 0000000000..e6efa0f185
--- /dev/null
+++ b/arch/loongarch/kvm/vcpu.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/entry-kvm.h>
+#include <asm/fpu.h>
+#include <asm/loongarch.h>
+#include <asm/setup.h>
+#include <asm/time.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
+{
+ return 0;
+}
+
+int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
+{
+ unsigned long timer_hz;
+ struct loongarch_csrs *csr;
+
+ vcpu->arch.vpid = 0;
+
+ hrtimer_init(&vcpu->arch.swtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
+ vcpu->arch.swtimer.function = kvm_swtimer_wakeup;
+
+ vcpu->arch.guest_eentry = (unsigned long)kvm_loongarch_ops->guest_eentry;
+ vcpu->arch.handle_exit = kvm_handle_exit;
+ vcpu->arch.csr = kzalloc(sizeof(struct loongarch_csrs), GFP_KERNEL);
+ if (!vcpu->arch.csr)
+ return -ENOMEM;
+
+ /*
+ * kvm all exceptions share one exception entry, and host <-> guest switch
+ * also switch excfg.VS field, keep host excfg.VS info here
+ */
+ vcpu->arch.host_ecfg = (read_csr_ecfg() & CSR_ECFG_VS);
+
+ /* Init */
+ vcpu->arch.last_sched_cpu = -1;
+
+ /*
+ * Initialize guest register state to valid architectural reset state.
+ */
+ timer_hz = calc_const_freq();
+ kvm_init_timer(vcpu, timer_hz);
+
+ /* Set Initialize mode for GUEST */
+ csr = vcpu->arch.csr;
+ kvm_write_sw_gcsr(csr, LOONGARCH_CSR_CRMD, CSR_CRMD_DA);
+
+ /* Set cpuid */
+ kvm_write_sw_gcsr(csr, LOONGARCH_CSR_TMID, vcpu->vcpu_id);
+
+ /* start with no pending virtual guest interrupts */
+ csr->csrs[LOONGARCH_CSR_GINTC] = 0;
+
+ return 0;
+}
+
+void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+ int cpu;
+ struct kvm_context *context;
+
+ hrtimer_cancel(&vcpu->arch.swtimer);
+ kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
+ kfree(vcpu->arch.csr);
+
+ /*
+ * If the vCPU is freed and reused as another vCPU, we don't want the
+ * matching pointer wrongly hanging around in last_vcpu.
+ */
+ for_each_possible_cpu(cpu) {
+ context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+ if (context->last_vcpu == vcpu)
+ context->last_vcpu = NULL;
+ }
+}
--
2.39.1

2023-09-15 01:54:26

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 05/29] LoongArch: KVM: Add vcpu related header files

Add LoongArch vcpu related header files, including vcpu csr
information, irq number defines, and some vcpu interfaces.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/include/asm/kvm_csr.h | 221 +++++++++++++++++++++++++
arch/loongarch/include/asm/kvm_vcpu.h | 107 ++++++++++++
arch/loongarch/include/asm/loongarch.h | 19 ++-
arch/loongarch/kvm/trace.h | 166 +++++++++++++++++++
4 files changed, 508 insertions(+), 5 deletions(-)
create mode 100644 arch/loongarch/include/asm/kvm_csr.h
create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
create mode 100644 arch/loongarch/kvm/trace.h

diff --git a/arch/loongarch/include/asm/kvm_csr.h b/arch/loongarch/include/asm/kvm_csr.h
new file mode 100644
index 0000000000..bcdff6724a
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_csr.h
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_CSR_H__
+#define __ASM_LOONGARCH_KVM_CSR_H__
+#include <asm/loongarch.h>
+#include <asm/kvm_vcpu.h>
+#include <linux/uaccess.h>
+#include <linux/kvm_host.h>
+
+/* binutils support virtualization instructions */
+#define gcsr_read(csr) \
+({ \
+ register unsigned long __v; \
+ __asm__ __volatile__( \
+ " gcsrrd %[val], %[reg]\n\t" \
+ : [val] "=r" (__v) \
+ : [reg] "i" (csr) \
+ : "memory"); \
+ __v; \
+})
+
+#define gcsr_write(v, csr) \
+({ \
+ register unsigned long __v = v; \
+ __asm__ __volatile__ ( \
+ " gcsrwr %[val], %[reg]\n\t" \
+ : [val] "+r" (__v) \
+ : [reg] "i" (csr) \
+ : "memory"); \
+})
+
+#define gcsr_xchg(v, m, csr) \
+({ \
+ register unsigned long __v = v; \
+ __asm__ __volatile__( \
+ " gcsrxchg %[val], %[mask], %[reg]\n\t" \
+ : [val] "+r" (__v) \
+ : [mask] "r" (m), [reg] "i" (csr) \
+ : "memory"); \
+ __v; \
+})
+
+/* Guest CSRS read and write */
+#define read_gcsr_crmd() gcsr_read(LOONGARCH_CSR_CRMD)
+#define write_gcsr_crmd(val) gcsr_write(val, LOONGARCH_CSR_CRMD)
+#define read_gcsr_prmd() gcsr_read(LOONGARCH_CSR_PRMD)
+#define write_gcsr_prmd(val) gcsr_write(val, LOONGARCH_CSR_PRMD)
+#define read_gcsr_euen() gcsr_read(LOONGARCH_CSR_EUEN)
+#define write_gcsr_euen(val) gcsr_write(val, LOONGARCH_CSR_EUEN)
+#define read_gcsr_misc() gcsr_read(LOONGARCH_CSR_MISC)
+#define write_gcsr_misc(val) gcsr_write(val, LOONGARCH_CSR_MISC)
+#define read_gcsr_ecfg() gcsr_read(LOONGARCH_CSR_ECFG)
+#define write_gcsr_ecfg(val) gcsr_write(val, LOONGARCH_CSR_ECFG)
+#define read_gcsr_estat() gcsr_read(LOONGARCH_CSR_ESTAT)
+#define write_gcsr_estat(val) gcsr_write(val, LOONGARCH_CSR_ESTAT)
+#define read_gcsr_era() gcsr_read(LOONGARCH_CSR_ERA)
+#define write_gcsr_era(val) gcsr_write(val, LOONGARCH_CSR_ERA)
+#define read_gcsr_badv() gcsr_read(LOONGARCH_CSR_BADV)
+#define write_gcsr_badv(val) gcsr_write(val, LOONGARCH_CSR_BADV)
+#define read_gcsr_badi() gcsr_read(LOONGARCH_CSR_BADI)
+#define write_gcsr_badi(val) gcsr_write(val, LOONGARCH_CSR_BADI)
+#define read_gcsr_eentry() gcsr_read(LOONGARCH_CSR_EENTRY)
+#define write_gcsr_eentry(val) gcsr_write(val, LOONGARCH_CSR_EENTRY)
+
+#define read_gcsr_tlbidx() gcsr_read(LOONGARCH_CSR_TLBIDX)
+#define write_gcsr_tlbidx(val) gcsr_write(val, LOONGARCH_CSR_TLBIDX)
+#define read_gcsr_tlbhi() gcsr_read(LOONGARCH_CSR_TLBEHI)
+#define write_gcsr_tlbhi(val) gcsr_write(val, LOONGARCH_CSR_TLBEHI)
+#define read_gcsr_tlblo0() gcsr_read(LOONGARCH_CSR_TLBELO0)
+#define write_gcsr_tlblo0(val) gcsr_write(val, LOONGARCH_CSR_TLBELO0)
+#define read_gcsr_tlblo1() gcsr_read(LOONGARCH_CSR_TLBELO1)
+#define write_gcsr_tlblo1(val) gcsr_write(val, LOONGARCH_CSR_TLBELO1)
+
+#define read_gcsr_asid() gcsr_read(LOONGARCH_CSR_ASID)
+#define write_gcsr_asid(val) gcsr_write(val, LOONGARCH_CSR_ASID)
+#define read_gcsr_pgdl() gcsr_read(LOONGARCH_CSR_PGDL)
+#define write_gcsr_pgdl(val) gcsr_write(val, LOONGARCH_CSR_PGDL)
+#define read_gcsr_pgdh() gcsr_read(LOONGARCH_CSR_PGDH)
+#define write_gcsr_pgdh(val) gcsr_write(val, LOONGARCH_CSR_PGDH)
+#define write_gcsr_pgd(val) gcsr_write(val, LOONGARCH_CSR_PGD)
+#define read_gcsr_pgd() gcsr_read(LOONGARCH_CSR_PGD)
+#define read_gcsr_pwctl0() gcsr_read(LOONGARCH_CSR_PWCTL0)
+#define write_gcsr_pwctl0(val) gcsr_write(val, LOONGARCH_CSR_PWCTL0)
+#define read_gcsr_pwctl1() gcsr_read(LOONGARCH_CSR_PWCTL1)
+#define write_gcsr_pwctl1(val) gcsr_write(val, LOONGARCH_CSR_PWCTL1)
+#define read_gcsr_stlbpgsize() gcsr_read(LOONGARCH_CSR_STLBPGSIZE)
+#define write_gcsr_stlbpgsize(val) gcsr_write(val, LOONGARCH_CSR_STLBPGSIZE)
+#define read_gcsr_rvacfg() gcsr_read(LOONGARCH_CSR_RVACFG)
+#define write_gcsr_rvacfg(val) gcsr_write(val, LOONGARCH_CSR_RVACFG)
+
+#define read_gcsr_cpuid() gcsr_read(LOONGARCH_CSR_CPUID)
+#define write_gcsr_cpuid(val) gcsr_write(val, LOONGARCH_CSR_CPUID)
+#define read_gcsr_prcfg1() gcsr_read(LOONGARCH_CSR_PRCFG1)
+#define write_gcsr_prcfg1(val) gcsr_write(val, LOONGARCH_CSR_PRCFG1)
+#define read_gcsr_prcfg2() gcsr_read(LOONGARCH_CSR_PRCFG2)
+#define write_gcsr_prcfg2(val) gcsr_write(val, LOONGARCH_CSR_PRCFG2)
+#define read_gcsr_prcfg3() gcsr_read(LOONGARCH_CSR_PRCFG3)
+#define write_gcsr_prcfg3(val) gcsr_write(val, LOONGARCH_CSR_PRCFG3)
+
+#define read_gcsr_kscratch0() gcsr_read(LOONGARCH_CSR_KS0)
+#define write_gcsr_kscratch0(val) gcsr_write(val, LOONGARCH_CSR_KS0)
+#define read_gcsr_kscratch1() gcsr_read(LOONGARCH_CSR_KS1)
+#define write_gcsr_kscratch1(val) gcsr_write(val, LOONGARCH_CSR_KS1)
+#define read_gcsr_kscratch2() gcsr_read(LOONGARCH_CSR_KS2)
+#define write_gcsr_kscratch2(val) gcsr_write(val, LOONGARCH_CSR_KS2)
+#define read_gcsr_kscratch3() gcsr_read(LOONGARCH_CSR_KS3)
+#define write_gcsr_kscratch3(val) gcsr_write(val, LOONGARCH_CSR_KS3)
+#define read_gcsr_kscratch4() gcsr_read(LOONGARCH_CSR_KS4)
+#define write_gcsr_kscratch4(val) gcsr_write(val, LOONGARCH_CSR_KS4)
+#define read_gcsr_kscratch5() gcsr_read(LOONGARCH_CSR_KS5)
+#define write_gcsr_kscratch5(val) gcsr_write(val, LOONGARCH_CSR_KS5)
+#define read_gcsr_kscratch6() gcsr_read(LOONGARCH_CSR_KS6)
+#define write_gcsr_kscratch6(val) gcsr_write(val, LOONGARCH_CSR_KS6)
+#define read_gcsr_kscratch7() gcsr_read(LOONGARCH_CSR_KS7)
+#define write_gcsr_kscratch7(val) gcsr_write(val, LOONGARCH_CSR_KS7)
+
+#define read_gcsr_timerid() gcsr_read(LOONGARCH_CSR_TMID)
+#define write_gcsr_timerid(val) gcsr_write(val, LOONGARCH_CSR_TMID)
+#define read_gcsr_timercfg() gcsr_read(LOONGARCH_CSR_TCFG)
+#define write_gcsr_timercfg(val) gcsr_write(val, LOONGARCH_CSR_TCFG)
+#define read_gcsr_timertick() gcsr_read(LOONGARCH_CSR_TVAL)
+#define write_gcsr_timertick(val) gcsr_write(val, LOONGARCH_CSR_TVAL)
+#define read_gcsr_timeroffset() gcsr_read(LOONGARCH_CSR_CNTC)
+#define write_gcsr_timeroffset(val) gcsr_write(val, LOONGARCH_CSR_CNTC)
+
+#define read_gcsr_llbctl() gcsr_read(LOONGARCH_CSR_LLBCTL)
+#define write_gcsr_llbctl(val) gcsr_write(val, LOONGARCH_CSR_LLBCTL)
+
+#define read_gcsr_tlbrentry() gcsr_read(LOONGARCH_CSR_TLBRENTRY)
+#define write_gcsr_tlbrentry(val) gcsr_write(val, LOONGARCH_CSR_TLBRENTRY)
+#define read_gcsr_tlbrbadv() gcsr_read(LOONGARCH_CSR_TLBRBADV)
+#define write_gcsr_tlbrbadv(val) gcsr_write(val, LOONGARCH_CSR_TLBRBADV)
+#define read_gcsr_tlbrera() gcsr_read(LOONGARCH_CSR_TLBRERA)
+#define write_gcsr_tlbrera(val) gcsr_write(val, LOONGARCH_CSR_TLBRERA)
+#define read_gcsr_tlbrsave() gcsr_read(LOONGARCH_CSR_TLBRSAVE)
+#define write_gcsr_tlbrsave(val) gcsr_write(val, LOONGARCH_CSR_TLBRSAVE)
+#define read_gcsr_tlbrelo0() gcsr_read(LOONGARCH_CSR_TLBRELO0)
+#define write_gcsr_tlbrelo0(val) gcsr_write(val, LOONGARCH_CSR_TLBRELO0)
+#define read_gcsr_tlbrelo1() gcsr_read(LOONGARCH_CSR_TLBRELO1)
+#define write_gcsr_tlbrelo1(val) gcsr_write(val, LOONGARCH_CSR_TLBRELO1)
+#define read_gcsr_tlbrehi() gcsr_read(LOONGARCH_CSR_TLBREHI)
+#define write_gcsr_tlbrehi(val) gcsr_write(val, LOONGARCH_CSR_TLBREHI)
+#define read_gcsr_tlbrprmd() gcsr_read(LOONGARCH_CSR_TLBRPRMD)
+#define write_gcsr_tlbrprmd(val) gcsr_write(val, LOONGARCH_CSR_TLBRPRMD)
+
+#define read_gcsr_directwin0() gcsr_read(LOONGARCH_CSR_DMWIN0)
+#define write_gcsr_directwin0(val) gcsr_write(val, LOONGARCH_CSR_DMWIN0)
+#define read_gcsr_directwin1() gcsr_read(LOONGARCH_CSR_DMWIN1)
+#define write_gcsr_directwin1(val) gcsr_write(val, LOONGARCH_CSR_DMWIN1)
+#define read_gcsr_directwin2() gcsr_read(LOONGARCH_CSR_DMWIN2)
+#define write_gcsr_directwin2(val) gcsr_write(val, LOONGARCH_CSR_DMWIN2)
+#define read_gcsr_directwin3() gcsr_read(LOONGARCH_CSR_DMWIN3)
+#define write_gcsr_directwin3(val) gcsr_write(val, LOONGARCH_CSR_DMWIN3)
+
+/* Guest related CSRs */
+#define read_csr_gtlbc() csr_read64(LOONGARCH_CSR_GTLBC)
+#define write_csr_gtlbc(val) csr_write64(val, LOONGARCH_CSR_GTLBC)
+#define read_csr_trgp() csr_read64(LOONGARCH_CSR_TRGP)
+#define read_csr_gcfg() csr_read64(LOONGARCH_CSR_GCFG)
+#define write_csr_gcfg(val) csr_write64(val, LOONGARCH_CSR_GCFG)
+#define read_csr_gstat() csr_read64(LOONGARCH_CSR_GSTAT)
+#define write_csr_gstat(val) csr_write64(val, LOONGARCH_CSR_GSTAT)
+#define read_csr_gintc() csr_read64(LOONGARCH_CSR_GINTC)
+#define write_csr_gintc(val) csr_write64(val, LOONGARCH_CSR_GINTC)
+#define read_csr_gcntc() csr_read64(LOONGARCH_CSR_GCNTC)
+#define write_csr_gcntc(val) csr_write64(val, LOONGARCH_CSR_GCNTC)
+
+#define __BUILD_GCSR_OP(name) __BUILD_CSR_COMMON(gcsr_##name)
+
+__BUILD_GCSR_OP(llbctl)
+__BUILD_GCSR_OP(tlbidx)
+__BUILD_CSR_OP(gcfg)
+__BUILD_CSR_OP(gstat)
+__BUILD_CSR_OP(gtlbc)
+__BUILD_CSR_OP(gintc)
+
+#define set_gcsr_estat(val) \
+ gcsr_xchg(val, val, LOONGARCH_CSR_ESTAT)
+#define clear_gcsr_estat(val) \
+ gcsr_xchg(~(val), val, LOONGARCH_CSR_ESTAT)
+
+#define kvm_read_hw_gcsr(id) gcsr_read(id)
+#define kvm_write_hw_gcsr(id, val) gcsr_write(val, id)
+
+int kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v);
+int kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 v);
+int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu);
+
+#define kvm_save_hw_gcsr(csr, gid) (csr->csrs[gid] = gcsr_read(gid))
+#define kvm_restore_hw_gcsr(csr, gid) (gcsr_write(csr->csrs[gid], gid))
+
+static __always_inline unsigned long kvm_read_sw_gcsr(struct loongarch_csrs *csr, int gid)
+{
+ return csr->csrs[gid];
+}
+
+static __always_inline void kvm_write_sw_gcsr(struct loongarch_csrs *csr,
+ int gid, unsigned long val)
+{
+ csr->csrs[gid] = val;
+}
+
+static __always_inline void kvm_set_sw_gcsr(struct loongarch_csrs *csr,
+ int gid, unsigned long val)
+{
+ csr->csrs[gid] |= val;
+}
+
+static __always_inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr,
+ int gid, unsigned long mask,
+ unsigned long val)
+{
+ unsigned long _mask = mask;
+
+ csr->csrs[gid] &= ~_mask;
+ csr->csrs[gid] |= val & _mask;
+}
+#endif /* __ASM_LOONGARCH_KVM_CSR_H__ */
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
new file mode 100644
index 0000000000..7756f27183
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_vcpu.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_VCPU_H__
+#define __ASM_LOONGARCH_KVM_VCPU_H__
+
+#include <linux/kvm_host.h>
+#include <asm/loongarch.h>
+
+/* Controlled by 0x5 guest exst */
+#define CPU_SIP0 (_ULCAST_(1))
+#define CPU_SIP1 (_ULCAST_(1) << 1)
+#define CPU_PMU (_ULCAST_(1) << 10)
+#define CPU_TIMER (_ULCAST_(1) << 11)
+#define CPU_IPI (_ULCAST_(1) << 12)
+
+/* Controlled by 0x52 guest exception VIP
+ * aligned to exst bit 5~12
+ */
+#define CPU_IP0 (_ULCAST_(1))
+#define CPU_IP1 (_ULCAST_(1) << 1)
+#define CPU_IP2 (_ULCAST_(1) << 2)
+#define CPU_IP3 (_ULCAST_(1) << 3)
+#define CPU_IP4 (_ULCAST_(1) << 4)
+#define CPU_IP5 (_ULCAST_(1) << 5)
+#define CPU_IP6 (_ULCAST_(1) << 6)
+#define CPU_IP7 (_ULCAST_(1) << 7)
+
+#define MNSEC_PER_SEC (NSEC_PER_SEC >> 20)
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_LOONGSON_IRQ_TYPE_SHIFT 24
+#define KVM_LOONGSON_IRQ_TYPE_MASK 0xff
+#define KVM_LOONGSON_IRQ_VCPU_SHIFT 16
+#define KVM_LOONGSON_IRQ_VCPU_MASK 0xff
+#define KVM_LOONGSON_IRQ_NUM_SHIFT 0
+#define KVM_LOONGSON_IRQ_NUM_MASK 0xffff
+
+/* Irq_type field */
+#define KVM_LOONGSON_IRQ_TYPE_CPU_IP 0
+#define KVM_LOONGSON_IRQ_TYPE_CPU_IO 1
+#define KVM_LOONGSON_IRQ_TYPE_HT 2
+#define KVM_LOONGSON_IRQ_TYPE_MSI 3
+#define KVM_LOONGSON_IRQ_TYPE_IOAPIC 4
+#define KVM_LOONGSON_IRQ_TYPE_ROUTE 5
+
+/* Out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_LOONGSON_IRQ_CPU_IRQ 0
+#define KVM_LOONGSON_IRQ_CPU_FIQ 1
+#define KVM_LOONGSON_CPU_IP_NUM 8
+
+typedef union loongarch_instruction larch_inst;
+typedef int (*exit_handle_fn)(struct kvm_vcpu *);
+
+int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst);
+int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst);
+int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_emu_idle(struct kvm_vcpu *vcpu);
+int kvm_handle_pv_hcall(struct kvm_vcpu *vcpu);
+int kvm_pending_timer(struct kvm_vcpu *vcpu);
+int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
+void kvm_deliver_intr(struct kvm_vcpu *vcpu);
+void kvm_deliver_exception(struct kvm_vcpu *vcpu);
+
+void kvm_own_fpu(struct kvm_vcpu *vcpu);
+void kvm_lose_fpu(struct kvm_vcpu *vcpu);
+void kvm_save_fpu(struct loongarch_fpu *fpu);
+void kvm_restore_fpu(struct loongarch_fpu *fpu);
+void kvm_restore_fcsr(struct loongarch_fpu *fpu);
+
+void kvm_acquire_timer(struct kvm_vcpu *vcpu);
+void kvm_reset_timer(struct kvm_vcpu *vcpu);
+void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz);
+void kvm_restore_timer(struct kvm_vcpu *vcpu);
+void kvm_save_timer(struct kvm_vcpu *vcpu);
+
+int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
+/*
+ * Loongarch KVM guest interrupt handling
+ */
+static inline void kvm_queue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
+{
+ set_bit(irq, &vcpu->arch.irq_pending);
+ clear_bit(irq, &vcpu->arch.irq_clear);
+}
+
+static inline void kvm_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
+{
+ clear_bit(irq, &vcpu->arch.irq_pending);
+ set_bit(irq, &vcpu->arch.irq_clear);
+}
+
+static inline int kvm_queue_exception(struct kvm_vcpu *vcpu,
+ unsigned int code, unsigned int subcode)
+{
+ /* only one exception can be injected */
+ if (!vcpu->arch.exception_pending) {
+ set_bit(code, &vcpu->arch.exception_pending);
+ vcpu->arch.subcode = subcode;
+ return 0;
+ } else
+ return -1;
+}
+#endif /* __ASM_LOONGARCH_KVM_VCPU_H__ */
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index 33531d432b..9b4957cefa 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -226,6 +226,7 @@
#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */
#define CSR_ECFG_VS_SHIFT 16
#define CSR_ECFG_VS_WIDTH 3
+#define CSR_ECFG_VS_SHIFT_END (CSR_ECFG_VS_SHIFT + CSR_ECFG_VS_WIDTH - 1)
#define CSR_ECFG_VS (_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT)
#define CSR_ECFG_IM_SHIFT 0
#define CSR_ECFG_IM_WIDTH 14
@@ -314,13 +315,14 @@
#define CSR_TLBLO1_V (_ULCAST_(0x1) << CSR_TLBLO1_V_SHIFT)

#define LOONGARCH_CSR_GTLBC 0x15 /* Guest TLB control */
-#define CSR_GTLBC_RID_SHIFT 16
-#define CSR_GTLBC_RID_WIDTH 8
-#define CSR_GTLBC_RID (_ULCAST_(0xff) << CSR_GTLBC_RID_SHIFT)
+#define CSR_GTLBC_TGID_SHIFT 16
+#define CSR_GTLBC_TGID_WIDTH 8
+#define CSR_GTLBC_TGID_SHIFT_END (CSR_GTLBC_TGID_SHIFT + CSR_GTLBC_TGID_WIDTH - 1)
+#define CSR_GTLBC_TGID (_ULCAST_(0xff) << CSR_GTLBC_TGID_SHIFT)
#define CSR_GTLBC_TOTI_SHIFT 13
#define CSR_GTLBC_TOTI (_ULCAST_(0x1) << CSR_GTLBC_TOTI_SHIFT)
-#define CSR_GTLBC_USERID_SHIFT 12
-#define CSR_GTLBC_USERID (_ULCAST_(0x1) << CSR_GTLBC_USERID_SHIFT)
+#define CSR_GTLBC_USETGID_SHIFT 12
+#define CSR_GTLBC_USETGID (_ULCAST_(0x1) << CSR_GTLBC_USETGID_SHIFT)
#define CSR_GTLBC_GMTLBSZ_SHIFT 0
#define CSR_GTLBC_GMTLBSZ_WIDTH 6
#define CSR_GTLBC_GMTLBSZ (_ULCAST_(0x3f) << CSR_GTLBC_GMTLBSZ_SHIFT)
@@ -475,6 +477,7 @@
#define LOONGARCH_CSR_GSTAT 0x50 /* Guest status */
#define CSR_GSTAT_GID_SHIFT 16
#define CSR_GSTAT_GID_WIDTH 8
+#define CSR_GSTAT_GID_SHIFT_END (CSR_GSTAT_GID_SHIFT + CSR_GSTAT_GID_WIDTH - 1)
#define CSR_GSTAT_GID (_ULCAST_(0xff) << CSR_GSTAT_GID_SHIFT)
#define CSR_GSTAT_GIDBIT_SHIFT 4
#define CSR_GSTAT_GIDBIT_WIDTH 6
@@ -525,6 +528,12 @@
#define CSR_GCFG_MATC_GUEST (_ULCAST_(0x0) << CSR_GCFG_MATC_SHITF)
#define CSR_GCFG_MATC_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATC_SHITF)
#define CSR_GCFG_MATC_NEST (_ULCAST_(0x2) << CSR_GCFG_MATC_SHITF)
+#define CSR_GCFG_MATP_NEST_SHIFT 2
+#define CSR_GCFG_MATP_NEST (_ULCAST_(0x1) << CSR_GCFG_MATP_NEST_SHIFT)
+#define CSR_GCFG_MATP_ROOT_SHIFT 1
+#define CSR_GCFG_MATP_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATP_ROOT_SHIFT)
+#define CSR_GCFG_MATP_GUEST_SHIFT 0
+#define CSR_GCFG_MATP_GUEST (_ULCAST_(0x1) << CSR_GCFG_MATP_GUEST_SHIFT)

#define LOONGARCH_CSR_GINTC 0x52 /* Guest interrupt control */
#define CSR_GINTC_HC_SHIFT 16
diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h
new file mode 100644
index 0000000000..134b5968f6
--- /dev/null
+++ b/arch/loongarch/kvm/trace.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+#include <asm/kvm_csr.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+
+/*
+ * Tracepoints for VM enters
+ */
+DECLARE_EVENT_CLASS(kvm_transition,
+ TP_PROTO(struct kvm_vcpu *vcpu),
+ TP_ARGS(vcpu),
+ TP_STRUCT__entry(
+ __field(unsigned long, pc)
+ ),
+
+ TP_fast_assign(
+ __entry->pc = vcpu->arch.pc;
+ ),
+
+ TP_printk("PC: 0x%08lx",
+ __entry->pc)
+);
+
+DEFINE_EVENT(kvm_transition, kvm_enter,
+ TP_PROTO(struct kvm_vcpu *vcpu),
+ TP_ARGS(vcpu));
+
+DEFINE_EVENT(kvm_transition, kvm_reenter,
+ TP_PROTO(struct kvm_vcpu *vcpu),
+ TP_ARGS(vcpu));
+
+DEFINE_EVENT(kvm_transition, kvm_out,
+ TP_PROTO(struct kvm_vcpu *vcpu),
+ TP_ARGS(vcpu));
+
+/* Further exit reasons */
+#define KVM_TRACE_EXIT_IDLE 64
+#define KVM_TRACE_EXIT_CACHE 65
+
+/* Tracepoints for VM exits */
+#define kvm_trace_symbol_exit_types \
+ { KVM_TRACE_EXIT_IDLE, "IDLE" }, \
+ { KVM_TRACE_EXIT_CACHE, "CACHE" }
+
+TRACE_EVENT(kvm_exit_gspr,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned int inst_word),
+ TP_ARGS(vcpu, inst_word),
+ TP_STRUCT__entry(
+ __field(unsigned int, inst_word)
+ ),
+
+ TP_fast_assign(
+ __entry->inst_word = inst_word;
+ ),
+
+ TP_printk("inst word: 0x%08x",
+ __entry->inst_word)
+);
+
+
+DECLARE_EVENT_CLASS(kvm_exit,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+ TP_ARGS(vcpu, reason),
+ TP_STRUCT__entry(
+ __field(unsigned long, pc)
+ __field(unsigned int, reason)
+ ),
+
+ TP_fast_assign(
+ __entry->pc = vcpu->arch.pc;
+ __entry->reason = reason;
+ ),
+
+ TP_printk("[%s]PC: 0x%08lx",
+ __print_symbolic(__entry->reason,
+ kvm_trace_symbol_exit_types),
+ __entry->pc)
+);
+
+DEFINE_EVENT(kvm_exit, kvm_exit_idle,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+ TP_ARGS(vcpu, reason));
+
+DEFINE_EVENT(kvm_exit, kvm_exit_cache,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+ TP_ARGS(vcpu, reason));
+
+DEFINE_EVENT(kvm_exit, kvm_exit,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
+ TP_ARGS(vcpu, reason));
+
+#define KVM_TRACE_AUX_RESTORE 0
+#define KVM_TRACE_AUX_SAVE 1
+#define KVM_TRACE_AUX_ENABLE 2
+#define KVM_TRACE_AUX_DISABLE 3
+#define KVM_TRACE_AUX_DISCARD 4
+
+#define KVM_TRACE_AUX_FPU 1
+
+#define kvm_trace_symbol_aux_op \
+ { KVM_TRACE_AUX_RESTORE, "restore" }, \
+ { KVM_TRACE_AUX_SAVE, "save" }, \
+ { KVM_TRACE_AUX_ENABLE, "enable" }, \
+ { KVM_TRACE_AUX_DISABLE, "disable" }, \
+ { KVM_TRACE_AUX_DISCARD, "discard" }
+
+#define kvm_trace_symbol_aux_state \
+ { KVM_TRACE_AUX_FPU, "FPU" }
+
+TRACE_EVENT(kvm_aux,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
+ unsigned int state),
+ TP_ARGS(vcpu, op, state),
+ TP_STRUCT__entry(
+ __field(unsigned long, pc)
+ __field(u8, op)
+ __field(u8, state)
+ ),
+
+ TP_fast_assign(
+ __entry->pc = vcpu->arch.pc;
+ __entry->op = op;
+ __entry->state = state;
+ ),
+
+ TP_printk("%s %s PC: 0x%08lx",
+ __print_symbolic(__entry->op,
+ kvm_trace_symbol_aux_op),
+ __print_symbolic(__entry->state,
+ kvm_trace_symbol_aux_state),
+ __entry->pc)
+);
+
+TRACE_EVENT(kvm_vpid_change,
+ TP_PROTO(struct kvm_vcpu *vcpu, unsigned long vpid),
+ TP_ARGS(vcpu, vpid),
+ TP_STRUCT__entry(
+ __field(unsigned long, vpid)
+ ),
+
+ TP_fast_assign(
+ __entry->vpid = vpid;
+ ),
+
+ TP_printk("vpid: 0x%08lx",
+ __entry->vpid)
+);
+
+#endif /* _TRACE_LOONGARCH64_KVM_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/loongarch/kvm
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.39.1

2023-09-15 01:54:31

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 11/29] LoongArch: KVM: Implement fpu related operations for vcpu

Implement LoongArch fpu related interface for vcpu, such as get fpu, set
fpu, own fpu and lose fpu, etc.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 60 +++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 6b1b2a058b..b8af4a200c 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -276,6 +276,66 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
return r;
}

+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ int i = 0;
+
+ /* no need vcpu_load and vcpu_put */
+ fpu->fcsr = vcpu->arch.fpu.fcsr;
+ fpu->fcc = vcpu->arch.fpu.fcc;
+ for (i = 0; i < NUM_FPU_REGS; i++)
+ memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], FPU_REG_WIDTH / 64);
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ int i = 0;
+
+ /* no need vcpu_load and vcpu_put */
+ vcpu->arch.fpu.fcsr = fpu->fcsr;
+ vcpu->arch.fpu.fcc = fpu->fcc;
+ for (i = 0; i < NUM_FPU_REGS; i++)
+ memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], FPU_REG_WIDTH / 64);
+
+ return 0;
+}
+
+/* Enable FPU for guest and restore context */
+void kvm_own_fpu(struct kvm_vcpu *vcpu)
+{
+ preempt_disable();
+
+ /*
+ * Enable FPU for guest
+ */
+ set_csr_euen(CSR_EUEN_FPEN);
+
+ kvm_restore_fpu(&vcpu->arch.fpu);
+ vcpu->arch.aux_inuse |= KVM_LARCH_FPU;
+ trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_FPU);
+
+ preempt_enable();
+}
+
+/* Save and disable FPU */
+void kvm_lose_fpu(struct kvm_vcpu *vcpu)
+{
+ preempt_disable();
+
+ if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
+ kvm_save_fpu(&vcpu->arch.fpu);
+ vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU;
+ trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
+
+ /* Disable FPU */
+ clear_csr_euen(CSR_EUEN_FPEN);
+ }
+
+ preempt_enable();
+}
+
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
{
return 0;
--
2.39.1

2023-09-15 01:54:32

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 12/29] LoongArch: KVM: Implement vcpu interrupt operations

Implement vcpu interrupt operations such as vcpu set irq and
vcpu clear irq, using set_gcsr_estat to set irq which is
parsed by the irq bitmap.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/interrupt.c | 185 +++++++++++++++++++++++++++++++++
arch/loongarch/kvm/vcpu.c | 37 +++++++
2 files changed, 222 insertions(+)
create mode 100644 arch/loongarch/kvm/interrupt.c

diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
new file mode 100644
index 0000000000..9df75a564e
--- /dev/null
+++ b/arch/loongarch/kvm/interrupt.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <asm/kvm_vcpu.h>
+#include <asm/kvm_csr.h>
+
+static unsigned int int_to_coreint[EXCCODE_INT_NUM] = {
+ [INT_TI] = CPU_TIMER,
+ [INT_IPI] = CPU_IPI,
+ [INT_SWI0] = CPU_SIP0,
+ [INT_SWI1] = CPU_SIP1,
+ [INT_HWI0] = CPU_IP0,
+ [INT_HWI1] = CPU_IP1,
+ [INT_HWI2] = CPU_IP2,
+ [INT_HWI3] = CPU_IP3,
+ [INT_HWI4] = CPU_IP4,
+ [INT_HWI5] = CPU_IP5,
+ [INT_HWI6] = CPU_IP6,
+ [INT_HWI7] = CPU_IP7,
+};
+
+static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
+{
+ unsigned int irq = 0;
+
+ clear_bit(priority, &vcpu->arch.irq_pending);
+ if (priority < EXCCODE_INT_NUM)
+ irq = int_to_coreint[priority];
+
+ switch (priority) {
+ case INT_TI:
+ case INT_IPI:
+ case INT_SWI0:
+ case INT_SWI1:
+ set_gcsr_estat(irq);
+ break;
+
+ case INT_HWI0 ... INT_HWI7:
+ set_csr_gintc(irq);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
+{
+ unsigned int irq = 0;
+
+ clear_bit(priority, &vcpu->arch.irq_clear);
+ if (priority < EXCCODE_INT_NUM)
+ irq = int_to_coreint[priority];
+
+ switch (priority) {
+ case INT_TI:
+ case INT_IPI:
+ case INT_SWI0:
+ case INT_SWI1:
+ clear_gcsr_estat(irq);
+ break;
+
+ case INT_HWI0 ... INT_HWI7:
+ clear_csr_gintc(irq);
+ break;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+void kvm_deliver_intr(struct kvm_vcpu *vcpu)
+{
+ unsigned long *pending = &vcpu->arch.irq_pending;
+ unsigned long *pending_clr = &vcpu->arch.irq_clear;
+ unsigned int priority;
+
+ if (!(*pending) && !(*pending_clr))
+ return;
+
+ if (*pending_clr) {
+ priority = __ffs(*pending_clr);
+ while (priority <= INT_IPI) {
+ kvm_irq_clear(vcpu, priority);
+ priority = find_next_bit(pending_clr,
+ BITS_PER_BYTE * sizeof(*pending_clr),
+ priority + 1);
+ }
+ }
+
+ if (*pending) {
+ priority = __ffs(*pending);
+ while (priority <= INT_IPI) {
+ kvm_irq_deliver(vcpu, priority);
+ priority = find_next_bit(pending,
+ BITS_PER_BYTE * sizeof(*pending),
+ priority + 1);
+ }
+ }
+}
+
+int kvm_pending_timer(struct kvm_vcpu *vcpu)
+{
+ return test_bit(INT_TI, &vcpu->arch.irq_pending);
+}
+
+/*
+ * Only support illegal instruction or illegal Address Error exception,
+ * Other exceptions are injected by hardware in kvm mode
+ */
+static void kvm_exception_deliver(struct kvm_vcpu *vcpu, unsigned int code,
+ unsigned int subcode)
+{
+ unsigned long val, vec_size;
+
+ /*
+ * BADV is added for EXCCODE_ADE exception
+ * Use pc register (gva address) if it is instruction exeception
+ * Else use badv from host side (gpa address) for data exeception
+ */
+ if (code == EXCCODE_ADE) {
+ if (subcode == EXSUBCODE_ADEF)
+ val = vcpu->arch.pc;
+ else
+ val = vcpu->arch.badv;
+ kvm_write_hw_gcsr(LOONGARCH_CSR_BADV, val);
+ }
+
+ /* set exception instruction */
+ kvm_write_hw_gcsr(LOONGARCH_CSR_BADI, vcpu->arch.badi);
+
+ /*
+ * save crmd in prmd
+ * set IRQ disabled and PLV0 with crmd
+ */
+ val = kvm_read_hw_gcsr(LOONGARCH_CSR_CRMD);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_PRMD, val);
+ val = val & ~(CSR_CRMD_PLV | CSR_CRMD_IE);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_CRMD, val);
+
+ /* set exception pc address */
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ERA, vcpu->arch.pc);
+
+ /*
+ * set exception code
+ * exception and interrupt can be inject at the same time
+ * hardware will handle exception first and then extern interrupt
+ * exception code is Ecode in ESTAT[16:21]
+ * interrupt code in ESTAT[0:12]
+ */
+ val = kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT);
+ val = (val & ~CSR_ESTAT_EXC) | code;
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ESTAT, val);
+
+ /*
+ * calculate expcetion entry address
+ */
+ val = kvm_read_hw_gcsr(LOONGARCH_CSR_ECFG);
+ vec_size = (val & CSR_ECFG_VS) >> CSR_ECFG_VS_SHIFT;
+ if (vec_size)
+ vec_size = (1 << vec_size) * 4;
+ val = kvm_read_hw_gcsr(LOONGARCH_CSR_EENTRY);
+ vcpu->arch.pc = val + code * vec_size;
+}
+
+void kvm_deliver_exception(struct kvm_vcpu *vcpu)
+{
+ unsigned long *pending = &vcpu->arch.exception_pending;
+ unsigned int code;
+
+ if (*pending) {
+ code = __ffs(*pending);
+ kvm_exception_deliver(vcpu, code, vcpu->arch.subcode);
+ *pending = 0;
+ vcpu->arch.subcode = 0;
+ }
+}
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index b8af4a200c..191d9f5517 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -336,6 +336,43 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
preempt_enable();
}

+int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
+{
+ int intr = (int)irq->irq;
+
+ if (intr > 0)
+ kvm_queue_irq(vcpu, intr);
+ else if (intr < 0)
+ kvm_dequeue_irq(vcpu, -intr);
+ else {
+ kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq);
+ return -EINVAL;
+ }
+
+ kvm_vcpu_kick(vcpu);
+ return 0;
+}
+
+long kvm_arch_vcpu_async_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+
+ if (ioctl == KVM_INTERRUPT) {
+ struct kvm_interrupt irq;
+
+ if (copy_from_user(&irq, argp, sizeof(irq)))
+ return -EFAULT;
+
+ kvm_debug("[%d] %s: irq: %d\n", vcpu->vcpu_id, __func__, irq.irq);
+
+ return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
+ }
+
+ return -ENOIOCTLCMD;
+}
+
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
{
return 0;
--
2.39.1

2023-09-15 01:54:35

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 14/29] LoongArch: KVM: Implement vcpu load and vcpu put operations

Implement LoongArch vcpu load and vcpu put operations, including
load csr value into hardware and save csr value into vcpu structure.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 199 ++++++++++++++++++++++++++++++++++++++
1 file changed, 199 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 42383f8648..7162e6ddb7 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -678,6 +678,205 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
}
}

+static int kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+ struct kvm_context *context;
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ bool migrated;
+
+ /*
+ * Have we migrated to a different CPU?
+ * If so, any old guest TLB state may be stale.
+ */
+ migrated = (vcpu->arch.last_sched_cpu != cpu);
+
+ /*
+ * Was this the last vCPU to run on this CPU?
+ * If not, any old guest state from this vCPU will have been clobbered.
+ */
+ context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+ if (migrated || (context->last_vcpu != vcpu))
+ vcpu->arch.aux_inuse &= ~KVM_LARCH_HWCSR_USABLE;
+ context->last_vcpu = vcpu;
+
+ /*
+ * Restore timer state regardless
+ */
+ kvm_restore_timer(vcpu);
+
+ /* Control guest page CCA attribute */
+ change_csr_gcfg(CSR_GCFG_MATC_MASK, CSR_GCFG_MATC_ROOT);
+
+ /* Don't bother restoring registers multiple times unless necessary */
+ if (vcpu->arch.aux_inuse & KVM_LARCH_HWCSR_USABLE)
+ return 0;
+
+ write_csr_gcntc((ulong)vcpu->kvm->arch.time_offset);
+ /*
+ * Restore guest CSR registers
+ */
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CRMD);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PRMD);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_EUEN);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_MISC);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ECFG);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ERA);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_BADV);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_BADI);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_EENTRY);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBIDX);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBEHI);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBELO0);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBELO1);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ASID);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PGDL);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PGDH);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PWCTL0);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PWCTL1);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_STLBPGSIZE);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_RVACFG);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CPUID);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS0);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS1);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS2);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS3);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS4);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS5);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS6);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_KS7);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TMID);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_CNTC);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRENTRY);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRBADV);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRERA);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRSAVE);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO0);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO1);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBREHI);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TLBRPRMD);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN0);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
+
+ /* restore Root.Guestexcept from unused Guest guestexcept register */
+ write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
+
+ /*
+ * We should clear linked load bit to break interrupted atomics. This
+ * prevents a SC on the next vCPU from succeeding by matching a LL on
+ * the previous vCPU.
+ */
+ if (vcpu->kvm->created_vcpus > 1)
+ set_gcsr_llbctl(CSR_LLBCTL_WCLLB);
+
+ vcpu->arch.aux_inuse |= KVM_LARCH_HWCSR_USABLE;
+ return 0;
+}
+
+void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (vcpu->arch.last_sched_cpu != cpu) {
+ kvm_debug("[%d->%d]KVM vCPU[%d] switch\n",
+ vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
+ /*
+ * Migrate the timer interrupt to the current CPU so that it
+ * always interrupts the guest and synchronously triggers a
+ * guest timer interrupt.
+ */
+ kvm_migrate_count(vcpu);
+ }
+
+ /* restore guest state to registers */
+ kvm_vcpu_load(vcpu, cpu);
+ local_irq_restore(flags);
+}
+
+static int kvm_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+
+ kvm_lose_fpu(vcpu);
+ /*
+ * update csr state from hardware if software csr state is stale,
+ * most csr registers are kept unchanged during process context
+ * switch except csr registers like remaining timer tick value and
+ * injected interrupt state.
+ */
+ if (!(vcpu->arch.aux_inuse & KVM_LARCH_CSR)) {
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CRMD);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRMD);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_EUEN);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_MISC);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ECFG);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ERA);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_BADV);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_BADI);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_EENTRY);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBIDX);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBEHI);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBELO0);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBELO1);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ASID);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGDL);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PGDH);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PWCTL0);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PWCTL1);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_STLBPGSIZE);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_RVACFG);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CPUID);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG1);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG2);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PRCFG3);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS0);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS1);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS2);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS3);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS4);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS5);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS6);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_KS7);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TMID);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_CNTC);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_LLBCTL);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRENTRY);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRBADV);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRERA);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRSAVE);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO0);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRELO1);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBREHI);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TLBRPRMD);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN0);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN1);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN2);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_DMWIN3);
+ vcpu->arch.aux_inuse |= KVM_LARCH_CSR;
+ }
+ /* save Root.Guestexcept in unused Guest guestexcept register */
+ kvm_save_timer(vcpu);
+ csr->csrs[LOONGARCH_CSR_GINTC] = read_csr_gintc();
+ return 0;
+}
+
+void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+{
+ unsigned long flags;
+ int cpu;
+
+ local_irq_save(flags);
+ cpu = smp_processor_id();
+ vcpu->arch.last_sched_cpu = cpu;
+
+ /* save guest state in registers */
+ kvm_vcpu_put(vcpu, cpu);
+ local_irq_restore(flags);
+}
+
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
{
int r = -EINTR;
--
2.39.1

2023-09-15 01:54:36

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 16/29] LoongArch: KVM: Implement virtual machine tlb operations

Implement LoongArch virtual machine tlb operations such as flush tlb by
specific gpa parameter and flush all of the virt machines tlb.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/tlb.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 arch/loongarch/kvm/tlb.c

diff --git a/arch/loongarch/kvm/tlb.c b/arch/loongarch/kvm/tlb.c
new file mode 100644
index 0000000000..0bcbd80ac6
--- /dev/null
+++ b/arch/loongarch/kvm/tlb.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/tlb.h>
+#include <asm/kvm_csr.h>
+
+int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ gpa &= (PAGE_MASK << 1);
+ invtlb(INVTLB_GID_ADDR, read_csr_gstat() & CSR_GSTAT_GID, gpa);
+ local_irq_restore(flags);
+ return 0;
+}
+
+/**
+ * kvm_flush_tlb_all() - Flush all root TLB entries for
+ * guests.
+ *
+ * Invalidate all entries including GVA-->GPA and GPA-->HPA mappings.
+ */
+void kvm_flush_tlb_all(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ invtlb_all(INVTLB_ALLGID, 0, 0);
+ local_irq_restore(flags);
+}
--
2.39.1

2023-09-15 01:54:36

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 18/29] LoongArch: KVM: Implement kvm mmu operations

Implement LoongArch kvm mmu, it is used to switch gpa to hpa when
guest exit because of address translation exception. This patch
implement allocate gpa page table, search gpa from it and flush guest
gpa in the table.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/include/asm/kvm_mmu.h | 138 ++++
arch/loongarch/kvm/mmu.c | 922 +++++++++++++++++++++++++++
2 files changed, 1060 insertions(+)
create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
create mode 100644 arch/loongarch/kvm/mmu.c

diff --git a/arch/loongarch/include/asm/kvm_mmu.h b/arch/loongarch/include/asm/kvm_mmu.h
new file mode 100644
index 0000000000..641524a4f2
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_mmu.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_LOONGARCH_KVM_MMU_H__
+#define __ASM_LOONGARCH_KVM_MMU_H__
+
+#include <linux/kvm_host.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+
+/*
+ * KVM_MMU_CACHE_MIN_PAGES is the number of GPA page table translation levels
+ * for which pages need to be cached.
+ */
+#define KVM_MMU_CACHE_MIN_PAGES (CONFIG_PGTABLE_LEVELS - 1)
+
+#define _KVM_FLUSH_PGTABLE 0x1
+#define _KVM_HAS_PGMASK 0x2
+#define kvm_pfn_pte(pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot))
+#define kvm_pte_pfn(x) ((phys_addr_t)((x & _PFN_MASK) >> PFN_PTE_SHIFT))
+
+typedef unsigned long kvm_pte_t;
+typedef struct kvm_ptw_ctx kvm_ptw_ctx;
+typedef int (*kvm_pte_ops)(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx);
+
+struct kvm_ptw_ctx {
+ kvm_pte_ops ops;
+ unsigned long flag;
+ /* for kvm_arch_mmu_enable_log_dirty_pt_masked use */
+ unsigned long mask;
+ unsigned long gfn;
+
+ /* page walk mmu info */
+ unsigned int level;
+ unsigned long pgtable_shift;
+ unsigned long invalid_entry;
+ unsigned long *invalid_ptes;
+ unsigned int *pte_shifts;
+ void *opaque;
+
+ /* free pte table page list */
+ struct list_head list;
+};
+
+kvm_pte_t *kvm_pgd_alloc(void);
+
+static inline void kvm_set_pte(kvm_pte_t *ptep, kvm_pte_t val)
+{
+ WRITE_ONCE(*ptep, val);
+}
+
+static inline int kvm_pte_write(kvm_pte_t pte) { return pte & _PAGE_WRITE; }
+static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & _PAGE_DIRTY; }
+static inline int kvm_pte_young(kvm_pte_t pte) { return pte & _PAGE_ACCESSED; }
+static inline int kvm_pte_huge(kvm_pte_t pte) { return pte & _PAGE_HUGE; }
+
+static inline kvm_pte_t kvm_pte_mkyoung(kvm_pte_t pte)
+{
+ return pte | _PAGE_ACCESSED;
+}
+
+static inline kvm_pte_t kvm_pte_mkold(kvm_pte_t pte)
+{
+ return pte & ~_PAGE_ACCESSED;
+}
+
+static inline kvm_pte_t kvm_pte_mkdirty(kvm_pte_t pte)
+{
+ return pte | _PAGE_DIRTY;
+}
+
+static inline kvm_pte_t kvm_pte_mkclean(kvm_pte_t pte)
+{
+ return pte & ~_PAGE_DIRTY;
+}
+
+static inline kvm_pte_t kvm_pte_mkhuge(kvm_pte_t pte)
+{
+ return pte | _PAGE_HUGE;
+}
+
+static inline kvm_pte_t kvm_pte_mksmall(kvm_pte_t pte)
+{
+ return pte & ~_PAGE_HUGE;
+}
+
+static inline int kvm_need_flush(kvm_ptw_ctx *ctx)
+{
+ return ctx->flag & _KVM_FLUSH_PGTABLE;
+}
+
+static inline kvm_pte_t *kvm_pgtable_offset(kvm_ptw_ctx *ctx, kvm_pte_t *table,
+ phys_addr_t addr)
+{
+
+ return table + ((addr >> ctx->pgtable_shift) & (PTRS_PER_PTE - 1));
+}
+
+static inline phys_addr_t kvm_pgtable_addr_end(kvm_ptw_ctx *ctx,
+ phys_addr_t addr, phys_addr_t end)
+{
+ phys_addr_t boundary, size;
+
+ size = 0x1UL << ctx->pgtable_shift;
+ boundary = (addr + size) & ~(size - 1);
+ return (boundary - 1 < end - 1) ? boundary : end;
+}
+
+static inline int kvm_pte_present(kvm_ptw_ctx *ctx, kvm_pte_t *entry)
+{
+ if (!ctx || ctx->level == 0)
+ return !!(*entry & _PAGE_PRESENT);
+
+ return *entry != ctx->invalid_entry;
+}
+
+static inline int kvm_pte_none(kvm_ptw_ctx *ctx, kvm_pte_t *entry)
+{
+ return *entry == ctx->invalid_entry;
+}
+
+static inline void kvm_ptw_enter(kvm_ptw_ctx *ctx)
+{
+ ctx->level--;
+ ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
+ ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
+}
+
+static inline void kvm_ptw_exit(kvm_ptw_ctx *ctx)
+{
+ ctx->level++;
+ ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
+ ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
+}
+
+#endif /* __ASM_LOONGARCH_KVM_MMU_H__ */
diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c
new file mode 100644
index 0000000000..cd73fcba92
--- /dev/null
+++ b/arch/loongarch/kvm/mmu.c
@@ -0,0 +1,922 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/highmem.h>
+#include <linux/page-flags.h>
+#include <linux/kvm_host.h>
+#include <linux/uaccess.h>
+#include <linux/hugetlb.h>
+#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/kvm_mmu.h>
+
+static inline void kvm_ptw_prepare(struct kvm *kvm, kvm_ptw_ctx *ctx)
+{
+ ctx->level = kvm->arch.root_level;
+ /* pte table */
+ ctx->invalid_ptes = kvm->arch.invalid_ptes;
+ ctx->pte_shifts = kvm->arch.pte_shifts;
+ ctx->pgtable_shift = ctx->pte_shifts[ctx->level];
+ ctx->invalid_entry = ctx->invalid_ptes[ctx->level];
+ ctx->opaque = kvm;
+}
+
+/*
+ * Mark a range of guest physical address space old (all accesses fault) in the
+ * VM's GPA page table to allow detection of commonly used pages.
+ */
+static int kvm_mkold_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
+{
+ if (kvm_pte_young(*pte)) {
+ *pte = kvm_pte_mkold(*pte);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * clear pte entry
+ */
+static int kvm_flush_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
+{
+ struct kvm *kvm;
+
+ kvm = ctx->opaque;
+ if (ctx->level)
+ kvm->stat.hugepages--;
+ else
+ kvm->stat.pages--;
+
+ *pte = ctx->invalid_entry;
+ return 1;
+}
+
+/*
+ * kvm_mkclean_pte
+ * Mark a range of guest physical address space clean (writes fault) in the VM's
+ * GPA page table to allow dirty page tracking.
+ */
+static int kvm_mkclean_pte(kvm_pte_t *pte, phys_addr_t addr, kvm_ptw_ctx *ctx)
+{
+ kvm_pte_t val;
+ gfn_t offset;
+
+ val = *pte;
+ /*
+ * For kvm_arch_mmu_enable_log_dirty_pt_masked with mask, start and end
+ * may cross hugepage, for first huge page parameter addr is equal to
+ * start, however for the second huge page addr is base address of
+ * this huge page, rather than start or end address
+ */
+ if ((ctx->flag & _KVM_HAS_PGMASK) && !kvm_pte_huge(val)) {
+ offset = (addr >> PAGE_SHIFT) - ctx->gfn;
+ if (!(BIT(offset) & ctx->mask))
+ return 0;
+ }
+
+ /*
+ * Does not support eager_page_split
+ * Need not split huge page now, just set write-proect pte bit
+ * Split huge page until next write fault
+ */
+ if (kvm_pte_dirty(val)) {
+ *pte = kvm_pte_mkclean(val);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * kvm_pgd_alloc() - Allocate and initialise a KVM GPA page directory.
+ *
+ * Allocate a blank KVM GPA page directory (PGD) for representing guest physical
+ * to host physical page mappings.
+ *
+ * Returns: Pointer to new KVM GPA page directory.
+ * NULL on allocation failure.
+ */
+kvm_pte_t *kvm_pgd_alloc(void)
+{
+ kvm_pte_t *pgd;
+
+ pgd = (kvm_pte_t *)__get_free_pages(GFP_KERNEL, 0);
+ if (pgd)
+ pgd_init((void *)pgd);
+
+ return pgd;
+}
+
+static void _kvm_pte_init(void *addr, unsigned long val)
+{
+ unsigned long *p, *end;
+
+ p = (unsigned long *)addr;
+ end = p + PTRS_PER_PTE;
+ do {
+ p[0] = val;
+ p[1] = val;
+ p[2] = val;
+ p[3] = val;
+ p[4] = val;
+ p += 8;
+ p[-3] = val;
+ p[-2] = val;
+ p[-1] = val;
+ } while (p != end);
+}
+
+/*
+ * Caller must hold kvm->mm_lock
+ *
+ * Walk the page tables of kvm to find the PTE corresponding to the
+ * address @addr. If page tables don't exist for @addr, they will be created
+ * from the MMU cache if @cache is not NULL.
+ */
+static kvm_pte_t *kvm_populate_gpa(struct kvm *kvm,
+ struct kvm_mmu_memory_cache *cache,
+ unsigned long addr, int level)
+{
+ kvm_ptw_ctx ctx;
+ kvm_pte_t *entry, *child;
+
+ kvm_ptw_prepare(kvm, &ctx);
+ child = kvm->arch.pgd;
+ while (ctx.level > level) {
+ entry = kvm_pgtable_offset(&ctx, child, addr);
+ if (kvm_pte_none(&ctx, entry)) {
+ if (!cache)
+ return NULL;
+
+ child = kvm_mmu_memory_cache_alloc(cache);
+ _kvm_pte_init(child, ctx.invalid_ptes[ctx.level - 1]);
+ kvm_set_pte(entry, __pa(child));
+ } else if (kvm_pte_huge(*entry)) {
+ return entry;
+ } else
+ child = (kvm_pte_t *)__va(PHYSADDR(*entry));
+ kvm_ptw_enter(&ctx);
+ }
+
+ entry = kvm_pgtable_offset(&ctx, child, addr);
+ return entry;
+}
+
+/*
+ * Page walker for VM shadow mmu at last level
+ * The last level is small pte page or huge pmd page
+ */
+static int kvm_ptw_leaf(kvm_pte_t *dir, phys_addr_t addr, phys_addr_t end,
+ kvm_ptw_ctx *ctx)
+{
+ kvm_pte_t *entry, *child;
+ phys_addr_t next, start, size;
+ struct list_head *list;
+ int ret;
+
+ ret = 0;
+ start = addr;
+ child = (kvm_pte_t *)__va(PHYSADDR(*dir));
+ entry = kvm_pgtable_offset(ctx, child, addr);
+ do {
+ next = addr + (0x1UL << ctx->pgtable_shift);
+ if (!kvm_pte_present(ctx, entry))
+ continue;
+
+ ret |= ctx->ops(entry, addr, ctx);
+ } while (entry++, addr = next, addr < end);
+
+ if (kvm_need_flush(ctx)) {
+ size = 0x1UL << (ctx->pgtable_shift + PAGE_SHIFT - 3);
+ if (start + size == end) {
+ list = (struct list_head *)child;
+ list_add_tail(list, &ctx->list);
+ *dir = ctx->invalid_ptes[ctx->level + 1];
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Page walker for VM shadow mmu at page table dir level
+ */
+static int kvm_ptw_dir(kvm_pte_t *dir, phys_addr_t addr, phys_addr_t end,
+ kvm_ptw_ctx *ctx)
+{
+ kvm_pte_t *entry, *child;
+ phys_addr_t next, start, size;
+ struct list_head *list;
+ int ret;
+
+ ret = 0;
+ start = addr;
+ child = (kvm_pte_t *)__va(PHYSADDR(*dir));
+ entry = kvm_pgtable_offset(ctx, child, addr);
+ do {
+ next = kvm_pgtable_addr_end(ctx, addr, end);
+ if (!kvm_pte_present(ctx, entry))
+ continue;
+
+ if (kvm_pte_huge(*entry)) {
+ ret |= ctx->ops(entry, addr, ctx);
+ continue;
+ }
+
+ kvm_ptw_enter(ctx);
+ if (ctx->level == 0)
+ ret |= kvm_ptw_leaf(entry, addr, next, ctx);
+ else
+ ret |= kvm_ptw_dir(entry, addr, next, ctx);
+ kvm_ptw_exit(ctx);
+ } while (entry++, addr = next, addr < end);
+
+ if (kvm_need_flush(ctx)) {
+ size = 0x1UL << (ctx->pgtable_shift + PAGE_SHIFT - 3);
+ if (start + size == end) {
+ list = (struct list_head *)child;
+ list_add_tail(list, &ctx->list);
+ *dir = ctx->invalid_ptes[ctx->level + 1];
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Page walker for VM shadow mmu at page root table
+ */
+static int kvm_ptw_top(kvm_pte_t *dir, phys_addr_t addr, phys_addr_t end,
+ kvm_ptw_ctx *ctx)
+{
+ kvm_pte_t *entry;
+ phys_addr_t next;
+ int ret;
+
+ ret = 0;
+ entry = kvm_pgtable_offset(ctx, dir, addr);
+ do {
+ next = kvm_pgtable_addr_end(ctx, addr, end);
+ if (!kvm_pte_present(ctx, entry))
+ continue;
+
+ kvm_ptw_enter(ctx);
+ ret |= kvm_ptw_dir(entry, addr, next, ctx);
+ kvm_ptw_exit(ctx);
+ } while (entry++, addr = next, addr < end);
+
+ return ret;
+}
+
+/**
+ * kvm_flush_range() - Flush a range of guest physical addresses.
+ * @kvm: KVM pointer.
+ * @start_gfn: Guest frame number of first page in GPA range to flush.
+ * @end_gfn: Guest frame number of last page in GPA range to flush.
+ * @lock: Whether to hold mmu_lock or not
+ *
+ * Flushes a range of GPA mappings from the GPA page tables.
+ *
+ */
+static void kvm_flush_range(struct kvm *kvm, gfn_t start_gfn, gfn_t end_gfn, int lock)
+{
+ struct list_head *pos, *temp;
+ kvm_ptw_ctx ctx;
+ int ret;
+
+ ctx.ops = kvm_flush_pte;
+ ctx.flag = _KVM_FLUSH_PGTABLE;
+ kvm_ptw_prepare(kvm, &ctx);
+ INIT_LIST_HEAD(&ctx.list);
+
+ if (lock) {
+ spin_lock(&kvm->mmu_lock);
+ ret = kvm_ptw_top(kvm->arch.pgd, start_gfn << PAGE_SHIFT,
+ end_gfn << PAGE_SHIFT, &ctx);
+ spin_unlock(&kvm->mmu_lock);
+ } else
+ ret = kvm_ptw_top(kvm->arch.pgd, start_gfn << PAGE_SHIFT,
+ end_gfn << PAGE_SHIFT, &ctx);
+
+ /* Flush vpid for each vCPU individually */
+ if (ret)
+ kvm_flush_remote_tlbs(kvm);
+
+ /*
+ * free pte table page after mmu_lock
+ * the pte table page is linked together with ctx.list
+ */
+ list_for_each_safe(pos, temp, &ctx.list) {
+ list_del(pos);
+ free_page((unsigned long)pos);
+ }
+}
+
+/*
+ * kvm_mkclean_gpa_pt() - Make a range of guest physical addresses clean.
+ * @kvm: KVM pointer.
+ * @start_gfn: Guest frame number of first page in GPA range to flush.
+ * @end_gfn: Guest frame number of last page in GPA range to flush.
+ *
+ * Make a range of GPA mappings clean so that guest writes will fault and
+ * trigger dirty page logging.
+ *
+ * The caller must hold the @kvm->mmu_lock spinlock.
+ *
+ * Returns: Whether any GPA mappings were modified, which would require
+ * derived mappings (GVA page tables & TLB enties) to be
+ * invalidated.
+ */
+static int kvm_mkclean_gpa_pt(struct kvm *kvm, gfn_t start_gfn, gfn_t end_gfn)
+{
+ kvm_ptw_ctx ctx;
+
+ ctx.ops = kvm_mkclean_pte;
+ ctx.flag = 0;
+ kvm_ptw_prepare(kvm, &ctx);
+ return kvm_ptw_top(kvm->arch.pgd, start_gfn << PAGE_SHIFT,
+ end_gfn << PAGE_SHIFT, &ctx);
+}
+
+/*
+ * kvm_arch_mmu_enable_log_dirty_pt_masked() - write protect dirty pages
+ * @kvm: The KVM pointer
+ * @slot: The memory slot associated with mask
+ * @gfn_offset: The gfn offset in memory slot
+ * @mask: The mask of dirty pages at offset 'gfn_offset' in this memory
+ * slot to be write protected
+ *
+ * Walks bits set in mask write protects the associated pte's. Caller must
+ * acquire @kvm->mmu_lock.
+ */
+void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
+ struct kvm_memory_slot *slot,
+ gfn_t gfn_offset, unsigned long mask)
+{
+ kvm_ptw_ctx ctx;
+ gfn_t base_gfn = slot->base_gfn + gfn_offset;
+ gfn_t start = base_gfn + __ffs(mask);
+ gfn_t end = base_gfn + __fls(mask) + 1;
+
+ ctx.ops = kvm_mkclean_pte;
+ ctx.flag = _KVM_HAS_PGMASK;
+ ctx.mask = mask;
+ ctx.gfn = base_gfn;
+ kvm_ptw_prepare(kvm, &ctx);
+
+ kvm_ptw_top(kvm->arch.pgd, start << PAGE_SHIFT, end << PAGE_SHIFT, &ctx);
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new,
+ enum kvm_mr_change change)
+{
+ int needs_flush;
+
+ /*
+ * If dirty page logging is enabled, write protect all pages in the slot
+ * ready for dirty logging.
+ *
+ * There is no need to do this in any of the following cases:
+ * CREATE: No dirty mappings will already exist.
+ * MOVE/DELETE: The old mappings will already have been cleaned up by
+ * kvm_arch_flush_shadow_memslot()
+ */
+ if (change == KVM_MR_FLAGS_ONLY &&
+ (!(old->flags & KVM_MEM_LOG_DIRTY_PAGES) &&
+ new->flags & KVM_MEM_LOG_DIRTY_PAGES)) {
+ spin_lock(&kvm->mmu_lock);
+ /* Write protect GPA page table entries */
+ needs_flush = kvm_mkclean_gpa_pt(kvm, new->base_gfn,
+ new->base_gfn + new->npages);
+ spin_unlock(&kvm->mmu_lock);
+ if (needs_flush)
+ kvm_flush_remote_tlbs(kvm);
+ }
+}
+
+void kvm_arch_flush_shadow_all(struct kvm *kvm)
+{
+ kvm_flush_range(kvm, 0, kvm->arch.gpa_size >> PAGE_SHIFT, 0);
+}
+
+void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
+ struct kvm_memory_slot *slot)
+{
+ /*
+ * The slot has been made invalid (ready for moving or deletion), so we
+ * need to ensure that it can no longer be accessed by any guest vCPUs.
+ */
+ kvm_flush_range(kvm, slot->base_gfn, slot->base_gfn + slot->npages, 1);
+}
+
+bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ kvm_ptw_ctx ctx;
+
+ ctx.ops = kvm_flush_pte;
+ /* do not free leaf pte table page */
+ ctx.flag = 0;
+ kvm_ptw_prepare(kvm, &ctx);
+ INIT_LIST_HEAD(&ctx.list);
+
+ return kvm_ptw_top(kvm->arch.pgd, range->start << PAGE_SHIFT,
+ range->end << PAGE_SHIFT, &ctx);
+}
+
+bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ gpa_t gpa = range->start << PAGE_SHIFT;
+ kvm_pte_t *ptep;
+ kvm_pfn_t pfn = pte_pfn(range->arg.pte);
+ unsigned long prot_bits;
+
+ ptep = kvm_populate_gpa(kvm, NULL, gpa, 0);
+ if (!ptep)
+ return false;
+
+ /* Replacing an absent or old page doesn't need flushes */
+ if (!kvm_pte_present(NULL, ptep) || !kvm_pte_young(*ptep)) {
+ kvm_set_pte(ptep, 0);
+ return false;
+ }
+
+ /* fill new pte if write protected or page migrated */
+ prot_bits = _PAGE_PRESENT | __READABLE;
+ prot_bits |= _CACHE_MASK & pte_val(range->arg.pte);
+
+ /*
+ * set _PAGE_WRITE or _PAGE_DIRTY iff old and new pte both support
+ * _PAGE_WRITE for map_page_fast if next page write fault
+ * _PAGE_DIRTY since gpa has already recorded as dirty page
+ */
+ prot_bits |= __WRITEABLE & *ptep & pte_val(range->arg.pte);
+ kvm_set_pte(ptep, kvm_pfn_pte(pfn, __pgprot(prot_bits)));
+ return true;
+}
+
+bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ kvm_ptw_ctx ctx;
+
+ ctx.ops = kvm_mkold_pte;
+ ctx.flag = 0;
+ kvm_ptw_prepare(kvm, &ctx);
+
+ return kvm_ptw_top(kvm->arch.pgd, range->start << PAGE_SHIFT,
+ range->end << PAGE_SHIFT, &ctx);
+}
+
+bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ gpa_t gpa = range->start << PAGE_SHIFT;
+ kvm_pte_t *ptep = kvm_populate_gpa(kvm, NULL, gpa, 0);
+
+ if (ptep && kvm_pte_present(NULL, ptep) && kvm_pte_young(*ptep))
+ return true;
+
+ return false;
+}
+
+/**
+ * kvm_map_page_fast() - Fast path GPA fault handler.
+ * @vcpu: vCPU pointer.
+ * @gpa: Guest physical address of fault.
+ * @write: Whether the fault was due to a write.
+ *
+ * Perform fast path GPA fault handling, doing all that can be done without
+ * calling into KVM. This handles marking old pages young (for idle page
+ * tracking), and dirtying of clean pages (for dirty page logging).
+ *
+ * Returns: 0 on success, in which case we can update derived mappings and
+ * resume guest execution.
+ * -EFAULT on failure due to absent GPA mapping or write to
+ * read-only page, in which case KVM must be consulted.
+ */
+static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa,
+ bool write)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_memory_slot *slot;
+ gfn_t gfn = gpa >> PAGE_SHIFT;
+ kvm_pte_t *ptep, changed, new;
+ kvm_pfn_t pfn = 0;
+ int ret = 0;
+
+ spin_lock(&kvm->mmu_lock);
+
+ /* Fast path - just check GPA page table for an existing entry */
+ ptep = kvm_populate_gpa(kvm, NULL, gpa, 0);
+ if (!ptep || !kvm_pte_present(NULL, ptep)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /* Track access to pages marked old */
+ new = *ptep;
+ if (!kvm_pte_young(new))
+ new = kvm_pte_mkyoung(new);
+ /* call kvm_set_pfn_accessed() after unlock */
+
+ if (write && !kvm_pte_dirty(new)) {
+ if (!kvm_pte_write(new)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (kvm_pte_huge(new)) {
+ /*
+ * Do not set write permission when dirty logging is
+ * enabled for HugePages
+ */
+ slot = gfn_to_memslot(kvm, gfn);
+ if (kvm_slot_dirty_track_enabled(slot)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ /* Track dirtying of writeable pages */
+ new = kvm_pte_mkdirty(new);
+ }
+
+ changed = new ^ (*ptep);
+ if (changed) {
+ kvm_set_pte(ptep, new);
+ pfn = kvm_pte_pfn(new);
+ }
+ spin_unlock(&kvm->mmu_lock);
+
+ /*
+ * Fixme: pfn may be freed after mmu_lock
+ * kvm_try_get_pfn(pfn)/kvm_release_pfn pair to prevent this?
+ */
+ if (kvm_pte_young(changed))
+ kvm_set_pfn_accessed(pfn);
+
+ if (kvm_pte_dirty(changed)) {
+ mark_page_dirty(kvm, gfn);
+ kvm_set_pfn_dirty(pfn);
+ }
+ return ret;
+out:
+ spin_unlock(&kvm->mmu_lock);
+ return ret;
+}
+
+static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
+ unsigned long hva, unsigned long map_size,
+ bool write)
+{
+ gpa_t gpa_start;
+ hva_t uaddr_start, uaddr_end;
+ size_t size;
+
+ /* Disable dirty logging on HugePages */
+ if (kvm_slot_dirty_track_enabled(memslot) && write)
+ return false;
+
+ size = memslot->npages * PAGE_SIZE;
+ gpa_start = memslot->base_gfn << PAGE_SHIFT;
+ uaddr_start = memslot->userspace_addr;
+ uaddr_end = uaddr_start + size;
+
+ /*
+ * Pages belonging to memslots that don't have the same alignment
+ * within a PMD for userspace and GPA cannot be mapped with stage-2
+ * PMD entries, because we'll end up mapping the wrong pages.
+ *
+ * Consider a layout like the following:
+ *
+ * memslot->userspace_addr:
+ * +-----+--------------------+--------------------+---+
+ * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
+ * +-----+--------------------+--------------------+---+
+ *
+ * memslot->base_gfn << PAGE_SIZE:
+ * +---+--------------------+--------------------+-----+
+ * |abc|def Stage-2 block | Stage-2 block |tvxyz|
+ * +---+--------------------+--------------------+-----+
+ *
+ * If we create those stage-2 blocks, we'll end up with this incorrect
+ * mapping:
+ * d -> f
+ * e -> g
+ * f -> h
+ */
+ if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
+ return false;
+
+ /*
+ * Next, let's make sure we're not trying to map anything not covered
+ * by the memslot. This means we have to prohibit block size mappings
+ * for the beginning and end of a non-block aligned and non-block sized
+ * memory slot (illustrated by the head and tail parts of the
+ * userspace view above containing pages 'abcde' and 'xyz',
+ * respectively).
+ *
+ * Note that it doesn't matter if we do the check using the
+ * userspace_addr or the base_gfn, as both are equally aligned (per
+ * the check above) and equally sized.
+ */
+ return (hva & ~(map_size - 1)) >= uaddr_start &&
+ (hva & ~(map_size - 1)) + map_size <= uaddr_end;
+}
+
+/*
+ * Lookup the mapping level for @gfn in the current mm.
+ *
+ * WARNING! Use of host_pfn_mapping_level() requires the caller and the end
+ * consumer to be tied into KVM's handlers for MMU notifier events!
+ *
+ * There are several ways to safely use this helper:
+ *
+ * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before
+ * consuming it. In this case, mmu_lock doesn't need to be held during the
+ * lookup, but it does need to be held while checking the MMU notifier.
+ *
+ * - Hold mmu_lock AND ensure there is no in-progress MMU notifier invalidation
+ * event for the hva. This can be done by explicit checking the MMU notifier
+ * or by ensuring that KVM already has a valid mapping that covers the hva.
+ *
+ * - Do not use the result to install new mappings, e.g. use the host mapping
+ * level only to decide whether or not to zap an entry. In this case, it's
+ * not required to hold mmu_lock (though it's highly likely the caller will
+ * want to hold mmu_lock anyways, e.g. to modify SPTEs).
+ *
+ * Note! The lookup can still race with modifications to host page tables, but
+ * the above "rules" ensure KVM will not _consume_ the result of the walk if a
+ * race with the primary MMU occurs.
+ */
+static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
+ const struct kvm_memory_slot *slot)
+{
+ int level = 0;
+ unsigned long hva;
+ unsigned long flags;
+ pgd_t pgd;
+ p4d_t p4d;
+ pud_t pud;
+ pmd_t pmd;
+
+ /*
+ * Note, using the already-retrieved memslot and __gfn_to_hva_memslot()
+ * is not solely for performance, it's also necessary to avoid the
+ * "writable" check in __gfn_to_hva_many(), which will always fail on
+ * read-only memslots due to gfn_to_hva() assuming writes. Earlier
+ * page fault steps have already verified the guest isn't writing a
+ * read-only memslot.
+ */
+ hva = __gfn_to_hva_memslot(slot, gfn);
+
+ /*
+ * Disable IRQs to prevent concurrent tear down of host page tables,
+ * e.g. if the primary MMU promotes a P*D to a huge page and then frees
+ * the original page table.
+ */
+ local_irq_save(flags);
+
+ /*
+ * Read each entry once. As above, a non-leaf entry can be promoted to
+ * a huge page _during_ this walk. Re-reading the entry could send the
+ * walk into the weeks, e.g. p*d_large() returns false (sees the old
+ * value) and then p*d_offset() walks into the target huge page instead
+ * of the old page table (sees the new value).
+ */
+ pgd = READ_ONCE(*pgd_offset(kvm->mm, hva));
+ if (pgd_none(pgd))
+ goto out;
+
+ p4d = READ_ONCE(*p4d_offset(&pgd, hva));
+ if (p4d_none(p4d) || !p4d_present(p4d))
+ goto out;
+
+ pud = READ_ONCE(*pud_offset(&p4d, hva));
+ if (pud_none(pud) || !pud_present(pud))
+ goto out;
+
+ pmd = READ_ONCE(*pmd_offset(&pud, hva));
+ if (pmd_none(pmd) || !pmd_present(pmd))
+ goto out;
+
+ if (kvm_pte_huge(pmd_val(pmd)))
+ level = 1;
+
+out:
+ local_irq_restore(flags);
+ return level;
+}
+
+/*
+ * split huge page
+ */
+static kvm_pte_t *kvm_split_huge(struct kvm_vcpu *vcpu, kvm_pte_t *ptep,
+ gfn_t gfn)
+{
+ int i;
+ kvm_pte_t val, *child;
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_mmu_memory_cache *memcache;
+
+ memcache = &vcpu->arch.mmu_page_cache;
+ child = kvm_mmu_memory_cache_alloc(memcache);
+ val = kvm_pte_mksmall(*ptep);
+ for (i = 0; i < PTRS_PER_PTE; i++) {
+ kvm_set_pte(child + i, val);
+ val += PAGE_SIZE;
+ }
+
+ /* the later kvm_flush_tlb_gpa will flush hugepage tlb */
+ kvm_set_pte(ptep, __pa(child));
+
+ kvm->stat.hugepages--;
+ kvm->stat.pages += PTRS_PER_PTE;
+ return child + (gfn & (PTRS_PER_PTE - 1));
+}
+
+/**
+ * kvm_map_page() - Map a guest physical page.
+ * @vcpu: vCPU pointer.
+ * @gpa: Guest physical address of fault.
+ * @write: Whether the fault was due to a write.
+ *
+ * Handle GPA faults by creating a new GPA mapping (or updating an existing
+ * one).
+ *
+ * This takes care of marking pages young or dirty (idle/dirty page tracking),
+ * asking KVM for the corresponding PFN, and creating a mapping in the GPA page
+ * tables. Derived mappings (GVA page tables and TLBs) must be handled by the
+ * caller.
+ *
+ * Returns: 0 on success
+ * -EFAULT if there is no memory region at @gpa or a write was
+ * attempted to a read-only memory region. This is usually handled
+ * as an MMIO access.
+ */
+static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write)
+{
+ bool writeable;
+ int srcu_idx, err, retry_no = 0, level;
+ unsigned long hva, mmu_seq, prot_bits;
+ kvm_pte_t *ptep, new_pte;
+ kvm_pfn_t pfn;
+ gfn_t gfn = gpa >> PAGE_SHIFT;
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_memory_slot *memslot;
+ struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
+
+ /* Try the fast path to handle old / clean pages */
+ srcu_idx = srcu_read_lock(&kvm->srcu);
+ err = kvm_map_page_fast(vcpu, gpa, write);
+ if (!err)
+ goto out;
+
+ memslot = gfn_to_memslot(kvm, gfn);
+ hva = gfn_to_hva_memslot_prot(memslot, gfn, &writeable);
+ if (kvm_is_error_hva(hva) || (write && !writeable)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* We need a minimum of cached pages ready for page table creation */
+ err = kvm_mmu_topup_memory_cache(memcache, KVM_MMU_CACHE_MIN_PAGES);
+ if (err)
+ goto out;
+
+retry:
+ /*
+ * Used to check for invalidations in progress, of the pfn that is
+ * returned by pfn_to_pfn_prot below.
+ */
+ mmu_seq = kvm->mmu_invalidate_seq;
+ /*
+ * Ensure the read of mmu_invalidate_seq isn't reordered with PTE reads in
+ * gfn_to_pfn_prot() (which calls get_user_pages()), so that we don't
+ * risk the page we get a reference to getting unmapped before we have a
+ * chance to grab the mmu_lock without mmu_invalidate_retry() noticing.
+ *
+ * This smp_rmb() pairs with the effective smp_wmb() of the combination
+ * of the pte_unmap_unlock() after the PTE is zapped, and the
+ * spin_lock() in kvm_mmu_invalidate_invalidate_<page|range_end>() before
+ * mmu_invalidate_seq is incremented.
+ */
+ smp_rmb();
+
+ /* Slow path - ask KVM core whether we can access this GPA */
+ pfn = gfn_to_pfn_prot(kvm, gfn, write, &writeable);
+ if (is_error_noslot_pfn(pfn)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* Check if an invalidation has taken place since we got pfn */
+ spin_lock(&kvm->mmu_lock);
+ if (mmu_invalidate_retry_hva(kvm, mmu_seq, hva)) {
+ /*
+ * This can happen when mappings are changed asynchronously, but
+ * also synchronously if a COW is triggered by
+ * gfn_to_pfn_prot().
+ */
+ spin_unlock(&kvm->mmu_lock);
+ kvm_release_pfn_clean(pfn);
+ if (retry_no > 100) {
+ retry_no = 0;
+ schedule();
+ }
+ retry_no++;
+ goto retry;
+ }
+
+ /*
+ * For emulated devices such virtio device, actual cache attribute is
+ * determined by physical machine.
+ * For pass through physical device, it should be uncachable
+ */
+ prot_bits = _PAGE_PRESENT | __READABLE;
+ if (pfn_valid(pfn))
+ prot_bits |= _CACHE_CC;
+ else
+ prot_bits |= _CACHE_SUC;
+
+ if (writeable) {
+ prot_bits |= _PAGE_WRITE;
+ if (write)
+ prot_bits |= __WRITEABLE;
+ }
+
+ /* Disable dirty logging on HugePages */
+ level = 0;
+ if (!fault_supports_huge_mapping(memslot, hva, PMD_SIZE, write)) {
+ level = 0;
+ } else {
+ level = host_pfn_mapping_level(kvm, gfn, memslot);
+ if (level == 1) {
+ gfn = gfn & ~(PTRS_PER_PTE - 1);
+ pfn = pfn & ~(PTRS_PER_PTE - 1);
+ }
+ }
+
+ /* Ensure page tables are allocated */
+ ptep = kvm_populate_gpa(kvm, memcache, gpa, level);
+ new_pte = kvm_pfn_pte(pfn, __pgprot(prot_bits));
+ if (level == 1) {
+ new_pte = kvm_pte_mkhuge(new_pte);
+ /*
+ * previous pmd entry is invalid_pte_table
+ * there is invalid tlb with small page
+ * need flush these invalid tlbs for current vcpu
+ */
+ kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+ ++kvm->stat.hugepages;
+ } else if (kvm_pte_huge(*ptep) && write)
+ ptep = kvm_split_huge(vcpu, ptep, gfn);
+ else
+ ++kvm->stat.pages;
+ kvm_set_pte(ptep, new_pte);
+ spin_unlock(&kvm->mmu_lock);
+
+ if (prot_bits & _PAGE_DIRTY) {
+ mark_page_dirty_in_slot(kvm, memslot, gfn);
+ kvm_set_pfn_dirty(pfn);
+ }
+
+ kvm_set_pfn_accessed(pfn);
+ kvm_release_pfn_clean(pfn);
+out:
+ srcu_read_unlock(&kvm->srcu, srcu_idx);
+ return err;
+}
+
+int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long gpa, bool write)
+{
+ int ret;
+
+ ret = kvm_map_page(vcpu, gpa, write);
+ if (ret)
+ return ret;
+
+ /* Invalidate this entry in the TLB */
+ return kvm_flush_tlb_gpa(vcpu, gpa);
+}
+
+void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
+{
+
+}
+
+int kvm_arch_prepare_memory_region(struct kvm *kvm,
+ const struct kvm_memory_slot *old,
+ struct kvm_memory_slot *new,
+ enum kvm_mr_change change)
+{
+ return 0;
+}
+
+void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
+ const struct kvm_memory_slot *memslot)
+{
+ kvm_flush_remote_tlbs(kvm);
+}
--
2.39.1

2023-09-15 01:54:39

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 19/29] LoongArch: KVM: Implement handle csr exception

Implement kvm handle LoongArch vcpu exit caused by reading and
writing csr. Using csr structure to emulate the registers.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/exit.c | 109 ++++++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
create mode 100644 arch/loongarch/kvm/exit.c

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
new file mode 100644
index 0000000000..f77175351b
--- /dev/null
+++ b/arch/loongarch/kvm/exit.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/preempt.h>
+#include <linux/vmalloc.h>
+#include <asm/fpu.h>
+#include <asm/inst.h>
+#include <asm/time.h>
+#include <asm/tlb.h>
+#include <asm/loongarch.h>
+#include <asm/numa.h>
+#include <asm/kvm_vcpu.h>
+#include <asm/kvm_csr.h>
+#include <linux/kvm_host.h>
+#include <asm/mmzone.h>
+#include "trace.h"
+
+static unsigned long kvm_emu_read_csr(struct kvm_vcpu *vcpu, int csrid)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ unsigned long val = 0;
+
+ /*
+ * From LoongArch Reference Manual Volume 1 Chapter 4.2.1
+ * For undefined csr id, return value is 0
+ */
+ if (get_gcsr_flag(csrid) & SW_GCSR)
+ val = kvm_read_sw_gcsr(csr, csrid);
+ else
+ pr_warn_once("Unsupport csrread 0x%x with pc %lx\n",
+ csrid, vcpu->arch.pc);
+ return val;
+}
+
+static unsigned long kvm_emu_write_csr(struct kvm_vcpu *vcpu, int csrid,
+ unsigned long val)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ unsigned long old = 0;
+
+ if (get_gcsr_flag(csrid) & SW_GCSR) {
+ old = kvm_read_sw_gcsr(csr, csrid);
+ kvm_write_sw_gcsr(csr, csrid, val);
+ } else
+ pr_warn_once("Unsupport csrwrite 0x%x with pc %lx\n",
+ csrid, vcpu->arch.pc);
+
+ return old;
+}
+
+static unsigned long kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid,
+ unsigned long csr_mask, unsigned long val)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ unsigned long old = 0;
+
+ if (get_gcsr_flag(csrid) & SW_GCSR) {
+ old = kvm_read_sw_gcsr(csr, csrid);
+ val = (old & ~csr_mask) | (val & csr_mask);
+ kvm_write_sw_gcsr(csr, csrid, val);
+ old = old & csr_mask;
+ } else
+ pr_warn_once("Unsupport csrxchg 0x%x with pc %lx\n",
+ csrid, vcpu->arch.pc);
+
+ return old;
+}
+
+static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
+{
+ unsigned int rd, rj, csrid;
+ unsigned long csr_mask;
+ unsigned long val = 0;
+
+ /*
+ * CSR value mask imm
+ * rj = 0 means csrrd
+ * rj = 1 means csrwr
+ * rj != 0,1 means csrxchg
+ */
+ rd = inst.reg2csr_format.rd;
+ rj = inst.reg2csr_format.rj;
+ csrid = inst.reg2csr_format.csr;
+
+ /* Process CSR ops */
+ if (rj == 0) {
+ /* process csrrd */
+ val = kvm_emu_read_csr(vcpu, csrid);
+ vcpu->arch.gprs[rd] = val;
+ } else if (rj == 1) {
+ /* process csrwr */
+ val = vcpu->arch.gprs[rd];
+ val = kvm_emu_write_csr(vcpu, csrid, val);
+ vcpu->arch.gprs[rd] = val;
+ } else {
+ /* process csrxchg */
+ val = vcpu->arch.gprs[rd];
+ csr_mask = vcpu->arch.gprs[rj];
+ val = kvm_emu_xchg_csr(vcpu, csrid, csr_mask, val);
+ vcpu->arch.gprs[rd] = val;
+ }
+
+ return EMULATE_DONE;
+}
--
2.39.1

2023-09-15 01:54:41

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 21/29] LoongArch: KVM: Implement handle idle exception

Implement kvm handle LoongArch vcpu idle exception, using kvm_vcpu_block
to emulate it.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/exit.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index 1a83eb9afe..9f3d9131c1 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -199,3 +199,23 @@ int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run)

return er;
}
+
+int kvm_emu_idle(struct kvm_vcpu *vcpu)
+{
+ ++vcpu->stat.idle_exits;
+ trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE);
+
+ if (!kvm_arch_vcpu_runnable(vcpu)) {
+ /*
+ * Switch to the software timer before halt-polling/blocking as
+ * the guest's timer may be a break event for the vCPU, and the
+ * hypervisor timer runs only when the CPU is in guest mode.
+ * Switch before halt-polling so that KVM recognizes an expired
+ * timer before blocking.
+ */
+ kvm_save_timer(vcpu);
+ kvm_vcpu_block(vcpu);
+ }
+
+ return EMULATE_DONE;
+}
--
2.39.1

2023-09-15 02:02:59

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 09/29] LoongArch: KVM: Implement vcpu get, vcpu set registers

Implement LoongArch vcpu get registers and set registers operations, it
is called when user space use the ioctl interface to get or set regs.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 244 ++++++++++++++++++++++++++++++++++++++
1 file changed, 244 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index bfc2ec1a88..1cc53f56d0 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -13,6 +13,250 @@
#define CREATE_TRACE_POINTS
#include "trace.h"

+int kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v)
+{
+ unsigned long val;
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+
+ if (get_gcsr_flag(id) & INVALID_GCSR)
+ return -EINVAL;
+
+ if (id == LOONGARCH_CSR_ESTAT) {
+ /* interrupt status IP0 -- IP7 from GINTC */
+ val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & 0xff;
+ *v = kvm_read_sw_gcsr(csr, id) | (val << 2);
+ return 0;
+ }
+
+ /*
+ * get software csr state if csrid is valid, since software
+ * csr state is consistent with hardware
+ */
+ *v = kvm_read_sw_gcsr(csr, id);
+
+ return 0;
+}
+
+int kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ int ret = 0, gintc;
+
+ if (get_gcsr_flag(id) & INVALID_GCSR)
+ return -EINVAL;
+
+ if (id == LOONGARCH_CSR_ESTAT) {
+ /* estat IP0~IP7 inject through guestexcept */
+ gintc = (val >> 2) & 0xff;
+ kvm_set_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc);
+
+ gintc = val & ~(0xffUL << 2);
+ kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, gintc);
+
+ return ret;
+ }
+
+ kvm_write_sw_gcsr(csr, id, val);
+ return ret;
+}
+
+static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg, u64 *v)
+{
+ int id, ret = 0;
+ u64 type = reg->id & KVM_REG_LOONGARCH_MASK;
+
+ switch (type) {
+ case KVM_REG_LOONGARCH_CSR:
+ id = KVM_GET_IOC_CSRIDX(reg->id);
+ ret = kvm_getcsr(vcpu, id, v);
+ break;
+ case KVM_REG_LOONGARCH_CPUCFG:
+ id = KVM_GET_IOC_CPUCFG_IDX(reg->id);
+ if (id >= 0 && id < KVM_MAX_CPUCFG_REGS)
+ *v = vcpu->arch.cpucfg[id];
+ else
+ ret = -EINVAL;
+ break;
+ case KVM_REG_LOONGARCH_KVM:
+ switch (reg->id & 0xf) {
+ case 4: /* counter reg */
+ *v = drdtime() + vcpu->kvm->arch.time_offset;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int kvm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ int ret = 0;
+ u64 v, size = reg->id & KVM_REG_SIZE_MASK;
+
+ switch (size) {
+ case KVM_REG_SIZE_U64:
+ ret = kvm_get_one_reg(vcpu, reg, &v);
+ if (ret)
+ return ret;
+ ret = put_user(v, (u64 __user *)(long)reg->addr);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg,
+ u64 v)
+{
+ int id, ret = 0;
+ u64 type = reg->id & KVM_REG_LOONGARCH_MASK;
+
+ switch (type) {
+ case KVM_REG_LOONGARCH_CSR:
+ id = KVM_GET_IOC_CSRIDX(reg->id);
+ ret = kvm_setcsr(vcpu, id, v);
+ break;
+ case KVM_REG_LOONGARCH_CPUCFG:
+ id = KVM_GET_IOC_CPUCFG_IDX(reg->id);
+ if (id >= 0 && id < KVM_MAX_CPUCFG_REGS)
+ vcpu->arch.cpucfg[id] = (u32)v;
+ else
+ ret = -EINVAL;
+ break;
+ case KVM_REG_LOONGARCH_KVM:
+ switch (reg->id & 0xf) {
+ case 3: /* counter reg */
+ /*
+ * gftoffset is relative with board, not vcpu
+ * only set for the first time for smp system
+ */
+ if (vcpu->vcpu_id == 0)
+ vcpu->kvm->arch.time_offset = (signed long)(v - drdtime());
+ break;
+ case 4: /* vcpu reset */
+ kvm_reset_timer(vcpu);
+ memset(&vcpu->arch.irq_pending, 0, sizeof(vcpu->arch.irq_pending));
+ memset(&vcpu->arch.irq_clear, 0, sizeof(vcpu->arch.irq_clear));
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int kvm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ int ret = 0;
+ u64 v, size = reg->id & KVM_REG_SIZE_MASK;
+
+ switch (size) {
+ case KVM_REG_SIZE_U64:
+ ret = get_user(v, (u64 __user *)(long)reg->addr);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return kvm_set_one_reg(vcpu, reg, v);
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -ENOIOCTLCMD;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
+ regs->gpr[i] = vcpu->arch.gprs[i];
+
+ regs->pc = vcpu->arch.pc;
+
+ return 0;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(vcpu->arch.gprs); i++)
+ vcpu->arch.gprs[i] = regs->gpr[i];
+ vcpu->arch.gprs[0] = 0; /* zero is special, and cannot be set. */
+ vcpu->arch.pc = regs->pc;
+
+ return 0;
+}
+
+long kvm_arch_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ long r;
+
+ /*
+ * Only software CSR should be modified
+ *
+ * If any hardware CSR register is modified, vcpu_load/vcpu_put pair
+ * should be used. Since CSR registers owns by this vcpu, if switch
+ * to other vcpus, other vcpus need reload CSR register.
+ *
+ * If software CSR is modified, bit KVM_LARCH_HWCSR_USABLE should
+ * be clear in vcpu->arch.aux_inuse, and vcpu_load will check
+ * aux_inuse flag and reload CSR form sw
+ */
+
+ switch (ioctl) {
+ case KVM_SET_ONE_REG:
+ case KVM_GET_ONE_REG: {
+ struct kvm_one_reg reg;
+
+ r = -EFAULT;
+ if (copy_from_user(&reg, argp, sizeof(reg)))
+ break;
+ if (ioctl == KVM_SET_ONE_REG) {
+ r = kvm_set_reg(vcpu, &reg);
+ vcpu->arch.aux_inuse &= ~KVM_LARCH_HWCSR_USABLE;
+ } else
+ r = kvm_get_reg(vcpu, &reg);
+ break;
+ }
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+ return r;
+}
+
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
{
return 0;
--
2.39.1

2023-09-15 02:03:11

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 04/29] LoongArch: KVM: Implement VM related functions

Implement LoongArch VM operations: Init and destroy vm interface,
allocating memory page to save the vm pgd when init vm. Implement
vm check extension, such as getting vcpu number info, memory slots
info, and fpu info. And implement vm status description.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vm.c | 92 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
create mode 100644 arch/loongarch/kvm/vm.c

diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
new file mode 100644
index 0000000000..abc345bf37
--- /dev/null
+++ b/arch/loongarch/kvm/vm.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_mmu.h>
+
+const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
+ KVM_GENERIC_VM_STATS(),
+ STATS_DESC_ICOUNTER(VM, pages),
+ STATS_DESC_ICOUNTER(VM, hugepages),
+};
+
+const struct kvm_stats_header kvm_vm_stats_header = {
+ .name_size = KVM_STATS_NAME_SIZE,
+ .num_desc = ARRAY_SIZE(kvm_vm_stats_desc),
+ .id_offset = sizeof(struct kvm_stats_header),
+ .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+ .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+ sizeof(kvm_vm_stats_desc),
+};
+
+int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
+{
+ int i;
+
+ /* Allocate page table to map GPA -> RPA */
+ kvm->arch.pgd = kvm_pgd_alloc();
+ if (!kvm->arch.pgd)
+ return -ENOMEM;
+
+ kvm_init_vmcs(kvm);
+ kvm->arch.gpa_size = BIT(cpu_vabits - 1);
+ kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1;
+ kvm->arch.invalid_ptes[0] = 0;
+ kvm->arch.invalid_ptes[1] = (unsigned long)invalid_pte_table;
+ kvm->arch.invalid_ptes[2] = (unsigned long)invalid_pmd_table;
+#if CONFIG_PGTABLE_LEVELS > 3
+ kvm->arch.invalid_ptes[3] = (unsigned long)invalid_pud_table;
+#endif
+ for (i = 0; i <= kvm->arch.root_level; i++)
+ kvm->arch.pte_shifts[i] = PAGE_SHIFT + i * (PAGE_SHIFT - 3);
+
+ return 0;
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
+ kvm_destroy_vcpus(kvm);
+ free_page((unsigned long)kvm->arch.pgd);
+ kvm->arch.pgd = NULL;
+}
+
+int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
+{
+ int r;
+
+ switch (ext) {
+ case KVM_CAP_ONE_REG:
+ case KVM_CAP_ENABLE_CAP:
+ case KVM_CAP_READONLY_MEM:
+ case KVM_CAP_SYNC_MMU:
+ case KVM_CAP_IMMEDIATE_EXIT:
+ case KVM_CAP_IOEVENTFD:
+ case KVM_CAP_MP_STATE:
+ r = 1;
+ break;
+ case KVM_CAP_NR_VCPUS:
+ r = num_online_cpus();
+ break;
+ case KVM_CAP_MAX_VCPUS:
+ r = KVM_MAX_VCPUS;
+ break;
+ case KVM_CAP_MAX_VCPU_ID:
+ r = KVM_MAX_VCPU_IDS;
+ break;
+ case KVM_CAP_NR_MEMSLOTS:
+ r = KVM_USER_MEM_SLOTS;
+ break;
+ default:
+ r = 0;
+ break;
+ }
+
+ return r;
+}
+
+int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
--
2.39.1

2023-09-15 02:03:29

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 15/29] LoongArch: KVM: Implement vcpu status description

Implement LoongArch vcpu status description such as idle exits counter,
signal exits counter, cpucfg exits counter, etc.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 7162e6ddb7..9cca9f4a0c 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -13,6 +13,23 @@
#define CREATE_TRACE_POINTS
#include "trace.h"

+const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
+ KVM_GENERIC_VCPU_STATS(),
+ STATS_DESC_COUNTER(VCPU, idle_exits),
+ STATS_DESC_COUNTER(VCPU, signal_exits),
+ STATS_DESC_COUNTER(VCPU, int_exits),
+ STATS_DESC_COUNTER(VCPU, cpucfg_exits),
+};
+
+const struct kvm_stats_header kvm_vcpu_stats_header = {
+ .name_size = KVM_STATS_NAME_SIZE,
+ .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc),
+ .id_offset = sizeof(struct kvm_stats_header),
+ .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE,
+ .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE +
+ sizeof(kvm_vcpu_stats_desc),
+};
+
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
{
return !!(vcpu->arch.irq_pending) &&
--
2.39.1

2023-09-15 02:03:31

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 26/29] LoongArch: KVM: Implement vcpu world switch

Implement LoongArch vcpu world switch, including vcpu enter guest and
vcpu exit from guest, both operations need to save or restore the host
and guest registers.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kernel/asm-offsets.c | 32 ++++
arch/loongarch/kvm/switch.S | 255 ++++++++++++++++++++++++++++
2 files changed, 287 insertions(+)
create mode 100644 arch/loongarch/kvm/switch.S

diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c
index 8da0726777..9c86ff9b53 100644
--- a/arch/loongarch/kernel/asm-offsets.c
+++ b/arch/loongarch/kernel/asm-offsets.c
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/kbuild.h>
#include <linux/suspend.h>
+#include <linux/kvm_host.h>
#include <asm/cpu-info.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -289,3 +290,34 @@ void output_fgraph_ret_regs_defines(void)
BLANK();
}
#endif
+
+static void __used output_kvm_defines(void)
+{
+ COMMENT(" KVM/LoongArch Specific offsets. ");
+
+ OFFSET(VCPU_FCSR0, kvm_vcpu_arch, fpu.fcsr);
+ OFFSET(VCPU_FCC, kvm_vcpu_arch, fpu.fcc);
+ BLANK();
+
+ OFFSET(KVM_VCPU_ARCH, kvm_vcpu, arch);
+ OFFSET(KVM_VCPU_KVM, kvm_vcpu, kvm);
+ OFFSET(KVM_VCPU_RUN, kvm_vcpu, run);
+ BLANK();
+
+ OFFSET(KVM_ARCH_HSP, kvm_vcpu_arch, host_sp);
+ OFFSET(KVM_ARCH_HTP, kvm_vcpu_arch, host_tp);
+ OFFSET(KVM_ARCH_HANDLE_EXIT, kvm_vcpu_arch, handle_exit);
+ OFFSET(KVM_ARCH_HPGD, kvm_vcpu_arch, host_pgd);
+ OFFSET(KVM_ARCH_GEENTRY, kvm_vcpu_arch, guest_eentry);
+ OFFSET(KVM_ARCH_GPC, kvm_vcpu_arch, pc);
+ OFFSET(KVM_ARCH_GGPR, kvm_vcpu_arch, gprs);
+ OFFSET(KVM_ARCH_HESTAT, kvm_vcpu_arch, host_estat);
+ OFFSET(KVM_ARCH_HBADV, kvm_vcpu_arch, badv);
+ OFFSET(KVM_ARCH_HBADI, kvm_vcpu_arch, badi);
+ OFFSET(KVM_ARCH_HECFG, kvm_vcpu_arch, host_ecfg);
+ OFFSET(KVM_ARCH_HEENTRY, kvm_vcpu_arch, host_eentry);
+ OFFSET(KVM_ARCH_HPERCPU, kvm_vcpu_arch, host_percpu);
+
+ OFFSET(KVM_GPGD, kvm, arch.pgd);
+ BLANK();
+}
diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S
new file mode 100644
index 0000000000..48b1f6a4f3
--- /dev/null
+++ b/arch/loongarch/kvm/switch.S
@@ -0,0 +1,255 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/linkage.h>
+#include <asm/stackframe.h>
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/regdef.h>
+#include <asm/loongarch.h>
+
+#define PT_GPR_OFFSET(x) (PT_R0 + 8*x)
+#define GGPR_OFFSET(x) (KVM_ARCH_GGPR + 8*x)
+
+.macro kvm_save_host_gpr base
+ .irp n,1,2,3,22,23,24,25,26,27,28,29,30,31
+ st.d $r\n, \base, PT_GPR_OFFSET(\n)
+ .endr
+.endm
+
+.macro kvm_restore_host_gpr base
+ .irp n,1,2,3,22,23,24,25,26,27,28,29,30,31
+ ld.d $r\n, \base, PT_GPR_OFFSET(\n)
+ .endr
+.endm
+
+/*
+ * save and restore all gprs except base register,
+ * and default value of base register is a2.
+ */
+.macro kvm_save_guest_gprs base
+ .irp n,1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ st.d $r\n, \base, GGPR_OFFSET(\n)
+ .endr
+.endm
+
+.macro kvm_restore_guest_gprs base
+ .irp n,1,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+ ld.d $r\n, \base, GGPR_OFFSET(\n)
+ .endr
+.endm
+
+/*
+ * prepare switch to guest, save host reg and restore guest reg.
+ * a2: kvm_vcpu_arch, don't touch it until 'ertn'
+ * t0, t1: temp register
+ */
+.macro kvm_switch_to_guest
+ /* set host excfg.VS=0, all exceptions share one exception entry */
+ csrrd t0, LOONGARCH_CSR_ECFG
+ bstrins.w t0, zero, CSR_ECFG_VS_SHIFT_END, CSR_ECFG_VS_SHIFT
+ csrwr t0, LOONGARCH_CSR_ECFG
+
+ /* Load up the new EENTRY */
+ ld.d t0, a2, KVM_ARCH_GEENTRY
+ csrwr t0, LOONGARCH_CSR_EENTRY
+
+ /* Set Guest ERA */
+ ld.d t0, a2, KVM_ARCH_GPC
+ csrwr t0, LOONGARCH_CSR_ERA
+
+ /* Save host PGDL */
+ csrrd t0, LOONGARCH_CSR_PGDL
+ st.d t0, a2, KVM_ARCH_HPGD
+
+ /* Switch to kvm */
+ ld.d t1, a2, KVM_VCPU_KVM - KVM_VCPU_ARCH
+
+ /* Load guest PGDL */
+ li.w t0, KVM_GPGD
+ ldx.d t0, t1, t0
+ csrwr t0, LOONGARCH_CSR_PGDL
+
+ /* Mix GID and RID */
+ csrrd t1, LOONGARCH_CSR_GSTAT
+ bstrpick.w t1, t1, CSR_GSTAT_GID_SHIFT_END, CSR_GSTAT_GID_SHIFT
+ csrrd t0, LOONGARCH_CSR_GTLBC
+ bstrins.w t0, t1, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT
+ csrwr t0, LOONGARCH_CSR_GTLBC
+
+ /*
+ * Switch to guest:
+ * GSTAT.PGM = 1, ERRCTL.ISERR = 0, TLBRPRMD.ISTLBR = 0
+ * ertn
+ */
+
+ /*
+ * Enable intr in root mode with future ertn so that host interrupt
+ * can be responsed during VM runs
+ * guest crmd comes from separate gcsr_CRMD register
+ */
+ ori t0, zero, CSR_PRMD_PIE
+ csrxchg t0, t0, LOONGARCH_CSR_PRMD
+
+ /* Set PVM bit to setup ertn to guest context */
+ ori t0, zero, CSR_GSTAT_PVM
+ csrxchg t0, t0, LOONGARCH_CSR_GSTAT
+
+ /* Load Guest gprs */
+ kvm_restore_guest_gprs a2
+ /* Load KVM_ARCH register */
+ ld.d a2, a2, (KVM_ARCH_GGPR + 8 * REG_A2)
+
+ ertn
+.endm
+
+ /*
+ * exception entry for general exception from guest mode
+ * - IRQ is disabled
+ * - kernel privilege in root mode
+ * - page mode keep unchanged from previous prmd in root mode
+ * - Fixme: tlb exception cannot happen since registers relative with TLB
+ * - is still in guest mode, such as pgd table/vmid registers etc,
+ * - will fix with hw page walk enabled in future
+ * load kvm_vcpu from reserved CSR KVM_VCPU_KS, and save a2 to KVM_TEMP_KS
+ */
+ .text
+ .cfi_sections .debug_frame
+SYM_CODE_START(kvm_vector_entry)
+ csrwr a2, KVM_TEMP_KS
+ csrrd a2, KVM_VCPU_KS
+ addi.d a2, a2, KVM_VCPU_ARCH
+
+ /* After save gprs, free to use any gpr */
+ kvm_save_guest_gprs a2
+ /* Save guest a2 */
+ csrrd t0, KVM_TEMP_KS
+ st.d t0, a2, (KVM_ARCH_GGPR + 8 * REG_A2)
+
+ /* a2: kvm_vcpu_arch, a1 is free to use */
+ csrrd s1, KVM_VCPU_KS
+ ld.d s0, s1, KVM_VCPU_RUN
+
+ csrrd t0, LOONGARCH_CSR_ESTAT
+ st.d t0, a2, KVM_ARCH_HESTAT
+ csrrd t0, LOONGARCH_CSR_ERA
+ st.d t0, a2, KVM_ARCH_GPC
+ csrrd t0, LOONGARCH_CSR_BADV
+ st.d t0, a2, KVM_ARCH_HBADV
+ csrrd t0, LOONGARCH_CSR_BADI
+ st.d t0, a2, KVM_ARCH_HBADI
+
+ /* Restore host excfg.VS */
+ csrrd t0, LOONGARCH_CSR_ECFG
+ ld.d t1, a2, KVM_ARCH_HECFG
+ or t0, t0, t1
+ csrwr t0, LOONGARCH_CSR_ECFG
+
+ /* Restore host eentry */
+ ld.d t0, a2, KVM_ARCH_HEENTRY
+ csrwr t0, LOONGARCH_CSR_EENTRY
+
+ /* restore host pgd table */
+ ld.d t0, a2, KVM_ARCH_HPGD
+ csrwr t0, LOONGARCH_CSR_PGDL
+
+ /*
+ * Disable PGM bit to enter root mode by default with next ertn
+ */
+ ori t0, zero, CSR_GSTAT_PVM
+ csrxchg zero, t0, LOONGARCH_CSR_GSTAT
+ /*
+ * Clear GTLBC.TGID field
+ * 0: for root tlb update in future tlb instr
+ * others: for guest tlb update like gpa to hpa in future tlb instr
+ */
+ csrrd t0, LOONGARCH_CSR_GTLBC
+ bstrins.w t0, zero, CSR_GTLBC_TGID_SHIFT_END, CSR_GTLBC_TGID_SHIFT
+ csrwr t0, LOONGARCH_CSR_GTLBC
+ ld.d tp, a2, KVM_ARCH_HTP
+ ld.d sp, a2, KVM_ARCH_HSP
+ /* restore per cpu register */
+ ld.d u0, a2, KVM_ARCH_HPERCPU
+ addi.d sp, sp, -PT_SIZE
+
+ /* Prepare handle exception */
+ or a0, s0, zero
+ or a1, s1, zero
+ ld.d t8, a2, KVM_ARCH_HANDLE_EXIT
+ jirl ra, t8, 0
+
+ or a2, s1, zero
+ addi.d a2, a2, KVM_VCPU_ARCH
+
+ /* resume host when ret <= 0 */
+ bge zero, a0, ret_to_host
+
+ /*
+ * return to guest
+ * save per cpu register again, maybe switched to another cpu
+ */
+ st.d u0, a2, KVM_ARCH_HPERCPU
+
+ /* Save kvm_vcpu to kscratch */
+ csrwr s1, KVM_VCPU_KS
+ kvm_switch_to_guest
+
+ret_to_host:
+ ld.d a2, a2, KVM_ARCH_HSP
+ addi.d a2, a2, -PT_SIZE
+ kvm_restore_host_gpr a2
+ jr ra
+
+SYM_INNER_LABEL(kvm_vector_entry_end, SYM_L_LOCAL)
+SYM_CODE_END(kvm_vector_entry)
+
+/*
+ * int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu)
+ *
+ * @register_param:
+ * a0: kvm_run* run
+ * a1: kvm_vcpu* vcpu
+ */
+SYM_FUNC_START(kvm_enter_guest)
+ /* allocate space in stack bottom */
+ addi.d a2, sp, -PT_SIZE
+ /* save host gprs */
+ kvm_save_host_gpr a2
+
+ /* save host crmd,prmd csr to stack */
+ csrrd a3, LOONGARCH_CSR_CRMD
+ st.d a3, a2, PT_CRMD
+ csrrd a3, LOONGARCH_CSR_PRMD
+ st.d a3, a2, PT_PRMD
+
+ addi.d a2, a1, KVM_VCPU_ARCH
+ st.d sp, a2, KVM_ARCH_HSP
+ st.d tp, a2, KVM_ARCH_HTP
+ /* Save per cpu register */
+ st.d u0, a2, KVM_ARCH_HPERCPU
+
+ /* Save kvm_vcpu to kscratch */
+ csrwr a1, KVM_VCPU_KS
+ kvm_switch_to_guest
+SYM_INNER_LABEL(kvm_enter_guest_end, SYM_L_LOCAL)
+SYM_FUNC_END(kvm_enter_guest)
+
+SYM_FUNC_START(kvm_save_fpu)
+ fpu_save_csr a0 t1
+ fpu_save_double a0 t1
+ fpu_save_cc a0 t1 t2
+ jr ra
+SYM_FUNC_END(kvm_save_fpu)
+
+SYM_FUNC_START(kvm_restore_fpu)
+ fpu_restore_double a0 t1
+ fpu_restore_csr a0 t1 t2
+ fpu_restore_cc a0 t1 t2
+ jr ra
+SYM_FUNC_END(kvm_restore_fpu)
+
+ .section ".rodata"
+SYM_DATA(kvm_vector_size, .quad kvm_vector_entry_end - kvm_vector_entry)
+SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
--
2.39.1

2023-09-15 02:03:39

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 22/29] LoongArch: KVM: Implement handle gspr exception

Implement kvm handle gspr exception interface, including emulate the
reading and writing of cpucfg, csr, iocsr resource.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/exit.c | 112 ++++++++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index 9f3d9131c1..a86586cdfc 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -219,3 +219,115 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu)

return EMULATE_DONE;
}
+
+static int kvm_trap_handle_gspr(struct kvm_vcpu *vcpu)
+{
+ enum emulation_result er = EMULATE_DONE;
+ struct kvm_run *run = vcpu->run;
+ larch_inst inst;
+ unsigned long curr_pc;
+ int rd, rj;
+ unsigned int index;
+
+ /*
+ * Fetch the instruction.
+ */
+ inst.word = vcpu->arch.badi;
+ curr_pc = vcpu->arch.pc;
+ update_pc(&vcpu->arch);
+
+ trace_kvm_exit_gspr(vcpu, inst.word);
+ er = EMULATE_FAIL;
+ switch (((inst.word >> 24) & 0xff)) {
+ case 0x0:
+ /* cpucfg GSPR */
+ if (inst.reg2_format.opcode == 0x1B) {
+ rd = inst.reg2_format.rd;
+ rj = inst.reg2_format.rj;
+ ++vcpu->stat.cpucfg_exits;
+ index = vcpu->arch.gprs[rj];
+ er = EMULATE_DONE;
+ /*
+ * By LoongArch Reference Manual 2.2.10.5
+ * return value is 0 for undefined cpucfg index
+ */
+ if (index < KVM_MAX_CPUCFG_REGS)
+ vcpu->arch.gprs[rd] = vcpu->arch.cpucfg[index];
+ else
+ vcpu->arch.gprs[rd] = 0;
+ }
+ break;
+ case 0x4:
+ /* csr GSPR */
+ er = kvm_handle_csr(vcpu, inst);
+ break;
+ case 0x6:
+ /* iocsr,cache,idle GSPR */
+ switch (((inst.word >> 22) & 0x3ff)) {
+ case 0x18:
+ /* cache GSPR */
+ er = EMULATE_DONE;
+ trace_kvm_exit_cache(vcpu, KVM_TRACE_EXIT_CACHE);
+ break;
+ case 0x19:
+ /* iocsr/idle GSPR */
+ switch (((inst.word >> 15) & 0x1ffff)) {
+ case 0xc90:
+ /* iocsr GSPR */
+ er = kvm_emu_iocsr(inst, run, vcpu);
+ break;
+ case 0xc91:
+ /* idle GSPR */
+ er = kvm_emu_idle(vcpu);
+ break;
+ default:
+ er = EMULATE_FAIL;
+ break;
+ }
+ break;
+ default:
+ er = EMULATE_FAIL;
+ break;
+ }
+ break;
+ default:
+ er = EMULATE_FAIL;
+ break;
+ }
+
+ /* Rollback PC only if emulation was unsuccessful */
+ if (er == EMULATE_FAIL) {
+ kvm_err("[%#lx]%s: unsupported gspr instruction 0x%08x\n",
+ curr_pc, __func__, inst.word);
+
+ kvm_arch_vcpu_dump_regs(vcpu);
+ vcpu->arch.pc = curr_pc;
+ }
+ return er;
+}
+
+/*
+ * Execute cpucfg instruction will tirggerGSPR,
+ * Also the access to unimplemented csrs 0x15
+ * 0x16, 0x50~0x53, 0x80, 0x81, 0x90~0x95, 0x98
+ * 0xc0~0xff, 0x100~0x109, 0x500~0x502,
+ * cache_op, idle_op iocsr ops the same
+ */
+static int kvm_handle_gspr(struct kvm_vcpu *vcpu)
+{
+ enum emulation_result er = EMULATE_DONE;
+ int ret = RESUME_GUEST;
+
+ er = kvm_trap_handle_gspr(vcpu);
+
+ if (er == EMULATE_DONE) {
+ ret = RESUME_GUEST;
+ } else if (er == EMULATE_DO_IOCSR) {
+ vcpu->run->exit_reason = KVM_EXIT_LOONGARCH_IOCSR;
+ ret = RESUME_HOST;
+ } else {
+ kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+ ret = RESUME_GUEST;
+ }
+ return ret;
+}
--
2.39.1

2023-09-15 02:03:53

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 17/29] LoongArch: KVM: Implement vcpu timer operations

Implement LoongArch vcpu timer operations such as init kvm timer,
require kvm timer, save kvm timer and restore kvm timer. When
vcpu exit, we use kvm soft timer to emulate hardware timer. If
timeout happens, the vcpu timer interrupt will be set and it is
going to be handled at vcpu next entrance.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/timer.c | 200 +++++++++++++++++++++++++++++++++++++
1 file changed, 200 insertions(+)
create mode 100644 arch/loongarch/kvm/timer.c

diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
new file mode 100644
index 0000000000..e084593c73
--- /dev/null
+++ b/arch/loongarch/kvm/timer.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_csr.h>
+#include <asm/kvm_vcpu.h>
+
+/*
+ * ktime_to_tick() - Scale ktime_t to timer tick value.
+ */
+static inline u64 ktime_to_tick(struct kvm_vcpu *vcpu, ktime_t now)
+{
+ u64 delta;
+
+ delta = ktime_to_ns(now);
+ return div_u64(delta * vcpu->arch.timer_mhz, MNSEC_PER_SEC);
+}
+
+static inline u64 tick_to_ns(struct kvm_vcpu *vcpu, u64 tick)
+{
+ return div_u64(tick * MNSEC_PER_SEC, vcpu->arch.timer_mhz);
+}
+
+/*
+ * Push timer forward on timeout.
+ * Handle an hrtimer event by push the hrtimer forward a period.
+ */
+static enum hrtimer_restart kvm_count_timeout(struct kvm_vcpu *vcpu)
+{
+ unsigned long cfg, period;
+
+ /* Add periodic tick to current expire time */
+ cfg = kvm_read_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG);
+ if (cfg & CSR_TCFG_PERIOD) {
+ period = tick_to_ns(vcpu, cfg & CSR_TCFG_VAL);
+ hrtimer_add_expires_ns(&vcpu->arch.swtimer, period);
+ return HRTIMER_RESTART;
+ } else
+ return HRTIMER_NORESTART;
+}
+
+/* low level hrtimer wake routine */
+enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
+{
+ struct kvm_vcpu *vcpu;
+
+ vcpu = container_of(timer, struct kvm_vcpu, arch.swtimer);
+ kvm_queue_irq(vcpu, INT_TI);
+ rcuwait_wake_up(&vcpu->wait);
+ return kvm_count_timeout(vcpu);
+}
+
+/*
+ * Initialise the timer to the specified frequency, zero it
+ */
+void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long timer_hz)
+{
+ vcpu->arch.timer_mhz = timer_hz >> 20;
+
+ /* Starting at 0 */
+ kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TVAL, 0);
+}
+
+/*
+ * Restore soft timer state from saved context.
+ */
+void kvm_restore_timer(struct kvm_vcpu *vcpu)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ ktime_t expire, now;
+ unsigned long cfg, delta, period;
+
+ /*
+ * Set guest stable timer cfg csr
+ */
+ cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
+ if (!(cfg & CSR_TCFG_EN)) {
+ /* guest timer is disabled, just restore timer registers */
+ kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
+ return;
+ }
+
+ /*
+ * set remainder tick value if not expired
+ */
+ now = ktime_get();
+ expire = vcpu->arch.expire;
+ if (ktime_before(now, expire))
+ delta = ktime_to_tick(vcpu, ktime_sub(expire, now));
+ else {
+ if (cfg & CSR_TCFG_PERIOD) {
+ period = cfg & CSR_TCFG_VAL;
+ delta = ktime_to_tick(vcpu, ktime_sub(now, expire));
+ delta = period - (delta % period);
+ } else
+ delta = 0;
+ /*
+ * inject timer here though sw timer should inject timer
+ * interrupt async already, since sw timer may be cancelled
+ * during injecting intr async in function kvm_acquire_timer
+ */
+ kvm_queue_irq(vcpu, INT_TI);
+ }
+
+ write_gcsr_timertick(delta);
+}
+
+/*
+ *
+ * Restore hard timer state and enable guest to access timer registers
+ * without trap
+ *
+ * it is called with irq disabled
+ */
+void kvm_acquire_timer(struct kvm_vcpu *vcpu)
+{
+ unsigned long cfg;
+
+ cfg = read_csr_gcfg();
+ if (!(cfg & CSR_GCFG_TIT))
+ return;
+
+ /* enable guest access to hard timer */
+ write_csr_gcfg(cfg & ~CSR_GCFG_TIT);
+
+ /*
+ * Freeze the soft-timer and sync the guest stable timer with it. We do
+ * this with interrupts disabled to avoid latency.
+ */
+ hrtimer_cancel(&vcpu->arch.swtimer);
+}
+
+/*
+ * Save guest timer state and switch to software emulation of guest
+ * timer. The hard timer must already be in use, so preemption should be
+ * disabled.
+ */
+static void _kvm_save_timer(struct kvm_vcpu *vcpu)
+{
+ unsigned long ticks, delta;
+ ktime_t expire;
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+
+ ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL);
+ delta = tick_to_ns(vcpu, ticks);
+ expire = ktime_add_ns(ktime_get(), delta);
+ vcpu->arch.expire = expire;
+ if (ticks) {
+ /*
+ * Update hrtimer to use new timeout
+ * HRTIMER_MODE_PINNED is suggested since vcpu may run in
+ * the same physical cpu in next time
+ */
+ hrtimer_cancel(&vcpu->arch.swtimer);
+ hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
+ } else
+ /*
+ * inject timer interrupt so that hall polling can dectect
+ * and exit
+ */
+ kvm_queue_irq(vcpu, INT_TI);
+}
+
+/*
+ * Save guest timer state and switch to soft guest timer if hard timer was in
+ * use.
+ */
+void kvm_save_timer(struct kvm_vcpu *vcpu)
+{
+ struct loongarch_csrs *csr = vcpu->arch.csr;
+ unsigned long cfg;
+
+ preempt_disable();
+ cfg = read_csr_gcfg();
+ if (!(cfg & CSR_GCFG_TIT)) {
+ /* disable guest use of hard timer */
+ write_csr_gcfg(cfg | CSR_GCFG_TIT);
+
+ /* save hard timer state */
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
+ if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN)
+ _kvm_save_timer(vcpu);
+ }
+
+ /* save timer-related state to vCPU context */
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+ preempt_enable();
+}
+
+void kvm_reset_timer(struct kvm_vcpu *vcpu)
+{
+ write_gcsr_timercfg(0);
+ kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG, 0);
+ hrtimer_cancel(&vcpu->arch.swtimer);
+}
--
2.39.1

2023-09-15 02:04:01

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 23/29] LoongArch: KVM: Implement handle mmio exception

Implement handle mmio exception, setting the mmio info into vcpu_run and
return to user space to handle it.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/exit.c | 307 ++++++++++++++++++++++++++++++++++++++
1 file changed, 307 insertions(+)

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index a86586cdfc..004b91055a 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -220,6 +220,265 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu)
return EMULATE_DONE;
}

+int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst)
+{
+ struct kvm_run *run = vcpu->run;
+ unsigned int rd, op8, opcode;
+ unsigned long rd_val = 0;
+ void *data = run->mmio.data;
+ unsigned long curr_pc;
+ int ret;
+
+ /*
+ * Update PC and hold onto current PC in case there is
+ * an error and we want to rollback the PC
+ */
+ curr_pc = vcpu->arch.pc;
+ update_pc(&vcpu->arch);
+
+ op8 = (inst.word >> 24) & 0xff;
+ run->mmio.phys_addr = vcpu->arch.badv;
+ ret = EMULATE_DO_MMIO;
+ if (op8 < 0x28) {
+ /* stptrw/d process */
+ rd = inst.reg2i14_format.rd;
+ opcode = inst.reg2i14_format.opcode;
+
+ switch (opcode) {
+ case stptrd_op:
+ run->mmio.len = 8;
+ *(unsigned long *)data = vcpu->arch.gprs[rd];
+ break;
+ case stptrw_op:
+ run->mmio.len = 4;
+ *(unsigned int *)data = vcpu->arch.gprs[rd];
+ break;
+ default:
+ ret = EMULATE_FAIL;
+ break;
+ }
+ } else if (op8 < 0x30) {
+ /* st.b/h/w/d process */
+ rd = inst.reg2i12_format.rd;
+ opcode = inst.reg2i12_format.opcode;
+ rd_val = vcpu->arch.gprs[rd];
+
+ switch (opcode) {
+ case std_op:
+ run->mmio.len = 8;
+ *(unsigned long *)data = rd_val;
+ break;
+ case stw_op:
+ run->mmio.len = 4;
+ *(unsigned int *)data = rd_val;
+ break;
+ case sth_op:
+ run->mmio.len = 2;
+ *(unsigned short *)data = rd_val;
+ break;
+ case stb_op:
+ run->mmio.len = 1;
+ *(unsigned char *)data = rd_val;
+ break;
+ default:
+ ret = EMULATE_FAIL;
+ break;
+ }
+ } else if (op8 == 0x38) {
+ /* stxb/h/w/d process */
+ rd = inst.reg3_format.rd;
+ opcode = inst.reg3_format.opcode;
+
+ switch (opcode) {
+ case stxb_op:
+ run->mmio.len = 1;
+ *(unsigned char *)data = vcpu->arch.gprs[rd];
+ break;
+ case stxh_op:
+ run->mmio.len = 2;
+ *(unsigned short *)data = vcpu->arch.gprs[rd];
+ break;
+ case stxw_op:
+ run->mmio.len = 4;
+ *(unsigned int *)data = vcpu->arch.gprs[rd];
+ break;
+ case stxd_op:
+ run->mmio.len = 8;
+ *(unsigned long *)data = vcpu->arch.gprs[rd];
+ break;
+ default:
+ ret = EMULATE_FAIL;
+ break;
+ }
+ } else
+ ret = EMULATE_FAIL;
+
+ if (ret == EMULATE_DO_MMIO) {
+ run->mmio.is_write = 1;
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_is_write = 1;
+ } else {
+ vcpu->arch.pc = curr_pc;
+ kvm_err("Write not supporded inst=0x%08x @%lx BadVaddr:%#lx\n",
+ inst.word, vcpu->arch.pc, vcpu->arch.badv);
+ kvm_arch_vcpu_dump_regs(vcpu);
+ /* Rollback PC if emulation was unsuccessful */
+ }
+
+ return ret;
+}
+
+int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst)
+{
+ unsigned int op8, opcode, rd;
+ struct kvm_run *run = vcpu->run;
+ int ret;
+
+ run->mmio.phys_addr = vcpu->arch.badv;
+ vcpu->mmio_needed = 2; /* signed */
+ op8 = (inst.word >> 24) & 0xff;
+ ret = EMULATE_DO_MMIO;
+
+ if (op8 < 0x28) {
+ /* ldptr.w/d process */
+ rd = inst.reg2i14_format.rd;
+ opcode = inst.reg2i14_format.opcode;
+
+ switch (opcode) {
+ case ldptrd_op:
+ run->mmio.len = 8;
+ break;
+ case ldptrw_op:
+ run->mmio.len = 4;
+ break;
+ default:
+ break;
+ }
+ } else if (op8 < 0x2f) {
+ /* ld.b/h/w/d, ld.bu/hu/wu process */
+ rd = inst.reg2i12_format.rd;
+ opcode = inst.reg2i12_format.opcode;
+
+ switch (opcode) {
+ case ldd_op:
+ run->mmio.len = 8;
+ break;
+ case ldwu_op:
+ vcpu->mmio_needed = 1; /* unsigned */
+ run->mmio.len = 4;
+ break;
+ case ldw_op:
+ run->mmio.len = 4;
+ break;
+ case ldhu_op:
+ vcpu->mmio_needed = 1; /* unsigned */
+ run->mmio.len = 2;
+ break;
+ case ldh_op:
+ run->mmio.len = 2;
+ break;
+ case ldbu_op:
+ vcpu->mmio_needed = 1; /* unsigned */
+ run->mmio.len = 1;
+ break;
+ case ldb_op:
+ run->mmio.len = 1;
+ break;
+ default:
+ ret = EMULATE_FAIL;
+ break;
+ }
+ } else if (op8 == 0x38) {
+ /* ldxb/h/w/d, ldxb/h/wu, ldgtb/h/w/d, ldleb/h/w/d process */
+ rd = inst.reg3_format.rd;
+ opcode = inst.reg3_format.opcode;
+
+ switch (opcode) {
+ case ldxb_op:
+ run->mmio.len = 1;
+ break;
+ case ldxbu_op:
+ run->mmio.len = 1;
+ vcpu->mmio_needed = 1; /* unsigned */
+ break;
+ case ldxh_op:
+ run->mmio.len = 2;
+ break;
+ case ldxhu_op:
+ run->mmio.len = 2;
+ vcpu->mmio_needed = 1; /* unsigned */
+ break;
+ case ldxw_op:
+ run->mmio.len = 4;
+ break;
+ case ldxwu_op:
+ run->mmio.len = 4;
+ vcpu->mmio_needed = 1; /* unsigned */
+ break;
+ case ldxd_op:
+ run->mmio.len = 8;
+ break;
+ default:
+ ret = EMULATE_FAIL;
+ break;
+ }
+ } else
+ ret = EMULATE_FAIL;
+
+ if (ret == EMULATE_DO_MMIO) {
+ /* Set for kvm_complete_mmio_read use */
+ vcpu->arch.io_gpr = rd;
+ run->mmio.is_write = 0;
+ vcpu->mmio_is_write = 0;
+ } else {
+ kvm_err("Load not supporded inst=0x%08x @%lx BadVaddr:%#lx\n",
+ inst.word, vcpu->arch.pc, vcpu->arch.badv);
+ kvm_arch_vcpu_dump_regs(vcpu);
+ vcpu->mmio_needed = 0;
+ }
+ return ret;
+}
+
+int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ unsigned long *gpr = &vcpu->arch.gprs[vcpu->arch.io_gpr];
+ enum emulation_result er = EMULATE_DONE;
+
+ /* update with new PC */
+ update_pc(&vcpu->arch);
+ switch (run->mmio.len) {
+ case 8:
+ *gpr = *(s64 *)run->mmio.data;
+ break;
+ case 4:
+ if (vcpu->mmio_needed == 2)
+ *gpr = *(int *)run->mmio.data;
+ else
+ *gpr = *(unsigned int *)run->mmio.data;
+ break;
+ case 2:
+ if (vcpu->mmio_needed == 2)
+ *gpr = *(short *) run->mmio.data;
+ else
+ *gpr = *(unsigned short *)run->mmio.data;
+
+ break;
+ case 1:
+ if (vcpu->mmio_needed == 2)
+ *gpr = *(char *) run->mmio.data;
+ else
+ *gpr = *(unsigned char *) run->mmio.data;
+ break;
+ default:
+ kvm_err("Bad MMIO length: %d,addr is 0x%lx",
+ run->mmio.len, vcpu->arch.badv);
+ er = EMULATE_FAIL;
+ break;
+ }
+
+ return er;
+}
+
static int kvm_trap_handle_gspr(struct kvm_vcpu *vcpu)
{
enum emulation_result er = EMULATE_DONE;
@@ -331,3 +590,51 @@ static int kvm_handle_gspr(struct kvm_vcpu *vcpu)
}
return ret;
}
+
+static int kvm_handle_mmu_fault(struct kvm_vcpu *vcpu, bool write)
+{
+ struct kvm_run *run = vcpu->run;
+ unsigned long badv = vcpu->arch.badv;
+ larch_inst inst;
+ enum emulation_result er = EMULATE_DONE;
+ int ret;
+
+ ret = kvm_handle_mm_fault(vcpu, badv, write);
+ if (ret) {
+ /* Treat as MMIO */
+ inst.word = vcpu->arch.badi;
+ if (write) {
+ er = kvm_emu_mmio_write(vcpu, inst);
+ } else {
+ /* A code fetch fault doesn't count as an MMIO */
+ if (kvm_is_ifetch_fault(&vcpu->arch)) {
+ kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEF);
+ return RESUME_GUEST;
+ }
+
+ er = kvm_emu_mmio_read(vcpu, inst);
+ }
+ }
+
+ if (er == EMULATE_DONE) {
+ ret = RESUME_GUEST;
+ } else if (er == EMULATE_DO_MMIO) {
+ run->exit_reason = KVM_EXIT_MMIO;
+ ret = RESUME_HOST;
+ } else {
+ kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEM);
+ ret = RESUME_GUEST;
+ }
+
+ return ret;
+}
+
+static int kvm_handle_write_fault(struct kvm_vcpu *vcpu)
+{
+ return kvm_handle_mmu_fault(vcpu, true);
+}
+
+static int kvm_handle_read_fault(struct kvm_vcpu *vcpu)
+{
+ return kvm_handle_mmu_fault(vcpu, false);
+}
--
2.39.1

2023-09-15 02:04:07

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 29/29] LoongArch: KVM: Add maintainers for LoongArch KVM

Add maintainers for LoongArch KVM.

Acked-by: Huacai Chen <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
MAINTAINERS | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 79630b7d94..2f99e033d8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11523,6 +11523,18 @@ F: include/kvm/arm_*
F: tools/testing/selftests/kvm/*/aarch64/
F: tools/testing/selftests/kvm/aarch64/

+KERNEL VIRTUAL MACHINE FOR LOONGARCH (KVM/LoongArch)
+M: Tianrui Zhao <[email protected]>
+M: Bibo Mao <[email protected]>
+M: Huacai Chen <[email protected]>
+L: [email protected]
+L: [email protected]
+S: Maintained
+T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
+F: arch/loongarch/include/asm/kvm*
+F: arch/loongarch/include/uapi/asm/kvm*
+F: arch/loongarch/kvm/
+
KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
M: Huacai Chen <[email protected]>
L: [email protected]
--
2.39.1

2023-09-15 04:12:45

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support

Hi, Tianrui,

On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>
> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
> assisted virtualization. With cpu virtualization, there are separate
> hw-supported user mode and kernel mode in guest mode. With memory
> virtualization, there are two-level hw mmu table for guest mode and host
> mode. Also there is separate hw cpu timer with consant frequency in
> guest mode, so that vm can migrate between hosts with different freq.
> Currently, we are able to boot LoongArch Linux Guests.
>
> Few key aspects of KVM LoongArch added by this series are:
> 1. Enable kvm hardware function when kvm module is loaded.
> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
> get general registers one by one.
> 3. Hardware access about MMU, timer and csr are emulated in kernel.
> 4. Hardwares such as mmio and iocsr device are emulated in user space
> such as APIC, IPI, pci devices etc.
>
> The running environment of LoongArch virt machine:
> 1. Cross tools for building kernel and uefi:
> https://github.com/loongson/build-tools
> 2. This series is based on the linux source code:
> https://github.com/loongson/linux-loongarch-kvm
> Build command:
> git checkout kvm-loongarch
> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
> 3. QEMU hypervisor with LoongArch supported:
> https://github.com/loongson/qemu
> Build command:
> git checkout kvm-loongarch
> ./configure --target-list="loongarch64-softmmu" --enable-kvm
> make
When I build qemu, I get:
[3/964] Compiling C object
libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
-I../target/loongarch -Isubprojects/dtc/libfdt
-I../subprojects/dtc/libfdt -Iqapi -Itrace c
In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
351 | uint64_t CSR_CPUID;
| ^~~~~~~~~
ninja: build stopped: subcommand failed.
make[1]: *** [Makefile:162: run-ninja] Error 1
make[1]: Leaving directory '/root/qemu/build'
make: *** [GNUmakefile:11: all] Error 2

Huacai

> 4. Uefi bios of LoongArch virt machine:
> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
> 5. you can also access the binary files we have already build:
> https://github.com/yangxiaojuan-loongson/qemu-binary
> The command to boot loongarch virt machine:
> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
> -serial stdio -monitor telnet:localhost:4495,server,nowait \
> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
> --nographic
>
> Changes for v21:
> 1. Remove unnecessary prefix '_' in some kvm function names.
> 2. Replace check_vmid with check_vpid, and move the functions
> to main.c.
> 3. Re-order the file names and config names by alphabetical
> in KVM makefile and Kconfig.
> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
> ioctl functions.
>
> changes for v20:
> 1. Remove the binary code of virtualization instructions in
> insn_def.h and csr_ops.S and directly use the default csrrd,
> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
> already supported them to compile the KVM. This can make our
> LoongArch KVM codes more maintainable and easier.
>
> changes for v19:
> 1. Use the common interface xfer_to_guest_mode_handle_work to
> Check conditions before entering the guest.
> 2. Add vcpu dirty ring support.
>
> changes for v18:
> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
> the stable_ktime_saved variable to expire.
> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
>
> changes for v17:
> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
> binutils that support LVZ assemble instruction.
> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
> handling.
> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
> when injecting IRQ.
> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
> kvm_arch.online_vcpus and kvm_arch.is_migrating,
> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
> since NR/NX bit is not set in kvm page fault handling.
>
> Changes for v16:
> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
> exit to avoid memory leak problem.
> 2. Simplify some assemble codes in switch.S which are necessary to be
> replaced with pseudo-instructions. And any other instructions do not need
> to be replaced anymore.
> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
> guest regs instructions when vcpu world switch.
> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
>
> Changes for v15:
> 1. Re-order some macros and variables in LoongArch kvm headers, put them
> together which have the same meaning.
> 2. Make some function definitions in one line, as it is not needed to split
> them.
> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
>
> Changes for v14:
> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
> loongarch/kvm/main.c, as it is not useful.
> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
> as it is used by virt/kvm.
> 3. Fix the LoongArch KVM source link in MAINTAINERS.
> 4. Improve LoongArch KVM documentation, such as add comment for
> LoongArch kvm_regs.
>
> Changes for v13:
> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
> remove the previous cpu_probe_lvz function.
> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
> FPU cap is enable by default, and do not support any other caps now.
> 3. Simplify the jirl instruction with jr when without return addr,
> simplify case HW0 ... HW7 statment in interrupt.c
> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
> cpu number by itself.
>
> Changes for v12:
> 1. Improve the gcsr write/read/xchg interface to avoid the previous
> instruction statment like parse_r and make the code easy understanding,
> they are implemented in asm/insn-def.h and the instructions consistent
> of "opcode" "rj" "rd" "simm14" arguments.
> 2. Fix the maintainers list of LoongArch KVM.
>
> Changes for v11:
> 1. Add maintainers for LoongArch KVM.
>
> Changes for v10:
> 1. Fix grammatical problems in LoongArch documentation.
> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
> vcpu put and vcpu load, so we remove it.
>
> Changes for v9:
> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
> previous unused macros.
> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
> to make them more standard.
>
> Changes for v8:
> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
> it, and remove the previous guest.ases. We do this to keep consistent
> with host cpu_data.options structure.
> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
> the asm/kvm_host.h.
> 3. Fix some unstandard spelling and grammar errors in comments, and
> improve a little code format to make it easier and standard.
>
> Changes for v7:
> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
> kernel test robot. The report link is:
> https://lore.kernel.org/oe-kbuild-all/[email protected]/
> 2. Fix loongarch kvm trace related compiling problems.
>
> Changes for v6:
> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
> loongarch parts.
>
> Changes for v5:
> 1. Implement get/set mp_state ioctl interface, and only the
> KVM_MP_STATE_RUNNABLE state is supported now, and other states
> will be completed in the future. The state is also used when vcpu
> run idle instruction, if vcpu state is changed to RUNNABLE, the
> vcpu will have the possibility to be woken up.
> 2. Supplement kvm document about loongarch-specific part, such as add
> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
> etc.
> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
>
> Changes for v4:
> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
> unchanged during process context switch, so we need not to update it
> every time. We can do this only if the soft csr is different form hardware.
> That is to say all of csrs should update after vcpu enter guest, as for
> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
> SW, we use software to emulate it, and others return false.
> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
> We have splited hw gcsr into three parts, so we can calculate the code offset
> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
> 4. Improve kvm mmu functions, such as flush page table and make clean page table
> interface.
>
> Changes for v3:
> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
> because a vpid will never be recycled if a vCPU migrates from physical CPU A
> to B and back to A.
> 2. Make some constant variables in kvm_context to global such as vpid_mask,
> guest_eentry, enter_guest, etc.
> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
> kvm_trace_gspr, etc.
> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
> so we move it to a new function kvm_pre_enter_guest.
> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
> and "<= 0" for resume host.
> 6. Fcsr and fpu registers are saved/restored together.
>
> Changes for v2:
> 1. Seprate the original patch-01 and patch-03 into small patches, and the
> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
> etc.
> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
> and we use the common KVM_{GET,SET}_ONE_REG to access register.
> 3. Use BIT(x) to replace the "1 << n_bits" statement.
>
> Tianrui Zhao (29):
> LoongArch: KVM: Add kvm related header files
> LoongArch: KVM: Implement kvm module related interface
> LoongArch: KVM: Implement kvm hardware enable, disable interface
> LoongArch: KVM: Implement VM related functions
> LoongArch: KVM: Add vcpu related header files
> LoongArch: KVM: Implement vcpu create and destroy interface
> LoongArch: KVM: Implement vcpu run interface
> LoongArch: KVM: Implement vcpu handle exit interface
> LoongArch: KVM: Implement vcpu get, vcpu set registers
> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
> LoongArch: KVM: Implement fpu related operations for vcpu
> LoongArch: KVM: Implement vcpu interrupt operations
> LoongArch: KVM: Implement misc vcpu related interfaces
> LoongArch: KVM: Implement vcpu load and vcpu put operations
> LoongArch: KVM: Implement vcpu status description
> LoongArch: KVM: Implement virtual machine tlb operations
> LoongArch: KVM: Implement vcpu timer operations
> LoongArch: KVM: Implement kvm mmu operations
> LoongArch: KVM: Implement handle csr exception
> LoongArch: KVM: Implement handle iocsr exception
> LoongArch: KVM: Implement handle idle exception
> LoongArch: KVM: Implement handle gspr exception
> LoongArch: KVM: Implement handle mmio exception
> LoongArch: KVM: Implement handle fpu exception
> LoongArch: KVM: Implement kvm exception vector
> LoongArch: KVM: Implement vcpu world switch
> LoongArch: KVM: Enable kvm config and add the makefile
> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
> LoongArch: KVM: Add maintainers for LoongArch KVM
>
> Documentation/virt/kvm/api.rst | 70 +-
> MAINTAINERS | 12 +
> arch/loongarch/Kbuild | 1 +
> arch/loongarch/Kconfig | 3 +
> arch/loongarch/configs/loongson3_defconfig | 2 +
> arch/loongarch/include/asm/inst.h | 16 +
> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
> arch/loongarch/include/asm/kvm_types.h | 11 +
> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
> arch/loongarch/include/asm/loongarch.h | 19 +-
> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
> arch/loongarch/kernel/asm-offsets.c | 32 +
> arch/loongarch/kvm/Kconfig | 45 +
> arch/loongarch/kvm/Makefile | 20 +
> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
> arch/loongarch/kvm/interrupt.c | 185 ++++
> arch/loongarch/kvm/main.c | 429 ++++++++++
> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
> arch/loongarch/kvm/switch.S | 255 ++++++
> arch/loongarch/kvm/timer.c | 200 +++++
> arch/loongarch/kvm/tlb.c | 34 +
> arch/loongarch/kvm/trace.h | 166 ++++
> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
> arch/loongarch/kvm/vm.c | 92 ++
> include/uapi/linux/kvm.h | 9 +
> 27 files changed, 4979 insertions(+), 14 deletions(-)
> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> create mode 100644 arch/loongarch/kvm/Kconfig
> create mode 100644 arch/loongarch/kvm/Makefile
> create mode 100644 arch/loongarch/kvm/exit.c
> create mode 100644 arch/loongarch/kvm/interrupt.c
> create mode 100644 arch/loongarch/kvm/main.c
> create mode 100644 arch/loongarch/kvm/mmu.c
> create mode 100644 arch/loongarch/kvm/switch.S
> create mode 100644 arch/loongarch/kvm/timer.c
> create mode 100644 arch/loongarch/kvm/tlb.c
> create mode 100644 arch/loongarch/kvm/trace.h
> create mode 100644 arch/loongarch/kvm/vcpu.c
> create mode 100644 arch/loongarch/kvm/vm.c
>
> --
> 2.39.1
>

2023-09-15 05:56:39

by zhaotianrui

[permalink] [raw]
Subject: [PATCH v21 08/29] LoongArch: KVM: Implement vcpu handle exit interface

Implement vcpu handle exit interface, getting the exit code by ESTAT
register and using kvm exception vector to handle it.

Reviewed-by: Bibo Mao <[email protected]>
Signed-off-by: Tianrui Zhao <[email protected]>
---
arch/loongarch/kvm/vcpu.c | 41 +++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)

diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index a510082e9b..bfc2ec1a88 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -104,6 +104,47 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
return ret;
}

+/*
+ * Return 1 for resume guest and "<= 0" for resume host.
+ */
+static int kvm_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
+{
+ unsigned long exst = vcpu->arch.host_estat;
+ u32 intr = exst & 0x1fff; /* ignore NMI */
+ u32 exccode = (exst & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
+ int ret = RESUME_GUEST;
+
+ vcpu->mode = OUTSIDE_GUEST_MODE;
+
+ /* Set a default exit reason */
+ run->exit_reason = KVM_EXIT_UNKNOWN;
+
+ guest_timing_exit_irqoff();
+ guest_state_exit_irqoff();
+ local_irq_enable();
+
+ trace_kvm_exit(vcpu, exccode);
+ if (exccode) {
+ ret = kvm_handle_fault(vcpu, exccode);
+ } else {
+ WARN(!intr, "vm exiting with suspicious irq\n");
+ ++vcpu->stat.int_exits;
+ }
+
+ if (ret == RESUME_GUEST)
+ ret = kvm_pre_enter_guest(vcpu);
+
+ if (ret != RESUME_GUEST) {
+ local_irq_disable();
+ return ret;
+ }
+
+ guest_timing_enter_irqoff();
+ guest_state_enter_irqoff();
+ trace_kvm_reenter(vcpu);
+ return RESUME_GUEST;
+}
+
int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
{
unsigned long timer_hz;
--
2.39.1

2023-09-15 06:59:40

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support


在 2023/9/15 下午12:11, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
>> assisted virtualization. With cpu virtualization, there are separate
>> hw-supported user mode and kernel mode in guest mode. With memory
>> virtualization, there are two-level hw mmu table for guest mode and host
>> mode. Also there is separate hw cpu timer with consant frequency in
>> guest mode, so that vm can migrate between hosts with different freq.
>> Currently, we are able to boot LoongArch Linux Guests.
>>
>> Few key aspects of KVM LoongArch added by this series are:
>> 1. Enable kvm hardware function when kvm module is loaded.
>> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
>> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
>> get general registers one by one.
>> 3. Hardware access about MMU, timer and csr are emulated in kernel.
>> 4. Hardwares such as mmio and iocsr device are emulated in user space
>> such as APIC, IPI, pci devices etc.
>>
>> The running environment of LoongArch virt machine:
>> 1. Cross tools for building kernel and uefi:
>> https://github.com/loongson/build-tools
>> 2. This series is based on the linux source code:
>> https://github.com/loongson/linux-loongarch-kvm
>> Build command:
>> git checkout kvm-loongarch
>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
>> 3. QEMU hypervisor with LoongArch supported:
>> https://github.com/loongson/qemu
>> Build command:
>> git checkout kvm-loongarch
>> ./configure --target-list="loongarch64-softmmu" --enable-kvm
>> make
> When I build qemu, I get:
> [3/964] Compiling C object
> libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
> -I../target/loongarch -Isubprojects/dtc/libfdt
> -I../subprojects/dtc/libfdt -Iqapi -Itrace c
> In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
> ../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
> 351 | uint64_t CSR_CPUID;
> | ^~~~~~~~~
> ninja: build stopped: subcommand failed.
> make[1]: *** [Makefile:162: run-ninja] Error 1
> make[1]: Leaving directory '/root/qemu/build'
> make: *** [GNUmakefile:11: all] Error 2
>
> Huacai
Sorry, I have submitted patch to fix this error, you could git pull to
update it.

Thanks
Tianrui Zhao
>
>> 4. Uefi bios of LoongArch virt machine:
>> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
>> 5. you can also access the binary files we have already build:
>> https://github.com/yangxiaojuan-loongson/qemu-binary
>> The command to boot loongarch virt machine:
>> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
>> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
>> -serial stdio -monitor telnet:localhost:4495,server,nowait \
>> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
>> --nographic
>>
>> Changes for v21:
>> 1. Remove unnecessary prefix '_' in some kvm function names.
>> 2. Replace check_vmid with check_vpid, and move the functions
>> to main.c.
>> 3. Re-order the file names and config names by alphabetical
>> in KVM makefile and Kconfig.
>> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
>> ioctl functions.
>>
>> changes for v20:
>> 1. Remove the binary code of virtualization instructions in
>> insn_def.h and csr_ops.S and directly use the default csrrd,
>> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
>> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
>> already supported them to compile the KVM. This can make our
>> LoongArch KVM codes more maintainable and easier.
>>
>> changes for v19:
>> 1. Use the common interface xfer_to_guest_mode_handle_work to
>> Check conditions before entering the guest.
>> 2. Add vcpu dirty ring support.
>>
>> changes for v18:
>> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
>> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
>> the stable_ktime_saved variable to expire.
>> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
>>
>> changes for v17:
>> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
>> binutils that support LVZ assemble instruction.
>> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
>> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
>> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
>> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
>> handling.
>> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
>> when injecting IRQ.
>> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
>> kvm_arch.online_vcpus and kvm_arch.is_migrating,
>> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
>> since NR/NX bit is not set in kvm page fault handling.
>>
>> Changes for v16:
>> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
>> exit to avoid memory leak problem.
>> 2. Simplify some assemble codes in switch.S which are necessary to be
>> replaced with pseudo-instructions. And any other instructions do not need
>> to be replaced anymore.
>> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
>> guest regs instructions when vcpu world switch.
>> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
>> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
>>
>> Changes for v15:
>> 1. Re-order some macros and variables in LoongArch kvm headers, put them
>> together which have the same meaning.
>> 2. Make some function definitions in one line, as it is not needed to split
>> them.
>> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
>>
>> Changes for v14:
>> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
>> loongarch/kvm/main.c, as it is not useful.
>> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
>> as it is used by virt/kvm.
>> 3. Fix the LoongArch KVM source link in MAINTAINERS.
>> 4. Improve LoongArch KVM documentation, such as add comment for
>> LoongArch kvm_regs.
>>
>> Changes for v13:
>> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
>> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
>> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
>> remove the previous cpu_probe_lvz function.
>> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
>> FPU cap is enable by default, and do not support any other caps now.
>> 3. Simplify the jirl instruction with jr when without return addr,
>> simplify case HW0 ... HW7 statment in interrupt.c
>> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
>> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
>> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
>> cpu number by itself.
>>
>> Changes for v12:
>> 1. Improve the gcsr write/read/xchg interface to avoid the previous
>> instruction statment like parse_r and make the code easy understanding,
>> they are implemented in asm/insn-def.h and the instructions consistent
>> of "opcode" "rj" "rd" "simm14" arguments.
>> 2. Fix the maintainers list of LoongArch KVM.
>>
>> Changes for v11:
>> 1. Add maintainers for LoongArch KVM.
>>
>> Changes for v10:
>> 1. Fix grammatical problems in LoongArch documentation.
>> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
>> vcpu put and vcpu load, so we remove it.
>>
>> Changes for v9:
>> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
>> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
>> previous unused macros.
>> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
>> to make them more standard.
>>
>> Changes for v8:
>> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
>> it, and remove the previous guest.ases. We do this to keep consistent
>> with host cpu_data.options structure.
>> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
>> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
>> the asm/kvm_host.h.
>> 3. Fix some unstandard spelling and grammar errors in comments, and
>> improve a little code format to make it easier and standard.
>>
>> Changes for v7:
>> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
>> kernel test robot. The report link is:
>> https://lore.kernel.org/oe-kbuild-all/[email protected]/
>> 2. Fix loongarch kvm trace related compiling problems.
>>
>> Changes for v6:
>> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
>> loongarch parts.
>>
>> Changes for v5:
>> 1. Implement get/set mp_state ioctl interface, and only the
>> KVM_MP_STATE_RUNNABLE state is supported now, and other states
>> will be completed in the future. The state is also used when vcpu
>> run idle instruction, if vcpu state is changed to RUNNABLE, the
>> vcpu will have the possibility to be woken up.
>> 2. Supplement kvm document about loongarch-specific part, such as add
>> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
>> etc.
>> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
>> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
>>
>> Changes for v4:
>> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
>> unchanged during process context switch, so we need not to update it
>> every time. We can do this only if the soft csr is different form hardware.
>> That is to say all of csrs should update after vcpu enter guest, as for
>> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
>> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
>> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
>> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
>> SW, we use software to emulate it, and others return false.
>> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
>> We have splited hw gcsr into three parts, so we can calculate the code offset
>> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
>> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
>> 4. Improve kvm mmu functions, such as flush page table and make clean page table
>> interface.
>>
>> Changes for v3:
>> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
>> because a vpid will never be recycled if a vCPU migrates from physical CPU A
>> to B and back to A.
>> 2. Make some constant variables in kvm_context to global such as vpid_mask,
>> guest_eentry, enter_guest, etc.
>> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
>> kvm_trace_gspr, etc.
>> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
>> so we move it to a new function kvm_pre_enter_guest.
>> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
>> and "<= 0" for resume host.
>> 6. Fcsr and fpu registers are saved/restored together.
>>
>> Changes for v2:
>> 1. Seprate the original patch-01 and patch-03 into small patches, and the
>> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
>> etc.
>> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
>> and we use the common KVM_{GET,SET}_ONE_REG to access register.
>> 3. Use BIT(x) to replace the "1 << n_bits" statement.
>>
>> Tianrui Zhao (29):
>> LoongArch: KVM: Add kvm related header files
>> LoongArch: KVM: Implement kvm module related interface
>> LoongArch: KVM: Implement kvm hardware enable, disable interface
>> LoongArch: KVM: Implement VM related functions
>> LoongArch: KVM: Add vcpu related header files
>> LoongArch: KVM: Implement vcpu create and destroy interface
>> LoongArch: KVM: Implement vcpu run interface
>> LoongArch: KVM: Implement vcpu handle exit interface
>> LoongArch: KVM: Implement vcpu get, vcpu set registers
>> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
>> LoongArch: KVM: Implement fpu related operations for vcpu
>> LoongArch: KVM: Implement vcpu interrupt operations
>> LoongArch: KVM: Implement misc vcpu related interfaces
>> LoongArch: KVM: Implement vcpu load and vcpu put operations
>> LoongArch: KVM: Implement vcpu status description
>> LoongArch: KVM: Implement virtual machine tlb operations
>> LoongArch: KVM: Implement vcpu timer operations
>> LoongArch: KVM: Implement kvm mmu operations
>> LoongArch: KVM: Implement handle csr exception
>> LoongArch: KVM: Implement handle iocsr exception
>> LoongArch: KVM: Implement handle idle exception
>> LoongArch: KVM: Implement handle gspr exception
>> LoongArch: KVM: Implement handle mmio exception
>> LoongArch: KVM: Implement handle fpu exception
>> LoongArch: KVM: Implement kvm exception vector
>> LoongArch: KVM: Implement vcpu world switch
>> LoongArch: KVM: Enable kvm config and add the makefile
>> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
>> LoongArch: KVM: Add maintainers for LoongArch KVM
>>
>> Documentation/virt/kvm/api.rst | 70 +-
>> MAINTAINERS | 12 +
>> arch/loongarch/Kbuild | 1 +
>> arch/loongarch/Kconfig | 3 +
>> arch/loongarch/configs/loongson3_defconfig | 2 +
>> arch/loongarch/include/asm/inst.h | 16 +
>> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
>> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
>> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
>> arch/loongarch/include/asm/kvm_types.h | 11 +
>> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
>> arch/loongarch/include/asm/loongarch.h | 19 +-
>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
>> arch/loongarch/kernel/asm-offsets.c | 32 +
>> arch/loongarch/kvm/Kconfig | 45 +
>> arch/loongarch/kvm/Makefile | 20 +
>> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
>> arch/loongarch/kvm/interrupt.c | 185 ++++
>> arch/loongarch/kvm/main.c | 429 ++++++++++
>> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
>> arch/loongarch/kvm/switch.S | 255 ++++++
>> arch/loongarch/kvm/timer.c | 200 +++++
>> arch/loongarch/kvm/tlb.c | 34 +
>> arch/loongarch/kvm/trace.h | 166 ++++
>> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
>> arch/loongarch/kvm/vm.c | 92 ++
>> include/uapi/linux/kvm.h | 9 +
>> 27 files changed, 4979 insertions(+), 14 deletions(-)
>> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>> create mode 100644 arch/loongarch/kvm/Kconfig
>> create mode 100644 arch/loongarch/kvm/Makefile
>> create mode 100644 arch/loongarch/kvm/exit.c
>> create mode 100644 arch/loongarch/kvm/interrupt.c
>> create mode 100644 arch/loongarch/kvm/main.c
>> create mode 100644 arch/loongarch/kvm/mmu.c
>> create mode 100644 arch/loongarch/kvm/switch.S
>> create mode 100644 arch/loongarch/kvm/timer.c
>> create mode 100644 arch/loongarch/kvm/tlb.c
>> create mode 100644 arch/loongarch/kvm/trace.h
>> create mode 100644 arch/loongarch/kvm/vcpu.c
>> create mode 100644 arch/loongarch/kvm/vm.c
>>
>> --
>> 2.39.1
>>

2023-09-15 07:14:42

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support

Hi, Tianrui,

On Fri, Sep 15, 2023 at 2:58 PM zhaotianrui <[email protected]> wrote:
>
>
> 在 2023/9/15 下午12:11, Huacai Chen 写道:
> > Hi, Tianrui,
> >
> > On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
> >> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
> >> assisted virtualization. With cpu virtualization, there are separate
> >> hw-supported user mode and kernel mode in guest mode. With memory
> >> virtualization, there are two-level hw mmu table for guest mode and host
> >> mode. Also there is separate hw cpu timer with consant frequency in
> >> guest mode, so that vm can migrate between hosts with different freq.
> >> Currently, we are able to boot LoongArch Linux Guests.
> >>
> >> Few key aspects of KVM LoongArch added by this series are:
> >> 1. Enable kvm hardware function when kvm module is loaded.
> >> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
> >> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
> >> get general registers one by one.
> >> 3. Hardware access about MMU, timer and csr are emulated in kernel.
> >> 4. Hardwares such as mmio and iocsr device are emulated in user space
> >> such as APIC, IPI, pci devices etc.
> >>
> >> The running environment of LoongArch virt machine:
> >> 1. Cross tools for building kernel and uefi:
> >> https://github.com/loongson/build-tools
> >> 2. This series is based on the linux source code:
> >> https://github.com/loongson/linux-loongarch-kvm
> >> Build command:
> >> git checkout kvm-loongarch
> >> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
> >> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
> >> 3. QEMU hypervisor with LoongArch supported:
> >> https://github.com/loongson/qemu
> >> Build command:
> >> git checkout kvm-loongarch
> >> ./configure --target-list="loongarch64-softmmu" --enable-kvm
> >> make
> > When I build qemu, I get:
> > [3/964] Compiling C object
> > libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> > FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> > cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
> > -I../target/loongarch -Isubprojects/dtc/libfdt
> > -I../subprojects/dtc/libfdt -Iqapi -Itrace c
> > In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
> > ../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
> > 351 | uint64_t CSR_CPUID;
> > | ^~~~~~~~~
> > ninja: build stopped: subcommand failed.
> > make[1]: *** [Makefile:162: run-ninja] Error 1
> > make[1]: Leaving directory '/root/qemu/build'
> > make: *** [GNUmakefile:11: all] Error 2
> >
> > Huacai
> Sorry, I have submitted patch to fix this error, you could git pull to
> update it.
After git pull, I get a new error:
[70/912] Compiling C object
libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-icount.c.o
[71/912] Compiling C object
libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-rr.c.o
[72/912] Linking target qemu-system-loongarch64
FAILED: qemu-system-loongarch64
cc -o qemu-system-loongarch64 libcommon.fa.p/hw_core_cpu-common.c.o
libcommon.fa.p/hw_core_machine-smp.c.o
libcommon.fa.p/gdbstub_syscalls.c.o libcommon.fap
/usr/bin/ld: libqemu-loongarch64-softmmu.fa.p/accel_kvm_kvm-all.c.o:
in function `kvm_init':
/root/qemu/build/../accel/kvm/kvm-all.c:2525:(.text+0x66f4): undefined
reference to `kvm_arch_get_default_type'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
make[1]: *** [Makefile:162: run-ninja] Error 1
make[1]: Leaving directory '/root/qemu/build'
make: *** [GNUmakefile:11: all] Error 2

Huacai

>
> Thanks
> Tianrui Zhao
> >
> >> 4. Uefi bios of LoongArch virt machine:
> >> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
> >> 5. you can also access the binary files we have already build:
> >> https://github.com/yangxiaojuan-loongson/qemu-binary
> >> The command to boot loongarch virt machine:
> >> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
> >> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
> >> -serial stdio -monitor telnet:localhost:4495,server,nowait \
> >> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
> >> --nographic
> >>
> >> Changes for v21:
> >> 1. Remove unnecessary prefix '_' in some kvm function names.
> >> 2. Replace check_vmid with check_vpid, and move the functions
> >> to main.c.
> >> 3. Re-order the file names and config names by alphabetical
> >> in KVM makefile and Kconfig.
> >> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
> >> ioctl functions.
> >>
> >> changes for v20:
> >> 1. Remove the binary code of virtualization instructions in
> >> insn_def.h and csr_ops.S and directly use the default csrrd,
> >> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
> >> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
> >> already supported them to compile the KVM. This can make our
> >> LoongArch KVM codes more maintainable and easier.
> >>
> >> changes for v19:
> >> 1. Use the common interface xfer_to_guest_mode_handle_work to
> >> Check conditions before entering the guest.
> >> 2. Add vcpu dirty ring support.
> >>
> >> changes for v18:
> >> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
> >> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
> >> the stable_ktime_saved variable to expire.
> >> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
> >>
> >> changes for v17:
> >> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
> >> binutils that support LVZ assemble instruction.
> >> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
> >> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
> >> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
> >> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
> >> handling.
> >> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
> >> when injecting IRQ.
> >> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
> >> kvm_arch.online_vcpus and kvm_arch.is_migrating,
> >> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
> >> since NR/NX bit is not set in kvm page fault handling.
> >>
> >> Changes for v16:
> >> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
> >> exit to avoid memory leak problem.
> >> 2. Simplify some assemble codes in switch.S which are necessary to be
> >> replaced with pseudo-instructions. And any other instructions do not need
> >> to be replaced anymore.
> >> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
> >> guest regs instructions when vcpu world switch.
> >> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
> >> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
> >>
> >> Changes for v15:
> >> 1. Re-order some macros and variables in LoongArch kvm headers, put them
> >> together which have the same meaning.
> >> 2. Make some function definitions in one line, as it is not needed to split
> >> them.
> >> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
> >>
> >> Changes for v14:
> >> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
> >> loongarch/kvm/main.c, as it is not useful.
> >> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
> >> as it is used by virt/kvm.
> >> 3. Fix the LoongArch KVM source link in MAINTAINERS.
> >> 4. Improve LoongArch KVM documentation, such as add comment for
> >> LoongArch kvm_regs.
> >>
> >> Changes for v13:
> >> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
> >> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
> >> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
> >> remove the previous cpu_probe_lvz function.
> >> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
> >> FPU cap is enable by default, and do not support any other caps now.
> >> 3. Simplify the jirl instruction with jr when without return addr,
> >> simplify case HW0 ... HW7 statment in interrupt.c
> >> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
> >> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
> >> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
> >> cpu number by itself.
> >>
> >> Changes for v12:
> >> 1. Improve the gcsr write/read/xchg interface to avoid the previous
> >> instruction statment like parse_r and make the code easy understanding,
> >> they are implemented in asm/insn-def.h and the instructions consistent
> >> of "opcode" "rj" "rd" "simm14" arguments.
> >> 2. Fix the maintainers list of LoongArch KVM.
> >>
> >> Changes for v11:
> >> 1. Add maintainers for LoongArch KVM.
> >>
> >> Changes for v10:
> >> 1. Fix grammatical problems in LoongArch documentation.
> >> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
> >> vcpu put and vcpu load, so we remove it.
> >>
> >> Changes for v9:
> >> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
> >> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
> >> previous unused macros.
> >> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
> >> to make them more standard.
> >>
> >> Changes for v8:
> >> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
> >> it, and remove the previous guest.ases. We do this to keep consistent
> >> with host cpu_data.options structure.
> >> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
> >> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
> >> the asm/kvm_host.h.
> >> 3. Fix some unstandard spelling and grammar errors in comments, and
> >> improve a little code format to make it easier and standard.
> >>
> >> Changes for v7:
> >> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
> >> kernel test robot. The report link is:
> >> https://lore.kernel.org/oe-kbuild-all/[email protected]/
> >> 2. Fix loongarch kvm trace related compiling problems.
> >>
> >> Changes for v6:
> >> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
> >> loongarch parts.
> >>
> >> Changes for v5:
> >> 1. Implement get/set mp_state ioctl interface, and only the
> >> KVM_MP_STATE_RUNNABLE state is supported now, and other states
> >> will be completed in the future. The state is also used when vcpu
> >> run idle instruction, if vcpu state is changed to RUNNABLE, the
> >> vcpu will have the possibility to be woken up.
> >> 2. Supplement kvm document about loongarch-specific part, such as add
> >> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
> >> etc.
> >> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
> >> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
> >>
> >> Changes for v4:
> >> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
> >> unchanged during process context switch, so we need not to update it
> >> every time. We can do this only if the soft csr is different form hardware.
> >> That is to say all of csrs should update after vcpu enter guest, as for
> >> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
> >> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
> >> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
> >> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
> >> SW, we use software to emulate it, and others return false.
> >> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
> >> We have splited hw gcsr into three parts, so we can calculate the code offset
> >> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
> >> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
> >> 4. Improve kvm mmu functions, such as flush page table and make clean page table
> >> interface.
> >>
> >> Changes for v3:
> >> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
> >> because a vpid will never be recycled if a vCPU migrates from physical CPU A
> >> to B and back to A.
> >> 2. Make some constant variables in kvm_context to global such as vpid_mask,
> >> guest_eentry, enter_guest, etc.
> >> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
> >> kvm_trace_gspr, etc.
> >> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
> >> so we move it to a new function kvm_pre_enter_guest.
> >> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
> >> and "<= 0" for resume host.
> >> 6. Fcsr and fpu registers are saved/restored together.
> >>
> >> Changes for v2:
> >> 1. Seprate the original patch-01 and patch-03 into small patches, and the
> >> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
> >> etc.
> >> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
> >> and we use the common KVM_{GET,SET}_ONE_REG to access register.
> >> 3. Use BIT(x) to replace the "1 << n_bits" statement.
> >>
> >> Tianrui Zhao (29):
> >> LoongArch: KVM: Add kvm related header files
> >> LoongArch: KVM: Implement kvm module related interface
> >> LoongArch: KVM: Implement kvm hardware enable, disable interface
> >> LoongArch: KVM: Implement VM related functions
> >> LoongArch: KVM: Add vcpu related header files
> >> LoongArch: KVM: Implement vcpu create and destroy interface
> >> LoongArch: KVM: Implement vcpu run interface
> >> LoongArch: KVM: Implement vcpu handle exit interface
> >> LoongArch: KVM: Implement vcpu get, vcpu set registers
> >> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
> >> LoongArch: KVM: Implement fpu related operations for vcpu
> >> LoongArch: KVM: Implement vcpu interrupt operations
> >> LoongArch: KVM: Implement misc vcpu related interfaces
> >> LoongArch: KVM: Implement vcpu load and vcpu put operations
> >> LoongArch: KVM: Implement vcpu status description
> >> LoongArch: KVM: Implement virtual machine tlb operations
> >> LoongArch: KVM: Implement vcpu timer operations
> >> LoongArch: KVM: Implement kvm mmu operations
> >> LoongArch: KVM: Implement handle csr exception
> >> LoongArch: KVM: Implement handle iocsr exception
> >> LoongArch: KVM: Implement handle idle exception
> >> LoongArch: KVM: Implement handle gspr exception
> >> LoongArch: KVM: Implement handle mmio exception
> >> LoongArch: KVM: Implement handle fpu exception
> >> LoongArch: KVM: Implement kvm exception vector
> >> LoongArch: KVM: Implement vcpu world switch
> >> LoongArch: KVM: Enable kvm config and add the makefile
> >> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
> >> LoongArch: KVM: Add maintainers for LoongArch KVM
> >>
> >> Documentation/virt/kvm/api.rst | 70 +-
> >> MAINTAINERS | 12 +
> >> arch/loongarch/Kbuild | 1 +
> >> arch/loongarch/Kconfig | 3 +
> >> arch/loongarch/configs/loongson3_defconfig | 2 +
> >> arch/loongarch/include/asm/inst.h | 16 +
> >> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
> >> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
> >> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
> >> arch/loongarch/include/asm/kvm_types.h | 11 +
> >> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
> >> arch/loongarch/include/asm/loongarch.h | 19 +-
> >> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
> >> arch/loongarch/kernel/asm-offsets.c | 32 +
> >> arch/loongarch/kvm/Kconfig | 45 +
> >> arch/loongarch/kvm/Makefile | 20 +
> >> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
> >> arch/loongarch/kvm/interrupt.c | 185 ++++
> >> arch/loongarch/kvm/main.c | 429 ++++++++++
> >> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
> >> arch/loongarch/kvm/switch.S | 255 ++++++
> >> arch/loongarch/kvm/timer.c | 200 +++++
> >> arch/loongarch/kvm/tlb.c | 34 +
> >> arch/loongarch/kvm/trace.h | 166 ++++
> >> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
> >> arch/loongarch/kvm/vm.c | 92 ++
> >> include/uapi/linux/kvm.h | 9 +
> >> 27 files changed, 4979 insertions(+), 14 deletions(-)
> >> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
> >> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> >> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
> >> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> >> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
> >> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> >> create mode 100644 arch/loongarch/kvm/Kconfig
> >> create mode 100644 arch/loongarch/kvm/Makefile
> >> create mode 100644 arch/loongarch/kvm/exit.c
> >> create mode 100644 arch/loongarch/kvm/interrupt.c
> >> create mode 100644 arch/loongarch/kvm/main.c
> >> create mode 100644 arch/loongarch/kvm/mmu.c
> >> create mode 100644 arch/loongarch/kvm/switch.S
> >> create mode 100644 arch/loongarch/kvm/timer.c
> >> create mode 100644 arch/loongarch/kvm/tlb.c
> >> create mode 100644 arch/loongarch/kvm/trace.h
> >> create mode 100644 arch/loongarch/kvm/vcpu.c
> >> create mode 100644 arch/loongarch/kvm/vm.c
> >>
> >> --
> >> 2.39.1
> >>
>

2023-09-15 08:01:36

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support


在 2023/9/15 下午3:10, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Fri, Sep 15, 2023 at 2:58 PM zhaotianrui <[email protected]> wrote:
>>
>> 在 2023/9/15 下午12:11, Huacai Chen 写道:
>>> Hi, Tianrui,
>>>
>>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>>>> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
>>>> assisted virtualization. With cpu virtualization, there are separate
>>>> hw-supported user mode and kernel mode in guest mode. With memory
>>>> virtualization, there are two-level hw mmu table for guest mode and host
>>>> mode. Also there is separate hw cpu timer with consant frequency in
>>>> guest mode, so that vm can migrate between hosts with different freq.
>>>> Currently, we are able to boot LoongArch Linux Guests.
>>>>
>>>> Few key aspects of KVM LoongArch added by this series are:
>>>> 1. Enable kvm hardware function when kvm module is loaded.
>>>> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
>>>> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
>>>> get general registers one by one.
>>>> 3. Hardware access about MMU, timer and csr are emulated in kernel.
>>>> 4. Hardwares such as mmio and iocsr device are emulated in user space
>>>> such as APIC, IPI, pci devices etc.
>>>>
>>>> The running environment of LoongArch virt machine:
>>>> 1. Cross tools for building kernel and uefi:
>>>> https://github.com/loongson/build-tools
>>>> 2. This series is based on the linux source code:
>>>> https://github.com/loongson/linux-loongarch-kvm
>>>> Build command:
>>>> git checkout kvm-loongarch
>>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
>>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
>>>> 3. QEMU hypervisor with LoongArch supported:
>>>> https://github.com/loongson/qemu
>>>> Build command:
>>>> git checkout kvm-loongarch
>>>> ./configure --target-list="loongarch64-softmmu" --enable-kvm
>>>> make
>>> When I build qemu, I get:
>>> [3/964] Compiling C object
>>> libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
>>> FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
>>> cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
>>> -I../target/loongarch -Isubprojects/dtc/libfdt
>>> -I../subprojects/dtc/libfdt -Iqapi -Itrace c
>>> In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
>>> ../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
>>> 351 | uint64_t CSR_CPUID;
>>> | ^~~~~~~~~
>>> ninja: build stopped: subcommand failed.
>>> make[1]: *** [Makefile:162: run-ninja] Error 1
>>> make[1]: Leaving directory '/root/qemu/build'
>>> make: *** [GNUmakefile:11: all] Error 2
>>>
>>> Huacai
>> Sorry, I have submitted patch to fix this error, you could git pull to
>> update it.
> After git pull, I get a new error:
> [70/912] Compiling C object
> libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-icount.c.o
> [71/912] Compiling C object
> libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-rr.c.o
> [72/912] Linking target qemu-system-loongarch64
> FAILED: qemu-system-loongarch64
> cc -o qemu-system-loongarch64 libcommon.fa.p/hw_core_cpu-common.c.o
> libcommon.fa.p/hw_core_machine-smp.c.o
> libcommon.fa.p/gdbstub_syscalls.c.o libcommon.fap
> /usr/bin/ld: libqemu-loongarch64-softmmu.fa.p/accel_kvm_kvm-all.c.o:
> in function `kvm_init':
> /root/qemu/build/../accel/kvm/kvm-all.c:2525:(.text+0x66f4): undefined
> reference to `kvm_arch_get_default_type'
> collect2: error: ld returned 1 exit status
> ninja: build stopped: subcommand failed.
> make[1]: *** [Makefile:162: run-ninja] Error 1
> make[1]: Leaving directory '/root/qemu/build'
> make: *** [GNUmakefile:11: all] Error 2
>
> Huacai
Sorry, I have resolved this mistake and submit to the source, you could
update it.

Thanks
Tianrui Zhao
>
>> Thanks
>> Tianrui Zhao
>>>> 4. Uefi bios of LoongArch virt machine:
>>>> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
>>>> 5. you can also access the binary files we have already build:
>>>> https://github.com/yangxiaojuan-loongson/qemu-binary
>>>> The command to boot loongarch virt machine:
>>>> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
>>>> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
>>>> -serial stdio -monitor telnet:localhost:4495,server,nowait \
>>>> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
>>>> --nographic
>>>>
>>>> Changes for v21:
>>>> 1. Remove unnecessary prefix '_' in some kvm function names.
>>>> 2. Replace check_vmid with check_vpid, and move the functions
>>>> to main.c.
>>>> 3. Re-order the file names and config names by alphabetical
>>>> in KVM makefile and Kconfig.
>>>> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
>>>> ioctl functions.
>>>>
>>>> changes for v20:
>>>> 1. Remove the binary code of virtualization instructions in
>>>> insn_def.h and csr_ops.S and directly use the default csrrd,
>>>> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
>>>> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
>>>> already supported them to compile the KVM. This can make our
>>>> LoongArch KVM codes more maintainable and easier.
>>>>
>>>> changes for v19:
>>>> 1. Use the common interface xfer_to_guest_mode_handle_work to
>>>> Check conditions before entering the guest.
>>>> 2. Add vcpu dirty ring support.
>>>>
>>>> changes for v18:
>>>> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
>>>> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
>>>> the stable_ktime_saved variable to expire.
>>>> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
>>>>
>>>> changes for v17:
>>>> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
>>>> binutils that support LVZ assemble instruction.
>>>> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
>>>> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
>>>> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
>>>> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
>>>> handling.
>>>> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
>>>> when injecting IRQ.
>>>> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
>>>> kvm_arch.online_vcpus and kvm_arch.is_migrating,
>>>> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
>>>> since NR/NX bit is not set in kvm page fault handling.
>>>>
>>>> Changes for v16:
>>>> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
>>>> exit to avoid memory leak problem.
>>>> 2. Simplify some assemble codes in switch.S which are necessary to be
>>>> replaced with pseudo-instructions. And any other instructions do not need
>>>> to be replaced anymore.
>>>> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
>>>> guest regs instructions when vcpu world switch.
>>>> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
>>>> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
>>>>
>>>> Changes for v15:
>>>> 1. Re-order some macros and variables in LoongArch kvm headers, put them
>>>> together which have the same meaning.
>>>> 2. Make some function definitions in one line, as it is not needed to split
>>>> them.
>>>> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
>>>>
>>>> Changes for v14:
>>>> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
>>>> loongarch/kvm/main.c, as it is not useful.
>>>> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
>>>> as it is used by virt/kvm.
>>>> 3. Fix the LoongArch KVM source link in MAINTAINERS.
>>>> 4. Improve LoongArch KVM documentation, such as add comment for
>>>> LoongArch kvm_regs.
>>>>
>>>> Changes for v13:
>>>> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
>>>> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
>>>> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
>>>> remove the previous cpu_probe_lvz function.
>>>> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
>>>> FPU cap is enable by default, and do not support any other caps now.
>>>> 3. Simplify the jirl instruction with jr when without return addr,
>>>> simplify case HW0 ... HW7 statment in interrupt.c
>>>> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
>>>> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
>>>> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
>>>> cpu number by itself.
>>>>
>>>> Changes for v12:
>>>> 1. Improve the gcsr write/read/xchg interface to avoid the previous
>>>> instruction statment like parse_r and make the code easy understanding,
>>>> they are implemented in asm/insn-def.h and the instructions consistent
>>>> of "opcode" "rj" "rd" "simm14" arguments.
>>>> 2. Fix the maintainers list of LoongArch KVM.
>>>>
>>>> Changes for v11:
>>>> 1. Add maintainers for LoongArch KVM.
>>>>
>>>> Changes for v10:
>>>> 1. Fix grammatical problems in LoongArch documentation.
>>>> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
>>>> vcpu put and vcpu load, so we remove it.
>>>>
>>>> Changes for v9:
>>>> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
>>>> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
>>>> previous unused macros.
>>>> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
>>>> to make them more standard.
>>>>
>>>> Changes for v8:
>>>> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
>>>> it, and remove the previous guest.ases. We do this to keep consistent
>>>> with host cpu_data.options structure.
>>>> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
>>>> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
>>>> the asm/kvm_host.h.
>>>> 3. Fix some unstandard spelling and grammar errors in comments, and
>>>> improve a little code format to make it easier and standard.
>>>>
>>>> Changes for v7:
>>>> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
>>>> kernel test robot. The report link is:
>>>> https://lore.kernel.org/oe-kbuild-all/[email protected]/
>>>> 2. Fix loongarch kvm trace related compiling problems.
>>>>
>>>> Changes for v6:
>>>> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
>>>> loongarch parts.
>>>>
>>>> Changes for v5:
>>>> 1. Implement get/set mp_state ioctl interface, and only the
>>>> KVM_MP_STATE_RUNNABLE state is supported now, and other states
>>>> will be completed in the future. The state is also used when vcpu
>>>> run idle instruction, if vcpu state is changed to RUNNABLE, the
>>>> vcpu will have the possibility to be woken up.
>>>> 2. Supplement kvm document about loongarch-specific part, such as add
>>>> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
>>>> etc.
>>>> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
>>>> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
>>>>
>>>> Changes for v4:
>>>> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
>>>> unchanged during process context switch, so we need not to update it
>>>> every time. We can do this only if the soft csr is different form hardware.
>>>> That is to say all of csrs should update after vcpu enter guest, as for
>>>> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
>>>> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
>>>> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
>>>> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
>>>> SW, we use software to emulate it, and others return false.
>>>> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
>>>> We have splited hw gcsr into three parts, so we can calculate the code offset
>>>> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
>>>> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
>>>> 4. Improve kvm mmu functions, such as flush page table and make clean page table
>>>> interface.
>>>>
>>>> Changes for v3:
>>>> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
>>>> because a vpid will never be recycled if a vCPU migrates from physical CPU A
>>>> to B and back to A.
>>>> 2. Make some constant variables in kvm_context to global such as vpid_mask,
>>>> guest_eentry, enter_guest, etc.
>>>> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
>>>> kvm_trace_gspr, etc.
>>>> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
>>>> so we move it to a new function kvm_pre_enter_guest.
>>>> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
>>>> and "<= 0" for resume host.
>>>> 6. Fcsr and fpu registers are saved/restored together.
>>>>
>>>> Changes for v2:
>>>> 1. Seprate the original patch-01 and patch-03 into small patches, and the
>>>> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
>>>> etc.
>>>> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
>>>> and we use the common KVM_{GET,SET}_ONE_REG to access register.
>>>> 3. Use BIT(x) to replace the "1 << n_bits" statement.
>>>>
>>>> Tianrui Zhao (29):
>>>> LoongArch: KVM: Add kvm related header files
>>>> LoongArch: KVM: Implement kvm module related interface
>>>> LoongArch: KVM: Implement kvm hardware enable, disable interface
>>>> LoongArch: KVM: Implement VM related functions
>>>> LoongArch: KVM: Add vcpu related header files
>>>> LoongArch: KVM: Implement vcpu create and destroy interface
>>>> LoongArch: KVM: Implement vcpu run interface
>>>> LoongArch: KVM: Implement vcpu handle exit interface
>>>> LoongArch: KVM: Implement vcpu get, vcpu set registers
>>>> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
>>>> LoongArch: KVM: Implement fpu related operations for vcpu
>>>> LoongArch: KVM: Implement vcpu interrupt operations
>>>> LoongArch: KVM: Implement misc vcpu related interfaces
>>>> LoongArch: KVM: Implement vcpu load and vcpu put operations
>>>> LoongArch: KVM: Implement vcpu status description
>>>> LoongArch: KVM: Implement virtual machine tlb operations
>>>> LoongArch: KVM: Implement vcpu timer operations
>>>> LoongArch: KVM: Implement kvm mmu operations
>>>> LoongArch: KVM: Implement handle csr exception
>>>> LoongArch: KVM: Implement handle iocsr exception
>>>> LoongArch: KVM: Implement handle idle exception
>>>> LoongArch: KVM: Implement handle gspr exception
>>>> LoongArch: KVM: Implement handle mmio exception
>>>> LoongArch: KVM: Implement handle fpu exception
>>>> LoongArch: KVM: Implement kvm exception vector
>>>> LoongArch: KVM: Implement vcpu world switch
>>>> LoongArch: KVM: Enable kvm config and add the makefile
>>>> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
>>>> LoongArch: KVM: Add maintainers for LoongArch KVM
>>>>
>>>> Documentation/virt/kvm/api.rst | 70 +-
>>>> MAINTAINERS | 12 +
>>>> arch/loongarch/Kbuild | 1 +
>>>> arch/loongarch/Kconfig | 3 +
>>>> arch/loongarch/configs/loongson3_defconfig | 2 +
>>>> arch/loongarch/include/asm/inst.h | 16 +
>>>> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
>>>> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
>>>> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
>>>> arch/loongarch/include/asm/kvm_types.h | 11 +
>>>> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
>>>> arch/loongarch/include/asm/loongarch.h | 19 +-
>>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
>>>> arch/loongarch/kernel/asm-offsets.c | 32 +
>>>> arch/loongarch/kvm/Kconfig | 45 +
>>>> arch/loongarch/kvm/Makefile | 20 +
>>>> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
>>>> arch/loongarch/kvm/interrupt.c | 185 ++++
>>>> arch/loongarch/kvm/main.c | 429 ++++++++++
>>>> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
>>>> arch/loongarch/kvm/switch.S | 255 ++++++
>>>> arch/loongarch/kvm/timer.c | 200 +++++
>>>> arch/loongarch/kvm/tlb.c | 34 +
>>>> arch/loongarch/kvm/trace.h | 166 ++++
>>>> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
>>>> arch/loongarch/kvm/vm.c | 92 ++
>>>> include/uapi/linux/kvm.h | 9 +
>>>> 27 files changed, 4979 insertions(+), 14 deletions(-)
>>>> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
>>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>>>> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
>>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>>>> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
>>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>>> create mode 100644 arch/loongarch/kvm/Kconfig
>>>> create mode 100644 arch/loongarch/kvm/Makefile
>>>> create mode 100644 arch/loongarch/kvm/exit.c
>>>> create mode 100644 arch/loongarch/kvm/interrupt.c
>>>> create mode 100644 arch/loongarch/kvm/main.c
>>>> create mode 100644 arch/loongarch/kvm/mmu.c
>>>> create mode 100644 arch/loongarch/kvm/switch.S
>>>> create mode 100644 arch/loongarch/kvm/timer.c
>>>> create mode 100644 arch/loongarch/kvm/tlb.c
>>>> create mode 100644 arch/loongarch/kvm/trace.h
>>>> create mode 100644 arch/loongarch/kvm/vcpu.c
>>>> create mode 100644 arch/loongarch/kvm/vm.c
>>>>
>>>> --
>>>> 2.39.1
>>>>

2023-09-16 03:19:56

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support

Hi, Tianrui,

On Fri, Sep 15, 2023 at 3:53 PM zhaotianrui <[email protected]> wrote:
>
>
> 在 2023/9/15 下午3:10, Huacai Chen 写道:
> > Hi, Tianrui,
> >
> > On Fri, Sep 15, 2023 at 2:58 PM zhaotianrui <[email protected]> wrote:
> >>
> >> 在 2023/9/15 下午12:11, Huacai Chen 写道:
> >>> Hi, Tianrui,
> >>>
> >>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
> >>>> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
> >>>> assisted virtualization. With cpu virtualization, there are separate
> >>>> hw-supported user mode and kernel mode in guest mode. With memory
> >>>> virtualization, there are two-level hw mmu table for guest mode and host
> >>>> mode. Also there is separate hw cpu timer with consant frequency in
> >>>> guest mode, so that vm can migrate between hosts with different freq.
> >>>> Currently, we are able to boot LoongArch Linux Guests.
> >>>>
> >>>> Few key aspects of KVM LoongArch added by this series are:
> >>>> 1. Enable kvm hardware function when kvm module is loaded.
> >>>> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
> >>>> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
> >>>> get general registers one by one.
> >>>> 3. Hardware access about MMU, timer and csr are emulated in kernel.
> >>>> 4. Hardwares such as mmio and iocsr device are emulated in user space
> >>>> such as APIC, IPI, pci devices etc.
> >>>>
> >>>> The running environment of LoongArch virt machine:
> >>>> 1. Cross tools for building kernel and uefi:
> >>>> https://github.com/loongson/build-tools
> >>>> 2. This series is based on the linux source code:
> >>>> https://github.com/loongson/linux-loongarch-kvm
> >>>> Build command:
> >>>> git checkout kvm-loongarch
> >>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
> >>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
> >>>> 3. QEMU hypervisor with LoongArch supported:
> >>>> https://github.com/loongson/qemu
> >>>> Build command:
> >>>> git checkout kvm-loongarch
> >>>> ./configure --target-list="loongarch64-softmmu" --enable-kvm
> >>>> make
> >>> When I build qemu, I get:
> >>> [3/964] Compiling C object
> >>> libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> >>> FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> >>> cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
> >>> -I../target/loongarch -Isubprojects/dtc/libfdt
> >>> -I../subprojects/dtc/libfdt -Iqapi -Itrace c
> >>> In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
> >>> ../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
> >>> 351 | uint64_t CSR_CPUID;
> >>> | ^~~~~~~~~
> >>> ninja: build stopped: subcommand failed.
> >>> make[1]: *** [Makefile:162: run-ninja] Error 1
> >>> make[1]: Leaving directory '/root/qemu/build'
> >>> make: *** [GNUmakefile:11: all] Error 2
> >>>
> >>> Huacai
> >> Sorry, I have submitted patch to fix this error, you could git pull to
> >> update it.
> > After git pull, I get a new error:
> > [70/912] Compiling C object
> > libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-icount.c.o
> > [71/912] Compiling C object
> > libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-rr.c.o
> > [72/912] Linking target qemu-system-loongarch64
> > FAILED: qemu-system-loongarch64
> > cc -o qemu-system-loongarch64 libcommon.fa.p/hw_core_cpu-common.c.o
> > libcommon.fa.p/hw_core_machine-smp.c.o
> > libcommon.fa.p/gdbstub_syscalls.c.o libcommon.fap
> > /usr/bin/ld: libqemu-loongarch64-softmmu.fa.p/accel_kvm_kvm-all.c.o:
> > in function `kvm_init':
> > /root/qemu/build/../accel/kvm/kvm-all.c:2525:(.text+0x66f4): undefined
> > reference to `kvm_arch_get_default_type'
> > collect2: error: ld returned 1 exit status
> > ninja: build stopped: subcommand failed.
> > make[1]: *** [Makefile:162: run-ninja] Error 1
> > make[1]: Leaving directory '/root/qemu/build'
> > make: *** [GNUmakefile:11: all] Error 2
> >
> > Huacai
> Sorry, I have resolved this mistake and submit to the source, you could
> update it.
I can test now, during my tests I may ask some other questions about
your patches. You just need to answer my questions and I will adjust
the code myself if needed. After that I will give you a final version
with Tested-by and you can simply send that as V22.

Huacai

>
> Thanks
> Tianrui Zhao
> >
> >> Thanks
> >> Tianrui Zhao
> >>>> 4. Uefi bios of LoongArch virt machine:
> >>>> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
> >>>> 5. you can also access the binary files we have already build:
> >>>> https://github.com/yangxiaojuan-loongson/qemu-binary
> >>>> The command to boot loongarch virt machine:
> >>>> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
> >>>> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
> >>>> -serial stdio -monitor telnet:localhost:4495,server,nowait \
> >>>> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
> >>>> --nographic
> >>>>
> >>>> Changes for v21:
> >>>> 1. Remove unnecessary prefix '_' in some kvm function names.
> >>>> 2. Replace check_vmid with check_vpid, and move the functions
> >>>> to main.c.
> >>>> 3. Re-order the file names and config names by alphabetical
> >>>> in KVM makefile and Kconfig.
> >>>> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
> >>>> ioctl functions.
> >>>>
> >>>> changes for v20:
> >>>> 1. Remove the binary code of virtualization instructions in
> >>>> insn_def.h and csr_ops.S and directly use the default csrrd,
> >>>> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
> >>>> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
> >>>> already supported them to compile the KVM. This can make our
> >>>> LoongArch KVM codes more maintainable and easier.
> >>>>
> >>>> changes for v19:
> >>>> 1. Use the common interface xfer_to_guest_mode_handle_work to
> >>>> Check conditions before entering the guest.
> >>>> 2. Add vcpu dirty ring support.
> >>>>
> >>>> changes for v18:
> >>>> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
> >>>> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
> >>>> the stable_ktime_saved variable to expire.
> >>>> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
> >>>>
> >>>> changes for v17:
> >>>> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
> >>>> binutils that support LVZ assemble instruction.
> >>>> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
> >>>> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
> >>>> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
> >>>> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
> >>>> handling.
> >>>> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
> >>>> when injecting IRQ.
> >>>> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
> >>>> kvm_arch.online_vcpus and kvm_arch.is_migrating,
> >>>> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
> >>>> since NR/NX bit is not set in kvm page fault handling.
> >>>>
> >>>> Changes for v16:
> >>>> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
> >>>> exit to avoid memory leak problem.
> >>>> 2. Simplify some assemble codes in switch.S which are necessary to be
> >>>> replaced with pseudo-instructions. And any other instructions do not need
> >>>> to be replaced anymore.
> >>>> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
> >>>> guest regs instructions when vcpu world switch.
> >>>> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
> >>>> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
> >>>>
> >>>> Changes for v15:
> >>>> 1. Re-order some macros and variables in LoongArch kvm headers, put them
> >>>> together which have the same meaning.
> >>>> 2. Make some function definitions in one line, as it is not needed to split
> >>>> them.
> >>>> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
> >>>>
> >>>> Changes for v14:
> >>>> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
> >>>> loongarch/kvm/main.c, as it is not useful.
> >>>> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
> >>>> as it is used by virt/kvm.
> >>>> 3. Fix the LoongArch KVM source link in MAINTAINERS.
> >>>> 4. Improve LoongArch KVM documentation, such as add comment for
> >>>> LoongArch kvm_regs.
> >>>>
> >>>> Changes for v13:
> >>>> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
> >>>> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
> >>>> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
> >>>> remove the previous cpu_probe_lvz function.
> >>>> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
> >>>> FPU cap is enable by default, and do not support any other caps now.
> >>>> 3. Simplify the jirl instruction with jr when without return addr,
> >>>> simplify case HW0 ... HW7 statment in interrupt.c
> >>>> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
> >>>> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
> >>>> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
> >>>> cpu number by itself.
> >>>>
> >>>> Changes for v12:
> >>>> 1. Improve the gcsr write/read/xchg interface to avoid the previous
> >>>> instruction statment like parse_r and make the code easy understanding,
> >>>> they are implemented in asm/insn-def.h and the instructions consistent
> >>>> of "opcode" "rj" "rd" "simm14" arguments.
> >>>> 2. Fix the maintainers list of LoongArch KVM.
> >>>>
> >>>> Changes for v11:
> >>>> 1. Add maintainers for LoongArch KVM.
> >>>>
> >>>> Changes for v10:
> >>>> 1. Fix grammatical problems in LoongArch documentation.
> >>>> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
> >>>> vcpu put and vcpu load, so we remove it.
> >>>>
> >>>> Changes for v9:
> >>>> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
> >>>> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
> >>>> previous unused macros.
> >>>> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
> >>>> to make them more standard.
> >>>>
> >>>> Changes for v8:
> >>>> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
> >>>> it, and remove the previous guest.ases. We do this to keep consistent
> >>>> with host cpu_data.options structure.
> >>>> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
> >>>> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
> >>>> the asm/kvm_host.h.
> >>>> 3. Fix some unstandard spelling and grammar errors in comments, and
> >>>> improve a little code format to make it easier and standard.
> >>>>
> >>>> Changes for v7:
> >>>> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
> >>>> kernel test robot. The report link is:
> >>>> https://lore.kernel.org/oe-kbuild-all/[email protected]/
> >>>> 2. Fix loongarch kvm trace related compiling problems.
> >>>>
> >>>> Changes for v6:
> >>>> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
> >>>> loongarch parts.
> >>>>
> >>>> Changes for v5:
> >>>> 1. Implement get/set mp_state ioctl interface, and only the
> >>>> KVM_MP_STATE_RUNNABLE state is supported now, and other states
> >>>> will be completed in the future. The state is also used when vcpu
> >>>> run idle instruction, if vcpu state is changed to RUNNABLE, the
> >>>> vcpu will have the possibility to be woken up.
> >>>> 2. Supplement kvm document about loongarch-specific part, such as add
> >>>> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
> >>>> etc.
> >>>> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
> >>>> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
> >>>>
> >>>> Changes for v4:
> >>>> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
> >>>> unchanged during process context switch, so we need not to update it
> >>>> every time. We can do this only if the soft csr is different form hardware.
> >>>> That is to say all of csrs should update after vcpu enter guest, as for
> >>>> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
> >>>> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
> >>>> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
> >>>> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
> >>>> SW, we use software to emulate it, and others return false.
> >>>> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
> >>>> We have splited hw gcsr into three parts, so we can calculate the code offset
> >>>> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
> >>>> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
> >>>> 4. Improve kvm mmu functions, such as flush page table and make clean page table
> >>>> interface.
> >>>>
> >>>> Changes for v3:
> >>>> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
> >>>> because a vpid will never be recycled if a vCPU migrates from physical CPU A
> >>>> to B and back to A.
> >>>> 2. Make some constant variables in kvm_context to global such as vpid_mask,
> >>>> guest_eentry, enter_guest, etc.
> >>>> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
> >>>> kvm_trace_gspr, etc.
> >>>> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
> >>>> so we move it to a new function kvm_pre_enter_guest.
> >>>> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
> >>>> and "<= 0" for resume host.
> >>>> 6. Fcsr and fpu registers are saved/restored together.
> >>>>
> >>>> Changes for v2:
> >>>> 1. Seprate the original patch-01 and patch-03 into small patches, and the
> >>>> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
> >>>> etc.
> >>>> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
> >>>> and we use the common KVM_{GET,SET}_ONE_REG to access register.
> >>>> 3. Use BIT(x) to replace the "1 << n_bits" statement.
> >>>>
> >>>> Tianrui Zhao (29):
> >>>> LoongArch: KVM: Add kvm related header files
> >>>> LoongArch: KVM: Implement kvm module related interface
> >>>> LoongArch: KVM: Implement kvm hardware enable, disable interface
> >>>> LoongArch: KVM: Implement VM related functions
> >>>> LoongArch: KVM: Add vcpu related header files
> >>>> LoongArch: KVM: Implement vcpu create and destroy interface
> >>>> LoongArch: KVM: Implement vcpu run interface
> >>>> LoongArch: KVM: Implement vcpu handle exit interface
> >>>> LoongArch: KVM: Implement vcpu get, vcpu set registers
> >>>> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
> >>>> LoongArch: KVM: Implement fpu related operations for vcpu
> >>>> LoongArch: KVM: Implement vcpu interrupt operations
> >>>> LoongArch: KVM: Implement misc vcpu related interfaces
> >>>> LoongArch: KVM: Implement vcpu load and vcpu put operations
> >>>> LoongArch: KVM: Implement vcpu status description
> >>>> LoongArch: KVM: Implement virtual machine tlb operations
> >>>> LoongArch: KVM: Implement vcpu timer operations
> >>>> LoongArch: KVM: Implement kvm mmu operations
> >>>> LoongArch: KVM: Implement handle csr exception
> >>>> LoongArch: KVM: Implement handle iocsr exception
> >>>> LoongArch: KVM: Implement handle idle exception
> >>>> LoongArch: KVM: Implement handle gspr exception
> >>>> LoongArch: KVM: Implement handle mmio exception
> >>>> LoongArch: KVM: Implement handle fpu exception
> >>>> LoongArch: KVM: Implement kvm exception vector
> >>>> LoongArch: KVM: Implement vcpu world switch
> >>>> LoongArch: KVM: Enable kvm config and add the makefile
> >>>> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
> >>>> LoongArch: KVM: Add maintainers for LoongArch KVM
> >>>>
> >>>> Documentation/virt/kvm/api.rst | 70 +-
> >>>> MAINTAINERS | 12 +
> >>>> arch/loongarch/Kbuild | 1 +
> >>>> arch/loongarch/Kconfig | 3 +
> >>>> arch/loongarch/configs/loongson3_defconfig | 2 +
> >>>> arch/loongarch/include/asm/inst.h | 16 +
> >>>> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
> >>>> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
> >>>> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
> >>>> arch/loongarch/include/asm/kvm_types.h | 11 +
> >>>> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
> >>>> arch/loongarch/include/asm/loongarch.h | 19 +-
> >>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
> >>>> arch/loongarch/kernel/asm-offsets.c | 32 +
> >>>> arch/loongarch/kvm/Kconfig | 45 +
> >>>> arch/loongarch/kvm/Makefile | 20 +
> >>>> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
> >>>> arch/loongarch/kvm/interrupt.c | 185 ++++
> >>>> arch/loongarch/kvm/main.c | 429 ++++++++++
> >>>> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
> >>>> arch/loongarch/kvm/switch.S | 255 ++++++
> >>>> arch/loongarch/kvm/timer.c | 200 +++++
> >>>> arch/loongarch/kvm/tlb.c | 34 +
> >>>> arch/loongarch/kvm/trace.h | 166 ++++
> >>>> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
> >>>> arch/loongarch/kvm/vm.c | 92 ++
> >>>> include/uapi/linux/kvm.h | 9 +
> >>>> 27 files changed, 4979 insertions(+), 14 deletions(-)
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
> >>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> >>>> create mode 100644 arch/loongarch/kvm/Kconfig
> >>>> create mode 100644 arch/loongarch/kvm/Makefile
> >>>> create mode 100644 arch/loongarch/kvm/exit.c
> >>>> create mode 100644 arch/loongarch/kvm/interrupt.c
> >>>> create mode 100644 arch/loongarch/kvm/main.c
> >>>> create mode 100644 arch/loongarch/kvm/mmu.c
> >>>> create mode 100644 arch/loongarch/kvm/switch.S
> >>>> create mode 100644 arch/loongarch/kvm/timer.c
> >>>> create mode 100644 arch/loongarch/kvm/tlb.c
> >>>> create mode 100644 arch/loongarch/kvm/trace.h
> >>>> create mode 100644 arch/loongarch/kvm/vcpu.c
> >>>> create mode 100644 arch/loongarch/kvm/vm.c
> >>>>
> >>>> --
> >>>> 2.39.1
> >>>>
>

2023-09-16 06:31:02

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support


在 2023/9/16 上午11:17, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Fri, Sep 15, 2023 at 3:53 PM zhaotianrui <[email protected]> wrote:
>>
>> 在 2023/9/15 下午3:10, Huacai Chen 写道:
>>> Hi, Tianrui,
>>>
>>> On Fri, Sep 15, 2023 at 2:58 PM zhaotianrui <[email protected]> wrote:
>>>> 在 2023/9/15 下午12:11, Huacai Chen 写道:
>>>>> Hi, Tianrui,
>>>>>
>>>>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>>>>>> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
>>>>>> assisted virtualization. With cpu virtualization, there are separate
>>>>>> hw-supported user mode and kernel mode in guest mode. With memory
>>>>>> virtualization, there are two-level hw mmu table for guest mode and host
>>>>>> mode. Also there is separate hw cpu timer with consant frequency in
>>>>>> guest mode, so that vm can migrate between hosts with different freq.
>>>>>> Currently, we are able to boot LoongArch Linux Guests.
>>>>>>
>>>>>> Few key aspects of KVM LoongArch added by this series are:
>>>>>> 1. Enable kvm hardware function when kvm module is loaded.
>>>>>> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
>>>>>> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
>>>>>> get general registers one by one.
>>>>>> 3. Hardware access about MMU, timer and csr are emulated in kernel.
>>>>>> 4. Hardwares such as mmio and iocsr device are emulated in user space
>>>>>> such as APIC, IPI, pci devices etc.
>>>>>>
>>>>>> The running environment of LoongArch virt machine:
>>>>>> 1. Cross tools for building kernel and uefi:
>>>>>> https://github.com/loongson/build-tools
>>>>>> 2. This series is based on the linux source code:
>>>>>> https://github.com/loongson/linux-loongarch-kvm
>>>>>> Build command:
>>>>>> git checkout kvm-loongarch
>>>>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
>>>>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
>>>>>> 3. QEMU hypervisor with LoongArch supported:
>>>>>> https://github.com/loongson/qemu
>>>>>> Build command:
>>>>>> git checkout kvm-loongarch
>>>>>> ./configure --target-list="loongarch64-softmmu" --enable-kvm
>>>>>> make
>>>>> When I build qemu, I get:
>>>>> [3/964] Compiling C object
>>>>> libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
>>>>> FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
>>>>> cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
>>>>> -I../target/loongarch -Isubprojects/dtc/libfdt
>>>>> -I../subprojects/dtc/libfdt -Iqapi -Itrace c
>>>>> In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
>>>>> ../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
>>>>> 351 | uint64_t CSR_CPUID;
>>>>> | ^~~~~~~~~
>>>>> ninja: build stopped: subcommand failed.
>>>>> make[1]: *** [Makefile:162: run-ninja] Error 1
>>>>> make[1]: Leaving directory '/root/qemu/build'
>>>>> make: *** [GNUmakefile:11: all] Error 2
>>>>>
>>>>> Huacai
>>>> Sorry, I have submitted patch to fix this error, you could git pull to
>>>> update it.
>>> After git pull, I get a new error:
>>> [70/912] Compiling C object
>>> libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-icount.c.o
>>> [71/912] Compiling C object
>>> libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-rr.c.o
>>> [72/912] Linking target qemu-system-loongarch64
>>> FAILED: qemu-system-loongarch64
>>> cc -o qemu-system-loongarch64 libcommon.fa.p/hw_core_cpu-common.c.o
>>> libcommon.fa.p/hw_core_machine-smp.c.o
>>> libcommon.fa.p/gdbstub_syscalls.c.o libcommon.fap
>>> /usr/bin/ld: libqemu-loongarch64-softmmu.fa.p/accel_kvm_kvm-all.c.o:
>>> in function `kvm_init':
>>> /root/qemu/build/../accel/kvm/kvm-all.c:2525:(.text+0x66f4): undefined
>>> reference to `kvm_arch_get_default_type'
>>> collect2: error: ld returned 1 exit status
>>> ninja: build stopped: subcommand failed.
>>> make[1]: *** [Makefile:162: run-ninja] Error 1
>>> make[1]: Leaving directory '/root/qemu/build'
>>> make: *** [GNUmakefile:11: all] Error 2
>>>
>>> Huacai
>> Sorry, I have resolved this mistake and submit to the source, you could
>> update it.
> I can test now, during my tests I may ask some other questions about
> your patches. You just need to answer my questions and I will adjust
> the code myself if needed. After that I will give you a final version
> with Tested-by and you can simply send that as V22.
>
> Huacai
Ok, thanks for your reviewing carefully.

Thanks
Tianrui Zhao
>
>> Thanks
>> Tianrui Zhao
>>>> Thanks
>>>> Tianrui Zhao
>>>>>> 4. Uefi bios of LoongArch virt machine:
>>>>>> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
>>>>>> 5. you can also access the binary files we have already build:
>>>>>> https://github.com/yangxiaojuan-loongson/qemu-binary
>>>>>> The command to boot loongarch virt machine:
>>>>>> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
>>>>>> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
>>>>>> -serial stdio -monitor telnet:localhost:4495,server,nowait \
>>>>>> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
>>>>>> --nographic
>>>>>>
>>>>>> Changes for v21:
>>>>>> 1. Remove unnecessary prefix '_' in some kvm function names.
>>>>>> 2. Replace check_vmid with check_vpid, and move the functions
>>>>>> to main.c.
>>>>>> 3. Re-order the file names and config names by alphabetical
>>>>>> in KVM makefile and Kconfig.
>>>>>> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
>>>>>> ioctl functions.
>>>>>>
>>>>>> changes for v20:
>>>>>> 1. Remove the binary code of virtualization instructions in
>>>>>> insn_def.h and csr_ops.S and directly use the default csrrd,
>>>>>> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
>>>>>> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
>>>>>> already supported them to compile the KVM. This can make our
>>>>>> LoongArch KVM codes more maintainable and easier.
>>>>>>
>>>>>> changes for v19:
>>>>>> 1. Use the common interface xfer_to_guest_mode_handle_work to
>>>>>> Check conditions before entering the guest.
>>>>>> 2. Add vcpu dirty ring support.
>>>>>>
>>>>>> changes for v18:
>>>>>> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
>>>>>> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
>>>>>> the stable_ktime_saved variable to expire.
>>>>>> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
>>>>>>
>>>>>> changes for v17:
>>>>>> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
>>>>>> binutils that support LVZ assemble instruction.
>>>>>> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
>>>>>> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
>>>>>> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
>>>>>> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
>>>>>> handling.
>>>>>> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
>>>>>> when injecting IRQ.
>>>>>> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
>>>>>> kvm_arch.online_vcpus and kvm_arch.is_migrating,
>>>>>> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
>>>>>> since NR/NX bit is not set in kvm page fault handling.
>>>>>>
>>>>>> Changes for v16:
>>>>>> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
>>>>>> exit to avoid memory leak problem.
>>>>>> 2. Simplify some assemble codes in switch.S which are necessary to be
>>>>>> replaced with pseudo-instructions. And any other instructions do not need
>>>>>> to be replaced anymore.
>>>>>> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
>>>>>> guest regs instructions when vcpu world switch.
>>>>>> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
>>>>>> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
>>>>>>
>>>>>> Changes for v15:
>>>>>> 1. Re-order some macros and variables in LoongArch kvm headers, put them
>>>>>> together which have the same meaning.
>>>>>> 2. Make some function definitions in one line, as it is not needed to split
>>>>>> them.
>>>>>> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
>>>>>>
>>>>>> Changes for v14:
>>>>>> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
>>>>>> loongarch/kvm/main.c, as it is not useful.
>>>>>> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
>>>>>> as it is used by virt/kvm.
>>>>>> 3. Fix the LoongArch KVM source link in MAINTAINERS.
>>>>>> 4. Improve LoongArch KVM documentation, such as add comment for
>>>>>> LoongArch kvm_regs.
>>>>>>
>>>>>> Changes for v13:
>>>>>> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
>>>>>> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
>>>>>> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
>>>>>> remove the previous cpu_probe_lvz function.
>>>>>> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
>>>>>> FPU cap is enable by default, and do not support any other caps now.
>>>>>> 3. Simplify the jirl instruction with jr when without return addr,
>>>>>> simplify case HW0 ... HW7 statment in interrupt.c
>>>>>> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
>>>>>> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
>>>>>> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
>>>>>> cpu number by itself.
>>>>>>
>>>>>> Changes for v12:
>>>>>> 1. Improve the gcsr write/read/xchg interface to avoid the previous
>>>>>> instruction statment like parse_r and make the code easy understanding,
>>>>>> they are implemented in asm/insn-def.h and the instructions consistent
>>>>>> of "opcode" "rj" "rd" "simm14" arguments.
>>>>>> 2. Fix the maintainers list of LoongArch KVM.
>>>>>>
>>>>>> Changes for v11:
>>>>>> 1. Add maintainers for LoongArch KVM.
>>>>>>
>>>>>> Changes for v10:
>>>>>> 1. Fix grammatical problems in LoongArch documentation.
>>>>>> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
>>>>>> vcpu put and vcpu load, so we remove it.
>>>>>>
>>>>>> Changes for v9:
>>>>>> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
>>>>>> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
>>>>>> previous unused macros.
>>>>>> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
>>>>>> to make them more standard.
>>>>>>
>>>>>> Changes for v8:
>>>>>> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
>>>>>> it, and remove the previous guest.ases. We do this to keep consistent
>>>>>> with host cpu_data.options structure.
>>>>>> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
>>>>>> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
>>>>>> the asm/kvm_host.h.
>>>>>> 3. Fix some unstandard spelling and grammar errors in comments, and
>>>>>> improve a little code format to make it easier and standard.
>>>>>>
>>>>>> Changes for v7:
>>>>>> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
>>>>>> kernel test robot. The report link is:
>>>>>> https://lore.kernel.org/oe-kbuild-all/[email protected]/
>>>>>> 2. Fix loongarch kvm trace related compiling problems.
>>>>>>
>>>>>> Changes for v6:
>>>>>> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
>>>>>> loongarch parts.
>>>>>>
>>>>>> Changes for v5:
>>>>>> 1. Implement get/set mp_state ioctl interface, and only the
>>>>>> KVM_MP_STATE_RUNNABLE state is supported now, and other states
>>>>>> will be completed in the future. The state is also used when vcpu
>>>>>> run idle instruction, if vcpu state is changed to RUNNABLE, the
>>>>>> vcpu will have the possibility to be woken up.
>>>>>> 2. Supplement kvm document about loongarch-specific part, such as add
>>>>>> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
>>>>>> etc.
>>>>>> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
>>>>>> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
>>>>>>
>>>>>> Changes for v4:
>>>>>> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
>>>>>> unchanged during process context switch, so we need not to update it
>>>>>> every time. We can do this only if the soft csr is different form hardware.
>>>>>> That is to say all of csrs should update after vcpu enter guest, as for
>>>>>> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
>>>>>> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
>>>>>> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
>>>>>> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
>>>>>> SW, we use software to emulate it, and others return false.
>>>>>> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
>>>>>> We have splited hw gcsr into three parts, so we can calculate the code offset
>>>>>> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
>>>>>> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
>>>>>> 4. Improve kvm mmu functions, such as flush page table and make clean page table
>>>>>> interface.
>>>>>>
>>>>>> Changes for v3:
>>>>>> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
>>>>>> because a vpid will never be recycled if a vCPU migrates from physical CPU A
>>>>>> to B and back to A.
>>>>>> 2. Make some constant variables in kvm_context to global such as vpid_mask,
>>>>>> guest_eentry, enter_guest, etc.
>>>>>> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
>>>>>> kvm_trace_gspr, etc.
>>>>>> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
>>>>>> so we move it to a new function kvm_pre_enter_guest.
>>>>>> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
>>>>>> and "<= 0" for resume host.
>>>>>> 6. Fcsr and fpu registers are saved/restored together.
>>>>>>
>>>>>> Changes for v2:
>>>>>> 1. Seprate the original patch-01 and patch-03 into small patches, and the
>>>>>> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
>>>>>> etc.
>>>>>> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
>>>>>> and we use the common KVM_{GET,SET}_ONE_REG to access register.
>>>>>> 3. Use BIT(x) to replace the "1 << n_bits" statement.
>>>>>>
>>>>>> Tianrui Zhao (29):
>>>>>> LoongArch: KVM: Add kvm related header files
>>>>>> LoongArch: KVM: Implement kvm module related interface
>>>>>> LoongArch: KVM: Implement kvm hardware enable, disable interface
>>>>>> LoongArch: KVM: Implement VM related functions
>>>>>> LoongArch: KVM: Add vcpu related header files
>>>>>> LoongArch: KVM: Implement vcpu create and destroy interface
>>>>>> LoongArch: KVM: Implement vcpu run interface
>>>>>> LoongArch: KVM: Implement vcpu handle exit interface
>>>>>> LoongArch: KVM: Implement vcpu get, vcpu set registers
>>>>>> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
>>>>>> LoongArch: KVM: Implement fpu related operations for vcpu
>>>>>> LoongArch: KVM: Implement vcpu interrupt operations
>>>>>> LoongArch: KVM: Implement misc vcpu related interfaces
>>>>>> LoongArch: KVM: Implement vcpu load and vcpu put operations
>>>>>> LoongArch: KVM: Implement vcpu status description
>>>>>> LoongArch: KVM: Implement virtual machine tlb operations
>>>>>> LoongArch: KVM: Implement vcpu timer operations
>>>>>> LoongArch: KVM: Implement kvm mmu operations
>>>>>> LoongArch: KVM: Implement handle csr exception
>>>>>> LoongArch: KVM: Implement handle iocsr exception
>>>>>> LoongArch: KVM: Implement handle idle exception
>>>>>> LoongArch: KVM: Implement handle gspr exception
>>>>>> LoongArch: KVM: Implement handle mmio exception
>>>>>> LoongArch: KVM: Implement handle fpu exception
>>>>>> LoongArch: KVM: Implement kvm exception vector
>>>>>> LoongArch: KVM: Implement vcpu world switch
>>>>>> LoongArch: KVM: Enable kvm config and add the makefile
>>>>>> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
>>>>>> LoongArch: KVM: Add maintainers for LoongArch KVM
>>>>>>
>>>>>> Documentation/virt/kvm/api.rst | 70 +-
>>>>>> MAINTAINERS | 12 +
>>>>>> arch/loongarch/Kbuild | 1 +
>>>>>> arch/loongarch/Kconfig | 3 +
>>>>>> arch/loongarch/configs/loongson3_defconfig | 2 +
>>>>>> arch/loongarch/include/asm/inst.h | 16 +
>>>>>> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
>>>>>> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
>>>>>> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
>>>>>> arch/loongarch/include/asm/kvm_types.h | 11 +
>>>>>> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
>>>>>> arch/loongarch/include/asm/loongarch.h | 19 +-
>>>>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
>>>>>> arch/loongarch/kernel/asm-offsets.c | 32 +
>>>>>> arch/loongarch/kvm/Kconfig | 45 +
>>>>>> arch/loongarch/kvm/Makefile | 20 +
>>>>>> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
>>>>>> arch/loongarch/kvm/interrupt.c | 185 ++++
>>>>>> arch/loongarch/kvm/main.c | 429 ++++++++++
>>>>>> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
>>>>>> arch/loongarch/kvm/switch.S | 255 ++++++
>>>>>> arch/loongarch/kvm/timer.c | 200 +++++
>>>>>> arch/loongarch/kvm/tlb.c | 34 +
>>>>>> arch/loongarch/kvm/trace.h | 166 ++++
>>>>>> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
>>>>>> arch/loongarch/kvm/vm.c | 92 ++
>>>>>> include/uapi/linux/kvm.h | 9 +
>>>>>> 27 files changed, 4979 insertions(+), 14 deletions(-)
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
>>>>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>>>>> create mode 100644 arch/loongarch/kvm/Kconfig
>>>>>> create mode 100644 arch/loongarch/kvm/Makefile
>>>>>> create mode 100644 arch/loongarch/kvm/exit.c
>>>>>> create mode 100644 arch/loongarch/kvm/interrupt.c
>>>>>> create mode 100644 arch/loongarch/kvm/main.c
>>>>>> create mode 100644 arch/loongarch/kvm/mmu.c
>>>>>> create mode 100644 arch/loongarch/kvm/switch.S
>>>>>> create mode 100644 arch/loongarch/kvm/timer.c
>>>>>> create mode 100644 arch/loongarch/kvm/tlb.c
>>>>>> create mode 100644 arch/loongarch/kvm/trace.h
>>>>>> create mode 100644 arch/loongarch/kvm/vcpu.c
>>>>>> create mode 100644 arch/loongarch/kvm/vm.c
>>>>>>
>>>>>> --
>>>>>> 2.39.1
>>>>>>

2023-09-16 08:50:14

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files

Hi, Tianrui,

On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>
> Add LoongArch KVM related header files, including kvm.h,
> kvm_host.h, kvm_types.h. All of those are about LoongArch
> virtualization features and kvm interfaces.
>
> Reviewed-by: Bibo Mao <[email protected]>
> Signed-off-by: Tianrui Zhao <[email protected]>
> ---
> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
> arch/loongarch/include/asm/kvm_types.h | 11 ++
> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
> include/uapi/linux/kvm.h | 9 +
> 4 files changed, 373 insertions(+)
> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>
> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
> new file mode 100644
> index 0000000000..00e0c1876b
> --- /dev/null
> +++ b/arch/loongarch/include/asm/kvm_host.h
> @@ -0,0 +1,245 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
> +#define __ASM_LOONGARCH_KVM_HOST_H__
> +
> +#include <linux/cpumask.h>
> +#include <linux/mutex.h>
> +#include <linux/hrtimer.h>
> +#include <linux/interrupt.h>
> +#include <linux/types.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_types.h>
> +#include <linux/threads.h>
> +#include <linux/spinlock.h>
> +
> +#include <asm/inst.h>
> +#include <asm/kvm_mmu.h>
> +#include <asm/loongarch.h>
> +
> +/* Loongarch KVM register ids */
> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> +
> +#define KVM_MAX_VCPUS 256
> +#define KVM_MAX_CPUCFG_REGS 21
> +/* memory slots that does not exposed to userspace */
> +#define KVM_PRIVATE_MEM_SLOTS 0
> +
> +#define KVM_HALT_POLL_NS_DEFAULT 500000
> +
> +struct kvm_vm_stat {
> + struct kvm_vm_stat_generic generic;
> + u64 pages;
> + u64 hugepages;
> +};
> +
> +struct kvm_vcpu_stat {
> + struct kvm_vcpu_stat_generic generic;
> + u64 idle_exits;
> + u64 signal_exits;
> + u64 int_exits;
> + u64 cpucfg_exits;
> +};
> +
> +struct kvm_arch_memory_slot {
> +};
> +
> +struct kvm_context {
> + unsigned long vpid_cache;
> + struct kvm_vcpu *last_vcpu;
> +};
> +
> +struct kvm_world_switch {
> + int (*guest_eentry)(void);
> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> + unsigned long page_order;
> +};
> +
> +#define MAX_PGTABLE_LEVELS 4
> +struct kvm_arch {
> + /* Guest physical mm */
> + kvm_pte_t *pgd;
> + unsigned long gpa_size;
> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
> + unsigned int root_level;
> +
> + s64 time_offset;
> + struct kvm_context __percpu *vmcs;
> +};
> +
> +#define CSR_MAX_NUMS 0x800
> +
> +struct loongarch_csrs {
> + unsigned long csrs[CSR_MAX_NUMS];
> +};
> +
> +/* Resume Flags */
> +#define RESUME_HOST 0
> +#define RESUME_GUEST 1
> +
> +enum emulation_result {
> + EMULATE_DONE, /* no further processing */
> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
> + EMULATE_FAIL, /* can't emulate this instruction */
> + EMULATE_EXCEPT, /* A guest exception has been generated */
> + EMULATE_DO_IOCSR, /* handle IOCSR request */
> +};
> +
> +#define KVM_LARCH_FPU (0x1 << 0)
> +#define KVM_LARCH_CSR (0x1 << 1)
> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
> +
> +struct kvm_vcpu_arch {
> + /*
> + * Switch pointer-to-function type to unsigned long
> + * for loading the value into register directly.
> + */
> + unsigned long host_eentry;
> + unsigned long guest_eentry;
> +
> + /* Pointers stored here for easy accessing from assembly code */
> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> +
> + /* Host registers preserved across guest mode execution */
> + unsigned long host_sp;
> + unsigned long host_tp;
> + unsigned long host_pgd;
> +
> + /* Host CSRs are used when handling exits from guest */
> + unsigned long badi;
> + unsigned long badv;
> + unsigned long host_ecfg;
> + unsigned long host_estat;
> + unsigned long host_percpu;
> +
> + /* GPRs */
> + unsigned long gprs[32];
> + unsigned long pc;
> +
> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
> + unsigned int aux_inuse;
> + /* FPU state */
> + struct loongarch_fpu fpu FPU_ALIGN;
> +
> + /* CSR state */
> + struct loongarch_csrs *csr;
> +
> + /* GPR used as IO source/target */
> + u32 io_gpr;
> +
> + struct hrtimer swtimer;
> + /* KVM register to control count timer */
> + u32 count_ctl;
> +
> + /* Bitmask of intr that are pending */
> + unsigned long irq_pending;
> + /* Bitmask of pending intr to be cleared */
> + unsigned long irq_clear;
> +
> + /* Bitmask of exceptions that are pending */
> + unsigned long exception_pending;
> + unsigned int subcode;
> +
> + /* Cache for pages needed inside spinlock regions */
> + struct kvm_mmu_memory_cache mmu_page_cache;
> +
> + /* vcpu's vpid */
> + u64 vpid;
> +
> + /* Frequency of stable timer in Hz */
> + u64 timer_mhz;
> + ktime_t expire;
> +
> + u64 core_ext_ioisr[4];
> +
> + /* Last CPU the vCPU state was loaded on */
> + int last_sched_cpu;
> + /* mp state */
> + struct kvm_mp_state mp_state;
> + /* cpucfg */
> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
> +};
> +
> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
> +{
> + return csr->csrs[reg];
> +}
> +
> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
> +{
> + csr->csrs[reg] = val;
> +}
> +
> +/* Helpers */
> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
> +{
> + return cpu_has_fpu;
> +}
> +
> +void kvm_init_fault(void);
> +
> +/* Debug: dump vcpu state */
> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
> +
> +/* MMU handling */
> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
> +void kvm_flush_tlb_all(void);
> +
> +#define KVM_ARCH_WANT_MMU_NOTIFIER
> +int kvm_unmap_hva_range(struct kvm *kvm,
> + unsigned long start, unsigned long end, bool blockable);
> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
> +
> +static inline void update_pc(struct kvm_vcpu_arch *arch)
> +{
> + arch->pc += 4;
> +}
> +
> +/**
> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
> + * @vcpu: Virtual CPU.
> + *
> + * Returns: Whether the TLBL exception was likely due to an instruction
> + * fetch fault rather than a data load fault.
> + */
> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
> +{
> + return arch->pc == arch->badv;
> +}
> +
> +/* Misc */
> +static inline void kvm_arch_hardware_unsetup(void) {}
> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
> +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) {}
> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
> + struct kvm_memory_slot *slot) {}
> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
> + const struct kvm_memory_slot *memslot);
> +void kvm_init_vmcs(struct kvm *kvm);
> +void kvm_vector_entry(void);
> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
> +extern const unsigned long kvm_vector_size;
> +extern const unsigned long kvm_enter_guest_size;
> +extern unsigned long vpid_mask;
> +extern struct kvm_world_switch *kvm_loongarch_ops;
> +
> +#define SW_GCSR (1 << 0)
> +#define HW_GCSR (1 << 1)
> +#define INVALID_GCSR (1 << 2)
> +int get_gcsr_flag(int csr);
> +extern void set_hw_gcsr(int csr_id, unsigned long val);
> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
> new file mode 100644
> index 0000000000..2fe1d4bdff
> --- /dev/null
> +++ b/arch/loongarch/include/asm/kvm_types.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
> +#define _ASM_LOONGARCH_KVM_TYPES_H
> +
> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
> +
> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
> new file mode 100644
> index 0000000000..fafda487d6
> --- /dev/null
> +++ b/arch/loongarch/include/uapi/asm/kvm.h
> @@ -0,0 +1,108 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
> +#define __UAPI_ASM_LOONGARCH_KVM_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * KVM Loongarch specific structures and definitions.
> + *
> + * Some parts derived from the x86 version of this file.
> + */
> +
> +#define __KVM_HAVE_READONLY_MEM
> +
> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
> +
> +/*
> + * for KVM_GET_REGS and KVM_SET_REGS
> + */
> +struct kvm_regs {
> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
> + __u64 gpr[32];
> + __u64 pc;
> +};
> +
> +/*
> + * for KVM_GET_FPU and KVM_SET_FPU
> + */
> +struct kvm_fpu {
> + __u32 fcsr;
> + __u64 fcc; /* 8x8 */
> + struct kvm_fpureg {
> + __u64 val64[4];
> + } fpr[32];
> +};
> +
> +/*
> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
> + * registers. The id field is broken down as follows:
> + *
> + * bits[63..52] - As per linux/kvm.h
> + * bits[51..32] - Must be zero.
> + * bits[31..16] - Register set.
> + *
> + * Register set = 0: GP registers from kvm_regs (see definitions below).
> + *
> + * Register set = 1: CSR registers.
> + *
> + * Register set = 2: KVM specific registers (see definitions below).
> + *
> + * Register set = 3: FPU / SIMD registers (see definitions below).
> + *
> + * Other sets registers may be added in the future. Each set would
> + * have its own identifier in bits[31..16].
> + */
> +
> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
How about rename to KVM_REG_LOONGARCH_FPSIMD?

Huacai

> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
> +#define KVM_CSR_IDX_MASK 0x7fff
> +#define KVM_CPUCFG_IDX_MASK 0x7fff
> +
> +/*
> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
> + */
> +
> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
> +
> +#define LOONGARCH_REG_SHIFT 3
> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
> +
> +struct kvm_debug_exit_arch {
> +};
> +
> +/* for KVM_SET_GUEST_DEBUG */
> +struct kvm_guest_debug_arch {
> +};
> +
> +/* definition of registers in kvm_run */
> +struct kvm_sync_regs {
> +};
> +
> +/* dummy definition */
> +struct kvm_sregs {
> +};
> +
> +struct kvm_iocsr_entry {
> + __u32 addr;
> + __u32 pad;
> + __u64 data;
> +};
> +
> +#define KVM_NR_IRQCHIPS 1
> +#define KVM_IRQCHIP_NUM_PINS 64
> +#define KVM_MAX_CORES 256
> +
> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 13065dd961..863f84619a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
> #define KVM_EXIT_RISCV_SBI 35
> #define KVM_EXIT_RISCV_CSR 36
> #define KVM_EXIT_NOTIFY 37
> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>
> /* For KVM_EXIT_INTERNAL_ERROR */
> /* Emulate instruction failed. */
> @@ -336,6 +337,13 @@ struct kvm_run {
> __u32 len;
> __u8 is_write;
> } mmio;
> + /* KVM_EXIT_LOONGARCH_IOCSR */
> + struct {
> + __u64 phys_addr;
> + __u8 data[8];
> + __u32 len;
> + __u8 is_write;
> + } iocsr_io;
> /* KVM_EXIT_HYPERCALL */
> struct {
> __u64 nr;
> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
> #define KVM_REG_ARM64 0x6000000000000000ULL
> #define KVM_REG_MIPS 0x7000000000000000ULL
> #define KVM_REG_RISCV 0x8000000000000000ULL
> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>
> #define KVM_REG_SIZE_SHIFT 52
> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
> --
> 2.39.1
>

2023-09-16 10:18:05

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 05/29] LoongArch: KVM: Add vcpu related header files

Hi, Tianrui,

On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>
> Add LoongArch vcpu related header files, including vcpu csr
> information, irq number defines, and some vcpu interfaces.
>
> Reviewed-by: Bibo Mao <[email protected]>
> Signed-off-by: Tianrui Zhao <[email protected]>
> ---
> arch/loongarch/include/asm/kvm_csr.h | 221 +++++++++++++++++++++++++
> arch/loongarch/include/asm/kvm_vcpu.h | 107 ++++++++++++
> arch/loongarch/include/asm/loongarch.h | 19 ++-
> arch/loongarch/kvm/trace.h | 166 +++++++++++++++++++
> 4 files changed, 508 insertions(+), 5 deletions(-)
> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
> create mode 100644 arch/loongarch/kvm/trace.h
>
> diff --git a/arch/loongarch/include/asm/kvm_csr.h b/arch/loongarch/include/asm/kvm_csr.h
> new file mode 100644
> index 0000000000..bcdff6724a
> --- /dev/null
> +++ b/arch/loongarch/include/asm/kvm_csr.h
> @@ -0,0 +1,221 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __ASM_LOONGARCH_KVM_CSR_H__
> +#define __ASM_LOONGARCH_KVM_CSR_H__
> +#include <asm/loongarch.h>
> +#include <asm/kvm_vcpu.h>
> +#include <linux/uaccess.h>
> +#include <linux/kvm_host.h>
> +
> +/* binutils support virtualization instructions */
> +#define gcsr_read(csr) \
> +({ \
> + register unsigned long __v; \
> + __asm__ __volatile__( \
> + " gcsrrd %[val], %[reg]\n\t" \
> + : [val] "=r" (__v) \
> + : [reg] "i" (csr) \
> + : "memory"); \
> + __v; \
> +})
> +
> +#define gcsr_write(v, csr) \
> +({ \
> + register unsigned long __v = v; \
> + __asm__ __volatile__ ( \
> + " gcsrwr %[val], %[reg]\n\t" \
> + : [val] "+r" (__v) \
> + : [reg] "i" (csr) \
> + : "memory"); \
> +})
> +
> +#define gcsr_xchg(v, m, csr) \
> +({ \
> + register unsigned long __v = v; \
> + __asm__ __volatile__( \
> + " gcsrxchg %[val], %[mask], %[reg]\n\t" \
> + : [val] "+r" (__v) \
> + : [mask] "r" (m), [reg] "i" (csr) \
> + : "memory"); \
> + __v; \
> +})
> +
> +/* Guest CSRS read and write */
> +#define read_gcsr_crmd() gcsr_read(LOONGARCH_CSR_CRMD)
> +#define write_gcsr_crmd(val) gcsr_write(val, LOONGARCH_CSR_CRMD)
> +#define read_gcsr_prmd() gcsr_read(LOONGARCH_CSR_PRMD)
> +#define write_gcsr_prmd(val) gcsr_write(val, LOONGARCH_CSR_PRMD)
> +#define read_gcsr_euen() gcsr_read(LOONGARCH_CSR_EUEN)
> +#define write_gcsr_euen(val) gcsr_write(val, LOONGARCH_CSR_EUEN)
> +#define read_gcsr_misc() gcsr_read(LOONGARCH_CSR_MISC)
> +#define write_gcsr_misc(val) gcsr_write(val, LOONGARCH_CSR_MISC)
> +#define read_gcsr_ecfg() gcsr_read(LOONGARCH_CSR_ECFG)
> +#define write_gcsr_ecfg(val) gcsr_write(val, LOONGARCH_CSR_ECFG)
> +#define read_gcsr_estat() gcsr_read(LOONGARCH_CSR_ESTAT)
> +#define write_gcsr_estat(val) gcsr_write(val, LOONGARCH_CSR_ESTAT)
> +#define read_gcsr_era() gcsr_read(LOONGARCH_CSR_ERA)
> +#define write_gcsr_era(val) gcsr_write(val, LOONGARCH_CSR_ERA)
> +#define read_gcsr_badv() gcsr_read(LOONGARCH_CSR_BADV)
> +#define write_gcsr_badv(val) gcsr_write(val, LOONGARCH_CSR_BADV)
> +#define read_gcsr_badi() gcsr_read(LOONGARCH_CSR_BADI)
> +#define write_gcsr_badi(val) gcsr_write(val, LOONGARCH_CSR_BADI)
> +#define read_gcsr_eentry() gcsr_read(LOONGARCH_CSR_EENTRY)
> +#define write_gcsr_eentry(val) gcsr_write(val, LOONGARCH_CSR_EENTRY)
> +
> +#define read_gcsr_tlbidx() gcsr_read(LOONGARCH_CSR_TLBIDX)
> +#define write_gcsr_tlbidx(val) gcsr_write(val, LOONGARCH_CSR_TLBIDX)
> +#define read_gcsr_tlbhi() gcsr_read(LOONGARCH_CSR_TLBEHI)
> +#define write_gcsr_tlbhi(val) gcsr_write(val, LOONGARCH_CSR_TLBEHI)
> +#define read_gcsr_tlblo0() gcsr_read(LOONGARCH_CSR_TLBELO0)
> +#define write_gcsr_tlblo0(val) gcsr_write(val, LOONGARCH_CSR_TLBELO0)
> +#define read_gcsr_tlblo1() gcsr_read(LOONGARCH_CSR_TLBELO1)
> +#define write_gcsr_tlblo1(val) gcsr_write(val, LOONGARCH_CSR_TLBELO1)
> +
> +#define read_gcsr_asid() gcsr_read(LOONGARCH_CSR_ASID)
> +#define write_gcsr_asid(val) gcsr_write(val, LOONGARCH_CSR_ASID)
> +#define read_gcsr_pgdl() gcsr_read(LOONGARCH_CSR_PGDL)
> +#define write_gcsr_pgdl(val) gcsr_write(val, LOONGARCH_CSR_PGDL)
> +#define read_gcsr_pgdh() gcsr_read(LOONGARCH_CSR_PGDH)
> +#define write_gcsr_pgdh(val) gcsr_write(val, LOONGARCH_CSR_PGDH)
> +#define write_gcsr_pgd(val) gcsr_write(val, LOONGARCH_CSR_PGD)
> +#define read_gcsr_pgd() gcsr_read(LOONGARCH_CSR_PGD)
> +#define read_gcsr_pwctl0() gcsr_read(LOONGARCH_CSR_PWCTL0)
> +#define write_gcsr_pwctl0(val) gcsr_write(val, LOONGARCH_CSR_PWCTL0)
> +#define read_gcsr_pwctl1() gcsr_read(LOONGARCH_CSR_PWCTL1)
> +#define write_gcsr_pwctl1(val) gcsr_write(val, LOONGARCH_CSR_PWCTL1)
> +#define read_gcsr_stlbpgsize() gcsr_read(LOONGARCH_CSR_STLBPGSIZE)
> +#define write_gcsr_stlbpgsize(val) gcsr_write(val, LOONGARCH_CSR_STLBPGSIZE)
> +#define read_gcsr_rvacfg() gcsr_read(LOONGARCH_CSR_RVACFG)
> +#define write_gcsr_rvacfg(val) gcsr_write(val, LOONGARCH_CSR_RVACFG)
> +
> +#define read_gcsr_cpuid() gcsr_read(LOONGARCH_CSR_CPUID)
> +#define write_gcsr_cpuid(val) gcsr_write(val, LOONGARCH_CSR_CPUID)
> +#define read_gcsr_prcfg1() gcsr_read(LOONGARCH_CSR_PRCFG1)
> +#define write_gcsr_prcfg1(val) gcsr_write(val, LOONGARCH_CSR_PRCFG1)
> +#define read_gcsr_prcfg2() gcsr_read(LOONGARCH_CSR_PRCFG2)
> +#define write_gcsr_prcfg2(val) gcsr_write(val, LOONGARCH_CSR_PRCFG2)
> +#define read_gcsr_prcfg3() gcsr_read(LOONGARCH_CSR_PRCFG3)
> +#define write_gcsr_prcfg3(val) gcsr_write(val, LOONGARCH_CSR_PRCFG3)
> +
> +#define read_gcsr_kscratch0() gcsr_read(LOONGARCH_CSR_KS0)
> +#define write_gcsr_kscratch0(val) gcsr_write(val, LOONGARCH_CSR_KS0)
> +#define read_gcsr_kscratch1() gcsr_read(LOONGARCH_CSR_KS1)
> +#define write_gcsr_kscratch1(val) gcsr_write(val, LOONGARCH_CSR_KS1)
> +#define read_gcsr_kscratch2() gcsr_read(LOONGARCH_CSR_KS2)
> +#define write_gcsr_kscratch2(val) gcsr_write(val, LOONGARCH_CSR_KS2)
> +#define read_gcsr_kscratch3() gcsr_read(LOONGARCH_CSR_KS3)
> +#define write_gcsr_kscratch3(val) gcsr_write(val, LOONGARCH_CSR_KS3)
> +#define read_gcsr_kscratch4() gcsr_read(LOONGARCH_CSR_KS4)
> +#define write_gcsr_kscratch4(val) gcsr_write(val, LOONGARCH_CSR_KS4)
> +#define read_gcsr_kscratch5() gcsr_read(LOONGARCH_CSR_KS5)
> +#define write_gcsr_kscratch5(val) gcsr_write(val, LOONGARCH_CSR_KS5)
> +#define read_gcsr_kscratch6() gcsr_read(LOONGARCH_CSR_KS6)
> +#define write_gcsr_kscratch6(val) gcsr_write(val, LOONGARCH_CSR_KS6)
> +#define read_gcsr_kscratch7() gcsr_read(LOONGARCH_CSR_KS7)
> +#define write_gcsr_kscratch7(val) gcsr_write(val, LOONGARCH_CSR_KS7)
> +
> +#define read_gcsr_timerid() gcsr_read(LOONGARCH_CSR_TMID)
> +#define write_gcsr_timerid(val) gcsr_write(val, LOONGARCH_CSR_TMID)
> +#define read_gcsr_timercfg() gcsr_read(LOONGARCH_CSR_TCFG)
> +#define write_gcsr_timercfg(val) gcsr_write(val, LOONGARCH_CSR_TCFG)
> +#define read_gcsr_timertick() gcsr_read(LOONGARCH_CSR_TVAL)
> +#define write_gcsr_timertick(val) gcsr_write(val, LOONGARCH_CSR_TVAL)
> +#define read_gcsr_timeroffset() gcsr_read(LOONGARCH_CSR_CNTC)
> +#define write_gcsr_timeroffset(val) gcsr_write(val, LOONGARCH_CSR_CNTC)
> +
> +#define read_gcsr_llbctl() gcsr_read(LOONGARCH_CSR_LLBCTL)
> +#define write_gcsr_llbctl(val) gcsr_write(val, LOONGARCH_CSR_LLBCTL)
> +
> +#define read_gcsr_tlbrentry() gcsr_read(LOONGARCH_CSR_TLBRENTRY)
> +#define write_gcsr_tlbrentry(val) gcsr_write(val, LOONGARCH_CSR_TLBRENTRY)
> +#define read_gcsr_tlbrbadv() gcsr_read(LOONGARCH_CSR_TLBRBADV)
> +#define write_gcsr_tlbrbadv(val) gcsr_write(val, LOONGARCH_CSR_TLBRBADV)
> +#define read_gcsr_tlbrera() gcsr_read(LOONGARCH_CSR_TLBRERA)
> +#define write_gcsr_tlbrera(val) gcsr_write(val, LOONGARCH_CSR_TLBRERA)
> +#define read_gcsr_tlbrsave() gcsr_read(LOONGARCH_CSR_TLBRSAVE)
> +#define write_gcsr_tlbrsave(val) gcsr_write(val, LOONGARCH_CSR_TLBRSAVE)
> +#define read_gcsr_tlbrelo0() gcsr_read(LOONGARCH_CSR_TLBRELO0)
> +#define write_gcsr_tlbrelo0(val) gcsr_write(val, LOONGARCH_CSR_TLBRELO0)
> +#define read_gcsr_tlbrelo1() gcsr_read(LOONGARCH_CSR_TLBRELO1)
> +#define write_gcsr_tlbrelo1(val) gcsr_write(val, LOONGARCH_CSR_TLBRELO1)
> +#define read_gcsr_tlbrehi() gcsr_read(LOONGARCH_CSR_TLBREHI)
> +#define write_gcsr_tlbrehi(val) gcsr_write(val, LOONGARCH_CSR_TLBREHI)
> +#define read_gcsr_tlbrprmd() gcsr_read(LOONGARCH_CSR_TLBRPRMD)
> +#define write_gcsr_tlbrprmd(val) gcsr_write(val, LOONGARCH_CSR_TLBRPRMD)
> +
> +#define read_gcsr_directwin0() gcsr_read(LOONGARCH_CSR_DMWIN0)
> +#define write_gcsr_directwin0(val) gcsr_write(val, LOONGARCH_CSR_DMWIN0)
> +#define read_gcsr_directwin1() gcsr_read(LOONGARCH_CSR_DMWIN1)
> +#define write_gcsr_directwin1(val) gcsr_write(val, LOONGARCH_CSR_DMWIN1)
> +#define read_gcsr_directwin2() gcsr_read(LOONGARCH_CSR_DMWIN2)
> +#define write_gcsr_directwin2(val) gcsr_write(val, LOONGARCH_CSR_DMWIN2)
> +#define read_gcsr_directwin3() gcsr_read(LOONGARCH_CSR_DMWIN3)
> +#define write_gcsr_directwin3(val) gcsr_write(val, LOONGARCH_CSR_DMWIN3)
> +
> +/* Guest related CSRs */
> +#define read_csr_gtlbc() csr_read64(LOONGARCH_CSR_GTLBC)
> +#define write_csr_gtlbc(val) csr_write64(val, LOONGARCH_CSR_GTLBC)
> +#define read_csr_trgp() csr_read64(LOONGARCH_CSR_TRGP)
> +#define read_csr_gcfg() csr_read64(LOONGARCH_CSR_GCFG)
> +#define write_csr_gcfg(val) csr_write64(val, LOONGARCH_CSR_GCFG)
> +#define read_csr_gstat() csr_read64(LOONGARCH_CSR_GSTAT)
> +#define write_csr_gstat(val) csr_write64(val, LOONGARCH_CSR_GSTAT)
> +#define read_csr_gintc() csr_read64(LOONGARCH_CSR_GINTC)
> +#define write_csr_gintc(val) csr_write64(val, LOONGARCH_CSR_GINTC)
> +#define read_csr_gcntc() csr_read64(LOONGARCH_CSR_GCNTC)
> +#define write_csr_gcntc(val) csr_write64(val, LOONGARCH_CSR_GCNTC)
> +
> +#define __BUILD_GCSR_OP(name) __BUILD_CSR_COMMON(gcsr_##name)
> +
> +__BUILD_GCSR_OP(llbctl)
> +__BUILD_GCSR_OP(tlbidx)
> +__BUILD_CSR_OP(gcfg)
> +__BUILD_CSR_OP(gstat)
> +__BUILD_CSR_OP(gtlbc)
> +__BUILD_CSR_OP(gintc)
> +
> +#define set_gcsr_estat(val) \
> + gcsr_xchg(val, val, LOONGARCH_CSR_ESTAT)
> +#define clear_gcsr_estat(val) \
> + gcsr_xchg(~(val), val, LOONGARCH_CSR_ESTAT)
> +
> +#define kvm_read_hw_gcsr(id) gcsr_read(id)
> +#define kvm_write_hw_gcsr(id, val) gcsr_write(val, id)
> +
> +int kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v);
> +int kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 v);
> +int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu);
> +
> +#define kvm_save_hw_gcsr(csr, gid) (csr->csrs[gid] = gcsr_read(gid))
> +#define kvm_restore_hw_gcsr(csr, gid) (gcsr_write(csr->csrs[gid], gid))
> +
> +static __always_inline unsigned long kvm_read_sw_gcsr(struct loongarch_csrs *csr, int gid)
> +{
> + return csr->csrs[gid];
> +}
> +
> +static __always_inline void kvm_write_sw_gcsr(struct loongarch_csrs *csr,
> + int gid, unsigned long val)
> +{
> + csr->csrs[gid] = val;
> +}
> +
> +static __always_inline void kvm_set_sw_gcsr(struct loongarch_csrs *csr,
> + int gid, unsigned long val)
> +{
> + csr->csrs[gid] |= val;
> +}
> +
> +static __always_inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr,
> + int gid, unsigned long mask,
> + unsigned long val)
> +{
> + unsigned long _mask = mask;
> +
> + csr->csrs[gid] &= ~_mask;
> + csr->csrs[gid] |= val & _mask;
> +}
> +#endif /* __ASM_LOONGARCH_KVM_CSR_H__ */
> diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
> new file mode 100644
> index 0000000000..7756f27183
> --- /dev/null
> +++ b/arch/loongarch/include/asm/kvm_vcpu.h
> @@ -0,0 +1,107 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __ASM_LOONGARCH_KVM_VCPU_H__
> +#define __ASM_LOONGARCH_KVM_VCPU_H__
> +
> +#include <linux/kvm_host.h>
> +#include <asm/loongarch.h>
> +
> +/* Controlled by 0x5 guest exst */
> +#define CPU_SIP0 (_ULCAST_(1))
> +#define CPU_SIP1 (_ULCAST_(1) << 1)
> +#define CPU_PMU (_ULCAST_(1) << 10)
> +#define CPU_TIMER (_ULCAST_(1) << 11)
> +#define CPU_IPI (_ULCAST_(1) << 12)
> +
> +/* Controlled by 0x52 guest exception VIP
> + * aligned to exst bit 5~12
> + */
> +#define CPU_IP0 (_ULCAST_(1))
> +#define CPU_IP1 (_ULCAST_(1) << 1)
> +#define CPU_IP2 (_ULCAST_(1) << 2)
> +#define CPU_IP3 (_ULCAST_(1) << 3)
> +#define CPU_IP4 (_ULCAST_(1) << 4)
> +#define CPU_IP5 (_ULCAST_(1) << 5)
> +#define CPU_IP6 (_ULCAST_(1) << 6)
> +#define CPU_IP7 (_ULCAST_(1) << 7)
> +
> +#define MNSEC_PER_SEC (NSEC_PER_SEC >> 20)
> +
> +/* KVM_IRQ_LINE irq field index values */
> +#define KVM_LOONGSON_IRQ_TYPE_SHIFT 24
> +#define KVM_LOONGSON_IRQ_TYPE_MASK 0xff
> +#define KVM_LOONGSON_IRQ_VCPU_SHIFT 16
> +#define KVM_LOONGSON_IRQ_VCPU_MASK 0xff
> +#define KVM_LOONGSON_IRQ_NUM_SHIFT 0
> +#define KVM_LOONGSON_IRQ_NUM_MASK 0xffff
> +
> +/* Irq_type field */
> +#define KVM_LOONGSON_IRQ_TYPE_CPU_IP 0
> +#define KVM_LOONGSON_IRQ_TYPE_CPU_IO 1
> +#define KVM_LOONGSON_IRQ_TYPE_HT 2
> +#define KVM_LOONGSON_IRQ_TYPE_MSI 3
> +#define KVM_LOONGSON_IRQ_TYPE_IOAPIC 4
> +#define KVM_LOONGSON_IRQ_TYPE_ROUTE 5
I think the types should be refined, so please give me a better definition.

> +
> +/* Out-of-kernel GIC cpu interrupt injection irq_number field */
> +#define KVM_LOONGSON_IRQ_CPU_IRQ 0
> +#define KVM_LOONGSON_IRQ_CPU_FIQ 1
> +#define KVM_LOONGSON_CPU_IP_NUM 8
And these lines should be removed, right?

Huacai

> +
> +typedef union loongarch_instruction larch_inst;
> +typedef int (*exit_handle_fn)(struct kvm_vcpu *);
> +
> +int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst);
> +int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst);
> +int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
> +int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
> +int kvm_emu_idle(struct kvm_vcpu *vcpu);
> +int kvm_handle_pv_hcall(struct kvm_vcpu *vcpu);
> +int kvm_pending_timer(struct kvm_vcpu *vcpu);
> +int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
> +void kvm_deliver_intr(struct kvm_vcpu *vcpu);
> +void kvm_deliver_exception(struct kvm_vcpu *vcpu);
> +
> +void kvm_own_fpu(struct kvm_vcpu *vcpu);
> +void kvm_lose_fpu(struct kvm_vcpu *vcpu);
> +void kvm_save_fpu(struct loongarch_fpu *fpu);
> +void kvm_restore_fpu(struct loongarch_fpu *fpu);
> +void kvm_restore_fcsr(struct loongarch_fpu *fpu);
> +
> +void kvm_acquire_timer(struct kvm_vcpu *vcpu);
> +void kvm_reset_timer(struct kvm_vcpu *vcpu);
> +void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz);
> +void kvm_restore_timer(struct kvm_vcpu *vcpu);
> +void kvm_save_timer(struct kvm_vcpu *vcpu);
> +
> +int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
> +/*
> + * Loongarch KVM guest interrupt handling
> + */
> +static inline void kvm_queue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
> +{
> + set_bit(irq, &vcpu->arch.irq_pending);
> + clear_bit(irq, &vcpu->arch.irq_clear);
> +}
> +
> +static inline void kvm_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
> +{
> + clear_bit(irq, &vcpu->arch.irq_pending);
> + set_bit(irq, &vcpu->arch.irq_clear);
> +}
> +
> +static inline int kvm_queue_exception(struct kvm_vcpu *vcpu,
> + unsigned int code, unsigned int subcode)
> +{
> + /* only one exception can be injected */
> + if (!vcpu->arch.exception_pending) {
> + set_bit(code, &vcpu->arch.exception_pending);
> + vcpu->arch.subcode = subcode;
> + return 0;
> + } else
> + return -1;
> +}
> +#endif /* __ASM_LOONGARCH_KVM_VCPU_H__ */
> diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
> index 33531d432b..9b4957cefa 100644
> --- a/arch/loongarch/include/asm/loongarch.h
> +++ b/arch/loongarch/include/asm/loongarch.h
> @@ -226,6 +226,7 @@
> #define LOONGARCH_CSR_ECFG 0x4 /* Exception config */
> #define CSR_ECFG_VS_SHIFT 16
> #define CSR_ECFG_VS_WIDTH 3
> +#define CSR_ECFG_VS_SHIFT_END (CSR_ECFG_VS_SHIFT + CSR_ECFG_VS_WIDTH - 1)
> #define CSR_ECFG_VS (_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT)
> #define CSR_ECFG_IM_SHIFT 0
> #define CSR_ECFG_IM_WIDTH 14
> @@ -314,13 +315,14 @@
> #define CSR_TLBLO1_V (_ULCAST_(0x1) << CSR_TLBLO1_V_SHIFT)
>
> #define LOONGARCH_CSR_GTLBC 0x15 /* Guest TLB control */
> -#define CSR_GTLBC_RID_SHIFT 16
> -#define CSR_GTLBC_RID_WIDTH 8
> -#define CSR_GTLBC_RID (_ULCAST_(0xff) << CSR_GTLBC_RID_SHIFT)
> +#define CSR_GTLBC_TGID_SHIFT 16
> +#define CSR_GTLBC_TGID_WIDTH 8
> +#define CSR_GTLBC_TGID_SHIFT_END (CSR_GTLBC_TGID_SHIFT + CSR_GTLBC_TGID_WIDTH - 1)
> +#define CSR_GTLBC_TGID (_ULCAST_(0xff) << CSR_GTLBC_TGID_SHIFT)
> #define CSR_GTLBC_TOTI_SHIFT 13
> #define CSR_GTLBC_TOTI (_ULCAST_(0x1) << CSR_GTLBC_TOTI_SHIFT)
> -#define CSR_GTLBC_USERID_SHIFT 12
> -#define CSR_GTLBC_USERID (_ULCAST_(0x1) << CSR_GTLBC_USERID_SHIFT)
> +#define CSR_GTLBC_USETGID_SHIFT 12
> +#define CSR_GTLBC_USETGID (_ULCAST_(0x1) << CSR_GTLBC_USETGID_SHIFT)
> #define CSR_GTLBC_GMTLBSZ_SHIFT 0
> #define CSR_GTLBC_GMTLBSZ_WIDTH 6
> #define CSR_GTLBC_GMTLBSZ (_ULCAST_(0x3f) << CSR_GTLBC_GMTLBSZ_SHIFT)
> @@ -475,6 +477,7 @@
> #define LOONGARCH_CSR_GSTAT 0x50 /* Guest status */
> #define CSR_GSTAT_GID_SHIFT 16
> #define CSR_GSTAT_GID_WIDTH 8
> +#define CSR_GSTAT_GID_SHIFT_END (CSR_GSTAT_GID_SHIFT + CSR_GSTAT_GID_WIDTH - 1)
> #define CSR_GSTAT_GID (_ULCAST_(0xff) << CSR_GSTAT_GID_SHIFT)
> #define CSR_GSTAT_GIDBIT_SHIFT 4
> #define CSR_GSTAT_GIDBIT_WIDTH 6
> @@ -525,6 +528,12 @@
> #define CSR_GCFG_MATC_GUEST (_ULCAST_(0x0) << CSR_GCFG_MATC_SHITF)
> #define CSR_GCFG_MATC_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATC_SHITF)
> #define CSR_GCFG_MATC_NEST (_ULCAST_(0x2) << CSR_GCFG_MATC_SHITF)
> +#define CSR_GCFG_MATP_NEST_SHIFT 2
> +#define CSR_GCFG_MATP_NEST (_ULCAST_(0x1) << CSR_GCFG_MATP_NEST_SHIFT)
> +#define CSR_GCFG_MATP_ROOT_SHIFT 1
> +#define CSR_GCFG_MATP_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATP_ROOT_SHIFT)
> +#define CSR_GCFG_MATP_GUEST_SHIFT 0
> +#define CSR_GCFG_MATP_GUEST (_ULCAST_(0x1) << CSR_GCFG_MATP_GUEST_SHIFT)
>
> #define LOONGARCH_CSR_GINTC 0x52 /* Guest interrupt control */
> #define CSR_GINTC_HC_SHIFT 16
> diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h
> new file mode 100644
> index 0000000000..134b5968f6
> --- /dev/null
> +++ b/arch/loongarch/kvm/trace.h
> @@ -0,0 +1,166 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
> +#define _TRACE_KVM_H
> +
> +#include <linux/tracepoint.h>
> +#include <asm/kvm_csr.h>
> +
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM kvm
> +
> +/*
> + * Tracepoints for VM enters
> + */
> +DECLARE_EVENT_CLASS(kvm_transition,
> + TP_PROTO(struct kvm_vcpu *vcpu),
> + TP_ARGS(vcpu),
> + TP_STRUCT__entry(
> + __field(unsigned long, pc)
> + ),
> +
> + TP_fast_assign(
> + __entry->pc = vcpu->arch.pc;
> + ),
> +
> + TP_printk("PC: 0x%08lx",
> + __entry->pc)
> +);
> +
> +DEFINE_EVENT(kvm_transition, kvm_enter,
> + TP_PROTO(struct kvm_vcpu *vcpu),
> + TP_ARGS(vcpu));
> +
> +DEFINE_EVENT(kvm_transition, kvm_reenter,
> + TP_PROTO(struct kvm_vcpu *vcpu),
> + TP_ARGS(vcpu));
> +
> +DEFINE_EVENT(kvm_transition, kvm_out,
> + TP_PROTO(struct kvm_vcpu *vcpu),
> + TP_ARGS(vcpu));
> +
> +/* Further exit reasons */
> +#define KVM_TRACE_EXIT_IDLE 64
> +#define KVM_TRACE_EXIT_CACHE 65
> +
> +/* Tracepoints for VM exits */
> +#define kvm_trace_symbol_exit_types \
> + { KVM_TRACE_EXIT_IDLE, "IDLE" }, \
> + { KVM_TRACE_EXIT_CACHE, "CACHE" }
> +
> +TRACE_EVENT(kvm_exit_gspr,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int inst_word),
> + TP_ARGS(vcpu, inst_word),
> + TP_STRUCT__entry(
> + __field(unsigned int, inst_word)
> + ),
> +
> + TP_fast_assign(
> + __entry->inst_word = inst_word;
> + ),
> +
> + TP_printk("inst word: 0x%08x",
> + __entry->inst_word)
> +);
> +
> +
> +DECLARE_EVENT_CLASS(kvm_exit,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
> + TP_ARGS(vcpu, reason),
> + TP_STRUCT__entry(
> + __field(unsigned long, pc)
> + __field(unsigned int, reason)
> + ),
> +
> + TP_fast_assign(
> + __entry->pc = vcpu->arch.pc;
> + __entry->reason = reason;
> + ),
> +
> + TP_printk("[%s]PC: 0x%08lx",
> + __print_symbolic(__entry->reason,
> + kvm_trace_symbol_exit_types),
> + __entry->pc)
> +);
> +
> +DEFINE_EVENT(kvm_exit, kvm_exit_idle,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
> + TP_ARGS(vcpu, reason));
> +
> +DEFINE_EVENT(kvm_exit, kvm_exit_cache,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
> + TP_ARGS(vcpu, reason));
> +
> +DEFINE_EVENT(kvm_exit, kvm_exit,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
> + TP_ARGS(vcpu, reason));
> +
> +#define KVM_TRACE_AUX_RESTORE 0
> +#define KVM_TRACE_AUX_SAVE 1
> +#define KVM_TRACE_AUX_ENABLE 2
> +#define KVM_TRACE_AUX_DISABLE 3
> +#define KVM_TRACE_AUX_DISCARD 4
> +
> +#define KVM_TRACE_AUX_FPU 1
> +
> +#define kvm_trace_symbol_aux_op \
> + { KVM_TRACE_AUX_RESTORE, "restore" }, \
> + { KVM_TRACE_AUX_SAVE, "save" }, \
> + { KVM_TRACE_AUX_ENABLE, "enable" }, \
> + { KVM_TRACE_AUX_DISABLE, "disable" }, \
> + { KVM_TRACE_AUX_DISCARD, "discard" }
> +
> +#define kvm_trace_symbol_aux_state \
> + { KVM_TRACE_AUX_FPU, "FPU" }
> +
> +TRACE_EVENT(kvm_aux,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
> + unsigned int state),
> + TP_ARGS(vcpu, op, state),
> + TP_STRUCT__entry(
> + __field(unsigned long, pc)
> + __field(u8, op)
> + __field(u8, state)
> + ),
> +
> + TP_fast_assign(
> + __entry->pc = vcpu->arch.pc;
> + __entry->op = op;
> + __entry->state = state;
> + ),
> +
> + TP_printk("%s %s PC: 0x%08lx",
> + __print_symbolic(__entry->op,
> + kvm_trace_symbol_aux_op),
> + __print_symbolic(__entry->state,
> + kvm_trace_symbol_aux_state),
> + __entry->pc)
> +);
> +
> +TRACE_EVENT(kvm_vpid_change,
> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned long vpid),
> + TP_ARGS(vcpu, vpid),
> + TP_STRUCT__entry(
> + __field(unsigned long, vpid)
> + ),
> +
> + TP_fast_assign(
> + __entry->vpid = vpid;
> + ),
> +
> + TP_printk("vpid: 0x%08lx",
> + __entry->vpid)
> +);
> +
> +#endif /* _TRACE_LOONGARCH64_KVM_H */
> +
> +#undef TRACE_INCLUDE_PATH
> +#define TRACE_INCLUDE_PATH ../../arch/loongarch/kvm
> +#undef TRACE_INCLUDE_FILE
> +#define TRACE_INCLUDE_FILE trace
> +
> +/* This part must be outside protection */
> +#include <trace/define_trace.h>
> --
> 2.39.1
>
>

2023-09-17 14:43:49

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files

Hi, Tianrui,

On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>
> Add LoongArch KVM related header files, including kvm.h,
> kvm_host.h, kvm_types.h. All of those are about LoongArch
> virtualization features and kvm interfaces.
>
> Reviewed-by: Bibo Mao <[email protected]>
> Signed-off-by: Tianrui Zhao <[email protected]>
> ---
> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
> arch/loongarch/include/asm/kvm_types.h | 11 ++
> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
> include/uapi/linux/kvm.h | 9 +
> 4 files changed, 373 insertions(+)
> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>
> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
> new file mode 100644
> index 0000000000..00e0c1876b
> --- /dev/null
> +++ b/arch/loongarch/include/asm/kvm_host.h
> @@ -0,0 +1,245 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
> +#define __ASM_LOONGARCH_KVM_HOST_H__
> +
> +#include <linux/cpumask.h>
> +#include <linux/mutex.h>
> +#include <linux/hrtimer.h>
> +#include <linux/interrupt.h>
> +#include <linux/types.h>
> +#include <linux/kvm.h>
> +#include <linux/kvm_types.h>
> +#include <linux/threads.h>
> +#include <linux/spinlock.h>
> +
> +#include <asm/inst.h>
> +#include <asm/kvm_mmu.h>
> +#include <asm/loongarch.h>
> +
> +/* Loongarch KVM register ids */
> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> +
> +#define KVM_MAX_VCPUS 256
> +#define KVM_MAX_CPUCFG_REGS 21
> +/* memory slots that does not exposed to userspace */
> +#define KVM_PRIVATE_MEM_SLOTS 0
> +
> +#define KVM_HALT_POLL_NS_DEFAULT 500000
> +
> +struct kvm_vm_stat {
> + struct kvm_vm_stat_generic generic;
> + u64 pages;
> + u64 hugepages;
> +};
> +
> +struct kvm_vcpu_stat {
> + struct kvm_vcpu_stat_generic generic;
> + u64 idle_exits;
> + u64 signal_exits;
> + u64 int_exits;
> + u64 cpucfg_exits;
> +};
> +
> +struct kvm_arch_memory_slot {
> +};
> +
> +struct kvm_context {
> + unsigned long vpid_cache;
> + struct kvm_vcpu *last_vcpu;
> +};
> +
> +struct kvm_world_switch {
> + int (*guest_eentry)(void);
> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> + unsigned long page_order;
> +};
> +
> +#define MAX_PGTABLE_LEVELS 4
> +struct kvm_arch {
> + /* Guest physical mm */
> + kvm_pte_t *pgd;
> + unsigned long gpa_size;
> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
> + unsigned int root_level;
> +
> + s64 time_offset;
> + struct kvm_context __percpu *vmcs;
> +};
> +
> +#define CSR_MAX_NUMS 0x800
> +
> +struct loongarch_csrs {
> + unsigned long csrs[CSR_MAX_NUMS];
> +};
> +
> +/* Resume Flags */
> +#define RESUME_HOST 0
> +#define RESUME_GUEST 1
> +
> +enum emulation_result {
> + EMULATE_DONE, /* no further processing */
> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
> + EMULATE_FAIL, /* can't emulate this instruction */
> + EMULATE_EXCEPT, /* A guest exception has been generated */
> + EMULATE_DO_IOCSR, /* handle IOCSR request */
> +};
> +
> +#define KVM_LARCH_FPU (0x1 << 0)
> +#define KVM_LARCH_CSR (0x1 << 1)
> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
> +
> +struct kvm_vcpu_arch {
> + /*
> + * Switch pointer-to-function type to unsigned long
> + * for loading the value into register directly.
> + */
> + unsigned long host_eentry;
> + unsigned long guest_eentry;
> +
> + /* Pointers stored here for easy accessing from assembly code */
> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> +
> + /* Host registers preserved across guest mode execution */
> + unsigned long host_sp;
> + unsigned long host_tp;
> + unsigned long host_pgd;
> +
> + /* Host CSRs are used when handling exits from guest */
> + unsigned long badi;
> + unsigned long badv;
> + unsigned long host_ecfg;
> + unsigned long host_estat;
> + unsigned long host_percpu;
> +
> + /* GPRs */
> + unsigned long gprs[32];
> + unsigned long pc;
> +
> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
> + unsigned int aux_inuse;
> + /* FPU state */
> + struct loongarch_fpu fpu FPU_ALIGN;
> +
> + /* CSR state */
> + struct loongarch_csrs *csr;
> +
> + /* GPR used as IO source/target */
> + u32 io_gpr;
> +
> + struct hrtimer swtimer;
> + /* KVM register to control count timer */
> + u32 count_ctl;
> +
> + /* Bitmask of intr that are pending */
> + unsigned long irq_pending;
> + /* Bitmask of pending intr to be cleared */
> + unsigned long irq_clear;
> +
> + /* Bitmask of exceptions that are pending */
> + unsigned long exception_pending;
> + unsigned int subcode;
> +
> + /* Cache for pages needed inside spinlock regions */
> + struct kvm_mmu_memory_cache mmu_page_cache;
> +
> + /* vcpu's vpid */
> + u64 vpid;
> +
> + /* Frequency of stable timer in Hz */
> + u64 timer_mhz;
> + ktime_t expire;
> +
> + u64 core_ext_ioisr[4];
> +
> + /* Last CPU the vCPU state was loaded on */
> + int last_sched_cpu;
> + /* mp state */
> + struct kvm_mp_state mp_state;
> + /* cpucfg */
> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
> +};
> +
> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
> +{
> + return csr->csrs[reg];
> +}
> +
> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
> +{
> + csr->csrs[reg] = val;
> +}
> +
> +/* Helpers */
> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
> +{
> + return cpu_has_fpu;
> +}
> +
> +void kvm_init_fault(void);
> +
> +/* Debug: dump vcpu state */
> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
> +
> +/* MMU handling */
> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
> +void kvm_flush_tlb_all(void);
> +
> +#define KVM_ARCH_WANT_MMU_NOTIFIER
> +int kvm_unmap_hva_range(struct kvm *kvm,
> + unsigned long start, unsigned long end, bool blockable);
> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
> +
> +static inline void update_pc(struct kvm_vcpu_arch *arch)
> +{
> + arch->pc += 4;
> +}
> +
> +/**
> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
> + * @vcpu: Virtual CPU.
> + *
> + * Returns: Whether the TLBL exception was likely due to an instruction
> + * fetch fault rather than a data load fault.
> + */
> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
> +{
> + return arch->pc == arch->badv;
> +}
> +
> +/* Misc */
> +static inline void kvm_arch_hardware_unsetup(void) {}
> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
> +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) {}
> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
> + struct kvm_memory_slot *slot) {}
> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
> + const struct kvm_memory_slot *memslot);
> +void kvm_init_vmcs(struct kvm *kvm);
> +void kvm_vector_entry(void);
> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
> +extern const unsigned long kvm_vector_size;
> +extern const unsigned long kvm_enter_guest_size;
> +extern unsigned long vpid_mask;
> +extern struct kvm_world_switch *kvm_loongarch_ops;
> +
> +#define SW_GCSR (1 << 0)
> +#define HW_GCSR (1 << 1)
> +#define INVALID_GCSR (1 << 2)
> +int get_gcsr_flag(int csr);
> +extern void set_hw_gcsr(int csr_id, unsigned long val);
> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
> new file mode 100644
> index 0000000000..2fe1d4bdff
> --- /dev/null
> +++ b/arch/loongarch/include/asm/kvm_types.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
> +#define _ASM_LOONGARCH_KVM_TYPES_H
> +
> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
> +
> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
> new file mode 100644
> index 0000000000..fafda487d6
> --- /dev/null
> +++ b/arch/loongarch/include/uapi/asm/kvm.h
> @@ -0,0 +1,108 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
> +#define __UAPI_ASM_LOONGARCH_KVM_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * KVM Loongarch specific structures and definitions.
> + *
> + * Some parts derived from the x86 version of this file.
> + */
> +
> +#define __KVM_HAVE_READONLY_MEM
> +
> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
> +
> +/*
> + * for KVM_GET_REGS and KVM_SET_REGS
> + */
> +struct kvm_regs {
> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
> + __u64 gpr[32];
> + __u64 pc;
> +};
> +
> +/*
> + * for KVM_GET_FPU and KVM_SET_FPU
> + */
> +struct kvm_fpu {
> + __u32 fcsr;
> + __u64 fcc; /* 8x8 */
> + struct kvm_fpureg {
> + __u64 val64[4];
> + } fpr[32];
> +};
> +
> +/*
> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
> + * registers. The id field is broken down as follows:
> + *
> + * bits[63..52] - As per linux/kvm.h
> + * bits[51..32] - Must be zero.
> + * bits[31..16] - Register set.
> + *
> + * Register set = 0: GP registers from kvm_regs (see definitions below).
> + *
> + * Register set = 1: CSR registers.
> + *
> + * Register set = 2: KVM specific registers (see definitions below).
> + *
> + * Register set = 3: FPU / SIMD registers (see definitions below).
> + *
> + * Other sets registers may be added in the future. Each set would
> + * have its own identifier in bits[31..16].
> + */
> +
> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
> +#define KVM_CSR_IDX_MASK 0x7fff
> +#define KVM_CPUCFG_IDX_MASK 0x7fff
> +
> +/*
> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
> + */
> +
> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
Why begin with 3? 0, 1, 2 reserved for what?

Huacai

> +
> +#define LOONGARCH_REG_SHIFT 3
> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
> +
> +struct kvm_debug_exit_arch {
> +};
> +
> +/* for KVM_SET_GUEST_DEBUG */
> +struct kvm_guest_debug_arch {
> +};
> +
> +/* definition of registers in kvm_run */
> +struct kvm_sync_regs {
> +};
> +
> +/* dummy definition */
> +struct kvm_sregs {
> +};
> +
> +struct kvm_iocsr_entry {
> + __u32 addr;
> + __u32 pad;
> + __u64 data;
> +};
> +
> +#define KVM_NR_IRQCHIPS 1
> +#define KVM_IRQCHIP_NUM_PINS 64
> +#define KVM_MAX_CORES 256
> +
> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 13065dd961..863f84619a 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
> #define KVM_EXIT_RISCV_SBI 35
> #define KVM_EXIT_RISCV_CSR 36
> #define KVM_EXIT_NOTIFY 37
> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>
> /* For KVM_EXIT_INTERNAL_ERROR */
> /* Emulate instruction failed. */
> @@ -336,6 +337,13 @@ struct kvm_run {
> __u32 len;
> __u8 is_write;
> } mmio;
> + /* KVM_EXIT_LOONGARCH_IOCSR */
> + struct {
> + __u64 phys_addr;
> + __u8 data[8];
> + __u32 len;
> + __u8 is_write;
> + } iocsr_io;
> /* KVM_EXIT_HYPERCALL */
> struct {
> __u64 nr;
> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
> #define KVM_REG_ARM64 0x6000000000000000ULL
> #define KVM_REG_MIPS 0x7000000000000000ULL
> #define KVM_REG_RISCV 0x8000000000000000ULL
> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>
> #define KVM_REG_SIZE_SHIFT 52
> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
> --
> 2.39.1
>

2023-09-18 01:33:56

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files


在 2023/9/16 下午4:48, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>> Add LoongArch KVM related header files, including kvm.h,
>> kvm_host.h, kvm_types.h. All of those are about LoongArch
>> virtualization features and kvm interfaces.
>>
>> Reviewed-by: Bibo Mao <[email protected]>
>> Signed-off-by: Tianrui Zhao <[email protected]>
>> ---
>> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
>> arch/loongarch/include/asm/kvm_types.h | 11 ++
>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
>> include/uapi/linux/kvm.h | 9 +
>> 4 files changed, 373 insertions(+)
>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>
>> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
>> new file mode 100644
>> index 0000000000..00e0c1876b
>> --- /dev/null
>> +++ b/arch/loongarch/include/asm/kvm_host.h
>> @@ -0,0 +1,245 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
>> +#define __ASM_LOONGARCH_KVM_HOST_H__
>> +
>> +#include <linux/cpumask.h>
>> +#include <linux/mutex.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/types.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_types.h>
>> +#include <linux/threads.h>
>> +#include <linux/spinlock.h>
>> +
>> +#include <asm/inst.h>
>> +#include <asm/kvm_mmu.h>
>> +#include <asm/loongarch.h>
>> +
>> +/* Loongarch KVM register ids */
>> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>> +
>> +#define KVM_MAX_VCPUS 256
>> +#define KVM_MAX_CPUCFG_REGS 21
>> +/* memory slots that does not exposed to userspace */
>> +#define KVM_PRIVATE_MEM_SLOTS 0
>> +
>> +#define KVM_HALT_POLL_NS_DEFAULT 500000
>> +
>> +struct kvm_vm_stat {
>> + struct kvm_vm_stat_generic generic;
>> + u64 pages;
>> + u64 hugepages;
>> +};
>> +
>> +struct kvm_vcpu_stat {
>> + struct kvm_vcpu_stat_generic generic;
>> + u64 idle_exits;
>> + u64 signal_exits;
>> + u64 int_exits;
>> + u64 cpucfg_exits;
>> +};
>> +
>> +struct kvm_arch_memory_slot {
>> +};
>> +
>> +struct kvm_context {
>> + unsigned long vpid_cache;
>> + struct kvm_vcpu *last_vcpu;
>> +};
>> +
>> +struct kvm_world_switch {
>> + int (*guest_eentry)(void);
>> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>> + unsigned long page_order;
>> +};
>> +
>> +#define MAX_PGTABLE_LEVELS 4
>> +struct kvm_arch {
>> + /* Guest physical mm */
>> + kvm_pte_t *pgd;
>> + unsigned long gpa_size;
>> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
>> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
>> + unsigned int root_level;
>> +
>> + s64 time_offset;
>> + struct kvm_context __percpu *vmcs;
>> +};
>> +
>> +#define CSR_MAX_NUMS 0x800
>> +
>> +struct loongarch_csrs {
>> + unsigned long csrs[CSR_MAX_NUMS];
>> +};
>> +
>> +/* Resume Flags */
>> +#define RESUME_HOST 0
>> +#define RESUME_GUEST 1
>> +
>> +enum emulation_result {
>> + EMULATE_DONE, /* no further processing */
>> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
>> + EMULATE_FAIL, /* can't emulate this instruction */
>> + EMULATE_EXCEPT, /* A guest exception has been generated */
>> + EMULATE_DO_IOCSR, /* handle IOCSR request */
>> +};
>> +
>> +#define KVM_LARCH_FPU (0x1 << 0)
>> +#define KVM_LARCH_CSR (0x1 << 1)
>> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
>> +
>> +struct kvm_vcpu_arch {
>> + /*
>> + * Switch pointer-to-function type to unsigned long
>> + * for loading the value into register directly.
>> + */
>> + unsigned long host_eentry;
>> + unsigned long guest_eentry;
>> +
>> + /* Pointers stored here for easy accessing from assembly code */
>> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>> +
>> + /* Host registers preserved across guest mode execution */
>> + unsigned long host_sp;
>> + unsigned long host_tp;
>> + unsigned long host_pgd;
>> +
>> + /* Host CSRs are used when handling exits from guest */
>> + unsigned long badi;
>> + unsigned long badv;
>> + unsigned long host_ecfg;
>> + unsigned long host_estat;
>> + unsigned long host_percpu;
>> +
>> + /* GPRs */
>> + unsigned long gprs[32];
>> + unsigned long pc;
>> +
>> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
>> + unsigned int aux_inuse;
>> + /* FPU state */
>> + struct loongarch_fpu fpu FPU_ALIGN;
>> +
>> + /* CSR state */
>> + struct loongarch_csrs *csr;
>> +
>> + /* GPR used as IO source/target */
>> + u32 io_gpr;
>> +
>> + struct hrtimer swtimer;
>> + /* KVM register to control count timer */
>> + u32 count_ctl;
>> +
>> + /* Bitmask of intr that are pending */
>> + unsigned long irq_pending;
>> + /* Bitmask of pending intr to be cleared */
>> + unsigned long irq_clear;
>> +
>> + /* Bitmask of exceptions that are pending */
>> + unsigned long exception_pending;
>> + unsigned int subcode;
>> +
>> + /* Cache for pages needed inside spinlock regions */
>> + struct kvm_mmu_memory_cache mmu_page_cache;
>> +
>> + /* vcpu's vpid */
>> + u64 vpid;
>> +
>> + /* Frequency of stable timer in Hz */
>> + u64 timer_mhz;
>> + ktime_t expire;
>> +
>> + u64 core_ext_ioisr[4];
>> +
>> + /* Last CPU the vCPU state was loaded on */
>> + int last_sched_cpu;
>> + /* mp state */
>> + struct kvm_mp_state mp_state;
>> + /* cpucfg */
>> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
>> +};
>> +
>> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
>> +{
>> + return csr->csrs[reg];
>> +}
>> +
>> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
>> +{
>> + csr->csrs[reg] = val;
>> +}
>> +
>> +/* Helpers */
>> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
>> +{
>> + return cpu_has_fpu;
>> +}
>> +
>> +void kvm_init_fault(void);
>> +
>> +/* Debug: dump vcpu state */
>> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
>> +
>> +/* MMU handling */
>> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
>> +void kvm_flush_tlb_all(void);
>> +
>> +#define KVM_ARCH_WANT_MMU_NOTIFIER
>> +int kvm_unmap_hva_range(struct kvm *kvm,
>> + unsigned long start, unsigned long end, bool blockable);
>> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
>> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
>> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>> +
>> +static inline void update_pc(struct kvm_vcpu_arch *arch)
>> +{
>> + arch->pc += 4;
>> +}
>> +
>> +/**
>> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
>> + * @vcpu: Virtual CPU.
>> + *
>> + * Returns: Whether the TLBL exception was likely due to an instruction
>> + * fetch fault rather than a data load fault.
>> + */
>> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
>> +{
>> + return arch->pc == arch->badv;
>> +}
>> +
>> +/* Misc */
>> +static inline void kvm_arch_hardware_unsetup(void) {}
>> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
>> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
>> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>> +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) {}
>> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
>> + struct kvm_memory_slot *slot) {}
>> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
>> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
>> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
>> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
>> + const struct kvm_memory_slot *memslot);
>> +void kvm_init_vmcs(struct kvm *kvm);
>> +void kvm_vector_entry(void);
>> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
>> +extern const unsigned long kvm_vector_size;
>> +extern const unsigned long kvm_enter_guest_size;
>> +extern unsigned long vpid_mask;
>> +extern struct kvm_world_switch *kvm_loongarch_ops;
>> +
>> +#define SW_GCSR (1 << 0)
>> +#define HW_GCSR (1 << 1)
>> +#define INVALID_GCSR (1 << 2)
>> +int get_gcsr_flag(int csr);
>> +extern void set_hw_gcsr(int csr_id, unsigned long val);
>> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
>> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
>> new file mode 100644
>> index 0000000000..2fe1d4bdff
>> --- /dev/null
>> +++ b/arch/loongarch/include/asm/kvm_types.h
>> @@ -0,0 +1,11 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
>> +#define _ASM_LOONGARCH_KVM_TYPES_H
>> +
>> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
>> +
>> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
>> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
>> new file mode 100644
>> index 0000000000..fafda487d6
>> --- /dev/null
>> +++ b/arch/loongarch/include/uapi/asm/kvm.h
>> @@ -0,0 +1,108 @@
>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
>> +#define __UAPI_ASM_LOONGARCH_KVM_H
>> +
>> +#include <linux/types.h>
>> +
>> +/*
>> + * KVM Loongarch specific structures and definitions.
>> + *
>> + * Some parts derived from the x86 version of this file.
>> + */
>> +
>> +#define __KVM_HAVE_READONLY_MEM
>> +
>> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
>> +
>> +/*
>> + * for KVM_GET_REGS and KVM_SET_REGS
>> + */
>> +struct kvm_regs {
>> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
>> + __u64 gpr[32];
>> + __u64 pc;
>> +};
>> +
>> +/*
>> + * for KVM_GET_FPU and KVM_SET_FPU
>> + */
>> +struct kvm_fpu {
>> + __u32 fcsr;
>> + __u64 fcc; /* 8x8 */
>> + struct kvm_fpureg {
>> + __u64 val64[4];
>> + } fpr[32];
>> +};
>> +
>> +/*
>> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
>> + * registers. The id field is broken down as follows:
>> + *
>> + * bits[63..52] - As per linux/kvm.h
>> + * bits[51..32] - Must be zero.
>> + * bits[31..16] - Register set.
>> + *
>> + * Register set = 0: GP registers from kvm_regs (see definitions below).
>> + *
>> + * Register set = 1: CSR registers.
>> + *
>> + * Register set = 2: KVM specific registers (see definitions below).
>> + *
>> + * Register set = 3: FPU / SIMD registers (see definitions below).
>> + *
>> + * Other sets registers may be added in the future. Each set would
>> + * have its own identifier in bits[31..16].
>> + */
>> +
>> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
>> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
>> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
>> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
> How about rename to KVM_REG_LOONGARCH_FPSIMD?
>
> Huacai
It will broke uapi used by user space software, it may cause
incompatible issue, so I think it is better to keep the original name.

Thanks
Tianrui Zhao
>
>> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
>> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
>> +#define KVM_CSR_IDX_MASK 0x7fff
>> +#define KVM_CPUCFG_IDX_MASK 0x7fff
>> +
>> +/*
>> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
>> + */
>> +
>> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
>> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
>> +
>> +#define LOONGARCH_REG_SHIFT 3
>> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
>> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
>> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
>> +
>> +struct kvm_debug_exit_arch {
>> +};
>> +
>> +/* for KVM_SET_GUEST_DEBUG */
>> +struct kvm_guest_debug_arch {
>> +};
>> +
>> +/* definition of registers in kvm_run */
>> +struct kvm_sync_regs {
>> +};
>> +
>> +/* dummy definition */
>> +struct kvm_sregs {
>> +};
>> +
>> +struct kvm_iocsr_entry {
>> + __u32 addr;
>> + __u32 pad;
>> + __u64 data;
>> +};
>> +
>> +#define KVM_NR_IRQCHIPS 1
>> +#define KVM_IRQCHIP_NUM_PINS 64
>> +#define KVM_MAX_CORES 256
>> +
>> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> index 13065dd961..863f84619a 100644
>> --- a/include/uapi/linux/kvm.h
>> +++ b/include/uapi/linux/kvm.h
>> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
>> #define KVM_EXIT_RISCV_SBI 35
>> #define KVM_EXIT_RISCV_CSR 36
>> #define KVM_EXIT_NOTIFY 37
>> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>>
>> /* For KVM_EXIT_INTERNAL_ERROR */
>> /* Emulate instruction failed. */
>> @@ -336,6 +337,13 @@ struct kvm_run {
>> __u32 len;
>> __u8 is_write;
>> } mmio;
>> + /* KVM_EXIT_LOONGARCH_IOCSR */
>> + struct {
>> + __u64 phys_addr;
>> + __u8 data[8];
>> + __u32 len;
>> + __u8 is_write;
>> + } iocsr_io;
>> /* KVM_EXIT_HYPERCALL */
>> struct {
>> __u64 nr;
>> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
>> #define KVM_REG_ARM64 0x6000000000000000ULL
>> #define KVM_REG_MIPS 0x7000000000000000ULL
>> #define KVM_REG_RISCV 0x8000000000000000ULL
>> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>>
>> #define KVM_REG_SIZE_SHIFT 52
>> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
>> --
>> 2.39.1
>>

2023-09-18 01:37:42

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files

Hi, Tianrui,

On Mon, Sep 18, 2023 at 9:32 AM zhaotianrui <[email protected]> wrote:
>
>
> 在 2023/9/16 下午4:48, Huacai Chen 写道:
> > Hi, Tianrui,
> >
> > On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
> >> Add LoongArch KVM related header files, including kvm.h,
> >> kvm_host.h, kvm_types.h. All of those are about LoongArch
> >> virtualization features and kvm interfaces.
> >>
> >> Reviewed-by: Bibo Mao <[email protected]>
> >> Signed-off-by: Tianrui Zhao <[email protected]>
> >> ---
> >> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
> >> arch/loongarch/include/asm/kvm_types.h | 11 ++
> >> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
> >> include/uapi/linux/kvm.h | 9 +
> >> 4 files changed, 373 insertions(+)
> >> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> >> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> >> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> >>
> >> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
> >> new file mode 100644
> >> index 0000000000..00e0c1876b
> >> --- /dev/null
> >> +++ b/arch/loongarch/include/asm/kvm_host.h
> >> @@ -0,0 +1,245 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >> + */
> >> +
> >> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
> >> +#define __ASM_LOONGARCH_KVM_HOST_H__
> >> +
> >> +#include <linux/cpumask.h>
> >> +#include <linux/mutex.h>
> >> +#include <linux/hrtimer.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/types.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_types.h>
> >> +#include <linux/threads.h>
> >> +#include <linux/spinlock.h>
> >> +
> >> +#include <asm/inst.h>
> >> +#include <asm/kvm_mmu.h>
> >> +#include <asm/loongarch.h>
> >> +
> >> +/* Loongarch KVM register ids */
> >> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> >> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> >> +
> >> +#define KVM_MAX_VCPUS 256
> >> +#define KVM_MAX_CPUCFG_REGS 21
> >> +/* memory slots that does not exposed to userspace */
> >> +#define KVM_PRIVATE_MEM_SLOTS 0
> >> +
> >> +#define KVM_HALT_POLL_NS_DEFAULT 500000
> >> +
> >> +struct kvm_vm_stat {
> >> + struct kvm_vm_stat_generic generic;
> >> + u64 pages;
> >> + u64 hugepages;
> >> +};
> >> +
> >> +struct kvm_vcpu_stat {
> >> + struct kvm_vcpu_stat_generic generic;
> >> + u64 idle_exits;
> >> + u64 signal_exits;
> >> + u64 int_exits;
> >> + u64 cpucfg_exits;
> >> +};
> >> +
> >> +struct kvm_arch_memory_slot {
> >> +};
> >> +
> >> +struct kvm_context {
> >> + unsigned long vpid_cache;
> >> + struct kvm_vcpu *last_vcpu;
> >> +};
> >> +
> >> +struct kvm_world_switch {
> >> + int (*guest_eentry)(void);
> >> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >> + unsigned long page_order;
> >> +};
> >> +
> >> +#define MAX_PGTABLE_LEVELS 4
> >> +struct kvm_arch {
> >> + /* Guest physical mm */
> >> + kvm_pte_t *pgd;
> >> + unsigned long gpa_size;
> >> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
> >> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
> >> + unsigned int root_level;
> >> +
> >> + s64 time_offset;
> >> + struct kvm_context __percpu *vmcs;
> >> +};
> >> +
> >> +#define CSR_MAX_NUMS 0x800
> >> +
> >> +struct loongarch_csrs {
> >> + unsigned long csrs[CSR_MAX_NUMS];
> >> +};
> >> +
> >> +/* Resume Flags */
> >> +#define RESUME_HOST 0
> >> +#define RESUME_GUEST 1
> >> +
> >> +enum emulation_result {
> >> + EMULATE_DONE, /* no further processing */
> >> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
> >> + EMULATE_FAIL, /* can't emulate this instruction */
> >> + EMULATE_EXCEPT, /* A guest exception has been generated */
> >> + EMULATE_DO_IOCSR, /* handle IOCSR request */
> >> +};
> >> +
> >> +#define KVM_LARCH_FPU (0x1 << 0)
> >> +#define KVM_LARCH_CSR (0x1 << 1)
> >> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
> >> +
> >> +struct kvm_vcpu_arch {
> >> + /*
> >> + * Switch pointer-to-function type to unsigned long
> >> + * for loading the value into register directly.
> >> + */
> >> + unsigned long host_eentry;
> >> + unsigned long guest_eentry;
> >> +
> >> + /* Pointers stored here for easy accessing from assembly code */
> >> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >> +
> >> + /* Host registers preserved across guest mode execution */
> >> + unsigned long host_sp;
> >> + unsigned long host_tp;
> >> + unsigned long host_pgd;
> >> +
> >> + /* Host CSRs are used when handling exits from guest */
> >> + unsigned long badi;
> >> + unsigned long badv;
> >> + unsigned long host_ecfg;
> >> + unsigned long host_estat;
> >> + unsigned long host_percpu;
> >> +
> >> + /* GPRs */
> >> + unsigned long gprs[32];
> >> + unsigned long pc;
> >> +
> >> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
> >> + unsigned int aux_inuse;
> >> + /* FPU state */
> >> + struct loongarch_fpu fpu FPU_ALIGN;
> >> +
> >> + /* CSR state */
> >> + struct loongarch_csrs *csr;
> >> +
> >> + /* GPR used as IO source/target */
> >> + u32 io_gpr;
> >> +
> >> + struct hrtimer swtimer;
> >> + /* KVM register to control count timer */
> >> + u32 count_ctl;
> >> +
> >> + /* Bitmask of intr that are pending */
> >> + unsigned long irq_pending;
> >> + /* Bitmask of pending intr to be cleared */
> >> + unsigned long irq_clear;
> >> +
> >> + /* Bitmask of exceptions that are pending */
> >> + unsigned long exception_pending;
> >> + unsigned int subcode;
> >> +
> >> + /* Cache for pages needed inside spinlock regions */
> >> + struct kvm_mmu_memory_cache mmu_page_cache;
> >> +
> >> + /* vcpu's vpid */
> >> + u64 vpid;
> >> +
> >> + /* Frequency of stable timer in Hz */
> >> + u64 timer_mhz;
> >> + ktime_t expire;
> >> +
> >> + u64 core_ext_ioisr[4];
> >> +
> >> + /* Last CPU the vCPU state was loaded on */
> >> + int last_sched_cpu;
> >> + /* mp state */
> >> + struct kvm_mp_state mp_state;
> >> + /* cpucfg */
> >> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
> >> +};
> >> +
> >> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
> >> +{
> >> + return csr->csrs[reg];
> >> +}
> >> +
> >> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
> >> +{
> >> + csr->csrs[reg] = val;
> >> +}
> >> +
> >> +/* Helpers */
> >> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
> >> +{
> >> + return cpu_has_fpu;
> >> +}
> >> +
> >> +void kvm_init_fault(void);
> >> +
> >> +/* Debug: dump vcpu state */
> >> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
> >> +
> >> +/* MMU handling */
> >> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
> >> +void kvm_flush_tlb_all(void);
> >> +
> >> +#define KVM_ARCH_WANT_MMU_NOTIFIER
> >> +int kvm_unmap_hva_range(struct kvm *kvm,
> >> + unsigned long start, unsigned long end, bool blockable);
> >> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
> >> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> >> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
> >> +
> >> +static inline void update_pc(struct kvm_vcpu_arch *arch)
> >> +{
> >> + arch->pc += 4;
> >> +}
> >> +
> >> +/**
> >> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
> >> + * @vcpu: Virtual CPU.
> >> + *
> >> + * Returns: Whether the TLBL exception was likely due to an instruction
> >> + * fetch fault rather than a data load fault.
> >> + */
> >> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
> >> +{
> >> + return arch->pc == arch->badv;
> >> +}
> >> +
> >> +/* Misc */
> >> +static inline void kvm_arch_hardware_unsetup(void) {}
> >> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> >> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
> >> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
> >> +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) {}
> >> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
> >> + struct kvm_memory_slot *slot) {}
> >> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
> >> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
> >> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
> >> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
> >> + const struct kvm_memory_slot *memslot);
> >> +void kvm_init_vmcs(struct kvm *kvm);
> >> +void kvm_vector_entry(void);
> >> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >> +extern const unsigned long kvm_vector_size;
> >> +extern const unsigned long kvm_enter_guest_size;
> >> +extern unsigned long vpid_mask;
> >> +extern struct kvm_world_switch *kvm_loongarch_ops;
> >> +
> >> +#define SW_GCSR (1 << 0)
> >> +#define HW_GCSR (1 << 1)
> >> +#define INVALID_GCSR (1 << 2)
> >> +int get_gcsr_flag(int csr);
> >> +extern void set_hw_gcsr(int csr_id, unsigned long val);
> >> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
> >> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
> >> new file mode 100644
> >> index 0000000000..2fe1d4bdff
> >> --- /dev/null
> >> +++ b/arch/loongarch/include/asm/kvm_types.h
> >> @@ -0,0 +1,11 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >> + */
> >> +
> >> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
> >> +#define _ASM_LOONGARCH_KVM_TYPES_H
> >> +
> >> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
> >> +
> >> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
> >> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
> >> new file mode 100644
> >> index 0000000000..fafda487d6
> >> --- /dev/null
> >> +++ b/arch/loongarch/include/uapi/asm/kvm.h
> >> @@ -0,0 +1,108 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> >> +/*
> >> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >> + */
> >> +
> >> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
> >> +#define __UAPI_ASM_LOONGARCH_KVM_H
> >> +
> >> +#include <linux/types.h>
> >> +
> >> +/*
> >> + * KVM Loongarch specific structures and definitions.
> >> + *
> >> + * Some parts derived from the x86 version of this file.
> >> + */
> >> +
> >> +#define __KVM_HAVE_READONLY_MEM
> >> +
> >> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
> >> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
> >> +
> >> +/*
> >> + * for KVM_GET_REGS and KVM_SET_REGS
> >> + */
> >> +struct kvm_regs {
> >> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
> >> + __u64 gpr[32];
> >> + __u64 pc;
> >> +};
> >> +
> >> +/*
> >> + * for KVM_GET_FPU and KVM_SET_FPU
> >> + */
> >> +struct kvm_fpu {
> >> + __u32 fcsr;
> >> + __u64 fcc; /* 8x8 */
> >> + struct kvm_fpureg {
> >> + __u64 val64[4];
> >> + } fpr[32];
> >> +};
> >> +
> >> +/*
> >> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
> >> + * registers. The id field is broken down as follows:
> >> + *
> >> + * bits[63..52] - As per linux/kvm.h
> >> + * bits[51..32] - Must be zero.
> >> + * bits[31..16] - Register set.
> >> + *
> >> + * Register set = 0: GP registers from kvm_regs (see definitions below).
> >> + *
> >> + * Register set = 1: CSR registers.
> >> + *
> >> + * Register set = 2: KVM specific registers (see definitions below).
> >> + *
> >> + * Register set = 3: FPU / SIMD registers (see definitions below).
> >> + *
> >> + * Other sets registers may be added in the future. Each set would
> >> + * have its own identifier in bits[31..16].
> >> + */
> >> +
> >> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
> >> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
> >> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
> >> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
> > How about rename to KVM_REG_LOONGARCH_FPSIMD?
> >
> > Huacai
> It will broke uapi used by user space software, it may cause
> incompatible issue, so I think it is better to keep the original name.
In your comments above it is not only FPU but FPU&SIMD, and this code
hasn't been upstream yet, how to break UAPI?

Huacai

>
> Thanks
> Tianrui Zhao
> >
> >> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
> >> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
> >> +#define KVM_CSR_IDX_MASK 0x7fff
> >> +#define KVM_CPUCFG_IDX_MASK 0x7fff
> >> +
> >> +/*
> >> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
> >> + */
> >> +
> >> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
> >> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
> >> +
> >> +#define LOONGARCH_REG_SHIFT 3
> >> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
> >> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
> >> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
> >> +
> >> +struct kvm_debug_exit_arch {
> >> +};
> >> +
> >> +/* for KVM_SET_GUEST_DEBUG */
> >> +struct kvm_guest_debug_arch {
> >> +};
> >> +
> >> +/* definition of registers in kvm_run */
> >> +struct kvm_sync_regs {
> >> +};
> >> +
> >> +/* dummy definition */
> >> +struct kvm_sregs {
> >> +};
> >> +
> >> +struct kvm_iocsr_entry {
> >> + __u32 addr;
> >> + __u32 pad;
> >> + __u64 data;
> >> +};
> >> +
> >> +#define KVM_NR_IRQCHIPS 1
> >> +#define KVM_IRQCHIP_NUM_PINS 64
> >> +#define KVM_MAX_CORES 256
> >> +
> >> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
> >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >> index 13065dd961..863f84619a 100644
> >> --- a/include/uapi/linux/kvm.h
> >> +++ b/include/uapi/linux/kvm.h
> >> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
> >> #define KVM_EXIT_RISCV_SBI 35
> >> #define KVM_EXIT_RISCV_CSR 36
> >> #define KVM_EXIT_NOTIFY 37
> >> +#define KVM_EXIT_LOONGARCH_IOCSR 38
> >>
> >> /* For KVM_EXIT_INTERNAL_ERROR */
> >> /* Emulate instruction failed. */
> >> @@ -336,6 +337,13 @@ struct kvm_run {
> >> __u32 len;
> >> __u8 is_write;
> >> } mmio;
> >> + /* KVM_EXIT_LOONGARCH_IOCSR */
> >> + struct {
> >> + __u64 phys_addr;
> >> + __u8 data[8];
> >> + __u32 len;
> >> + __u8 is_write;
> >> + } iocsr_io;
> >> /* KVM_EXIT_HYPERCALL */
> >> struct {
> >> __u64 nr;
> >> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
> >> #define KVM_REG_ARM64 0x6000000000000000ULL
> >> #define KVM_REG_MIPS 0x7000000000000000ULL
> >> #define KVM_REG_RISCV 0x8000000000000000ULL
> >> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
> >>
> >> #define KVM_REG_SIZE_SHIFT 52
> >> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
> >> --
> >> 2.39.1
> >>
>
>

2023-09-18 02:24:27

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 05/29] LoongArch: KVM: Add vcpu related header files


在 2023/9/16 下午6:16, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>> Add LoongArch vcpu related header files, including vcpu csr
>> information, irq number defines, and some vcpu interfaces.
>>
>> Reviewed-by: Bibo Mao <[email protected]>
>> Signed-off-by: Tianrui Zhao <[email protected]>
>> ---
>> arch/loongarch/include/asm/kvm_csr.h | 221 +++++++++++++++++++++++++
>> arch/loongarch/include/asm/kvm_vcpu.h | 107 ++++++++++++
>> arch/loongarch/include/asm/loongarch.h | 19 ++-
>> arch/loongarch/kvm/trace.h | 166 +++++++++++++++++++
>> 4 files changed, 508 insertions(+), 5 deletions(-)
>> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
>> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
>> create mode 100644 arch/loongarch/kvm/trace.h
>>
>> diff --git a/arch/loongarch/include/asm/kvm_csr.h b/arch/loongarch/include/asm/kvm_csr.h
>> new file mode 100644
>> index 0000000000..bcdff6724a
>> --- /dev/null
>> +++ b/arch/loongarch/include/asm/kvm_csr.h
>> @@ -0,0 +1,221 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef __ASM_LOONGARCH_KVM_CSR_H__
>> +#define __ASM_LOONGARCH_KVM_CSR_H__
>> +#include <asm/loongarch.h>
>> +#include <asm/kvm_vcpu.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/kvm_host.h>
>> +
>> +/* binutils support virtualization instructions */
>> +#define gcsr_read(csr) \
>> +({ \
>> + register unsigned long __v; \
>> + __asm__ __volatile__( \
>> + " gcsrrd %[val], %[reg]\n\t" \
>> + : [val] "=r" (__v) \
>> + : [reg] "i" (csr) \
>> + : "memory"); \
>> + __v; \
>> +})
>> +
>> +#define gcsr_write(v, csr) \
>> +({ \
>> + register unsigned long __v = v; \
>> + __asm__ __volatile__ ( \
>> + " gcsrwr %[val], %[reg]\n\t" \
>> + : [val] "+r" (__v) \
>> + : [reg] "i" (csr) \
>> + : "memory"); \
>> +})
>> +
>> +#define gcsr_xchg(v, m, csr) \
>> +({ \
>> + register unsigned long __v = v; \
>> + __asm__ __volatile__( \
>> + " gcsrxchg %[val], %[mask], %[reg]\n\t" \
>> + : [val] "+r" (__v) \
>> + : [mask] "r" (m), [reg] "i" (csr) \
>> + : "memory"); \
>> + __v; \
>> +})
>> +
>> +/* Guest CSRS read and write */
>> +#define read_gcsr_crmd() gcsr_read(LOONGARCH_CSR_CRMD)
>> +#define write_gcsr_crmd(val) gcsr_write(val, LOONGARCH_CSR_CRMD)
>> +#define read_gcsr_prmd() gcsr_read(LOONGARCH_CSR_PRMD)
>> +#define write_gcsr_prmd(val) gcsr_write(val, LOONGARCH_CSR_PRMD)
>> +#define read_gcsr_euen() gcsr_read(LOONGARCH_CSR_EUEN)
>> +#define write_gcsr_euen(val) gcsr_write(val, LOONGARCH_CSR_EUEN)
>> +#define read_gcsr_misc() gcsr_read(LOONGARCH_CSR_MISC)
>> +#define write_gcsr_misc(val) gcsr_write(val, LOONGARCH_CSR_MISC)
>> +#define read_gcsr_ecfg() gcsr_read(LOONGARCH_CSR_ECFG)
>> +#define write_gcsr_ecfg(val) gcsr_write(val, LOONGARCH_CSR_ECFG)
>> +#define read_gcsr_estat() gcsr_read(LOONGARCH_CSR_ESTAT)
>> +#define write_gcsr_estat(val) gcsr_write(val, LOONGARCH_CSR_ESTAT)
>> +#define read_gcsr_era() gcsr_read(LOONGARCH_CSR_ERA)
>> +#define write_gcsr_era(val) gcsr_write(val, LOONGARCH_CSR_ERA)
>> +#define read_gcsr_badv() gcsr_read(LOONGARCH_CSR_BADV)
>> +#define write_gcsr_badv(val) gcsr_write(val, LOONGARCH_CSR_BADV)
>> +#define read_gcsr_badi() gcsr_read(LOONGARCH_CSR_BADI)
>> +#define write_gcsr_badi(val) gcsr_write(val, LOONGARCH_CSR_BADI)
>> +#define read_gcsr_eentry() gcsr_read(LOONGARCH_CSR_EENTRY)
>> +#define write_gcsr_eentry(val) gcsr_write(val, LOONGARCH_CSR_EENTRY)
>> +
>> +#define read_gcsr_tlbidx() gcsr_read(LOONGARCH_CSR_TLBIDX)
>> +#define write_gcsr_tlbidx(val) gcsr_write(val, LOONGARCH_CSR_TLBIDX)
>> +#define read_gcsr_tlbhi() gcsr_read(LOONGARCH_CSR_TLBEHI)
>> +#define write_gcsr_tlbhi(val) gcsr_write(val, LOONGARCH_CSR_TLBEHI)
>> +#define read_gcsr_tlblo0() gcsr_read(LOONGARCH_CSR_TLBELO0)
>> +#define write_gcsr_tlblo0(val) gcsr_write(val, LOONGARCH_CSR_TLBELO0)
>> +#define read_gcsr_tlblo1() gcsr_read(LOONGARCH_CSR_TLBELO1)
>> +#define write_gcsr_tlblo1(val) gcsr_write(val, LOONGARCH_CSR_TLBELO1)
>> +
>> +#define read_gcsr_asid() gcsr_read(LOONGARCH_CSR_ASID)
>> +#define write_gcsr_asid(val) gcsr_write(val, LOONGARCH_CSR_ASID)
>> +#define read_gcsr_pgdl() gcsr_read(LOONGARCH_CSR_PGDL)
>> +#define write_gcsr_pgdl(val) gcsr_write(val, LOONGARCH_CSR_PGDL)
>> +#define read_gcsr_pgdh() gcsr_read(LOONGARCH_CSR_PGDH)
>> +#define write_gcsr_pgdh(val) gcsr_write(val, LOONGARCH_CSR_PGDH)
>> +#define write_gcsr_pgd(val) gcsr_write(val, LOONGARCH_CSR_PGD)
>> +#define read_gcsr_pgd() gcsr_read(LOONGARCH_CSR_PGD)
>> +#define read_gcsr_pwctl0() gcsr_read(LOONGARCH_CSR_PWCTL0)
>> +#define write_gcsr_pwctl0(val) gcsr_write(val, LOONGARCH_CSR_PWCTL0)
>> +#define read_gcsr_pwctl1() gcsr_read(LOONGARCH_CSR_PWCTL1)
>> +#define write_gcsr_pwctl1(val) gcsr_write(val, LOONGARCH_CSR_PWCTL1)
>> +#define read_gcsr_stlbpgsize() gcsr_read(LOONGARCH_CSR_STLBPGSIZE)
>> +#define write_gcsr_stlbpgsize(val) gcsr_write(val, LOONGARCH_CSR_STLBPGSIZE)
>> +#define read_gcsr_rvacfg() gcsr_read(LOONGARCH_CSR_RVACFG)
>> +#define write_gcsr_rvacfg(val) gcsr_write(val, LOONGARCH_CSR_RVACFG)
>> +
>> +#define read_gcsr_cpuid() gcsr_read(LOONGARCH_CSR_CPUID)
>> +#define write_gcsr_cpuid(val) gcsr_write(val, LOONGARCH_CSR_CPUID)
>> +#define read_gcsr_prcfg1() gcsr_read(LOONGARCH_CSR_PRCFG1)
>> +#define write_gcsr_prcfg1(val) gcsr_write(val, LOONGARCH_CSR_PRCFG1)
>> +#define read_gcsr_prcfg2() gcsr_read(LOONGARCH_CSR_PRCFG2)
>> +#define write_gcsr_prcfg2(val) gcsr_write(val, LOONGARCH_CSR_PRCFG2)
>> +#define read_gcsr_prcfg3() gcsr_read(LOONGARCH_CSR_PRCFG3)
>> +#define write_gcsr_prcfg3(val) gcsr_write(val, LOONGARCH_CSR_PRCFG3)
>> +
>> +#define read_gcsr_kscratch0() gcsr_read(LOONGARCH_CSR_KS0)
>> +#define write_gcsr_kscratch0(val) gcsr_write(val, LOONGARCH_CSR_KS0)
>> +#define read_gcsr_kscratch1() gcsr_read(LOONGARCH_CSR_KS1)
>> +#define write_gcsr_kscratch1(val) gcsr_write(val, LOONGARCH_CSR_KS1)
>> +#define read_gcsr_kscratch2() gcsr_read(LOONGARCH_CSR_KS2)
>> +#define write_gcsr_kscratch2(val) gcsr_write(val, LOONGARCH_CSR_KS2)
>> +#define read_gcsr_kscratch3() gcsr_read(LOONGARCH_CSR_KS3)
>> +#define write_gcsr_kscratch3(val) gcsr_write(val, LOONGARCH_CSR_KS3)
>> +#define read_gcsr_kscratch4() gcsr_read(LOONGARCH_CSR_KS4)
>> +#define write_gcsr_kscratch4(val) gcsr_write(val, LOONGARCH_CSR_KS4)
>> +#define read_gcsr_kscratch5() gcsr_read(LOONGARCH_CSR_KS5)
>> +#define write_gcsr_kscratch5(val) gcsr_write(val, LOONGARCH_CSR_KS5)
>> +#define read_gcsr_kscratch6() gcsr_read(LOONGARCH_CSR_KS6)
>> +#define write_gcsr_kscratch6(val) gcsr_write(val, LOONGARCH_CSR_KS6)
>> +#define read_gcsr_kscratch7() gcsr_read(LOONGARCH_CSR_KS7)
>> +#define write_gcsr_kscratch7(val) gcsr_write(val, LOONGARCH_CSR_KS7)
>> +
>> +#define read_gcsr_timerid() gcsr_read(LOONGARCH_CSR_TMID)
>> +#define write_gcsr_timerid(val) gcsr_write(val, LOONGARCH_CSR_TMID)
>> +#define read_gcsr_timercfg() gcsr_read(LOONGARCH_CSR_TCFG)
>> +#define write_gcsr_timercfg(val) gcsr_write(val, LOONGARCH_CSR_TCFG)
>> +#define read_gcsr_timertick() gcsr_read(LOONGARCH_CSR_TVAL)
>> +#define write_gcsr_timertick(val) gcsr_write(val, LOONGARCH_CSR_TVAL)
>> +#define read_gcsr_timeroffset() gcsr_read(LOONGARCH_CSR_CNTC)
>> +#define write_gcsr_timeroffset(val) gcsr_write(val, LOONGARCH_CSR_CNTC)
>> +
>> +#define read_gcsr_llbctl() gcsr_read(LOONGARCH_CSR_LLBCTL)
>> +#define write_gcsr_llbctl(val) gcsr_write(val, LOONGARCH_CSR_LLBCTL)
>> +
>> +#define read_gcsr_tlbrentry() gcsr_read(LOONGARCH_CSR_TLBRENTRY)
>> +#define write_gcsr_tlbrentry(val) gcsr_write(val, LOONGARCH_CSR_TLBRENTRY)
>> +#define read_gcsr_tlbrbadv() gcsr_read(LOONGARCH_CSR_TLBRBADV)
>> +#define write_gcsr_tlbrbadv(val) gcsr_write(val, LOONGARCH_CSR_TLBRBADV)
>> +#define read_gcsr_tlbrera() gcsr_read(LOONGARCH_CSR_TLBRERA)
>> +#define write_gcsr_tlbrera(val) gcsr_write(val, LOONGARCH_CSR_TLBRERA)
>> +#define read_gcsr_tlbrsave() gcsr_read(LOONGARCH_CSR_TLBRSAVE)
>> +#define write_gcsr_tlbrsave(val) gcsr_write(val, LOONGARCH_CSR_TLBRSAVE)
>> +#define read_gcsr_tlbrelo0() gcsr_read(LOONGARCH_CSR_TLBRELO0)
>> +#define write_gcsr_tlbrelo0(val) gcsr_write(val, LOONGARCH_CSR_TLBRELO0)
>> +#define read_gcsr_tlbrelo1() gcsr_read(LOONGARCH_CSR_TLBRELO1)
>> +#define write_gcsr_tlbrelo1(val) gcsr_write(val, LOONGARCH_CSR_TLBRELO1)
>> +#define read_gcsr_tlbrehi() gcsr_read(LOONGARCH_CSR_TLBREHI)
>> +#define write_gcsr_tlbrehi(val) gcsr_write(val, LOONGARCH_CSR_TLBREHI)
>> +#define read_gcsr_tlbrprmd() gcsr_read(LOONGARCH_CSR_TLBRPRMD)
>> +#define write_gcsr_tlbrprmd(val) gcsr_write(val, LOONGARCH_CSR_TLBRPRMD)
>> +
>> +#define read_gcsr_directwin0() gcsr_read(LOONGARCH_CSR_DMWIN0)
>> +#define write_gcsr_directwin0(val) gcsr_write(val, LOONGARCH_CSR_DMWIN0)
>> +#define read_gcsr_directwin1() gcsr_read(LOONGARCH_CSR_DMWIN1)
>> +#define write_gcsr_directwin1(val) gcsr_write(val, LOONGARCH_CSR_DMWIN1)
>> +#define read_gcsr_directwin2() gcsr_read(LOONGARCH_CSR_DMWIN2)
>> +#define write_gcsr_directwin2(val) gcsr_write(val, LOONGARCH_CSR_DMWIN2)
>> +#define read_gcsr_directwin3() gcsr_read(LOONGARCH_CSR_DMWIN3)
>> +#define write_gcsr_directwin3(val) gcsr_write(val, LOONGARCH_CSR_DMWIN3)
>> +
>> +/* Guest related CSRs */
>> +#define read_csr_gtlbc() csr_read64(LOONGARCH_CSR_GTLBC)
>> +#define write_csr_gtlbc(val) csr_write64(val, LOONGARCH_CSR_GTLBC)
>> +#define read_csr_trgp() csr_read64(LOONGARCH_CSR_TRGP)
>> +#define read_csr_gcfg() csr_read64(LOONGARCH_CSR_GCFG)
>> +#define write_csr_gcfg(val) csr_write64(val, LOONGARCH_CSR_GCFG)
>> +#define read_csr_gstat() csr_read64(LOONGARCH_CSR_GSTAT)
>> +#define write_csr_gstat(val) csr_write64(val, LOONGARCH_CSR_GSTAT)
>> +#define read_csr_gintc() csr_read64(LOONGARCH_CSR_GINTC)
>> +#define write_csr_gintc(val) csr_write64(val, LOONGARCH_CSR_GINTC)
>> +#define read_csr_gcntc() csr_read64(LOONGARCH_CSR_GCNTC)
>> +#define write_csr_gcntc(val) csr_write64(val, LOONGARCH_CSR_GCNTC)
>> +
>> +#define __BUILD_GCSR_OP(name) __BUILD_CSR_COMMON(gcsr_##name)
>> +
>> +__BUILD_GCSR_OP(llbctl)
>> +__BUILD_GCSR_OP(tlbidx)
>> +__BUILD_CSR_OP(gcfg)
>> +__BUILD_CSR_OP(gstat)
>> +__BUILD_CSR_OP(gtlbc)
>> +__BUILD_CSR_OP(gintc)
>> +
>> +#define set_gcsr_estat(val) \
>> + gcsr_xchg(val, val, LOONGARCH_CSR_ESTAT)
>> +#define clear_gcsr_estat(val) \
>> + gcsr_xchg(~(val), val, LOONGARCH_CSR_ESTAT)
>> +
>> +#define kvm_read_hw_gcsr(id) gcsr_read(id)
>> +#define kvm_write_hw_gcsr(id, val) gcsr_write(val, id)
>> +
>> +int kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *v);
>> +int kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 v);
>> +int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu);
>> +
>> +#define kvm_save_hw_gcsr(csr, gid) (csr->csrs[gid] = gcsr_read(gid))
>> +#define kvm_restore_hw_gcsr(csr, gid) (gcsr_write(csr->csrs[gid], gid))
>> +
>> +static __always_inline unsigned long kvm_read_sw_gcsr(struct loongarch_csrs *csr, int gid)
>> +{
>> + return csr->csrs[gid];
>> +}
>> +
>> +static __always_inline void kvm_write_sw_gcsr(struct loongarch_csrs *csr,
>> + int gid, unsigned long val)
>> +{
>> + csr->csrs[gid] = val;
>> +}
>> +
>> +static __always_inline void kvm_set_sw_gcsr(struct loongarch_csrs *csr,
>> + int gid, unsigned long val)
>> +{
>> + csr->csrs[gid] |= val;
>> +}
>> +
>> +static __always_inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr,
>> + int gid, unsigned long mask,
>> + unsigned long val)
>> +{
>> + unsigned long _mask = mask;
>> +
>> + csr->csrs[gid] &= ~_mask;
>> + csr->csrs[gid] |= val & _mask;
>> +}
>> +#endif /* __ASM_LOONGARCH_KVM_CSR_H__ */
>> diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
>> new file mode 100644
>> index 0000000000..7756f27183
>> --- /dev/null
>> +++ b/arch/loongarch/include/asm/kvm_vcpu.h
>> @@ -0,0 +1,107 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef __ASM_LOONGARCH_KVM_VCPU_H__
>> +#define __ASM_LOONGARCH_KVM_VCPU_H__
>> +
>> +#include <linux/kvm_host.h>
>> +#include <asm/loongarch.h>
>> +
>> +/* Controlled by 0x5 guest exst */
>> +#define CPU_SIP0 (_ULCAST_(1))
>> +#define CPU_SIP1 (_ULCAST_(1) << 1)
>> +#define CPU_PMU (_ULCAST_(1) << 10)
>> +#define CPU_TIMER (_ULCAST_(1) << 11)
>> +#define CPU_IPI (_ULCAST_(1) << 12)
>> +
>> +/* Controlled by 0x52 guest exception VIP
>> + * aligned to exst bit 5~12
>> + */
>> +#define CPU_IP0 (_ULCAST_(1))
>> +#define CPU_IP1 (_ULCAST_(1) << 1)
>> +#define CPU_IP2 (_ULCAST_(1) << 2)
>> +#define CPU_IP3 (_ULCAST_(1) << 3)
>> +#define CPU_IP4 (_ULCAST_(1) << 4)
>> +#define CPU_IP5 (_ULCAST_(1) << 5)
>> +#define CPU_IP6 (_ULCAST_(1) << 6)
>> +#define CPU_IP7 (_ULCAST_(1) << 7)
>> +
>> +#define MNSEC_PER_SEC (NSEC_PER_SEC >> 20)
>> +
>> +/* KVM_IRQ_LINE irq field index values */
>> +#define KVM_LOONGSON_IRQ_TYPE_SHIFT 24
>> +#define KVM_LOONGSON_IRQ_TYPE_MASK 0xff
>> +#define KVM_LOONGSON_IRQ_VCPU_SHIFT 16
>> +#define KVM_LOONGSON_IRQ_VCPU_MASK 0xff
>> +#define KVM_LOONGSON_IRQ_NUM_SHIFT 0
>> +#define KVM_LOONGSON_IRQ_NUM_MASK 0xffff
>> +
>> +/* Irq_type field */
>> +#define KVM_LOONGSON_IRQ_TYPE_CPU_IP 0
>> +#define KVM_LOONGSON_IRQ_TYPE_CPU_IO 1
>> +#define KVM_LOONGSON_IRQ_TYPE_HT 2
>> +#define KVM_LOONGSON_IRQ_TYPE_MSI 3
>> +#define KVM_LOONGSON_IRQ_TYPE_IOAPIC 4
>> +#define KVM_LOONGSON_IRQ_TYPE_ROUTE 5
> I think the types should be refined, so please give me a better definition.

Thanks for the advice, and these can be removed, as these are not used.

>
>> +
>> +/* Out-of-kernel GIC cpu interrupt injection irq_number field */
>> +#define KVM_LOONGSON_IRQ_CPU_IRQ 0
>> +#define KVM_LOONGSON_IRQ_CPU_FIQ 1
>> +#define KVM_LOONGSON_CPU_IP_NUM 8
> And these lines should be removed, right?
Yes, these also can be removed.

Thanks
Tianrui Zhao
>
> Huacai
>
>> +
>> +typedef union loongarch_instruction larch_inst;
>> +typedef int (*exit_handle_fn)(struct kvm_vcpu *);
>> +
>> +int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst);
>> +int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst);
>> +int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
>> +int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run);
>> +int kvm_emu_idle(struct kvm_vcpu *vcpu);
>> +int kvm_handle_pv_hcall(struct kvm_vcpu *vcpu);
>> +int kvm_pending_timer(struct kvm_vcpu *vcpu);
>> +int kvm_handle_fault(struct kvm_vcpu *vcpu, int fault);
>> +void kvm_deliver_intr(struct kvm_vcpu *vcpu);
>> +void kvm_deliver_exception(struct kvm_vcpu *vcpu);
>> +
>> +void kvm_own_fpu(struct kvm_vcpu *vcpu);
>> +void kvm_lose_fpu(struct kvm_vcpu *vcpu);
>> +void kvm_save_fpu(struct loongarch_fpu *fpu);
>> +void kvm_restore_fpu(struct loongarch_fpu *fpu);
>> +void kvm_restore_fcsr(struct loongarch_fpu *fpu);
>> +
>> +void kvm_acquire_timer(struct kvm_vcpu *vcpu);
>> +void kvm_reset_timer(struct kvm_vcpu *vcpu);
>> +void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz);
>> +void kvm_restore_timer(struct kvm_vcpu *vcpu);
>> +void kvm_save_timer(struct kvm_vcpu *vcpu);
>> +
>> +int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
>> +/*
>> + * Loongarch KVM guest interrupt handling
>> + */
>> +static inline void kvm_queue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
>> +{
>> + set_bit(irq, &vcpu->arch.irq_pending);
>> + clear_bit(irq, &vcpu->arch.irq_clear);
>> +}
>> +
>> +static inline void kvm_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int irq)
>> +{
>> + clear_bit(irq, &vcpu->arch.irq_pending);
>> + set_bit(irq, &vcpu->arch.irq_clear);
>> +}
>> +
>> +static inline int kvm_queue_exception(struct kvm_vcpu *vcpu,
>> + unsigned int code, unsigned int subcode)
>> +{
>> + /* only one exception can be injected */
>> + if (!vcpu->arch.exception_pending) {
>> + set_bit(code, &vcpu->arch.exception_pending);
>> + vcpu->arch.subcode = subcode;
>> + return 0;
>> + } else
>> + return -1;
>> +}
>> +#endif /* __ASM_LOONGARCH_KVM_VCPU_H__ */
>> diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
>> index 33531d432b..9b4957cefa 100644
>> --- a/arch/loongarch/include/asm/loongarch.h
>> +++ b/arch/loongarch/include/asm/loongarch.h
>> @@ -226,6 +226,7 @@
>> #define LOONGARCH_CSR_ECFG 0x4 /* Exception config */
>> #define CSR_ECFG_VS_SHIFT 16
>> #define CSR_ECFG_VS_WIDTH 3
>> +#define CSR_ECFG_VS_SHIFT_END (CSR_ECFG_VS_SHIFT + CSR_ECFG_VS_WIDTH - 1)
>> #define CSR_ECFG_VS (_ULCAST_(0x7) << CSR_ECFG_VS_SHIFT)
>> #define CSR_ECFG_IM_SHIFT 0
>> #define CSR_ECFG_IM_WIDTH 14
>> @@ -314,13 +315,14 @@
>> #define CSR_TLBLO1_V (_ULCAST_(0x1) << CSR_TLBLO1_V_SHIFT)
>>
>> #define LOONGARCH_CSR_GTLBC 0x15 /* Guest TLB control */
>> -#define CSR_GTLBC_RID_SHIFT 16
>> -#define CSR_GTLBC_RID_WIDTH 8
>> -#define CSR_GTLBC_RID (_ULCAST_(0xff) << CSR_GTLBC_RID_SHIFT)
>> +#define CSR_GTLBC_TGID_SHIFT 16
>> +#define CSR_GTLBC_TGID_WIDTH 8
>> +#define CSR_GTLBC_TGID_SHIFT_END (CSR_GTLBC_TGID_SHIFT + CSR_GTLBC_TGID_WIDTH - 1)
>> +#define CSR_GTLBC_TGID (_ULCAST_(0xff) << CSR_GTLBC_TGID_SHIFT)
>> #define CSR_GTLBC_TOTI_SHIFT 13
>> #define CSR_GTLBC_TOTI (_ULCAST_(0x1) << CSR_GTLBC_TOTI_SHIFT)
>> -#define CSR_GTLBC_USERID_SHIFT 12
>> -#define CSR_GTLBC_USERID (_ULCAST_(0x1) << CSR_GTLBC_USERID_SHIFT)
>> +#define CSR_GTLBC_USETGID_SHIFT 12
>> +#define CSR_GTLBC_USETGID (_ULCAST_(0x1) << CSR_GTLBC_USETGID_SHIFT)
>> #define CSR_GTLBC_GMTLBSZ_SHIFT 0
>> #define CSR_GTLBC_GMTLBSZ_WIDTH 6
>> #define CSR_GTLBC_GMTLBSZ (_ULCAST_(0x3f) << CSR_GTLBC_GMTLBSZ_SHIFT)
>> @@ -475,6 +477,7 @@
>> #define LOONGARCH_CSR_GSTAT 0x50 /* Guest status */
>> #define CSR_GSTAT_GID_SHIFT 16
>> #define CSR_GSTAT_GID_WIDTH 8
>> +#define CSR_GSTAT_GID_SHIFT_END (CSR_GSTAT_GID_SHIFT + CSR_GSTAT_GID_WIDTH - 1)
>> #define CSR_GSTAT_GID (_ULCAST_(0xff) << CSR_GSTAT_GID_SHIFT)
>> #define CSR_GSTAT_GIDBIT_SHIFT 4
>> #define CSR_GSTAT_GIDBIT_WIDTH 6
>> @@ -525,6 +528,12 @@
>> #define CSR_GCFG_MATC_GUEST (_ULCAST_(0x0) << CSR_GCFG_MATC_SHITF)
>> #define CSR_GCFG_MATC_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATC_SHITF)
>> #define CSR_GCFG_MATC_NEST (_ULCAST_(0x2) << CSR_GCFG_MATC_SHITF)
>> +#define CSR_GCFG_MATP_NEST_SHIFT 2
>> +#define CSR_GCFG_MATP_NEST (_ULCAST_(0x1) << CSR_GCFG_MATP_NEST_SHIFT)
>> +#define CSR_GCFG_MATP_ROOT_SHIFT 1
>> +#define CSR_GCFG_MATP_ROOT (_ULCAST_(0x1) << CSR_GCFG_MATP_ROOT_SHIFT)
>> +#define CSR_GCFG_MATP_GUEST_SHIFT 0
>> +#define CSR_GCFG_MATP_GUEST (_ULCAST_(0x1) << CSR_GCFG_MATP_GUEST_SHIFT)
>>
>> #define LOONGARCH_CSR_GINTC 0x52 /* Guest interrupt control */
>> #define CSR_GINTC_HC_SHIFT 16
>> diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h
>> new file mode 100644
>> index 0000000000..134b5968f6
>> --- /dev/null
>> +++ b/arch/loongarch/kvm/trace.h
>> @@ -0,0 +1,166 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
>> +#define _TRACE_KVM_H
>> +
>> +#include <linux/tracepoint.h>
>> +#include <asm/kvm_csr.h>
>> +
>> +#undef TRACE_SYSTEM
>> +#define TRACE_SYSTEM kvm
>> +
>> +/*
>> + * Tracepoints for VM enters
>> + */
>> +DECLARE_EVENT_CLASS(kvm_transition,
>> + TP_PROTO(struct kvm_vcpu *vcpu),
>> + TP_ARGS(vcpu),
>> + TP_STRUCT__entry(
>> + __field(unsigned long, pc)
>> + ),
>> +
>> + TP_fast_assign(
>> + __entry->pc = vcpu->arch.pc;
>> + ),
>> +
>> + TP_printk("PC: 0x%08lx",
>> + __entry->pc)
>> +);
>> +
>> +DEFINE_EVENT(kvm_transition, kvm_enter,
>> + TP_PROTO(struct kvm_vcpu *vcpu),
>> + TP_ARGS(vcpu));
>> +
>> +DEFINE_EVENT(kvm_transition, kvm_reenter,
>> + TP_PROTO(struct kvm_vcpu *vcpu),
>> + TP_ARGS(vcpu));
>> +
>> +DEFINE_EVENT(kvm_transition, kvm_out,
>> + TP_PROTO(struct kvm_vcpu *vcpu),
>> + TP_ARGS(vcpu));
>> +
>> +/* Further exit reasons */
>> +#define KVM_TRACE_EXIT_IDLE 64
>> +#define KVM_TRACE_EXIT_CACHE 65
>> +
>> +/* Tracepoints for VM exits */
>> +#define kvm_trace_symbol_exit_types \
>> + { KVM_TRACE_EXIT_IDLE, "IDLE" }, \
>> + { KVM_TRACE_EXIT_CACHE, "CACHE" }
>> +
>> +TRACE_EVENT(kvm_exit_gspr,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int inst_word),
>> + TP_ARGS(vcpu, inst_word),
>> + TP_STRUCT__entry(
>> + __field(unsigned int, inst_word)
>> + ),
>> +
>> + TP_fast_assign(
>> + __entry->inst_word = inst_word;
>> + ),
>> +
>> + TP_printk("inst word: 0x%08x",
>> + __entry->inst_word)
>> +);
>> +
>> +
>> +DECLARE_EVENT_CLASS(kvm_exit,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
>> + TP_ARGS(vcpu, reason),
>> + TP_STRUCT__entry(
>> + __field(unsigned long, pc)
>> + __field(unsigned int, reason)
>> + ),
>> +
>> + TP_fast_assign(
>> + __entry->pc = vcpu->arch.pc;
>> + __entry->reason = reason;
>> + ),
>> +
>> + TP_printk("[%s]PC: 0x%08lx",
>> + __print_symbolic(__entry->reason,
>> + kvm_trace_symbol_exit_types),
>> + __entry->pc)
>> +);
>> +
>> +DEFINE_EVENT(kvm_exit, kvm_exit_idle,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
>> + TP_ARGS(vcpu, reason));
>> +
>> +DEFINE_EVENT(kvm_exit, kvm_exit_cache,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
>> + TP_ARGS(vcpu, reason));
>> +
>> +DEFINE_EVENT(kvm_exit, kvm_exit,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int reason),
>> + TP_ARGS(vcpu, reason));
>> +
>> +#define KVM_TRACE_AUX_RESTORE 0
>> +#define KVM_TRACE_AUX_SAVE 1
>> +#define KVM_TRACE_AUX_ENABLE 2
>> +#define KVM_TRACE_AUX_DISABLE 3
>> +#define KVM_TRACE_AUX_DISCARD 4
>> +
>> +#define KVM_TRACE_AUX_FPU 1
>> +
>> +#define kvm_trace_symbol_aux_op \
>> + { KVM_TRACE_AUX_RESTORE, "restore" }, \
>> + { KVM_TRACE_AUX_SAVE, "save" }, \
>> + { KVM_TRACE_AUX_ENABLE, "enable" }, \
>> + { KVM_TRACE_AUX_DISABLE, "disable" }, \
>> + { KVM_TRACE_AUX_DISCARD, "discard" }
>> +
>> +#define kvm_trace_symbol_aux_state \
>> + { KVM_TRACE_AUX_FPU, "FPU" }
>> +
>> +TRACE_EVENT(kvm_aux,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
>> + unsigned int state),
>> + TP_ARGS(vcpu, op, state),
>> + TP_STRUCT__entry(
>> + __field(unsigned long, pc)
>> + __field(u8, op)
>> + __field(u8, state)
>> + ),
>> +
>> + TP_fast_assign(
>> + __entry->pc = vcpu->arch.pc;
>> + __entry->op = op;
>> + __entry->state = state;
>> + ),
>> +
>> + TP_printk("%s %s PC: 0x%08lx",
>> + __print_symbolic(__entry->op,
>> + kvm_trace_symbol_aux_op),
>> + __print_symbolic(__entry->state,
>> + kvm_trace_symbol_aux_state),
>> + __entry->pc)
>> +);
>> +
>> +TRACE_EVENT(kvm_vpid_change,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned long vpid),
>> + TP_ARGS(vcpu, vpid),
>> + TP_STRUCT__entry(
>> + __field(unsigned long, vpid)
>> + ),
>> +
>> + TP_fast_assign(
>> + __entry->vpid = vpid;
>> + ),
>> +
>> + TP_printk("vpid: 0x%08lx",
>> + __entry->vpid)
>> +);
>> +
>> +#endif /* _TRACE_LOONGARCH64_KVM_H */
>> +
>> +#undef TRACE_INCLUDE_PATH
>> +#define TRACE_INCLUDE_PATH ../../arch/loongarch/kvm
>> +#undef TRACE_INCLUDE_FILE
>> +#define TRACE_INCLUDE_FILE trace
>> +
>> +/* This part must be outside protection */
>> +#include <trace/define_trace.h>
>> --
>> 2.39.1
>>
>>

2023-09-18 06:29:29

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files


在 2023/9/18 上午9:36, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Mon, Sep 18, 2023 at 9:32 AM zhaotianrui <[email protected]> wrote:
>>
>> 在 2023/9/16 下午4:48, Huacai Chen 写道:
>>> Hi, Tianrui,
>>>
>>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>>>> Add LoongArch KVM related header files, including kvm.h,
>>>> kvm_host.h, kvm_types.h. All of those are about LoongArch
>>>> virtualization features and kvm interfaces.
>>>>
>>>> Reviewed-by: Bibo Mao <[email protected]>
>>>> Signed-off-by: Tianrui Zhao <[email protected]>
>>>> ---
>>>> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
>>>> arch/loongarch/include/asm/kvm_types.h | 11 ++
>>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
>>>> include/uapi/linux/kvm.h | 9 +
>>>> 4 files changed, 373 insertions(+)
>>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>>>
>>>> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
>>>> new file mode 100644
>>>> index 0000000000..00e0c1876b
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/include/asm/kvm_host.h
>>>> @@ -0,0 +1,245 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/*
>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
>>>> +#define __ASM_LOONGARCH_KVM_HOST_H__
>>>> +
>>>> +#include <linux/cpumask.h>
>>>> +#include <linux/mutex.h>
>>>> +#include <linux/hrtimer.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/types.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_types.h>
>>>> +#include <linux/threads.h>
>>>> +#include <linux/spinlock.h>
>>>> +
>>>> +#include <asm/inst.h>
>>>> +#include <asm/kvm_mmu.h>
>>>> +#include <asm/loongarch.h>
>>>> +
>>>> +/* Loongarch KVM register ids */
>>>> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>>>> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>>>> +
>>>> +#define KVM_MAX_VCPUS 256
>>>> +#define KVM_MAX_CPUCFG_REGS 21
>>>> +/* memory slots that does not exposed to userspace */
>>>> +#define KVM_PRIVATE_MEM_SLOTS 0
>>>> +
>>>> +#define KVM_HALT_POLL_NS_DEFAULT 500000
>>>> +
>>>> +struct kvm_vm_stat {
>>>> + struct kvm_vm_stat_generic generic;
>>>> + u64 pages;
>>>> + u64 hugepages;
>>>> +};
>>>> +
>>>> +struct kvm_vcpu_stat {
>>>> + struct kvm_vcpu_stat_generic generic;
>>>> + u64 idle_exits;
>>>> + u64 signal_exits;
>>>> + u64 int_exits;
>>>> + u64 cpucfg_exits;
>>>> +};
>>>> +
>>>> +struct kvm_arch_memory_slot {
>>>> +};
>>>> +
>>>> +struct kvm_context {
>>>> + unsigned long vpid_cache;
>>>> + struct kvm_vcpu *last_vcpu;
>>>> +};
>>>> +
>>>> +struct kvm_world_switch {
>>>> + int (*guest_eentry)(void);
>>>> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>> + unsigned long page_order;
>>>> +};
>>>> +
>>>> +#define MAX_PGTABLE_LEVELS 4
>>>> +struct kvm_arch {
>>>> + /* Guest physical mm */
>>>> + kvm_pte_t *pgd;
>>>> + unsigned long gpa_size;
>>>> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
>>>> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
>>>> + unsigned int root_level;
>>>> +
>>>> + s64 time_offset;
>>>> + struct kvm_context __percpu *vmcs;
>>>> +};
>>>> +
>>>> +#define CSR_MAX_NUMS 0x800
>>>> +
>>>> +struct loongarch_csrs {
>>>> + unsigned long csrs[CSR_MAX_NUMS];
>>>> +};
>>>> +
>>>> +/* Resume Flags */
>>>> +#define RESUME_HOST 0
>>>> +#define RESUME_GUEST 1
>>>> +
>>>> +enum emulation_result {
>>>> + EMULATE_DONE, /* no further processing */
>>>> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
>>>> + EMULATE_FAIL, /* can't emulate this instruction */
>>>> + EMULATE_EXCEPT, /* A guest exception has been generated */
>>>> + EMULATE_DO_IOCSR, /* handle IOCSR request */
>>>> +};
>>>> +
>>>> +#define KVM_LARCH_FPU (0x1 << 0)
>>>> +#define KVM_LARCH_CSR (0x1 << 1)
>>>> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
>>>> +
>>>> +struct kvm_vcpu_arch {
>>>> + /*
>>>> + * Switch pointer-to-function type to unsigned long
>>>> + * for loading the value into register directly.
>>>> + */
>>>> + unsigned long host_eentry;
>>>> + unsigned long guest_eentry;
>>>> +
>>>> + /* Pointers stored here for easy accessing from assembly code */
>>>> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>> +
>>>> + /* Host registers preserved across guest mode execution */
>>>> + unsigned long host_sp;
>>>> + unsigned long host_tp;
>>>> + unsigned long host_pgd;
>>>> +
>>>> + /* Host CSRs are used when handling exits from guest */
>>>> + unsigned long badi;
>>>> + unsigned long badv;
>>>> + unsigned long host_ecfg;
>>>> + unsigned long host_estat;
>>>> + unsigned long host_percpu;
>>>> +
>>>> + /* GPRs */
>>>> + unsigned long gprs[32];
>>>> + unsigned long pc;
>>>> +
>>>> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
>>>> + unsigned int aux_inuse;
>>>> + /* FPU state */
>>>> + struct loongarch_fpu fpu FPU_ALIGN;
>>>> +
>>>> + /* CSR state */
>>>> + struct loongarch_csrs *csr;
>>>> +
>>>> + /* GPR used as IO source/target */
>>>> + u32 io_gpr;
>>>> +
>>>> + struct hrtimer swtimer;
>>>> + /* KVM register to control count timer */
>>>> + u32 count_ctl;
>>>> +
>>>> + /* Bitmask of intr that are pending */
>>>> + unsigned long irq_pending;
>>>> + /* Bitmask of pending intr to be cleared */
>>>> + unsigned long irq_clear;
>>>> +
>>>> + /* Bitmask of exceptions that are pending */
>>>> + unsigned long exception_pending;
>>>> + unsigned int subcode;
>>>> +
>>>> + /* Cache for pages needed inside spinlock regions */
>>>> + struct kvm_mmu_memory_cache mmu_page_cache;
>>>> +
>>>> + /* vcpu's vpid */
>>>> + u64 vpid;
>>>> +
>>>> + /* Frequency of stable timer in Hz */
>>>> + u64 timer_mhz;
>>>> + ktime_t expire;
>>>> +
>>>> + u64 core_ext_ioisr[4];
>>>> +
>>>> + /* Last CPU the vCPU state was loaded on */
>>>> + int last_sched_cpu;
>>>> + /* mp state */
>>>> + struct kvm_mp_state mp_state;
>>>> + /* cpucfg */
>>>> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
>>>> +};
>>>> +
>>>> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
>>>> +{
>>>> + return csr->csrs[reg];
>>>> +}
>>>> +
>>>> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
>>>> +{
>>>> + csr->csrs[reg] = val;
>>>> +}
>>>> +
>>>> +/* Helpers */
>>>> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
>>>> +{
>>>> + return cpu_has_fpu;
>>>> +}
>>>> +
>>>> +void kvm_init_fault(void);
>>>> +
>>>> +/* Debug: dump vcpu state */
>>>> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
>>>> +
>>>> +/* MMU handling */
>>>> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
>>>> +void kvm_flush_tlb_all(void);
>>>> +
>>>> +#define KVM_ARCH_WANT_MMU_NOTIFIER
>>>> +int kvm_unmap_hva_range(struct kvm *kvm,
>>>> + unsigned long start, unsigned long end, bool blockable);
>>>> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
>>>> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
>>>> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>>>> +
>>>> +static inline void update_pc(struct kvm_vcpu_arch *arch)
>>>> +{
>>>> + arch->pc += 4;
>>>> +}
>>>> +
>>>> +/**
>>>> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
>>>> + * @vcpu: Virtual CPU.
>>>> + *
>>>> + * Returns: Whether the TLBL exception was likely due to an instruction
>>>> + * fetch fault rather than a data load fault.
>>>> + */
>>>> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
>>>> +{
>>>> + return arch->pc == arch->badv;
>>>> +}
>>>> +
>>>> +/* Misc */
>>>> +static inline void kvm_arch_hardware_unsetup(void) {}
>>>> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
>>>> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
>>>> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>>>> +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) {}
>>>> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
>>>> + struct kvm_memory_slot *slot) {}
>>>> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
>>>> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
>>>> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
>>>> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
>>>> + const struct kvm_memory_slot *memslot);
>>>> +void kvm_init_vmcs(struct kvm *kvm);
>>>> +void kvm_vector_entry(void);
>>>> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>> +extern const unsigned long kvm_vector_size;
>>>> +extern const unsigned long kvm_enter_guest_size;
>>>> +extern unsigned long vpid_mask;
>>>> +extern struct kvm_world_switch *kvm_loongarch_ops;
>>>> +
>>>> +#define SW_GCSR (1 << 0)
>>>> +#define HW_GCSR (1 << 1)
>>>> +#define INVALID_GCSR (1 << 2)
>>>> +int get_gcsr_flag(int csr);
>>>> +extern void set_hw_gcsr(int csr_id, unsigned long val);
>>>> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
>>>> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
>>>> new file mode 100644
>>>> index 0000000000..2fe1d4bdff
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/include/asm/kvm_types.h
>>>> @@ -0,0 +1,11 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/*
>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
>>>> +#define _ASM_LOONGARCH_KVM_TYPES_H
>>>> +
>>>> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
>>>> +
>>>> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
>>>> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
>>>> new file mode 100644
>>>> index 0000000000..fafda487d6
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/include/uapi/asm/kvm.h
>>>> @@ -0,0 +1,108 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>>>> +/*
>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
>>>> +#define __UAPI_ASM_LOONGARCH_KVM_H
>>>> +
>>>> +#include <linux/types.h>
>>>> +
>>>> +/*
>>>> + * KVM Loongarch specific structures and definitions.
>>>> + *
>>>> + * Some parts derived from the x86 version of this file.
>>>> + */
>>>> +
>>>> +#define __KVM_HAVE_READONLY_MEM
>>>> +
>>>> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>>> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
>>>> +
>>>> +/*
>>>> + * for KVM_GET_REGS and KVM_SET_REGS
>>>> + */
>>>> +struct kvm_regs {
>>>> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
>>>> + __u64 gpr[32];
>>>> + __u64 pc;
>>>> +};
>>>> +
>>>> +/*
>>>> + * for KVM_GET_FPU and KVM_SET_FPU
>>>> + */
>>>> +struct kvm_fpu {
>>>> + __u32 fcsr;
>>>> + __u64 fcc; /* 8x8 */
>>>> + struct kvm_fpureg {
>>>> + __u64 val64[4];
>>>> + } fpr[32];
>>>> +};
>>>> +
>>>> +/*
>>>> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
>>>> + * registers. The id field is broken down as follows:
>>>> + *
>>>> + * bits[63..52] - As per linux/kvm.h
>>>> + * bits[51..32] - Must be zero.
>>>> + * bits[31..16] - Register set.
>>>> + *
>>>> + * Register set = 0: GP registers from kvm_regs (see definitions below).
>>>> + *
>>>> + * Register set = 1: CSR registers.
>>>> + *
>>>> + * Register set = 2: KVM specific registers (see definitions below).
>>>> + *
>>>> + * Register set = 3: FPU / SIMD registers (see definitions below).
>>>> + *
>>>> + * Other sets registers may be added in the future. Each set would
>>>> + * have its own identifier in bits[31..16].
>>>> + */
>>>> +
>>>> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
>>>> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
>>>> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
>>>> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
>>> How about rename to KVM_REG_LOONGARCH_FPSIMD?
>>>
>>> Huacai
>> It will broke uapi used by user space software, it may cause
>> incompatible issue, so I think it is better to keep the original name.
> In your comments above it is not only FPU but FPU&SIMD, and this code
> hasn't been upstream yet, how to break UAPI?
We want to apply this patch series to our other project when it is
upstream, so we need update the previous codes and it may break the
uapi. What do you think of it?

Thanks
Tianrui Zhao
>
> Huacai
>
>> Thanks
>> Tianrui Zhao
>>>> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
>>>> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
>>>> +#define KVM_CSR_IDX_MASK 0x7fff
>>>> +#define KVM_CPUCFG_IDX_MASK 0x7fff
>>>> +
>>>> +/*
>>>> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
>>>> + */
>>>> +
>>>> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
>>>> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
>>>> +
>>>> +#define LOONGARCH_REG_SHIFT 3
>>>> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
>>>> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
>>>> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
>>>> +
>>>> +struct kvm_debug_exit_arch {
>>>> +};
>>>> +
>>>> +/* for KVM_SET_GUEST_DEBUG */
>>>> +struct kvm_guest_debug_arch {
>>>> +};
>>>> +
>>>> +/* definition of registers in kvm_run */
>>>> +struct kvm_sync_regs {
>>>> +};
>>>> +
>>>> +/* dummy definition */
>>>> +struct kvm_sregs {
>>>> +};
>>>> +
>>>> +struct kvm_iocsr_entry {
>>>> + __u32 addr;
>>>> + __u32 pad;
>>>> + __u64 data;
>>>> +};
>>>> +
>>>> +#define KVM_NR_IRQCHIPS 1
>>>> +#define KVM_IRQCHIP_NUM_PINS 64
>>>> +#define KVM_MAX_CORES 256
>>>> +
>>>> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>> index 13065dd961..863f84619a 100644
>>>> --- a/include/uapi/linux/kvm.h
>>>> +++ b/include/uapi/linux/kvm.h
>>>> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
>>>> #define KVM_EXIT_RISCV_SBI 35
>>>> #define KVM_EXIT_RISCV_CSR 36
>>>> #define KVM_EXIT_NOTIFY 37
>>>> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>>>>
>>>> /* For KVM_EXIT_INTERNAL_ERROR */
>>>> /* Emulate instruction failed. */
>>>> @@ -336,6 +337,13 @@ struct kvm_run {
>>>> __u32 len;
>>>> __u8 is_write;
>>>> } mmio;
>>>> + /* KVM_EXIT_LOONGARCH_IOCSR */
>>>> + struct {
>>>> + __u64 phys_addr;
>>>> + __u8 data[8];
>>>> + __u32 len;
>>>> + __u8 is_write;
>>>> + } iocsr_io;
>>>> /* KVM_EXIT_HYPERCALL */
>>>> struct {
>>>> __u64 nr;
>>>> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
>>>> #define KVM_REG_ARM64 0x6000000000000000ULL
>>>> #define KVM_REG_MIPS 0x7000000000000000ULL
>>>> #define KVM_REG_RISCV 0x8000000000000000ULL
>>>> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>>>>
>>>> #define KVM_REG_SIZE_SHIFT 52
>>>> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
>>>> --
>>>> 2.39.1
>>>>
>>

2023-09-18 06:34:40

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files


在 2023/9/17 下午10:22, Huacai Chen 写道:
> Hi, Tianrui,
>
> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>> Add LoongArch KVM related header files, including kvm.h,
>> kvm_host.h, kvm_types.h. All of those are about LoongArch
>> virtualization features and kvm interfaces.
>>
>> Reviewed-by: Bibo Mao <[email protected]>
>> Signed-off-by: Tianrui Zhao <[email protected]>
>> ---
>> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
>> arch/loongarch/include/asm/kvm_types.h | 11 ++
>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
>> include/uapi/linux/kvm.h | 9 +
>> 4 files changed, 373 insertions(+)
>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>
>> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
>> new file mode 100644
>> index 0000000000..00e0c1876b
>> --- /dev/null
>> +++ b/arch/loongarch/include/asm/kvm_host.h
>> @@ -0,0 +1,245 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
>> +#define __ASM_LOONGARCH_KVM_HOST_H__
>> +
>> +#include <linux/cpumask.h>
>> +#include <linux/mutex.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/types.h>
>> +#include <linux/kvm.h>
>> +#include <linux/kvm_types.h>
>> +#include <linux/threads.h>
>> +#include <linux/spinlock.h>
>> +
>> +#include <asm/inst.h>
>> +#include <asm/kvm_mmu.h>
>> +#include <asm/loongarch.h>
>> +
>> +/* Loongarch KVM register ids */
>> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>> +
>> +#define KVM_MAX_VCPUS 256
>> +#define KVM_MAX_CPUCFG_REGS 21
>> +/* memory slots that does not exposed to userspace */
>> +#define KVM_PRIVATE_MEM_SLOTS 0
>> +
>> +#define KVM_HALT_POLL_NS_DEFAULT 500000
>> +
>> +struct kvm_vm_stat {
>> + struct kvm_vm_stat_generic generic;
>> + u64 pages;
>> + u64 hugepages;
>> +};
>> +
>> +struct kvm_vcpu_stat {
>> + struct kvm_vcpu_stat_generic generic;
>> + u64 idle_exits;
>> + u64 signal_exits;
>> + u64 int_exits;
>> + u64 cpucfg_exits;
>> +};
>> +
>> +struct kvm_arch_memory_slot {
>> +};
>> +
>> +struct kvm_context {
>> + unsigned long vpid_cache;
>> + struct kvm_vcpu *last_vcpu;
>> +};
>> +
>> +struct kvm_world_switch {
>> + int (*guest_eentry)(void);
>> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>> + unsigned long page_order;
>> +};
>> +
>> +#define MAX_PGTABLE_LEVELS 4
>> +struct kvm_arch {
>> + /* Guest physical mm */
>> + kvm_pte_t *pgd;
>> + unsigned long gpa_size;
>> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
>> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
>> + unsigned int root_level;
>> +
>> + s64 time_offset;
>> + struct kvm_context __percpu *vmcs;
>> +};
>> +
>> +#define CSR_MAX_NUMS 0x800
>> +
>> +struct loongarch_csrs {
>> + unsigned long csrs[CSR_MAX_NUMS];
>> +};
>> +
>> +/* Resume Flags */
>> +#define RESUME_HOST 0
>> +#define RESUME_GUEST 1
>> +
>> +enum emulation_result {
>> + EMULATE_DONE, /* no further processing */
>> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
>> + EMULATE_FAIL, /* can't emulate this instruction */
>> + EMULATE_EXCEPT, /* A guest exception has been generated */
>> + EMULATE_DO_IOCSR, /* handle IOCSR request */
>> +};
>> +
>> +#define KVM_LARCH_FPU (0x1 << 0)
>> +#define KVM_LARCH_CSR (0x1 << 1)
>> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
>> +
>> +struct kvm_vcpu_arch {
>> + /*
>> + * Switch pointer-to-function type to unsigned long
>> + * for loading the value into register directly.
>> + */
>> + unsigned long host_eentry;
>> + unsigned long guest_eentry;
>> +
>> + /* Pointers stored here for easy accessing from assembly code */
>> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>> +
>> + /* Host registers preserved across guest mode execution */
>> + unsigned long host_sp;
>> + unsigned long host_tp;
>> + unsigned long host_pgd;
>> +
>> + /* Host CSRs are used when handling exits from guest */
>> + unsigned long badi;
>> + unsigned long badv;
>> + unsigned long host_ecfg;
>> + unsigned long host_estat;
>> + unsigned long host_percpu;
>> +
>> + /* GPRs */
>> + unsigned long gprs[32];
>> + unsigned long pc;
>> +
>> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
>> + unsigned int aux_inuse;
>> + /* FPU state */
>> + struct loongarch_fpu fpu FPU_ALIGN;
>> +
>> + /* CSR state */
>> + struct loongarch_csrs *csr;
>> +
>> + /* GPR used as IO source/target */
>> + u32 io_gpr;
>> +
>> + struct hrtimer swtimer;
>> + /* KVM register to control count timer */
>> + u32 count_ctl;
>> +
>> + /* Bitmask of intr that are pending */
>> + unsigned long irq_pending;
>> + /* Bitmask of pending intr to be cleared */
>> + unsigned long irq_clear;
>> +
>> + /* Bitmask of exceptions that are pending */
>> + unsigned long exception_pending;
>> + unsigned int subcode;
>> +
>> + /* Cache for pages needed inside spinlock regions */
>> + struct kvm_mmu_memory_cache mmu_page_cache;
>> +
>> + /* vcpu's vpid */
>> + u64 vpid;
>> +
>> + /* Frequency of stable timer in Hz */
>> + u64 timer_mhz;
>> + ktime_t expire;
>> +
>> + u64 core_ext_ioisr[4];
>> +
>> + /* Last CPU the vCPU state was loaded on */
>> + int last_sched_cpu;
>> + /* mp state */
>> + struct kvm_mp_state mp_state;
>> + /* cpucfg */
>> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
>> +};
>> +
>> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
>> +{
>> + return csr->csrs[reg];
>> +}
>> +
>> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
>> +{
>> + csr->csrs[reg] = val;
>> +}
>> +
>> +/* Helpers */
>> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
>> +{
>> + return cpu_has_fpu;
>> +}
>> +
>> +void kvm_init_fault(void);
>> +
>> +/* Debug: dump vcpu state */
>> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
>> +
>> +/* MMU handling */
>> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
>> +void kvm_flush_tlb_all(void);
>> +
>> +#define KVM_ARCH_WANT_MMU_NOTIFIER
>> +int kvm_unmap_hva_range(struct kvm *kvm,
>> + unsigned long start, unsigned long end, bool blockable);
>> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
>> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
>> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>> +
>> +static inline void update_pc(struct kvm_vcpu_arch *arch)
>> +{
>> + arch->pc += 4;
>> +}
>> +
>> +/**
>> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
>> + * @vcpu: Virtual CPU.
>> + *
>> + * Returns: Whether the TLBL exception was likely due to an instruction
>> + * fetch fault rather than a data load fault.
>> + */
>> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
>> +{
>> + return arch->pc == arch->badv;
>> +}
>> +
>> +/* Misc */
>> +static inline void kvm_arch_hardware_unsetup(void) {}
>> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
>> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
>> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>> +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) {}
>> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
>> + struct kvm_memory_slot *slot) {}
>> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
>> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
>> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
>> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
>> + const struct kvm_memory_slot *memslot);
>> +void kvm_init_vmcs(struct kvm *kvm);
>> +void kvm_vector_entry(void);
>> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
>> +extern const unsigned long kvm_vector_size;
>> +extern const unsigned long kvm_enter_guest_size;
>> +extern unsigned long vpid_mask;
>> +extern struct kvm_world_switch *kvm_loongarch_ops;
>> +
>> +#define SW_GCSR (1 << 0)
>> +#define HW_GCSR (1 << 1)
>> +#define INVALID_GCSR (1 << 2)
>> +int get_gcsr_flag(int csr);
>> +extern void set_hw_gcsr(int csr_id, unsigned long val);
>> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
>> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
>> new file mode 100644
>> index 0000000000..2fe1d4bdff
>> --- /dev/null
>> +++ b/arch/loongarch/include/asm/kvm_types.h
>> @@ -0,0 +1,11 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
>> +#define _ASM_LOONGARCH_KVM_TYPES_H
>> +
>> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
>> +
>> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
>> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
>> new file mode 100644
>> index 0000000000..fafda487d6
>> --- /dev/null
>> +++ b/arch/loongarch/include/uapi/asm/kvm.h
>> @@ -0,0 +1,108 @@
>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>> +/*
>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>> + */
>> +
>> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
>> +#define __UAPI_ASM_LOONGARCH_KVM_H
>> +
>> +#include <linux/types.h>
>> +
>> +/*
>> + * KVM Loongarch specific structures and definitions.
>> + *
>> + * Some parts derived from the x86 version of this file.
>> + */
>> +
>> +#define __KVM_HAVE_READONLY_MEM
>> +
>> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
>> +
>> +/*
>> + * for KVM_GET_REGS and KVM_SET_REGS
>> + */
>> +struct kvm_regs {
>> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
>> + __u64 gpr[32];
>> + __u64 pc;
>> +};
>> +
>> +/*
>> + * for KVM_GET_FPU and KVM_SET_FPU
>> + */
>> +struct kvm_fpu {
>> + __u32 fcsr;
>> + __u64 fcc; /* 8x8 */
>> + struct kvm_fpureg {
>> + __u64 val64[4];
>> + } fpr[32];
>> +};
>> +
>> +/*
>> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
>> + * registers. The id field is broken down as follows:
>> + *
>> + * bits[63..52] - As per linux/kvm.h
>> + * bits[51..32] - Must be zero.
>> + * bits[31..16] - Register set.
>> + *
>> + * Register set = 0: GP registers from kvm_regs (see definitions below).
>> + *
>> + * Register set = 1: CSR registers.
>> + *
>> + * Register set = 2: KVM specific registers (see definitions below).
>> + *
>> + * Register set = 3: FPU / SIMD registers (see definitions below).
>> + *
>> + * Other sets registers may be added in the future. Each set would
>> + * have its own identifier in bits[31..16].
>> + */
>> +
>> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
>> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
>> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
>> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
>> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
>> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
>> +#define KVM_CSR_IDX_MASK 0x7fff
>> +#define KVM_CPUCFG_IDX_MASK 0x7fff
>> +
>> +/*
>> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
>> + */
>> +
>> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
>> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
> Why begin with 3? 0, 1, 2 reserved for what?
They are keep consistent with our original codes, and 0,1,2 are not used
now.

Thanks
Tianrui Zhao
>
> Huacai
>
>> +
>> +#define LOONGARCH_REG_SHIFT 3
>> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
>> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
>> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
>> +
>> +struct kvm_debug_exit_arch {
>> +};
>> +
>> +/* for KVM_SET_GUEST_DEBUG */
>> +struct kvm_guest_debug_arch {
>> +};
>> +
>> +/* definition of registers in kvm_run */
>> +struct kvm_sync_regs {
>> +};
>> +
>> +/* dummy definition */
>> +struct kvm_sregs {
>> +};
>> +
>> +struct kvm_iocsr_entry {
>> + __u32 addr;
>> + __u32 pad;
>> + __u64 data;
>> +};
>> +
>> +#define KVM_NR_IRQCHIPS 1
>> +#define KVM_IRQCHIP_NUM_PINS 64
>> +#define KVM_MAX_CORES 256
>> +
>> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> index 13065dd961..863f84619a 100644
>> --- a/include/uapi/linux/kvm.h
>> +++ b/include/uapi/linux/kvm.h
>> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
>> #define KVM_EXIT_RISCV_SBI 35
>> #define KVM_EXIT_RISCV_CSR 36
>> #define KVM_EXIT_NOTIFY 37
>> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>>
>> /* For KVM_EXIT_INTERNAL_ERROR */
>> /* Emulate instruction failed. */
>> @@ -336,6 +337,13 @@ struct kvm_run {
>> __u32 len;
>> __u8 is_write;
>> } mmio;
>> + /* KVM_EXIT_LOONGARCH_IOCSR */
>> + struct {
>> + __u64 phys_addr;
>> + __u8 data[8];
>> + __u32 len;
>> + __u8 is_write;
>> + } iocsr_io;
>> /* KVM_EXIT_HYPERCALL */
>> struct {
>> __u64 nr;
>> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
>> #define KVM_REG_ARM64 0x6000000000000000ULL
>> #define KVM_REG_MIPS 0x7000000000000000ULL
>> #define KVM_REG_RISCV 0x8000000000000000ULL
>> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>>
>> #define KVM_REG_SIZE_SHIFT 52
>> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
>> --
>> 2.39.1
>>

2023-09-18 06:38:09

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files

On Mon, Sep 18, 2023 at 2:28 PM zhaotianrui <[email protected]> wrote:
>
>
> 在 2023/9/18 上午9:36, Huacai Chen 写道:
> > Hi, Tianrui,
> >
> > On Mon, Sep 18, 2023 at 9:32 AM zhaotianrui <[email protected]> wrote:
> >>
> >> 在 2023/9/16 下午4:48, Huacai Chen 写道:
> >>> Hi, Tianrui,
> >>>
> >>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
> >>>> Add LoongArch KVM related header files, including kvm.h,
> >>>> kvm_host.h, kvm_types.h. All of those are about LoongArch
> >>>> virtualization features and kvm interfaces.
> >>>>
> >>>> Reviewed-by: Bibo Mao <[email protected]>
> >>>> Signed-off-by: Tianrui Zhao <[email protected]>
> >>>> ---
> >>>> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
> >>>> arch/loongarch/include/asm/kvm_types.h | 11 ++
> >>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
> >>>> include/uapi/linux/kvm.h | 9 +
> >>>> 4 files changed, 373 insertions(+)
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> >>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> >>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> >>>>
> >>>> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
> >>>> new file mode 100644
> >>>> index 0000000000..00e0c1876b
> >>>> --- /dev/null
> >>>> +++ b/arch/loongarch/include/asm/kvm_host.h
> >>>> @@ -0,0 +1,245 @@
> >>>> +/* SPDX-License-Identifier: GPL-2.0 */
> >>>> +/*
> >>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >>>> + */
> >>>> +
> >>>> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
> >>>> +#define __ASM_LOONGARCH_KVM_HOST_H__
> >>>> +
> >>>> +#include <linux/cpumask.h>
> >>>> +#include <linux/mutex.h>
> >>>> +#include <linux/hrtimer.h>
> >>>> +#include <linux/interrupt.h>
> >>>> +#include <linux/types.h>
> >>>> +#include <linux/kvm.h>
> >>>> +#include <linux/kvm_types.h>
> >>>> +#include <linux/threads.h>
> >>>> +#include <linux/spinlock.h>
> >>>> +
> >>>> +#include <asm/inst.h>
> >>>> +#include <asm/kvm_mmu.h>
> >>>> +#include <asm/loongarch.h>
> >>>> +
> >>>> +/* Loongarch KVM register ids */
> >>>> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> >>>> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> >>>> +
> >>>> +#define KVM_MAX_VCPUS 256
> >>>> +#define KVM_MAX_CPUCFG_REGS 21
> >>>> +/* memory slots that does not exposed to userspace */
> >>>> +#define KVM_PRIVATE_MEM_SLOTS 0
> >>>> +
> >>>> +#define KVM_HALT_POLL_NS_DEFAULT 500000
> >>>> +
> >>>> +struct kvm_vm_stat {
> >>>> + struct kvm_vm_stat_generic generic;
> >>>> + u64 pages;
> >>>> + u64 hugepages;
> >>>> +};
> >>>> +
> >>>> +struct kvm_vcpu_stat {
> >>>> + struct kvm_vcpu_stat_generic generic;
> >>>> + u64 idle_exits;
> >>>> + u64 signal_exits;
> >>>> + u64 int_exits;
> >>>> + u64 cpucfg_exits;
> >>>> +};
> >>>> +
> >>>> +struct kvm_arch_memory_slot {
> >>>> +};
> >>>> +
> >>>> +struct kvm_context {
> >>>> + unsigned long vpid_cache;
> >>>> + struct kvm_vcpu *last_vcpu;
> >>>> +};
> >>>> +
> >>>> +struct kvm_world_switch {
> >>>> + int (*guest_eentry)(void);
> >>>> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >>>> + unsigned long page_order;
> >>>> +};
> >>>> +
> >>>> +#define MAX_PGTABLE_LEVELS 4
> >>>> +struct kvm_arch {
> >>>> + /* Guest physical mm */
> >>>> + kvm_pte_t *pgd;
> >>>> + unsigned long gpa_size;
> >>>> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
> >>>> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
> >>>> + unsigned int root_level;
> >>>> +
> >>>> + s64 time_offset;
> >>>> + struct kvm_context __percpu *vmcs;
> >>>> +};
> >>>> +
> >>>> +#define CSR_MAX_NUMS 0x800
> >>>> +
> >>>> +struct loongarch_csrs {
> >>>> + unsigned long csrs[CSR_MAX_NUMS];
> >>>> +};
> >>>> +
> >>>> +/* Resume Flags */
> >>>> +#define RESUME_HOST 0
> >>>> +#define RESUME_GUEST 1
> >>>> +
> >>>> +enum emulation_result {
> >>>> + EMULATE_DONE, /* no further processing */
> >>>> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
> >>>> + EMULATE_FAIL, /* can't emulate this instruction */
> >>>> + EMULATE_EXCEPT, /* A guest exception has been generated */
> >>>> + EMULATE_DO_IOCSR, /* handle IOCSR request */
> >>>> +};
> >>>> +
> >>>> +#define KVM_LARCH_FPU (0x1 << 0)
> >>>> +#define KVM_LARCH_CSR (0x1 << 1)
> >>>> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
> >>>> +
> >>>> +struct kvm_vcpu_arch {
> >>>> + /*
> >>>> + * Switch pointer-to-function type to unsigned long
> >>>> + * for loading the value into register directly.
> >>>> + */
> >>>> + unsigned long host_eentry;
> >>>> + unsigned long guest_eentry;
> >>>> +
> >>>> + /* Pointers stored here for easy accessing from assembly code */
> >>>> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >>>> +
> >>>> + /* Host registers preserved across guest mode execution */
> >>>> + unsigned long host_sp;
> >>>> + unsigned long host_tp;
> >>>> + unsigned long host_pgd;
> >>>> +
> >>>> + /* Host CSRs are used when handling exits from guest */
> >>>> + unsigned long badi;
> >>>> + unsigned long badv;
> >>>> + unsigned long host_ecfg;
> >>>> + unsigned long host_estat;
> >>>> + unsigned long host_percpu;
> >>>> +
> >>>> + /* GPRs */
> >>>> + unsigned long gprs[32];
> >>>> + unsigned long pc;
> >>>> +
> >>>> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
> >>>> + unsigned int aux_inuse;
> >>>> + /* FPU state */
> >>>> + struct loongarch_fpu fpu FPU_ALIGN;
> >>>> +
> >>>> + /* CSR state */
> >>>> + struct loongarch_csrs *csr;
> >>>> +
> >>>> + /* GPR used as IO source/target */
> >>>> + u32 io_gpr;
> >>>> +
> >>>> + struct hrtimer swtimer;
> >>>> + /* KVM register to control count timer */
> >>>> + u32 count_ctl;
> >>>> +
> >>>> + /* Bitmask of intr that are pending */
> >>>> + unsigned long irq_pending;
> >>>> + /* Bitmask of pending intr to be cleared */
> >>>> + unsigned long irq_clear;
> >>>> +
> >>>> + /* Bitmask of exceptions that are pending */
> >>>> + unsigned long exception_pending;
> >>>> + unsigned int subcode;
> >>>> +
> >>>> + /* Cache for pages needed inside spinlock regions */
> >>>> + struct kvm_mmu_memory_cache mmu_page_cache;
> >>>> +
> >>>> + /* vcpu's vpid */
> >>>> + u64 vpid;
> >>>> +
> >>>> + /* Frequency of stable timer in Hz */
> >>>> + u64 timer_mhz;
> >>>> + ktime_t expire;
> >>>> +
> >>>> + u64 core_ext_ioisr[4];
> >>>> +
> >>>> + /* Last CPU the vCPU state was loaded on */
> >>>> + int last_sched_cpu;
> >>>> + /* mp state */
> >>>> + struct kvm_mp_state mp_state;
> >>>> + /* cpucfg */
> >>>> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
> >>>> +};
> >>>> +
> >>>> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
> >>>> +{
> >>>> + return csr->csrs[reg];
> >>>> +}
> >>>> +
> >>>> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
> >>>> +{
> >>>> + csr->csrs[reg] = val;
> >>>> +}
> >>>> +
> >>>> +/* Helpers */
> >>>> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
> >>>> +{
> >>>> + return cpu_has_fpu;
> >>>> +}
> >>>> +
> >>>> +void kvm_init_fault(void);
> >>>> +
> >>>> +/* Debug: dump vcpu state */
> >>>> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
> >>>> +
> >>>> +/* MMU handling */
> >>>> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
> >>>> +void kvm_flush_tlb_all(void);
> >>>> +
> >>>> +#define KVM_ARCH_WANT_MMU_NOTIFIER
> >>>> +int kvm_unmap_hva_range(struct kvm *kvm,
> >>>> + unsigned long start, unsigned long end, bool blockable);
> >>>> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
> >>>> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> >>>> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
> >>>> +
> >>>> +static inline void update_pc(struct kvm_vcpu_arch *arch)
> >>>> +{
> >>>> + arch->pc += 4;
> >>>> +}
> >>>> +
> >>>> +/**
> >>>> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
> >>>> + * @vcpu: Virtual CPU.
> >>>> + *
> >>>> + * Returns: Whether the TLBL exception was likely due to an instruction
> >>>> + * fetch fault rather than a data load fault.
> >>>> + */
> >>>> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
> >>>> +{
> >>>> + return arch->pc == arch->badv;
> >>>> +}
> >>>> +
> >>>> +/* Misc */
> >>>> +static inline void kvm_arch_hardware_unsetup(void) {}
> >>>> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> >>>> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
> >>>> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
> >>>> +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) {}
> >>>> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
> >>>> + struct kvm_memory_slot *slot) {}
> >>>> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
> >>>> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
> >>>> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
> >>>> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
> >>>> + const struct kvm_memory_slot *memslot);
> >>>> +void kvm_init_vmcs(struct kvm *kvm);
> >>>> +void kvm_vector_entry(void);
> >>>> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >>>> +extern const unsigned long kvm_vector_size;
> >>>> +extern const unsigned long kvm_enter_guest_size;
> >>>> +extern unsigned long vpid_mask;
> >>>> +extern struct kvm_world_switch *kvm_loongarch_ops;
> >>>> +
> >>>> +#define SW_GCSR (1 << 0)
> >>>> +#define HW_GCSR (1 << 1)
> >>>> +#define INVALID_GCSR (1 << 2)
> >>>> +int get_gcsr_flag(int csr);
> >>>> +extern void set_hw_gcsr(int csr_id, unsigned long val);
> >>>> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
> >>>> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
> >>>> new file mode 100644
> >>>> index 0000000000..2fe1d4bdff
> >>>> --- /dev/null
> >>>> +++ b/arch/loongarch/include/asm/kvm_types.h
> >>>> @@ -0,0 +1,11 @@
> >>>> +/* SPDX-License-Identifier: GPL-2.0 */
> >>>> +/*
> >>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >>>> + */
> >>>> +
> >>>> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
> >>>> +#define _ASM_LOONGARCH_KVM_TYPES_H
> >>>> +
> >>>> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
> >>>> +
> >>>> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
> >>>> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
> >>>> new file mode 100644
> >>>> index 0000000000..fafda487d6
> >>>> --- /dev/null
> >>>> +++ b/arch/loongarch/include/uapi/asm/kvm.h
> >>>> @@ -0,0 +1,108 @@
> >>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> >>>> +/*
> >>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >>>> + */
> >>>> +
> >>>> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
> >>>> +#define __UAPI_ASM_LOONGARCH_KVM_H
> >>>> +
> >>>> +#include <linux/types.h>
> >>>> +
> >>>> +/*
> >>>> + * KVM Loongarch specific structures and definitions.
> >>>> + *
> >>>> + * Some parts derived from the x86 version of this file.
> >>>> + */
> >>>> +
> >>>> +#define __KVM_HAVE_READONLY_MEM
> >>>> +
> >>>> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
> >>>> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
> >>>> +
> >>>> +/*
> >>>> + * for KVM_GET_REGS and KVM_SET_REGS
> >>>> + */
> >>>> +struct kvm_regs {
> >>>> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
> >>>> + __u64 gpr[32];
> >>>> + __u64 pc;
> >>>> +};
> >>>> +
> >>>> +/*
> >>>> + * for KVM_GET_FPU and KVM_SET_FPU
> >>>> + */
> >>>> +struct kvm_fpu {
> >>>> + __u32 fcsr;
> >>>> + __u64 fcc; /* 8x8 */
> >>>> + struct kvm_fpureg {
> >>>> + __u64 val64[4];
> >>>> + } fpr[32];
> >>>> +};
> >>>> +
> >>>> +/*
> >>>> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
> >>>> + * registers. The id field is broken down as follows:
> >>>> + *
> >>>> + * bits[63..52] - As per linux/kvm.h
> >>>> + * bits[51..32] - Must be zero.
> >>>> + * bits[31..16] - Register set.
> >>>> + *
> >>>> + * Register set = 0: GP registers from kvm_regs (see definitions below).
> >>>> + *
> >>>> + * Register set = 1: CSR registers.
> >>>> + *
> >>>> + * Register set = 2: KVM specific registers (see definitions below).
> >>>> + *
> >>>> + * Register set = 3: FPU / SIMD registers (see definitions below).
> >>>> + *
> >>>> + * Other sets registers may be added in the future. Each set would
> >>>> + * have its own identifier in bits[31..16].
> >>>> + */
> >>>> +
> >>>> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
> >>>> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
> >>>> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
> >>>> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
> >>> How about rename to KVM_REG_LOONGARCH_FPSIMD?
> >>>
> >>> Huacai
> >> It will broke uapi used by user space software, it may cause
> >> incompatible issue, so I think it is better to keep the original name.
> > In your comments above it is not only FPU but FPU&SIMD, and this code
> > hasn't been upstream yet, how to break UAPI?
> We want to apply this patch series to our other project when it is
> upstream, so we need update the previous codes and it may break the
> uapi. What do you think of it?
Generally, the kernel is the first one to be upstream, so kernel can
do anything reasonable, other projects should align to kernel when
they want to get upstream.

Huacai

>
> Thanks
> Tianrui Zhao
> >
> > Huacai
> >
> >> Thanks
> >> Tianrui Zhao
> >>>> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
> >>>> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
> >>>> +#define KVM_CSR_IDX_MASK 0x7fff
> >>>> +#define KVM_CPUCFG_IDX_MASK 0x7fff
> >>>> +
> >>>> +/*
> >>>> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
> >>>> + */
> >>>> +
> >>>> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
> >>>> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
> >>>> +
> >>>> +#define LOONGARCH_REG_SHIFT 3
> >>>> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
> >>>> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
> >>>> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
> >>>> +
> >>>> +struct kvm_debug_exit_arch {
> >>>> +};
> >>>> +
> >>>> +/* for KVM_SET_GUEST_DEBUG */
> >>>> +struct kvm_guest_debug_arch {
> >>>> +};
> >>>> +
> >>>> +/* definition of registers in kvm_run */
> >>>> +struct kvm_sync_regs {
> >>>> +};
> >>>> +
> >>>> +/* dummy definition */
> >>>> +struct kvm_sregs {
> >>>> +};
> >>>> +
> >>>> +struct kvm_iocsr_entry {
> >>>> + __u32 addr;
> >>>> + __u32 pad;
> >>>> + __u64 data;
> >>>> +};
> >>>> +
> >>>> +#define KVM_NR_IRQCHIPS 1
> >>>> +#define KVM_IRQCHIP_NUM_PINS 64
> >>>> +#define KVM_MAX_CORES 256
> >>>> +
> >>>> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
> >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >>>> index 13065dd961..863f84619a 100644
> >>>> --- a/include/uapi/linux/kvm.h
> >>>> +++ b/include/uapi/linux/kvm.h
> >>>> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
> >>>> #define KVM_EXIT_RISCV_SBI 35
> >>>> #define KVM_EXIT_RISCV_CSR 36
> >>>> #define KVM_EXIT_NOTIFY 37
> >>>> +#define KVM_EXIT_LOONGARCH_IOCSR 38
> >>>>
> >>>> /* For KVM_EXIT_INTERNAL_ERROR */
> >>>> /* Emulate instruction failed. */
> >>>> @@ -336,6 +337,13 @@ struct kvm_run {
> >>>> __u32 len;
> >>>> __u8 is_write;
> >>>> } mmio;
> >>>> + /* KVM_EXIT_LOONGARCH_IOCSR */
> >>>> + struct {
> >>>> + __u64 phys_addr;
> >>>> + __u8 data[8];
> >>>> + __u32 len;
> >>>> + __u8 is_write;
> >>>> + } iocsr_io;
> >>>> /* KVM_EXIT_HYPERCALL */
> >>>> struct {
> >>>> __u64 nr;
> >>>> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
> >>>> #define KVM_REG_ARM64 0x6000000000000000ULL
> >>>> #define KVM_REG_MIPS 0x7000000000000000ULL
> >>>> #define KVM_REG_RISCV 0x8000000000000000ULL
> >>>> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
> >>>>
> >>>> #define KVM_REG_SIZE_SHIFT 52
> >>>> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
> >>>> --
> >>>> 2.39.1
> >>>>
> >>
>

2023-09-18 06:39:18

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files

On Mon, Sep 18, 2023 at 2:32 PM zhaotianrui <[email protected]> wrote:
>
>
> 在 2023/9/17 下午10:22, Huacai Chen 写道:
> > Hi, Tianrui,
> >
> > On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
> >> Add LoongArch KVM related header files, including kvm.h,
> >> kvm_host.h, kvm_types.h. All of those are about LoongArch
> >> virtualization features and kvm interfaces.
> >>
> >> Reviewed-by: Bibo Mao <[email protected]>
> >> Signed-off-by: Tianrui Zhao <[email protected]>
> >> ---
> >> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
> >> arch/loongarch/include/asm/kvm_types.h | 11 ++
> >> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
> >> include/uapi/linux/kvm.h | 9 +
> >> 4 files changed, 373 insertions(+)
> >> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> >> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> >> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> >>
> >> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
> >> new file mode 100644
> >> index 0000000000..00e0c1876b
> >> --- /dev/null
> >> +++ b/arch/loongarch/include/asm/kvm_host.h
> >> @@ -0,0 +1,245 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >> + */
> >> +
> >> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
> >> +#define __ASM_LOONGARCH_KVM_HOST_H__
> >> +
> >> +#include <linux/cpumask.h>
> >> +#include <linux/mutex.h>
> >> +#include <linux/hrtimer.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/types.h>
> >> +#include <linux/kvm.h>
> >> +#include <linux/kvm_types.h>
> >> +#include <linux/threads.h>
> >> +#include <linux/spinlock.h>
> >> +
> >> +#include <asm/inst.h>
> >> +#include <asm/kvm_mmu.h>
> >> +#include <asm/loongarch.h>
> >> +
> >> +/* Loongarch KVM register ids */
> >> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> >> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
> >> +
> >> +#define KVM_MAX_VCPUS 256
> >> +#define KVM_MAX_CPUCFG_REGS 21
> >> +/* memory slots that does not exposed to userspace */
> >> +#define KVM_PRIVATE_MEM_SLOTS 0
> >> +
> >> +#define KVM_HALT_POLL_NS_DEFAULT 500000
> >> +
> >> +struct kvm_vm_stat {
> >> + struct kvm_vm_stat_generic generic;
> >> + u64 pages;
> >> + u64 hugepages;
> >> +};
> >> +
> >> +struct kvm_vcpu_stat {
> >> + struct kvm_vcpu_stat_generic generic;
> >> + u64 idle_exits;
> >> + u64 signal_exits;
> >> + u64 int_exits;
> >> + u64 cpucfg_exits;
> >> +};
> >> +
> >> +struct kvm_arch_memory_slot {
> >> +};
> >> +
> >> +struct kvm_context {
> >> + unsigned long vpid_cache;
> >> + struct kvm_vcpu *last_vcpu;
> >> +};
> >> +
> >> +struct kvm_world_switch {
> >> + int (*guest_eentry)(void);
> >> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >> + unsigned long page_order;
> >> +};
> >> +
> >> +#define MAX_PGTABLE_LEVELS 4
> >> +struct kvm_arch {
> >> + /* Guest physical mm */
> >> + kvm_pte_t *pgd;
> >> + unsigned long gpa_size;
> >> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
> >> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
> >> + unsigned int root_level;
> >> +
> >> + s64 time_offset;
> >> + struct kvm_context __percpu *vmcs;
> >> +};
> >> +
> >> +#define CSR_MAX_NUMS 0x800
> >> +
> >> +struct loongarch_csrs {
> >> + unsigned long csrs[CSR_MAX_NUMS];
> >> +};
> >> +
> >> +/* Resume Flags */
> >> +#define RESUME_HOST 0
> >> +#define RESUME_GUEST 1
> >> +
> >> +enum emulation_result {
> >> + EMULATE_DONE, /* no further processing */
> >> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
> >> + EMULATE_FAIL, /* can't emulate this instruction */
> >> + EMULATE_EXCEPT, /* A guest exception has been generated */
> >> + EMULATE_DO_IOCSR, /* handle IOCSR request */
> >> +};
> >> +
> >> +#define KVM_LARCH_FPU (0x1 << 0)
> >> +#define KVM_LARCH_CSR (0x1 << 1)
> >> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
> >> +
> >> +struct kvm_vcpu_arch {
> >> + /*
> >> + * Switch pointer-to-function type to unsigned long
> >> + * for loading the value into register directly.
> >> + */
> >> + unsigned long host_eentry;
> >> + unsigned long guest_eentry;
> >> +
> >> + /* Pointers stored here for easy accessing from assembly code */
> >> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >> +
> >> + /* Host registers preserved across guest mode execution */
> >> + unsigned long host_sp;
> >> + unsigned long host_tp;
> >> + unsigned long host_pgd;
> >> +
> >> + /* Host CSRs are used when handling exits from guest */
> >> + unsigned long badi;
> >> + unsigned long badv;
> >> + unsigned long host_ecfg;
> >> + unsigned long host_estat;
> >> + unsigned long host_percpu;
> >> +
> >> + /* GPRs */
> >> + unsigned long gprs[32];
> >> + unsigned long pc;
> >> +
> >> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
> >> + unsigned int aux_inuse;
> >> + /* FPU state */
> >> + struct loongarch_fpu fpu FPU_ALIGN;
> >> +
> >> + /* CSR state */
> >> + struct loongarch_csrs *csr;
> >> +
> >> + /* GPR used as IO source/target */
> >> + u32 io_gpr;
> >> +
> >> + struct hrtimer swtimer;
> >> + /* KVM register to control count timer */
> >> + u32 count_ctl;
> >> +
> >> + /* Bitmask of intr that are pending */
> >> + unsigned long irq_pending;
> >> + /* Bitmask of pending intr to be cleared */
> >> + unsigned long irq_clear;
> >> +
> >> + /* Bitmask of exceptions that are pending */
> >> + unsigned long exception_pending;
> >> + unsigned int subcode;
> >> +
> >> + /* Cache for pages needed inside spinlock regions */
> >> + struct kvm_mmu_memory_cache mmu_page_cache;
> >> +
> >> + /* vcpu's vpid */
> >> + u64 vpid;
> >> +
> >> + /* Frequency of stable timer in Hz */
> >> + u64 timer_mhz;
> >> + ktime_t expire;
> >> +
> >> + u64 core_ext_ioisr[4];
> >> +
> >> + /* Last CPU the vCPU state was loaded on */
> >> + int last_sched_cpu;
> >> + /* mp state */
> >> + struct kvm_mp_state mp_state;
> >> + /* cpucfg */
> >> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
> >> +};
> >> +
> >> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
> >> +{
> >> + return csr->csrs[reg];
> >> +}
> >> +
> >> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
> >> +{
> >> + csr->csrs[reg] = val;
> >> +}
> >> +
> >> +/* Helpers */
> >> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
> >> +{
> >> + return cpu_has_fpu;
> >> +}
> >> +
> >> +void kvm_init_fault(void);
> >> +
> >> +/* Debug: dump vcpu state */
> >> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
> >> +
> >> +/* MMU handling */
> >> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
> >> +void kvm_flush_tlb_all(void);
> >> +
> >> +#define KVM_ARCH_WANT_MMU_NOTIFIER
> >> +int kvm_unmap_hva_range(struct kvm *kvm,
> >> + unsigned long start, unsigned long end, bool blockable);
> >> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
> >> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
> >> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
> >> +
> >> +static inline void update_pc(struct kvm_vcpu_arch *arch)
> >> +{
> >> + arch->pc += 4;
> >> +}
> >> +
> >> +/**
> >> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
> >> + * @vcpu: Virtual CPU.
> >> + *
> >> + * Returns: Whether the TLBL exception was likely due to an instruction
> >> + * fetch fault rather than a data load fault.
> >> + */
> >> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
> >> +{
> >> + return arch->pc == arch->badv;
> >> +}
> >> +
> >> +/* Misc */
> >> +static inline void kvm_arch_hardware_unsetup(void) {}
> >> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
> >> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
> >> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
> >> +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) {}
> >> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
> >> + struct kvm_memory_slot *slot) {}
> >> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
> >> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
> >> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
> >> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
> >> + const struct kvm_memory_slot *memslot);
> >> +void kvm_init_vmcs(struct kvm *kvm);
> >> +void kvm_vector_entry(void);
> >> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
> >> +extern const unsigned long kvm_vector_size;
> >> +extern const unsigned long kvm_enter_guest_size;
> >> +extern unsigned long vpid_mask;
> >> +extern struct kvm_world_switch *kvm_loongarch_ops;
> >> +
> >> +#define SW_GCSR (1 << 0)
> >> +#define HW_GCSR (1 << 1)
> >> +#define INVALID_GCSR (1 << 2)
> >> +int get_gcsr_flag(int csr);
> >> +extern void set_hw_gcsr(int csr_id, unsigned long val);
> >> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
> >> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
> >> new file mode 100644
> >> index 0000000000..2fe1d4bdff
> >> --- /dev/null
> >> +++ b/arch/loongarch/include/asm/kvm_types.h
> >> @@ -0,0 +1,11 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >> + */
> >> +
> >> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
> >> +#define _ASM_LOONGARCH_KVM_TYPES_H
> >> +
> >> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
> >> +
> >> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
> >> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
> >> new file mode 100644
> >> index 0000000000..fafda487d6
> >> --- /dev/null
> >> +++ b/arch/loongarch/include/uapi/asm/kvm.h
> >> @@ -0,0 +1,108 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> >> +/*
> >> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
> >> + */
> >> +
> >> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
> >> +#define __UAPI_ASM_LOONGARCH_KVM_H
> >> +
> >> +#include <linux/types.h>
> >> +
> >> +/*
> >> + * KVM Loongarch specific structures and definitions.
> >> + *
> >> + * Some parts derived from the x86 version of this file.
> >> + */
> >> +
> >> +#define __KVM_HAVE_READONLY_MEM
> >> +
> >> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
> >> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
> >> +
> >> +/*
> >> + * for KVM_GET_REGS and KVM_SET_REGS
> >> + */
> >> +struct kvm_regs {
> >> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
> >> + __u64 gpr[32];
> >> + __u64 pc;
> >> +};
> >> +
> >> +/*
> >> + * for KVM_GET_FPU and KVM_SET_FPU
> >> + */
> >> +struct kvm_fpu {
> >> + __u32 fcsr;
> >> + __u64 fcc; /* 8x8 */
> >> + struct kvm_fpureg {
> >> + __u64 val64[4];
> >> + } fpr[32];
> >> +};
> >> +
> >> +/*
> >> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
> >> + * registers. The id field is broken down as follows:
> >> + *
> >> + * bits[63..52] - As per linux/kvm.h
> >> + * bits[51..32] - Must be zero.
> >> + * bits[31..16] - Register set.
> >> + *
> >> + * Register set = 0: GP registers from kvm_regs (see definitions below).
> >> + *
> >> + * Register set = 1: CSR registers.
> >> + *
> >> + * Register set = 2: KVM specific registers (see definitions below).
> >> + *
> >> + * Register set = 3: FPU / SIMD registers (see definitions below).
> >> + *
> >> + * Other sets registers may be added in the future. Each set would
> >> + * have its own identifier in bits[31..16].
> >> + */
> >> +
> >> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
> >> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
> >> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
> >> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
> >> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
> >> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
> >> +#define KVM_CSR_IDX_MASK 0x7fff
> >> +#define KVM_CPUCFG_IDX_MASK 0x7fff
> >> +
> >> +/*
> >> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
> >> + */
> >> +
> >> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
> >> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
> > Why begin with 3? 0, 1, 2 reserved for what?
> They are keep consistent with our original codes, and 0,1,2 are not used
> now.
The same as KVM_REG_LOONGARCH_FPU, kernel is the first one, so I
suggest beginning with 0 or 1, but don't begin with 3.

Huacai

>
> Thanks
> Tianrui Zhao
> >
> > Huacai
> >
> >> +
> >> +#define LOONGARCH_REG_SHIFT 3
> >> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
> >> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
> >> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
> >> +
> >> +struct kvm_debug_exit_arch {
> >> +};
> >> +
> >> +/* for KVM_SET_GUEST_DEBUG */
> >> +struct kvm_guest_debug_arch {
> >> +};
> >> +
> >> +/* definition of registers in kvm_run */
> >> +struct kvm_sync_regs {
> >> +};
> >> +
> >> +/* dummy definition */
> >> +struct kvm_sregs {
> >> +};
> >> +
> >> +struct kvm_iocsr_entry {
> >> + __u32 addr;
> >> + __u32 pad;
> >> + __u64 data;
> >> +};
> >> +
> >> +#define KVM_NR_IRQCHIPS 1
> >> +#define KVM_IRQCHIP_NUM_PINS 64
> >> +#define KVM_MAX_CORES 256
> >> +
> >> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
> >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >> index 13065dd961..863f84619a 100644
> >> --- a/include/uapi/linux/kvm.h
> >> +++ b/include/uapi/linux/kvm.h
> >> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
> >> #define KVM_EXIT_RISCV_SBI 35
> >> #define KVM_EXIT_RISCV_CSR 36
> >> #define KVM_EXIT_NOTIFY 37
> >> +#define KVM_EXIT_LOONGARCH_IOCSR 38
> >>
> >> /* For KVM_EXIT_INTERNAL_ERROR */
> >> /* Emulate instruction failed. */
> >> @@ -336,6 +337,13 @@ struct kvm_run {
> >> __u32 len;
> >> __u8 is_write;
> >> } mmio;
> >> + /* KVM_EXIT_LOONGARCH_IOCSR */
> >> + struct {
> >> + __u64 phys_addr;
> >> + __u8 data[8];
> >> + __u32 len;
> >> + __u8 is_write;
> >> + } iocsr_io;
> >> /* KVM_EXIT_HYPERCALL */
> >> struct {
> >> __u64 nr;
> >> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
> >> #define KVM_REG_ARM64 0x6000000000000000ULL
> >> #define KVM_REG_MIPS 0x7000000000000000ULL
> >> #define KVM_REG_RISCV 0x8000000000000000ULL
> >> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
> >>
> >> #define KVM_REG_SIZE_SHIFT 52
> >> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
> >> --
> >> 2.39.1
> >>
>

2023-09-19 02:58:04

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files


在 2023/9/18 下午2:35, Huacai Chen 写道:
> On Mon, Sep 18, 2023 at 2:28 PM zhaotianrui <[email protected]> wrote:
>>
>> 在 2023/9/18 上午9:36, Huacai Chen 写道:
>>> Hi, Tianrui,
>>>
>>> On Mon, Sep 18, 2023 at 9:32 AM zhaotianrui <[email protected]> wrote:
>>>> 在 2023/9/16 下午4:48, Huacai Chen 写道:
>>>>> Hi, Tianrui,
>>>>>
>>>>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>>>>>> Add LoongArch KVM related header files, including kvm.h,
>>>>>> kvm_host.h, kvm_types.h. All of those are about LoongArch
>>>>>> virtualization features and kvm interfaces.
>>>>>>
>>>>>> Reviewed-by: Bibo Mao <[email protected]>
>>>>>> Signed-off-by: Tianrui Zhao <[email protected]>
>>>>>> ---
>>>>>> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
>>>>>> arch/loongarch/include/asm/kvm_types.h | 11 ++
>>>>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
>>>>>> include/uapi/linux/kvm.h | 9 +
>>>>>> 4 files changed, 373 insertions(+)
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>>>>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>>>>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>>>>>
>>>>>> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
>>>>>> new file mode 100644
>>>>>> index 0000000000..00e0c1876b
>>>>>> --- /dev/null
>>>>>> +++ b/arch/loongarch/include/asm/kvm_host.h
>>>>>> @@ -0,0 +1,245 @@
>>>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>>>> +/*
>>>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
>>>>>> +#define __ASM_LOONGARCH_KVM_HOST_H__
>>>>>> +
>>>>>> +#include <linux/cpumask.h>
>>>>>> +#include <linux/mutex.h>
>>>>>> +#include <linux/hrtimer.h>
>>>>>> +#include <linux/interrupt.h>
>>>>>> +#include <linux/types.h>
>>>>>> +#include <linux/kvm.h>
>>>>>> +#include <linux/kvm_types.h>
>>>>>> +#include <linux/threads.h>
>>>>>> +#include <linux/spinlock.h>
>>>>>> +
>>>>>> +#include <asm/inst.h>
>>>>>> +#include <asm/kvm_mmu.h>
>>>>>> +#include <asm/loongarch.h>
>>>>>> +
>>>>>> +/* Loongarch KVM register ids */
>>>>>> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>>>>>> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>>>>>> +
>>>>>> +#define KVM_MAX_VCPUS 256
>>>>>> +#define KVM_MAX_CPUCFG_REGS 21
>>>>>> +/* memory slots that does not exposed to userspace */
>>>>>> +#define KVM_PRIVATE_MEM_SLOTS 0
>>>>>> +
>>>>>> +#define KVM_HALT_POLL_NS_DEFAULT 500000
>>>>>> +
>>>>>> +struct kvm_vm_stat {
>>>>>> + struct kvm_vm_stat_generic generic;
>>>>>> + u64 pages;
>>>>>> + u64 hugepages;
>>>>>> +};
>>>>>> +
>>>>>> +struct kvm_vcpu_stat {
>>>>>> + struct kvm_vcpu_stat_generic generic;
>>>>>> + u64 idle_exits;
>>>>>> + u64 signal_exits;
>>>>>> + u64 int_exits;
>>>>>> + u64 cpucfg_exits;
>>>>>> +};
>>>>>> +
>>>>>> +struct kvm_arch_memory_slot {
>>>>>> +};
>>>>>> +
>>>>>> +struct kvm_context {
>>>>>> + unsigned long vpid_cache;
>>>>>> + struct kvm_vcpu *last_vcpu;
>>>>>> +};
>>>>>> +
>>>>>> +struct kvm_world_switch {
>>>>>> + int (*guest_eentry)(void);
>>>>>> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>>>> + unsigned long page_order;
>>>>>> +};
>>>>>> +
>>>>>> +#define MAX_PGTABLE_LEVELS 4
>>>>>> +struct kvm_arch {
>>>>>> + /* Guest physical mm */
>>>>>> + kvm_pte_t *pgd;
>>>>>> + unsigned long gpa_size;
>>>>>> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
>>>>>> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
>>>>>> + unsigned int root_level;
>>>>>> +
>>>>>> + s64 time_offset;
>>>>>> + struct kvm_context __percpu *vmcs;
>>>>>> +};
>>>>>> +
>>>>>> +#define CSR_MAX_NUMS 0x800
>>>>>> +
>>>>>> +struct loongarch_csrs {
>>>>>> + unsigned long csrs[CSR_MAX_NUMS];
>>>>>> +};
>>>>>> +
>>>>>> +/* Resume Flags */
>>>>>> +#define RESUME_HOST 0
>>>>>> +#define RESUME_GUEST 1
>>>>>> +
>>>>>> +enum emulation_result {
>>>>>> + EMULATE_DONE, /* no further processing */
>>>>>> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
>>>>>> + EMULATE_FAIL, /* can't emulate this instruction */
>>>>>> + EMULATE_EXCEPT, /* A guest exception has been generated */
>>>>>> + EMULATE_DO_IOCSR, /* handle IOCSR request */
>>>>>> +};
>>>>>> +
>>>>>> +#define KVM_LARCH_FPU (0x1 << 0)
>>>>>> +#define KVM_LARCH_CSR (0x1 << 1)
>>>>>> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
>>>>>> +
>>>>>> +struct kvm_vcpu_arch {
>>>>>> + /*
>>>>>> + * Switch pointer-to-function type to unsigned long
>>>>>> + * for loading the value into register directly.
>>>>>> + */
>>>>>> + unsigned long host_eentry;
>>>>>> + unsigned long guest_eentry;
>>>>>> +
>>>>>> + /* Pointers stored here for easy accessing from assembly code */
>>>>>> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>>>> +
>>>>>> + /* Host registers preserved across guest mode execution */
>>>>>> + unsigned long host_sp;
>>>>>> + unsigned long host_tp;
>>>>>> + unsigned long host_pgd;
>>>>>> +
>>>>>> + /* Host CSRs are used when handling exits from guest */
>>>>>> + unsigned long badi;
>>>>>> + unsigned long badv;
>>>>>> + unsigned long host_ecfg;
>>>>>> + unsigned long host_estat;
>>>>>> + unsigned long host_percpu;
>>>>>> +
>>>>>> + /* GPRs */
>>>>>> + unsigned long gprs[32];
>>>>>> + unsigned long pc;
>>>>>> +
>>>>>> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
>>>>>> + unsigned int aux_inuse;
>>>>>> + /* FPU state */
>>>>>> + struct loongarch_fpu fpu FPU_ALIGN;
>>>>>> +
>>>>>> + /* CSR state */
>>>>>> + struct loongarch_csrs *csr;
>>>>>> +
>>>>>> + /* GPR used as IO source/target */
>>>>>> + u32 io_gpr;
>>>>>> +
>>>>>> + struct hrtimer swtimer;
>>>>>> + /* KVM register to control count timer */
>>>>>> + u32 count_ctl;
>>>>>> +
>>>>>> + /* Bitmask of intr that are pending */
>>>>>> + unsigned long irq_pending;
>>>>>> + /* Bitmask of pending intr to be cleared */
>>>>>> + unsigned long irq_clear;
>>>>>> +
>>>>>> + /* Bitmask of exceptions that are pending */
>>>>>> + unsigned long exception_pending;
>>>>>> + unsigned int subcode;
>>>>>> +
>>>>>> + /* Cache for pages needed inside spinlock regions */
>>>>>> + struct kvm_mmu_memory_cache mmu_page_cache;
>>>>>> +
>>>>>> + /* vcpu's vpid */
>>>>>> + u64 vpid;
>>>>>> +
>>>>>> + /* Frequency of stable timer in Hz */
>>>>>> + u64 timer_mhz;
>>>>>> + ktime_t expire;
>>>>>> +
>>>>>> + u64 core_ext_ioisr[4];
>>>>>> +
>>>>>> + /* Last CPU the vCPU state was loaded on */
>>>>>> + int last_sched_cpu;
>>>>>> + /* mp state */
>>>>>> + struct kvm_mp_state mp_state;
>>>>>> + /* cpucfg */
>>>>>> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
>>>>>> +};
>>>>>> +
>>>>>> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
>>>>>> +{
>>>>>> + return csr->csrs[reg];
>>>>>> +}
>>>>>> +
>>>>>> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
>>>>>> +{
>>>>>> + csr->csrs[reg] = val;
>>>>>> +}
>>>>>> +
>>>>>> +/* Helpers */
>>>>>> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
>>>>>> +{
>>>>>> + return cpu_has_fpu;
>>>>>> +}
>>>>>> +
>>>>>> +void kvm_init_fault(void);
>>>>>> +
>>>>>> +/* Debug: dump vcpu state */
>>>>>> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
>>>>>> +
>>>>>> +/* MMU handling */
>>>>>> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
>>>>>> +void kvm_flush_tlb_all(void);
>>>>>> +
>>>>>> +#define KVM_ARCH_WANT_MMU_NOTIFIER
>>>>>> +int kvm_unmap_hva_range(struct kvm *kvm,
>>>>>> + unsigned long start, unsigned long end, bool blockable);
>>>>>> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
>>>>>> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
>>>>>> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>>>>>> +
>>>>>> +static inline void update_pc(struct kvm_vcpu_arch *arch)
>>>>>> +{
>>>>>> + arch->pc += 4;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
>>>>>> + * @vcpu: Virtual CPU.
>>>>>> + *
>>>>>> + * Returns: Whether the TLBL exception was likely due to an instruction
>>>>>> + * fetch fault rather than a data load fault.
>>>>>> + */
>>>>>> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
>>>>>> +{
>>>>>> + return arch->pc == arch->badv;
>>>>>> +}
>>>>>> +
>>>>>> +/* Misc */
>>>>>> +static inline void kvm_arch_hardware_unsetup(void) {}
>>>>>> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
>>>>>> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
>>>>>> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>>>>>> +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) {}
>>>>>> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
>>>>>> + struct kvm_memory_slot *slot) {}
>>>>>> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
>>>>>> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
>>>>>> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
>>>>>> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
>>>>>> + const struct kvm_memory_slot *memslot);
>>>>>> +void kvm_init_vmcs(struct kvm *kvm);
>>>>>> +void kvm_vector_entry(void);
>>>>>> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>>>> +extern const unsigned long kvm_vector_size;
>>>>>> +extern const unsigned long kvm_enter_guest_size;
>>>>>> +extern unsigned long vpid_mask;
>>>>>> +extern struct kvm_world_switch *kvm_loongarch_ops;
>>>>>> +
>>>>>> +#define SW_GCSR (1 << 0)
>>>>>> +#define HW_GCSR (1 << 1)
>>>>>> +#define INVALID_GCSR (1 << 2)
>>>>>> +int get_gcsr_flag(int csr);
>>>>>> +extern void set_hw_gcsr(int csr_id, unsigned long val);
>>>>>> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
>>>>>> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
>>>>>> new file mode 100644
>>>>>> index 0000000000..2fe1d4bdff
>>>>>> --- /dev/null
>>>>>> +++ b/arch/loongarch/include/asm/kvm_types.h
>>>>>> @@ -0,0 +1,11 @@
>>>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>>>> +/*
>>>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
>>>>>> +#define _ASM_LOONGARCH_KVM_TYPES_H
>>>>>> +
>>>>>> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
>>>>>> +
>>>>>> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
>>>>>> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
>>>>>> new file mode 100644
>>>>>> index 0000000000..fafda487d6
>>>>>> --- /dev/null
>>>>>> +++ b/arch/loongarch/include/uapi/asm/kvm.h
>>>>>> @@ -0,0 +1,108 @@
>>>>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>>>>>> +/*
>>>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
>>>>>> +#define __UAPI_ASM_LOONGARCH_KVM_H
>>>>>> +
>>>>>> +#include <linux/types.h>
>>>>>> +
>>>>>> +/*
>>>>>> + * KVM Loongarch specific structures and definitions.
>>>>>> + *
>>>>>> + * Some parts derived from the x86 version of this file.
>>>>>> + */
>>>>>> +
>>>>>> +#define __KVM_HAVE_READONLY_MEM
>>>>>> +
>>>>>> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>>>>> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
>>>>>> +
>>>>>> +/*
>>>>>> + * for KVM_GET_REGS and KVM_SET_REGS
>>>>>> + */
>>>>>> +struct kvm_regs {
>>>>>> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
>>>>>> + __u64 gpr[32];
>>>>>> + __u64 pc;
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * for KVM_GET_FPU and KVM_SET_FPU
>>>>>> + */
>>>>>> +struct kvm_fpu {
>>>>>> + __u32 fcsr;
>>>>>> + __u64 fcc; /* 8x8 */
>>>>>> + struct kvm_fpureg {
>>>>>> + __u64 val64[4];
>>>>>> + } fpr[32];
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
>>>>>> + * registers. The id field is broken down as follows:
>>>>>> + *
>>>>>> + * bits[63..52] - As per linux/kvm.h
>>>>>> + * bits[51..32] - Must be zero.
>>>>>> + * bits[31..16] - Register set.
>>>>>> + *
>>>>>> + * Register set = 0: GP registers from kvm_regs (see definitions below).
>>>>>> + *
>>>>>> + * Register set = 1: CSR registers.
>>>>>> + *
>>>>>> + * Register set = 2: KVM specific registers (see definitions below).
>>>>>> + *
>>>>>> + * Register set = 3: FPU / SIMD registers (see definitions below).
>>>>>> + *
>>>>>> + * Other sets registers may be added in the future. Each set would
>>>>>> + * have its own identifier in bits[31..16].
>>>>>> + */
>>>>>> +
>>>>>> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
>>>>>> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
>>>>>> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
>>>>>> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
>>>>> How about rename to KVM_REG_LOONGARCH_FPSIMD?
>>>>>
>>>>> Huacai
>>>> It will broke uapi used by user space software, it may cause
>>>> incompatible issue, so I think it is better to keep the original name.
>>> In your comments above it is not only FPU but FPU&SIMD, and this code
>>> hasn't been upstream yet, how to break UAPI?
>> We want to apply this patch series to our other project when it is
>> upstream, so we need update the previous codes and it may break the
>> uapi. What do you think of it?
> Generally, the kernel is the first one to be upstream, so kernel can
> do anything reasonable, other projects should align to kernel when
> they want to get upstream.
>
> Huacai
Thanks for your advice, I understand your meaning above and I think it
is better to rename to KVM_REG_LOONGARCH_FPSIMD.

Thanks
Tianrui Zhao
>
>> Thanks
>> Tianrui Zhao
>>> Huacai
>>>
>>>> Thanks
>>>> Tianrui Zhao
>>>>>> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
>>>>>> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
>>>>>> +#define KVM_CSR_IDX_MASK 0x7fff
>>>>>> +#define KVM_CPUCFG_IDX_MASK 0x7fff
>>>>>> +
>>>>>> +/*
>>>>>> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
>>>>>> + */
>>>>>> +
>>>>>> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
>>>>>> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
>>>>>> +
>>>>>> +#define LOONGARCH_REG_SHIFT 3
>>>>>> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
>>>>>> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
>>>>>> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
>>>>>> +
>>>>>> +struct kvm_debug_exit_arch {
>>>>>> +};
>>>>>> +
>>>>>> +/* for KVM_SET_GUEST_DEBUG */
>>>>>> +struct kvm_guest_debug_arch {
>>>>>> +};
>>>>>> +
>>>>>> +/* definition of registers in kvm_run */
>>>>>> +struct kvm_sync_regs {
>>>>>> +};
>>>>>> +
>>>>>> +/* dummy definition */
>>>>>> +struct kvm_sregs {
>>>>>> +};
>>>>>> +
>>>>>> +struct kvm_iocsr_entry {
>>>>>> + __u32 addr;
>>>>>> + __u32 pad;
>>>>>> + __u64 data;
>>>>>> +};
>>>>>> +
>>>>>> +#define KVM_NR_IRQCHIPS 1
>>>>>> +#define KVM_IRQCHIP_NUM_PINS 64
>>>>>> +#define KVM_MAX_CORES 256
>>>>>> +
>>>>>> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
>>>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>>>> index 13065dd961..863f84619a 100644
>>>>>> --- a/include/uapi/linux/kvm.h
>>>>>> +++ b/include/uapi/linux/kvm.h
>>>>>> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
>>>>>> #define KVM_EXIT_RISCV_SBI 35
>>>>>> #define KVM_EXIT_RISCV_CSR 36
>>>>>> #define KVM_EXIT_NOTIFY 37
>>>>>> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>>>>>>
>>>>>> /* For KVM_EXIT_INTERNAL_ERROR */
>>>>>> /* Emulate instruction failed. */
>>>>>> @@ -336,6 +337,13 @@ struct kvm_run {
>>>>>> __u32 len;
>>>>>> __u8 is_write;
>>>>>> } mmio;
>>>>>> + /* KVM_EXIT_LOONGARCH_IOCSR */
>>>>>> + struct {
>>>>>> + __u64 phys_addr;
>>>>>> + __u8 data[8];
>>>>>> + __u32 len;
>>>>>> + __u8 is_write;
>>>>>> + } iocsr_io;
>>>>>> /* KVM_EXIT_HYPERCALL */
>>>>>> struct {
>>>>>> __u64 nr;
>>>>>> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
>>>>>> #define KVM_REG_ARM64 0x6000000000000000ULL
>>>>>> #define KVM_REG_MIPS 0x7000000000000000ULL
>>>>>> #define KVM_REG_RISCV 0x8000000000000000ULL
>>>>>> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>>>>>>
>>>>>> #define KVM_REG_SIZE_SHIFT 52
>>>>>> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
>>>>>> --
>>>>>> 2.39.1
>>>>>>

2023-09-19 02:59:09

by zhaotianrui

[permalink] [raw]
Subject: Re: [PATCH v21 01/29] LoongArch: KVM: Add kvm related header files


在 2023/9/18 下午2:37, Huacai Chen 写道:
> On Mon, Sep 18, 2023 at 2:32 PM zhaotianrui <[email protected]> wrote:
>>
>> 在 2023/9/17 下午10:22, Huacai Chen 写道:
>>> Hi, Tianrui,
>>>
>>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
>>>> Add LoongArch KVM related header files, including kvm.h,
>>>> kvm_host.h, kvm_types.h. All of those are about LoongArch
>>>> virtualization features and kvm interfaces.
>>>>
>>>> Reviewed-by: Bibo Mao <[email protected]>
>>>> Signed-off-by: Tianrui Zhao <[email protected]>
>>>> ---
>>>> arch/loongarch/include/asm/kvm_host.h | 245 +++++++++++++++++++++++++
>>>> arch/loongarch/include/asm/kvm_types.h | 11 ++
>>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++++++++++
>>>> include/uapi/linux/kvm.h | 9 +
>>>> 4 files changed, 373 insertions(+)
>>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
>>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
>>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
>>>>
>>>> diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
>>>> new file mode 100644
>>>> index 0000000000..00e0c1876b
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/include/asm/kvm_host.h
>>>> @@ -0,0 +1,245 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/*
>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#ifndef __ASM_LOONGARCH_KVM_HOST_H__
>>>> +#define __ASM_LOONGARCH_KVM_HOST_H__
>>>> +
>>>> +#include <linux/cpumask.h>
>>>> +#include <linux/mutex.h>
>>>> +#include <linux/hrtimer.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/types.h>
>>>> +#include <linux/kvm.h>
>>>> +#include <linux/kvm_types.h>
>>>> +#include <linux/threads.h>
>>>> +#include <linux/spinlock.h>
>>>> +
>>>> +#include <asm/inst.h>
>>>> +#include <asm/kvm_mmu.h>
>>>> +#include <asm/loongarch.h>
>>>> +
>>>> +/* Loongarch KVM register ids */
>>>> +#define KVM_GET_IOC_CSRIDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>>>> +#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
>>>> +
>>>> +#define KVM_MAX_VCPUS 256
>>>> +#define KVM_MAX_CPUCFG_REGS 21
>>>> +/* memory slots that does not exposed to userspace */
>>>> +#define KVM_PRIVATE_MEM_SLOTS 0
>>>> +
>>>> +#define KVM_HALT_POLL_NS_DEFAULT 500000
>>>> +
>>>> +struct kvm_vm_stat {
>>>> + struct kvm_vm_stat_generic generic;
>>>> + u64 pages;
>>>> + u64 hugepages;
>>>> +};
>>>> +
>>>> +struct kvm_vcpu_stat {
>>>> + struct kvm_vcpu_stat_generic generic;
>>>> + u64 idle_exits;
>>>> + u64 signal_exits;
>>>> + u64 int_exits;
>>>> + u64 cpucfg_exits;
>>>> +};
>>>> +
>>>> +struct kvm_arch_memory_slot {
>>>> +};
>>>> +
>>>> +struct kvm_context {
>>>> + unsigned long vpid_cache;
>>>> + struct kvm_vcpu *last_vcpu;
>>>> +};
>>>> +
>>>> +struct kvm_world_switch {
>>>> + int (*guest_eentry)(void);
>>>> + int (*enter_guest)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>> + unsigned long page_order;
>>>> +};
>>>> +
>>>> +#define MAX_PGTABLE_LEVELS 4
>>>> +struct kvm_arch {
>>>> + /* Guest physical mm */
>>>> + kvm_pte_t *pgd;
>>>> + unsigned long gpa_size;
>>>> + unsigned long invalid_ptes[MAX_PGTABLE_LEVELS];
>>>> + unsigned int pte_shifts[MAX_PGTABLE_LEVELS];
>>>> + unsigned int root_level;
>>>> +
>>>> + s64 time_offset;
>>>> + struct kvm_context __percpu *vmcs;
>>>> +};
>>>> +
>>>> +#define CSR_MAX_NUMS 0x800
>>>> +
>>>> +struct loongarch_csrs {
>>>> + unsigned long csrs[CSR_MAX_NUMS];
>>>> +};
>>>> +
>>>> +/* Resume Flags */
>>>> +#define RESUME_HOST 0
>>>> +#define RESUME_GUEST 1
>>>> +
>>>> +enum emulation_result {
>>>> + EMULATE_DONE, /* no further processing */
>>>> + EMULATE_DO_MMIO, /* kvm_run filled with MMIO request */
>>>> + EMULATE_FAIL, /* can't emulate this instruction */
>>>> + EMULATE_EXCEPT, /* A guest exception has been generated */
>>>> + EMULATE_DO_IOCSR, /* handle IOCSR request */
>>>> +};
>>>> +
>>>> +#define KVM_LARCH_FPU (0x1 << 0)
>>>> +#define KVM_LARCH_CSR (0x1 << 1)
>>>> +#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
>>>> +
>>>> +struct kvm_vcpu_arch {
>>>> + /*
>>>> + * Switch pointer-to-function type to unsigned long
>>>> + * for loading the value into register directly.
>>>> + */
>>>> + unsigned long host_eentry;
>>>> + unsigned long guest_eentry;
>>>> +
>>>> + /* Pointers stored here for easy accessing from assembly code */
>>>> + int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>> +
>>>> + /* Host registers preserved across guest mode execution */
>>>> + unsigned long host_sp;
>>>> + unsigned long host_tp;
>>>> + unsigned long host_pgd;
>>>> +
>>>> + /* Host CSRs are used when handling exits from guest */
>>>> + unsigned long badi;
>>>> + unsigned long badv;
>>>> + unsigned long host_ecfg;
>>>> + unsigned long host_estat;
>>>> + unsigned long host_percpu;
>>>> +
>>>> + /* GPRs */
>>>> + unsigned long gprs[32];
>>>> + unsigned long pc;
>>>> +
>>>> + /* Which auxiliary state is loaded (KVM_LARCH_*) */
>>>> + unsigned int aux_inuse;
>>>> + /* FPU state */
>>>> + struct loongarch_fpu fpu FPU_ALIGN;
>>>> +
>>>> + /* CSR state */
>>>> + struct loongarch_csrs *csr;
>>>> +
>>>> + /* GPR used as IO source/target */
>>>> + u32 io_gpr;
>>>> +
>>>> + struct hrtimer swtimer;
>>>> + /* KVM register to control count timer */
>>>> + u32 count_ctl;
>>>> +
>>>> + /* Bitmask of intr that are pending */
>>>> + unsigned long irq_pending;
>>>> + /* Bitmask of pending intr to be cleared */
>>>> + unsigned long irq_clear;
>>>> +
>>>> + /* Bitmask of exceptions that are pending */
>>>> + unsigned long exception_pending;
>>>> + unsigned int subcode;
>>>> +
>>>> + /* Cache for pages needed inside spinlock regions */
>>>> + struct kvm_mmu_memory_cache mmu_page_cache;
>>>> +
>>>> + /* vcpu's vpid */
>>>> + u64 vpid;
>>>> +
>>>> + /* Frequency of stable timer in Hz */
>>>> + u64 timer_mhz;
>>>> + ktime_t expire;
>>>> +
>>>> + u64 core_ext_ioisr[4];
>>>> +
>>>> + /* Last CPU the vCPU state was loaded on */
>>>> + int last_sched_cpu;
>>>> + /* mp state */
>>>> + struct kvm_mp_state mp_state;
>>>> + /* cpucfg */
>>>> + u32 cpucfg[KVM_MAX_CPUCFG_REGS];
>>>> +};
>>>> +
>>>> +static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
>>>> +{
>>>> + return csr->csrs[reg];
>>>> +}
>>>> +
>>>> +static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned long val)
>>>> +{
>>>> + csr->csrs[reg] = val;
>>>> +}
>>>> +
>>>> +/* Helpers */
>>>> +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
>>>> +{
>>>> + return cpu_has_fpu;
>>>> +}
>>>> +
>>>> +void kvm_init_fault(void);
>>>> +
>>>> +/* Debug: dump vcpu state */
>>>> +int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
>>>> +
>>>> +/* MMU handling */
>>>> +int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
>>>> +void kvm_flush_tlb_all(void);
>>>> +
>>>> +#define KVM_ARCH_WANT_MMU_NOTIFIER
>>>> +int kvm_unmap_hva_range(struct kvm *kvm,
>>>> + unsigned long start, unsigned long end, bool blockable);
>>>> +void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
>>>> +int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
>>>> +int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
>>>> +
>>>> +static inline void update_pc(struct kvm_vcpu_arch *arch)
>>>> +{
>>>> + arch->pc += 4;
>>>> +}
>>>> +
>>>> +/**
>>>> + * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
>>>> + * @vcpu: Virtual CPU.
>>>> + *
>>>> + * Returns: Whether the TLBL exception was likely due to an instruction
>>>> + * fetch fault rather than a data load fault.
>>>> + */
>>>> +static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *arch)
>>>> +{
>>>> + return arch->pc == arch->badv;
>>>> +}
>>>> +
>>>> +/* Misc */
>>>> +static inline void kvm_arch_hardware_unsetup(void) {}
>>>> +static inline void kvm_arch_sync_events(struct kvm *kvm) {}
>>>> +static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {}
>>>> +static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
>>>> +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) {}
>>>> +static inline void kvm_arch_free_memslot(struct kvm *kvm,
>>>> + struct kvm_memory_slot *slot) {}
>>>> +void kvm_check_vpid(struct kvm_vcpu *vcpu);
>>>> +enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer);
>>>> +int kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
>>>> +void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
>>>> + const struct kvm_memory_slot *memslot);
>>>> +void kvm_init_vmcs(struct kvm *kvm);
>>>> +void kvm_vector_entry(void);
>>>> +int kvm_enter_guest(struct kvm_run *run, struct kvm_vcpu *vcpu);
>>>> +extern const unsigned long kvm_vector_size;
>>>> +extern const unsigned long kvm_enter_guest_size;
>>>> +extern unsigned long vpid_mask;
>>>> +extern struct kvm_world_switch *kvm_loongarch_ops;
>>>> +
>>>> +#define SW_GCSR (1 << 0)
>>>> +#define HW_GCSR (1 << 1)
>>>> +#define INVALID_GCSR (1 << 2)
>>>> +int get_gcsr_flag(int csr);
>>>> +extern void set_hw_gcsr(int csr_id, unsigned long val);
>>>> +#endif /* __ASM_LOONGARCH_KVM_HOST_H__ */
>>>> diff --git a/arch/loongarch/include/asm/kvm_types.h b/arch/loongarch/include/asm/kvm_types.h
>>>> new file mode 100644
>>>> index 0000000000..2fe1d4bdff
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/include/asm/kvm_types.h
>>>> @@ -0,0 +1,11 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>> +/*
>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#ifndef _ASM_LOONGARCH_KVM_TYPES_H
>>>> +#define _ASM_LOONGARCH_KVM_TYPES_H
>>>> +
>>>> +#define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40
>>>> +
>>>> +#endif /* _ASM_LOONGARCH_KVM_TYPES_H */
>>>> diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
>>>> new file mode 100644
>>>> index 0000000000..fafda487d6
>>>> --- /dev/null
>>>> +++ b/arch/loongarch/include/uapi/asm/kvm.h
>>>> @@ -0,0 +1,108 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
>>>> +/*
>>>> + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
>>>> + */
>>>> +
>>>> +#ifndef __UAPI_ASM_LOONGARCH_KVM_H
>>>> +#define __UAPI_ASM_LOONGARCH_KVM_H
>>>> +
>>>> +#include <linux/types.h>
>>>> +
>>>> +/*
>>>> + * KVM Loongarch specific structures and definitions.
>>>> + *
>>>> + * Some parts derived from the x86 version of this file.
>>>> + */
>>>> +
>>>> +#define __KVM_HAVE_READONLY_MEM
>>>> +
>>>> +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>>> +#define KVM_DIRTY_LOG_PAGE_OFFSET 64
>>>> +
>>>> +/*
>>>> + * for KVM_GET_REGS and KVM_SET_REGS
>>>> + */
>>>> +struct kvm_regs {
>>>> + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
>>>> + __u64 gpr[32];
>>>> + __u64 pc;
>>>> +};
>>>> +
>>>> +/*
>>>> + * for KVM_GET_FPU and KVM_SET_FPU
>>>> + */
>>>> +struct kvm_fpu {
>>>> + __u32 fcsr;
>>>> + __u64 fcc; /* 8x8 */
>>>> + struct kvm_fpureg {
>>>> + __u64 val64[4];
>>>> + } fpr[32];
>>>> +};
>>>> +
>>>> +/*
>>>> + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various
>>>> + * registers. The id field is broken down as follows:
>>>> + *
>>>> + * bits[63..52] - As per linux/kvm.h
>>>> + * bits[51..32] - Must be zero.
>>>> + * bits[31..16] - Register set.
>>>> + *
>>>> + * Register set = 0: GP registers from kvm_regs (see definitions below).
>>>> + *
>>>> + * Register set = 1: CSR registers.
>>>> + *
>>>> + * Register set = 2: KVM specific registers (see definitions below).
>>>> + *
>>>> + * Register set = 3: FPU / SIMD registers (see definitions below).
>>>> + *
>>>> + * Other sets registers may be added in the future. Each set would
>>>> + * have its own identifier in bits[31..16].
>>>> + */
>>>> +
>>>> +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL)
>>>> +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL)
>>>> +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL)
>>>> +#define KVM_REG_LOONGARCH_FPU (KVM_REG_LOONGARCH | 0x30000ULL)
>>>> +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL)
>>>> +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL)
>>>> +#define KVM_CSR_IDX_MASK 0x7fff
>>>> +#define KVM_CPUCFG_IDX_MASK 0x7fff
>>>> +
>>>> +/*
>>>> + * KVM_REG_LOONGARCH_KVM - KVM specific control registers.
>>>> + */
>>>> +
>>>> +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3)
>>>> +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 4)
>>> Why begin with 3? 0, 1, 2 reserved for what?
>> They are keep consistent with our original codes, and 0,1,2 are not used
>> now.
> The same as KVM_REG_LOONGARCH_FPU, kernel is the first one, so I
> suggest beginning with 0 or 1, but don't begin with 3.
>
> Huacai
Thanks for your advice, it is better to change the beginning to 0,1.

Thanks
Tianrui Zhao
>
>> Thanks
>> Tianrui Zhao
>>> Huacai
>>>
>>>> +
>>>> +#define LOONGARCH_REG_SHIFT 3
>>>> +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
>>>> +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
>>>> +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
>>>> +
>>>> +struct kvm_debug_exit_arch {
>>>> +};
>>>> +
>>>> +/* for KVM_SET_GUEST_DEBUG */
>>>> +struct kvm_guest_debug_arch {
>>>> +};
>>>> +
>>>> +/* definition of registers in kvm_run */
>>>> +struct kvm_sync_regs {
>>>> +};
>>>> +
>>>> +/* dummy definition */
>>>> +struct kvm_sregs {
>>>> +};
>>>> +
>>>> +struct kvm_iocsr_entry {
>>>> + __u32 addr;
>>>> + __u32 pad;
>>>> + __u64 data;
>>>> +};
>>>> +
>>>> +#define KVM_NR_IRQCHIPS 1
>>>> +#define KVM_IRQCHIP_NUM_PINS 64
>>>> +#define KVM_MAX_CORES 256
>>>> +
>>>> +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>> index 13065dd961..863f84619a 100644
>>>> --- a/include/uapi/linux/kvm.h
>>>> +++ b/include/uapi/linux/kvm.h
>>>> @@ -264,6 +264,7 @@ struct kvm_xen_exit {
>>>> #define KVM_EXIT_RISCV_SBI 35
>>>> #define KVM_EXIT_RISCV_CSR 36
>>>> #define KVM_EXIT_NOTIFY 37
>>>> +#define KVM_EXIT_LOONGARCH_IOCSR 38
>>>>
>>>> /* For KVM_EXIT_INTERNAL_ERROR */
>>>> /* Emulate instruction failed. */
>>>> @@ -336,6 +337,13 @@ struct kvm_run {
>>>> __u32 len;
>>>> __u8 is_write;
>>>> } mmio;
>>>> + /* KVM_EXIT_LOONGARCH_IOCSR */
>>>> + struct {
>>>> + __u64 phys_addr;
>>>> + __u8 data[8];
>>>> + __u32 len;
>>>> + __u8 is_write;
>>>> + } iocsr_io;
>>>> /* KVM_EXIT_HYPERCALL */
>>>> struct {
>>>> __u64 nr;
>>>> @@ -1362,6 +1370,7 @@ struct kvm_dirty_tlb {
>>>> #define KVM_REG_ARM64 0x6000000000000000ULL
>>>> #define KVM_REG_MIPS 0x7000000000000000ULL
>>>> #define KVM_REG_RISCV 0x8000000000000000ULL
>>>> +#define KVM_REG_LOONGARCH 0x9000000000000000ULL
>>>>
>>>> #define KVM_REG_SIZE_SHIFT 52
>>>> #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
>>>> --
>>>> 2.39.1
>>>>

2023-09-21 04:56:21

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support

On Sat, Sep 16, 2023 at 5:17 AM Huacai Chen <[email protected]> wrote:
> I can test now, during my tests I may ask some other questions about
> your patches. You just need to answer my questions and I will adjust
> the code myself if needed. After that I will give you a final version
> with Tested-by and you can simply send that as V22.

Since you are preparing yourself the v22, you could also send it to me
as a pull request.

Thanks,

Paolo

2023-09-21 17:37:13

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support

Hi, Tianrui,

On Sat, Sep 16, 2023 at 2:30 PM zhaotianrui <[email protected]> wrote:
>
>
> 在 2023/9/16 上午11:17, Huacai Chen 写道:
> > Hi, Tianrui,
> >
> > On Fri, Sep 15, 2023 at 3:53 PM zhaotianrui <[email protected]> wrote:
> >>
> >> 在 2023/9/15 下午3:10, Huacai Chen 写道:
> >>> Hi, Tianrui,
> >>>
> >>> On Fri, Sep 15, 2023 at 2:58 PM zhaotianrui <[email protected]> wrote:
> >>>> 在 2023/9/15 下午12:11, Huacai Chen 写道:
> >>>>> Hi, Tianrui,
> >>>>>
> >>>>> On Fri, Sep 15, 2023 at 9:50 AM Tianrui Zhao <[email protected]> wrote:
> >>>>>> This series adds KVM LoongArch support. Loongson 3A5000 supports hardware
> >>>>>> assisted virtualization. With cpu virtualization, there are separate
> >>>>>> hw-supported user mode and kernel mode in guest mode. With memory
> >>>>>> virtualization, there are two-level hw mmu table for guest mode and host
> >>>>>> mode. Also there is separate hw cpu timer with consant frequency in
> >>>>>> guest mode, so that vm can migrate between hosts with different freq.
> >>>>>> Currently, we are able to boot LoongArch Linux Guests.
> >>>>>>
> >>>>>> Few key aspects of KVM LoongArch added by this series are:
> >>>>>> 1. Enable kvm hardware function when kvm module is loaded.
> >>>>>> 2. Implement VM and vcpu related ioctl interface such as vcpu create,
> >>>>>> vcpu run etc. GET_ONE_REG/SET_ONE_REG ioctl commands are use to
> >>>>>> get general registers one by one.
> >>>>>> 3. Hardware access about MMU, timer and csr are emulated in kernel.
> >>>>>> 4. Hardwares such as mmio and iocsr device are emulated in user space
> >>>>>> such as APIC, IPI, pci devices etc.
> >>>>>>
> >>>>>> The running environment of LoongArch virt machine:
> >>>>>> 1. Cross tools for building kernel and uefi:
> >>>>>> https://github.com/loongson/build-tools
> >>>>>> 2. This series is based on the linux source code:
> >>>>>> https://github.com/loongson/linux-loongarch-kvm
> >>>>>> Build command:
> >>>>>> git checkout kvm-loongarch
> >>>>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- loongson3_defconfig
> >>>>>> make ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu-
> >>>>>> 3. QEMU hypervisor with LoongArch supported:
> >>>>>> https://github.com/loongson/qemu
> >>>>>> Build command:
> >>>>>> git checkout kvm-loongarch
> >>>>>> ./configure --target-list="loongarch64-softmmu" --enable-kvm
> >>>>>> make
> >>>>> When I build qemu, I get:
> >>>>> [3/964] Compiling C object
> >>>>> libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> >>>>> FAILED: libqemu-loongarch64-softmmu.fa.p/target_loongarch_loongarch-qmp-cmds.c.o
> >>>>> cc -Ilibqemu-loongarch64-softmmu.fa.p -I. -I.. -Itarget/loongarch
> >>>>> -I../target/loongarch -Isubprojects/dtc/libfdt
> >>>>> -I../subprojects/dtc/libfdt -Iqapi -Itrace c
> >>>>> In file included from ../target/loongarch/loongarch-qmp-cmds.c:11:
> >>>>> ../target/loongarch/cpu.h:351:14: error: duplicate member 'CSR_CPUID'
> >>>>> 351 | uint64_t CSR_CPUID;
> >>>>> | ^~~~~~~~~
> >>>>> ninja: build stopped: subcommand failed.
> >>>>> make[1]: *** [Makefile:162: run-ninja] Error 1
> >>>>> make[1]: Leaving directory '/root/qemu/build'
> >>>>> make: *** [GNUmakefile:11: all] Error 2
> >>>>>
> >>>>> Huacai
> >>>> Sorry, I have submitted patch to fix this error, you could git pull to
> >>>> update it.
> >>> After git pull, I get a new error:
> >>> [70/912] Compiling C object
> >>> libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-icount.c.o
> >>> [71/912] Compiling C object
> >>> libqemu-loongarch64-softmmu.fa.p/accel_tcg_tcg-accel-ops-rr.c.o
> >>> [72/912] Linking target qemu-system-loongarch64
> >>> FAILED: qemu-system-loongarch64
> >>> cc -o qemu-system-loongarch64 libcommon.fa.p/hw_core_cpu-common.c.o
> >>> libcommon.fa.p/hw_core_machine-smp.c.o
> >>> libcommon.fa.p/gdbstub_syscalls.c.o libcommon.fap
> >>> /usr/bin/ld: libqemu-loongarch64-softmmu.fa.p/accel_kvm_kvm-all.c.o:
> >>> in function `kvm_init':
> >>> /root/qemu/build/../accel/kvm/kvm-all.c:2525:(.text+0x66f4): undefined
> >>> reference to `kvm_arch_get_default_type'
> >>> collect2: error: ld returned 1 exit status
> >>> ninja: build stopped: subcommand failed.
> >>> make[1]: *** [Makefile:162: run-ninja] Error 1
> >>> make[1]: Leaving directory '/root/qemu/build'
> >>> make: *** [GNUmakefile:11: all] Error 2
> >>>
> >>> Huacai
> >> Sorry, I have resolved this mistake and submit to the source, you could
> >> update it.
> > I can test now, during my tests I may ask some other questions about
> > your patches. You just need to answer my questions and I will adjust
> > the code myself if needed. After that I will give you a final version
> > with Tested-by and you can simply send that as V22.
> >
> > Huacai
> Ok, thanks for your reviewing carefully.

Now I complete my test and the final version is here:
https://github.com/chenhuacai/linux/commits/loongarch-next

You can pick the last 25 commits as v22. But please do a complete
testing before sending patches. And please contact with me if you have
any problems.

Changes for v22:
1. Combine very small patches.
2. Define KVM_REG_LOONGARCH_KVM registers begin with 1.
3. Remove unused KVM_LOONGSON_IRQ_* definitions.
4. Mark HW_GCSR/SW_GCSR correctly in kvm_init_gcsr_flag().
5. Make kvm_flush_tlb_gpa() be a void function, since it always return 0.
6. Rename KVM_REG_LOONGARCH_FPU to KVM_REG_LOONGARCH_FPSIMD which is
more accurate.
7. Rename KVM_LARCH_CSR to KVM_LARCH_SWCSR_LATEST, corresponding to
KVM_LARCH_HWCSR_USABLE.
8. Rename int_to_coreint to priority_to_irq, corresponding to the
defined varible names.
9. Replace if-else with switch-case in kvm_handle_csr().
10. Replace if-else with switch-case in
kvm_emu_mmio_read()/kvm_emu_mmio_write().
11. Remove ANON_INODES/SRCU in Kconfig since they are already selected
unconditinally.
12. Many coding style adjustment and typo fixes.



Huacai

>
> Thanks
> Tianrui Zhao
> >
> >> Thanks
> >> Tianrui Zhao
> >>>> Thanks
> >>>> Tianrui Zhao
> >>>>>> 4. Uefi bios of LoongArch virt machine:
> >>>>>> Link: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
> >>>>>> 5. you can also access the binary files we have already build:
> >>>>>> https://github.com/yangxiaojuan-loongson/qemu-binary
> >>>>>> The command to boot loongarch virt machine:
> >>>>>> $ qemu-system-loongarch64 -machine virt -m 4G -cpu la464 \
> >>>>>> -smp 1 -bios QEMU_EFI.fd -kernel vmlinuz.efi -initrd ramdisk \
> >>>>>> -serial stdio -monitor telnet:localhost:4495,server,nowait \
> >>>>>> -append "root=/dev/ram rdinit=/sbin/init console=ttyS0,115200" \
> >>>>>> --nographic
> >>>>>>
> >>>>>> Changes for v21:
> >>>>>> 1. Remove unnecessary prefix '_' in some kvm function names.
> >>>>>> 2. Replace check_vmid with check_vpid, and move the functions
> >>>>>> to main.c.
> >>>>>> 3. Re-order the file names and config names by alphabetical
> >>>>>> in KVM makefile and Kconfig.
> >>>>>> 4. Code clean up for KVM mmu and get,set gcsr and vcpu_arch
> >>>>>> ioctl functions.
> >>>>>>
> >>>>>> changes for v20:
> >>>>>> 1. Remove the binary code of virtualization instructions in
> >>>>>> insn_def.h and csr_ops.S and directly use the default csrrd,
> >>>>>> csrwr,csrxchg instructions. And let CONFIG_KVM depends on the
> >>>>>> AS_HAS_LVZ_EXTENSION, so we should use the binutils that have
> >>>>>> already supported them to compile the KVM. This can make our
> >>>>>> LoongArch KVM codes more maintainable and easier.
> >>>>>>
> >>>>>> changes for v19:
> >>>>>> 1. Use the common interface xfer_to_guest_mode_handle_work to
> >>>>>> Check conditions before entering the guest.
> >>>>>> 2. Add vcpu dirty ring support.
> >>>>>>
> >>>>>> changes for v18:
> >>>>>> 1. Code cleanup for vcpu timer: remove unnecessary timer_period_ns,
> >>>>>> timer_bias, timer_dyn_bias variables in kvm_vcpu_arch and rename
> >>>>>> the stable_ktime_saved variable to expire.
> >>>>>> 2. Change the value of KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE to 40.
> >>>>>>
> >>>>>> changes for v17:
> >>>>>> 1. Add CONFIG_AS_HAS_LVZ_EXTENSION config option which depends on
> >>>>>> binutils that support LVZ assemble instruction.
> >>>>>> 2. Change kvm mmu related functions, such as rename level2_ptw_pgd
> >>>>>> to kvm_ptw_pgd, replace kvm_flush_range with kvm_ptw_pgd pagewalk
> >>>>>> framework, replace kvm_arch.gpa_mm with kvm_arch.pgd, set
> >>>>>> mark_page_dirty/kvm_set_pfn_dirty out of mmu_lock in kvm page fault
> >>>>>> handling.
> >>>>>> 3. Replace kvm_loongarch_interrupt with standard kvm_interrupt
> >>>>>> when injecting IRQ.
> >>>>>> 4. Replace vcpu_arch.last_exec_cpu with existing vcpu.cpu, remove
> >>>>>> kvm_arch.online_vcpus and kvm_arch.is_migrating,
> >>>>>> 5. Remove EXCCODE_TLBNR and EXCCODE_TLBNX in kvm exception table,
> >>>>>> since NR/NX bit is not set in kvm page fault handling.
> >>>>>>
> >>>>>> Changes for v16:
> >>>>>> 1. Free allocated memory of vmcs,kvm_loongarch_ops in kvm module init,
> >>>>>> exit to avoid memory leak problem.
> >>>>>> 2. Simplify some assemble codes in switch.S which are necessary to be
> >>>>>> replaced with pseudo-instructions. And any other instructions do not need
> >>>>>> to be replaced anymore.
> >>>>>> 3. Add kvm_{save,restore}_guest_gprs macros to replace these ld.d,st.d
> >>>>>> guest regs instructions when vcpu world switch.
> >>>>>> 4. It is more secure to disable irq when flush guest tlb by gpa, so replace
> >>>>>> preempt_disable with loacl_irq_save in kvm_flush_tlb_gpa.
> >>>>>>
> >>>>>> Changes for v15:
> >>>>>> 1. Re-order some macros and variables in LoongArch kvm headers, put them
> >>>>>> together which have the same meaning.
> >>>>>> 2. Make some function definitions in one line, as it is not needed to split
> >>>>>> them.
> >>>>>> 3. Re-name some macros such as KVM_REG_LOONGARCH_GPR.
> >>>>>>
> >>>>>> Changes for v14:
> >>>>>> 1. Remove the macro CONFIG_KVM_GENERIC_HARDWARE_ENABLING in
> >>>>>> loongarch/kvm/main.c, as it is not useful.
> >>>>>> 2. Add select KVM_GENERIC_HARDWARE_ENABLING in loongarch/kvm/Kconfig,
> >>>>>> as it is used by virt/kvm.
> >>>>>> 3. Fix the LoongArch KVM source link in MAINTAINERS.
> >>>>>> 4. Improve LoongArch KVM documentation, such as add comment for
> >>>>>> LoongArch kvm_regs.
> >>>>>>
> >>>>>> Changes for v13:
> >>>>>> 1. Remove patch-28 "Implement probe virtualization when cpu init", as the
> >>>>>> virtualization information about FPU,PMP,LSX in guest.options,options_dyn
> >>>>>> is not used and the gcfg reg value can be read in kvm_hardware_enable, so
> >>>>>> remove the previous cpu_probe_lvz function.
> >>>>>> 2. Fix vcpu_enable_cap interface, it should return -EINVAL directly, as
> >>>>>> FPU cap is enable by default, and do not support any other caps now.
> >>>>>> 3. Simplify the jirl instruction with jr when without return addr,
> >>>>>> simplify case HW0 ... HW7 statment in interrupt.c
> >>>>>> 4. Rename host_stack,host_gp in kvm_vcpu_arch to host_sp,host_tp.
> >>>>>> 5. Remove 'cpu' parameter in _kvm_check_requests, as 'cpu' is not used,
> >>>>>> and remove 'cpu' parameter in kvm_check_vmid function, as it can get
> >>>>>> cpu number by itself.
> >>>>>>
> >>>>>> Changes for v12:
> >>>>>> 1. Improve the gcsr write/read/xchg interface to avoid the previous
> >>>>>> instruction statment like parse_r and make the code easy understanding,
> >>>>>> they are implemented in asm/insn-def.h and the instructions consistent
> >>>>>> of "opcode" "rj" "rd" "simm14" arguments.
> >>>>>> 2. Fix the maintainers list of LoongArch KVM.
> >>>>>>
> >>>>>> Changes for v11:
> >>>>>> 1. Add maintainers for LoongArch KVM.
> >>>>>>
> >>>>>> Changes for v10:
> >>>>>> 1. Fix grammatical problems in LoongArch documentation.
> >>>>>> 2. It is not necessary to save or restore the LOONGARCH_CSR_PGD when
> >>>>>> vcpu put and vcpu load, so we remove it.
> >>>>>>
> >>>>>> Changes for v9:
> >>>>>> 1. Apply the new defined interrupt number macros in loongarch.h to kvm,
> >>>>>> such as INT_SWI0, INT_HWI0, INT_TI, INT_IPI, etc. And remove the
> >>>>>> previous unused macros.
> >>>>>> 2. Remove unused variables in kvm_vcpu_arch, and reorder the variables
> >>>>>> to make them more standard.
> >>>>>>
> >>>>>> Changes for v8:
> >>>>>> 1. Adjust the cpu_data.guest.options structure, add the ases flag into
> >>>>>> it, and remove the previous guest.ases. We do this to keep consistent
> >>>>>> with host cpu_data.options structure.
> >>>>>> 2. Remove the "#include <asm/kvm_host.h>" in some files which also
> >>>>>> include the "<linux/kvm_host.h>". As linux/kvm_host.h already include
> >>>>>> the asm/kvm_host.h.
> >>>>>> 3. Fix some unstandard spelling and grammar errors in comments, and
> >>>>>> improve a little code format to make it easier and standard.
> >>>>>>
> >>>>>> Changes for v7:
> >>>>>> 1. Fix the kvm_save/restore_hw_gcsr compiling warnings reported by
> >>>>>> kernel test robot. The report link is:
> >>>>>> https://lore.kernel.org/oe-kbuild-all/[email protected]/
> >>>>>> 2. Fix loongarch kvm trace related compiling problems.
> >>>>>>
> >>>>>> Changes for v6:
> >>>>>> 1. Fix the Documentation/virt/kvm/api.rst compile warning about
> >>>>>> loongarch parts.
> >>>>>>
> >>>>>> Changes for v5:
> >>>>>> 1. Implement get/set mp_state ioctl interface, and only the
> >>>>>> KVM_MP_STATE_RUNNABLE state is supported now, and other states
> >>>>>> will be completed in the future. The state is also used when vcpu
> >>>>>> run idle instruction, if vcpu state is changed to RUNNABLE, the
> >>>>>> vcpu will have the possibility to be woken up.
> >>>>>> 2. Supplement kvm document about loongarch-specific part, such as add
> >>>>>> api introduction for GET/SET_ONE_REG, GET/SET_FPU, GET/SET_MP_STATE,
> >>>>>> etc.
> >>>>>> 3. Improve the kvm_switch_to_guest function in switch.S, remove the
> >>>>>> previous tmp,tmp1 arguments and replace it with t0,t1 reg.
> >>>>>>
> >>>>>> Changes for v4:
> >>>>>> 1. Add a csr_need_update flag in _vcpu_put, as most csr registers keep
> >>>>>> unchanged during process context switch, so we need not to update it
> >>>>>> every time. We can do this only if the soft csr is different form hardware.
> >>>>>> That is to say all of csrs should update after vcpu enter guest, as for
> >>>>>> set_csr_ioctl, we have written soft csr to keep consistent with hardware.
> >>>>>> 2. Improve get/set_csr_ioctl interface, we set SW or HW or INVALID flag
> >>>>>> for all csrs according to it's features when kvm init. In get/set_csr_ioctl,
> >>>>>> if csr is HW, we use gcsrrd/ gcsrwr instruction to access it, else if csr is
> >>>>>> SW, we use software to emulate it, and others return false.
> >>>>>> 3. Add set_hw_gcsr function in csr_ops.S, and it is used in set_csr_ioctl.
> >>>>>> We have splited hw gcsr into three parts, so we can calculate the code offset
> >>>>>> by gcsrid and jump here to run the gcsrwr instruction. We use this function to
> >>>>>> make the code easier and avoid to use the previous SET_HW_GCSR(XXX) interface.
> >>>>>> 4. Improve kvm mmu functions, such as flush page table and make clean page table
> >>>>>> interface.
> >>>>>>
> >>>>>> Changes for v3:
> >>>>>> 1. Remove the vpid array list in kvm_vcpu_arch and use a vpid variable here,
> >>>>>> because a vpid will never be recycled if a vCPU migrates from physical CPU A
> >>>>>> to B and back to A.
> >>>>>> 2. Make some constant variables in kvm_context to global such as vpid_mask,
> >>>>>> guest_eentry, enter_guest, etc.
> >>>>>> 3. Add some new tracepoints, such as kvm_trace_idle, kvm_trace_cache,
> >>>>>> kvm_trace_gspr, etc.
> >>>>>> 4. There are some duplicate codes in kvm_handle_exit and kvm_vcpu_run,
> >>>>>> so we move it to a new function kvm_pre_enter_guest.
> >>>>>> 5. Change the RESUME_HOST, RESUME_GUEST value, return 1 for resume guest
> >>>>>> and "<= 0" for resume host.
> >>>>>> 6. Fcsr and fpu registers are saved/restored together.
> >>>>>>
> >>>>>> Changes for v2:
> >>>>>> 1. Seprate the original patch-01 and patch-03 into small patches, and the
> >>>>>> patches mainly contain kvm module init, module exit, vcpu create, vcpu run,
> >>>>>> etc.
> >>>>>> 2. Remove the original KVM_{GET,SET}_CSRS ioctl in the kvm uapi header,
> >>>>>> and we use the common KVM_{GET,SET}_ONE_REG to access register.
> >>>>>> 3. Use BIT(x) to replace the "1 << n_bits" statement.
> >>>>>>
> >>>>>> Tianrui Zhao (29):
> >>>>>> LoongArch: KVM: Add kvm related header files
> >>>>>> LoongArch: KVM: Implement kvm module related interface
> >>>>>> LoongArch: KVM: Implement kvm hardware enable, disable interface
> >>>>>> LoongArch: KVM: Implement VM related functions
> >>>>>> LoongArch: KVM: Add vcpu related header files
> >>>>>> LoongArch: KVM: Implement vcpu create and destroy interface
> >>>>>> LoongArch: KVM: Implement vcpu run interface
> >>>>>> LoongArch: KVM: Implement vcpu handle exit interface
> >>>>>> LoongArch: KVM: Implement vcpu get, vcpu set registers
> >>>>>> LoongArch: KVM: Implement vcpu ENABLE_CAP ioctl interface
> >>>>>> LoongArch: KVM: Implement fpu related operations for vcpu
> >>>>>> LoongArch: KVM: Implement vcpu interrupt operations
> >>>>>> LoongArch: KVM: Implement misc vcpu related interfaces
> >>>>>> LoongArch: KVM: Implement vcpu load and vcpu put operations
> >>>>>> LoongArch: KVM: Implement vcpu status description
> >>>>>> LoongArch: KVM: Implement virtual machine tlb operations
> >>>>>> LoongArch: KVM: Implement vcpu timer operations
> >>>>>> LoongArch: KVM: Implement kvm mmu operations
> >>>>>> LoongArch: KVM: Implement handle csr exception
> >>>>>> LoongArch: KVM: Implement handle iocsr exception
> >>>>>> LoongArch: KVM: Implement handle idle exception
> >>>>>> LoongArch: KVM: Implement handle gspr exception
> >>>>>> LoongArch: KVM: Implement handle mmio exception
> >>>>>> LoongArch: KVM: Implement handle fpu exception
> >>>>>> LoongArch: KVM: Implement kvm exception vector
> >>>>>> LoongArch: KVM: Implement vcpu world switch
> >>>>>> LoongArch: KVM: Enable kvm config and add the makefile
> >>>>>> LoongArch: KVM: Supplement kvm document about LoongArch-specific part
> >>>>>> LoongArch: KVM: Add maintainers for LoongArch KVM
> >>>>>>
> >>>>>> Documentation/virt/kvm/api.rst | 70 +-
> >>>>>> MAINTAINERS | 12 +
> >>>>>> arch/loongarch/Kbuild | 1 +
> >>>>>> arch/loongarch/Kconfig | 3 +
> >>>>>> arch/loongarch/configs/loongson3_defconfig | 2 +
> >>>>>> arch/loongarch/include/asm/inst.h | 16 +
> >>>>>> arch/loongarch/include/asm/kvm_csr.h | 221 +++++
> >>>>>> arch/loongarch/include/asm/kvm_host.h | 245 ++++++
> >>>>>> arch/loongarch/include/asm/kvm_mmu.h | 138 +++
> >>>>>> arch/loongarch/include/asm/kvm_types.h | 11 +
> >>>>>> arch/loongarch/include/asm/kvm_vcpu.h | 107 +++
> >>>>>> arch/loongarch/include/asm/loongarch.h | 19 +-
> >>>>>> arch/loongarch/include/uapi/asm/kvm.h | 108 +++
> >>>>>> arch/loongarch/kernel/asm-offsets.c | 32 +
> >>>>>> arch/loongarch/kvm/Kconfig | 45 +
> >>>>>> arch/loongarch/kvm/Makefile | 20 +
> >>>>>> arch/loongarch/kvm/exit.c | 711 ++++++++++++++++
> >>>>>> arch/loongarch/kvm/interrupt.c | 185 ++++
> >>>>>> arch/loongarch/kvm/main.c | 429 ++++++++++
> >>>>>> arch/loongarch/kvm/mmu.c | 922 ++++++++++++++++++++
> >>>>>> arch/loongarch/kvm/switch.S | 255 ++++++
> >>>>>> arch/loongarch/kvm/timer.c | 200 +++++
> >>>>>> arch/loongarch/kvm/tlb.c | 34 +
> >>>>>> arch/loongarch/kvm/trace.h | 166 ++++
> >>>>>> arch/loongarch/kvm/vcpu.c | 940 +++++++++++++++++++++
> >>>>>> arch/loongarch/kvm/vm.c | 92 ++
> >>>>>> include/uapi/linux/kvm.h | 9 +
> >>>>>> 27 files changed, 4979 insertions(+), 14 deletions(-)
> >>>>>> create mode 100644 arch/loongarch/include/asm/kvm_csr.h
> >>>>>> create mode 100644 arch/loongarch/include/asm/kvm_host.h
> >>>>>> create mode 100644 arch/loongarch/include/asm/kvm_mmu.h
> >>>>>> create mode 100644 arch/loongarch/include/asm/kvm_types.h
> >>>>>> create mode 100644 arch/loongarch/include/asm/kvm_vcpu.h
> >>>>>> create mode 100644 arch/loongarch/include/uapi/asm/kvm.h
> >>>>>> create mode 100644 arch/loongarch/kvm/Kconfig
> >>>>>> create mode 100644 arch/loongarch/kvm/Makefile
> >>>>>> create mode 100644 arch/loongarch/kvm/exit.c
> >>>>>> create mode 100644 arch/loongarch/kvm/interrupt.c
> >>>>>> create mode 100644 arch/loongarch/kvm/main.c
> >>>>>> create mode 100644 arch/loongarch/kvm/mmu.c
> >>>>>> create mode 100644 arch/loongarch/kvm/switch.S
> >>>>>> create mode 100644 arch/loongarch/kvm/timer.c
> >>>>>> create mode 100644 arch/loongarch/kvm/tlb.c
> >>>>>> create mode 100644 arch/loongarch/kvm/trace.h
> >>>>>> create mode 100644 arch/loongarch/kvm/vcpu.c
> >>>>>> create mode 100644 arch/loongarch/kvm/vm.c
> >>>>>>
> >>>>>> --
> >>>>>> 2.39.1
> >>>>>>
>
>

2023-09-21 22:54:45

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH v21 00/29] Add KVM LoongArch support

Hi, Paolo,

On Wed, Sep 20, 2023 at 11:23 PM Paolo Bonzini <[email protected]> wrote:
>
> On Sat, Sep 16, 2023 at 5:17 AM Huacai Chen <[email protected]> wrote:
> > I can test now, during my tests I may ask some other questions about
> > your patches. You just need to answer my questions and I will adjust
> > the code myself if needed. After that I will give you a final version
> > with Tested-by and you can simply send that as V22.
>
> Since you are preparing yourself the v22, you could also send it to me
> as a pull request.
OK, after Tianrui sends v22 to the maillist, if there are no more
comments, I will send you a pull request after one or two weeks.
Thanks.

Huacai

>
> Thanks,
>
> Paolo
>