mips: Add KVM T&E segment support for TCG
authorJames Hogan <james.hogan@imgtec.com>
Mon, 31 Jul 2017 13:09:13 +0000 (14:09 +0100)
committerYongbok Kim <yongbok.kim@imgtec.com>
Wed, 2 Aug 2017 21:18:06 +0000 (22:18 +0100)
MIPS KVM trap & emulate guest kernels have a different segment layout
compared with traditional MIPS kernels, to allow both the user and
kernel code to run from the user address segment without repeatedly
trapping to KVM.

QEMU currently supports this layout only for KVM, but its sometimes
useful to be able to run these kernels in QEMU on a PC, so enable it for
TCG too.

This also paves the way for MIPS KVM VZ support (which uses the normal
virtual memory layout) by abstracting whether user mode kernel segments
are in use.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Yongbok Kim <yongbok.kim@imgtec.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org
Reviewed-by: Richard Henderson <rth@twiddle.net>
[Yongbok Kim:
  minor change]
Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
hw/mips/addr.c
hw/mips/mips_malta.c
include/hw/mips/cpudevs.h
target/mips/helper.c
target/mips/translate.c

index e4e86b4a75487d09789b0e1f34149851853101e6..4da46e17319a269cf1673e2ff911797b39387baa 100644 (file)
@@ -24,6 +24,8 @@
 #include "hw/hw.h"
 #include "hw/mips/cpudevs.h"
 
+static int mips_um_ksegs;
+
 uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
 {
     return addr & 0x1fffffffll;
@@ -38,3 +40,13 @@ uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr)
 {
     return addr | 0x40000000ll;
 }
+
+bool mips_um_ksegs_enabled(void)
+{
+    return mips_um_ksegs;
+}
+
+void mips_um_ksegs_enable(void)
+{
+    mips_um_ksegs = 1;
+}
index 9dcec27304ddf753b5a29d049a659b692e7e495d..af678f57845394f51324c7939d3a5a33395b399e 100644 (file)
@@ -818,23 +818,20 @@ static int64_t load_kernel (void)
         exit(1);
     }
 
-    /* Sanity check where the kernel has been linked */
-    if (kvm_enabled()) {
-        if (kernel_entry & 0x80000000ll) {
+    /* Check where the kernel has been linked */
+    if (kernel_entry & 0x80000000ll) {
+        if (kvm_enabled()) {
             error_report("KVM guest kernels must be linked in useg. "
                          "Did you forget to enable CONFIG_KVM_GUEST?");
             exit(1);
         }
 
-        xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
+        xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
     } else {
-        if (!(kernel_entry & 0x80000000ll)) {
-            error_report("KVM guest kernels aren't supported with TCG. "
-                         "Did you unintentionally enable CONFIG_KVM_GUEST?");
-            exit(1);
-        }
+        /* if kernel entry is in useg it is probably a KVM T&E kernel */
+        mips_um_ksegs_enable();
 
-        xlate_to_kseg0 = cpu_mips_phys_to_kseg0;
+        xlate_to_kseg0 = cpu_mips_kvm_um_phys_to_kseg0;
     }
 
     /* load initrd */
index 698339b83ec771abe18ea2e8b5f3bb2152ca3883..291f59281a046a07b020079029cca97559f46a11 100644 (file)
@@ -5,11 +5,12 @@
 
 /* Definitions for MIPS CPU internal devices.  */
 
-/* mips_addr.c */
+/* addr.c */
 uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
 uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
 uint64_t cpu_mips_kvm_um_phys_to_kseg0(void *opaque, uint64_t addr);
-
+bool mips_um_ksegs_enabled(void);
+void mips_um_ksegs_enable(void);
 
 /* mips_int.c */
 void cpu_mips_irq_init_cpu(MIPSCPU *cpu);
index 05883b9f425198bf21c0fddc6af2c399aeb0f6c7..ca39aca08a6471db173664f358be4f858d366301 100644 (file)
 #include "qemu/osdep.h"
 
 #include "cpu.h"
-#include "sysemu/kvm.h"
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 #include "exec/log.h"
+#include "hw/mips/cpudevs.h"
 
 enum {
     TLBRET_XI = -6,
@@ -225,7 +225,7 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
 #define KVM_KSEG0_BASE  ((target_ulong)(int32_t)0x40000000UL)
 #define KVM_KSEG2_BASE  ((target_ulong)(int32_t)0x60000000UL)
 
-    if (kvm_enabled()) {
+    if (mips_um_ksegs_enabled()) {
         /* KVM T&E adds guest kernel segments in useg */
         if (real_address >= KVM_KSEG0_BASE) {
             if (real_address < KVM_KSEG2_BASE) {
index 0bca700fb380f2cdaab5830c0062bfc3134904eb..88f518b43cff5bfce84255496e947658d0606e46 100644 (file)
 #include "exec/exec-all.h"
 #include "tcg-op.h"
 #include "exec/cpu_ldst.h"
+#include "hw/mips/cpudevs.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
-#include "sysemu/kvm.h"
 #include "exec/semihost.h"
 
 #include "target/mips/trace.h"
@@ -20635,7 +20635,7 @@ void cpu_state_reset(CPUMIPSState *env)
     env->CP0_Wired = 0;
     env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
     env->CP0_EBase = (cs->cpu_index & 0x3FF);
-    if (kvm_enabled()) {
+    if (mips_um_ksegs_enabled()) {
         env->CP0_EBase |= 0x40000000;
     } else {
         env->CP0_EBase |= (int32_t)0x80000000;