Skip to contentSkip to conversation

SVM support

RFC PATCH In review Alexander Graf 6 participants 10 messages Aug 22, 2007 – Aug 25, 2007

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 SVM support

Hi,

this patch adds support for SVM (the virtual machine extension on amd64) to qemu's x86_64 target. It still needs cleanup (splitting, indentation, etc) and lacks some basic functionality but maybe someone will find interest in it as it is already.

In kvm real and protected modes work flawlessly as far as I can tell (minix and 32-bit linux worked).
Long mode seems to work quite ok as well, though I am not able to get a Linux kernel booted up (MenuetOS works).

What does work?

- VMRUN, VMLOAD, VMSAVE, VMEXIT, STGI, CLGI
- Event injection
- All interceptions (well, maybe I did oversee one or two)
- Context switching to the VM and back to the VMM

What is missing?

- According to the SVM specification NPTs are optional, so I did not include them (yet)
- Everything related to device virtualisation
- The "Secure" part of the extension (would need TPM emulation for that)
- Debugging support (maybe it does work, I actually have never tried to debug a kvm virtualised machine)
- I included a dirty hack to update EIP on every instruction.
- TSC_OFFSET
- ASID support
- Sanity checks
- Task switch and Ferr_Freeze Intercepts
- VMMCALL
- SMM support
- SVM-Lock

I hope this is useful to someone.
I am going to continue to refine this patch until it implements all of the SVM specification.

Comments as well as patches are greatly appreciated.

Thanks,

Alexander Graf

target-i386/helper2.c +28 -3
Index: qemu/target-i386/helper2.c
===================================================================
@@ -27,8 +27,9 @@
 
 #include "cpu.h"
 #include "exec-all.h"
+#include "svm.h"
 
-//#define DEBUG_MMU
+// #define DEBUG_MMU
 
 #ifdef USE_CODE_COPY
 #include <asm/ldt.h>
@@ -111,6 +112,7 @@ CPUX86State *cpu_x86_init(void)
                                CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
                                CPUID_PAT);
         env->pat = 0x0007040600070406ULL;
+        env->cpuid_ext3_features = CPUID_EXT3_SVM;
         env->cpuid_ext_features = CPUID_EXT_SSE3;
         env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
         env->cpuid_features |= CPUID_APIC;
@@ -131,7 +133,7 @@ CPUX86State *cpu_x86_init(void)
         /* currently not enabled for std i386 because not fully tested */
         env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
         env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
-        env->cpuid_xlevel = 0x80000008;
+        env->cpuid_xlevel = 0x8000000a;
 
         /* these features are needed for Win64 and aren't fully implemented */
         env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
@@ -160,6 +162,7 @@ void cpu_reset(CPUX86State *env)
 #ifdef CONFIG_SOFTMMU
     env->hflags |= HF_SOFTMMU_MASK;
 #endif
+    env->hflags |= HF_GIF_MASK;
 
     cpu_x86_update_cr0(env, 0x60000010);
     env->a20_mask = 0xffffffff;
@@ -639,10 +642,12 @@ int cpu_x86_handle_mmu_fault(CPUX86State
             pml4e = ldq_phys(pml4e_addr);
             if (!(pml4e & PG_PRESENT_MASK)) {
                 error_code = 0;
+		//printf("a");
                 goto do_fault;
             }
             if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
                 error_code = PG_ERROR_RSVD_MASK;
+		//printf("b");
                 goto do_fault;
             }
             if (!(pml4e & PG_ACCESSED_MASK)) {
@@ -655,10 +660,12 @@ int cpu_x86_handle_mmu_fault(CPUX86State
             pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK)) {
                 error_code = 0;
+		//printf("c(addr=%#llx, pdpe_addr=%#lx, pdpe=%#lx, a20_mask=%#lx)", addr, pdpe_addr, pdpe, env->a20_mask);
                 goto do_fault;
             }
             if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
                 error_code = PG_ERROR_RSVD_MASK;
+		//printf("d");
                 goto do_fault;
             }
             ptep &= pdpe ^ PG_NX_MASK;
@@ -675,6 +682,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State
             pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK)) {
                 error_code = 0;
+		//printf("e");
                 goto do_fault;
             }
             ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
@@ -685,10 +693,12 @@ int cpu_x86_handle_mmu_fault(CPUX86State
         pde = ldq_phys(pde_addr);
         if (!(pde & PG_PRESENT_MASK)) {
             error_code = 0;
+            //printf("f(addr=%#llx, pdpe_addr=%#lx, pdpe=%#lx, pde_addr=%#lx, pde=%#lx, a20_mask=%#lx)", addr, pdpe_addr, pdpe, pde_addr, pde, env->a20_mask);
             goto do_fault;
         }
         if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
             error_code = PG_ERROR_RSVD_MASK;
+	    //printf("g");
             goto do_fault;
         }
         ptep &= pde ^ PG_NX_MASK;
@@ -728,11 +738,18 @@ int cpu_x86_handle_mmu_fault(CPUX86State
                 env->a20_mask;
             pte = ldq_phys(pte_addr);
             if (!(pte & PG_PRESENT_MASK)) {
+		target_ulong pte_addri;
                 error_code = 0;
+                pte_addri = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff))) & env->a20_mask;
+                //printf("h(addr=%#llx, pdpe_addr=%#lx, pdpe=%#lx, pde_addr=%#lx, pde=%#lx,pte_addr=%#lx, pte=%#lx, pte_addri=%#x, ptei=%#x, a20_mask=%#lx)", addr, pdpe_addr, pdpe, pde_addr, pde, pte_addr, pte, pte_addri, ldq_phys(pte_addri), env->a20_mask);
+/*		for(pte_addri = (pde & PHYS_ADDR_MASK); (pte_addri & PHYS_ADDR_MASK) == (pde & PHYS_ADDR_MASK); pte_addri += 8) {
+			//printf("%#llx - %#llx\n", pte_addri, ldq_phys(pte_addri));
+		}*/
                 goto do_fault;
             }
             if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
                 error_code = PG_ERROR_RSVD_MASK;
+	    	//printf("i");
                 goto do_fault;
             }
             /* combine pde and pte nx, user and rw protections */
@@ -770,6 +787,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State
         pde = ldl_phys(pde_addr);
         if (!(pde & PG_PRESENT_MASK)) {
             error_code = 0;
+	    //printf("j");
             goto do_fault;
         }
         /* if PSE bit is set, then we use a 4MB page */
@@ -808,6 +826,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State
             pte = ldl_phys(pte_addr);
             if (!(pte & PG_PRESENT_MASK)) {
                 error_code = 0;
+	    	//printf("k");
                 goto do_fault;
             }
             /* combine pde and pte user and rw protections */
@@ -863,7 +882,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State
  do_fault_protect:
     error_code = PG_ERROR_P_MASK;
  do_fault:
-    env->cr[2] = addr;
     error_code |= (is_write << PG_ERROR_W_BIT);
     if (is_user)
         error_code |= PG_ERROR_U_MASK;
@@ -871,8 +889,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State
         (env->efer & MSR_EFER_NXE) && 
         (env->cr[4] & CR4_PAE_MASK))
         error_code |= PG_ERROR_I_D_MASK;
+    if(INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) {
+        stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr);
+    } else {
+        env->cr[2] = addr;
+    }
     env->error_code = error_code;
     env->exception_index = EXCP0E_PAGE;
+    if(env->hflags & HF_SVM_MASK) // the VMM will handle this
+        return 2;
     return 1;
 }
 
target-i386/translate.c +108 -6

336 lines not on this page · raw message

target-i386/cpu.h +23 -0
Index: qemu/target-i386/cpu.h
===================================================================
@@ -46,6 +46,8 @@
 
 #include "softfloat.h"
 
+#include "svm.h"
+
 #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(__APPLE__)
 #define USE_CODE_COPY
 #endif
@@ -84,6 +86,7 @@
 #define DESC_AVL_MASK   (1 << 20)
 #define DESC_P_MASK     (1 << 15)
 #define DESC_DPL_SHIFT  13
+#define DESC_DPL_MASK   (1 << DESC_DPL_SHIFT)
 #define DESC_S_MASK     (1 << 12)
 #define DESC_TYPE_SHIFT 8
 #define DESC_A_MASK     (1 << 8)
@@ -149,6 +152,9 @@
 #define HF_VM_SHIFT         17 /* must be same as eflags */
 #define HF_HALTED_SHIFT     18 /* CPU halted */
 #define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+#define HF_SVM_SHIFT        20 /* CPU in SVM mode */
+#define HF_GIF_SHIFT        21 /* if set CPU takes interrupts */
+#define HF_HIF_SHIFT        22 /* shadow copy of IF_MASK when in SVM */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +172,9 @@
 #define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
 #define HF_HALTED_MASK       (1 << HF_HALTED_SHIFT)
 #define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+#define HF_SVM_MASK          (1 << HF_SVM_SHIFT)
+#define HF_GIF_MASK          (1 << HF_GIF_SHIFT)
+#define HF_HIF_MASK          (1 << HF_HIF_SHIFT)
 
 #define CR0_PE_MASK  (1 << 0)
 #define CR0_MP_MASK  (1 << 1)
@@ -249,6 +258,8 @@
 #define MSR_GSBASE                      0xc0000101
 #define MSR_KERNELGSBASE                0xc0000102
 
+#define MSR_VM_HSAVE_PA                 0xc0010117
+
 /* cpuid_features bits */
 #define CPUID_FP87 (1 << 0)
 #define CPUID_VME  (1 << 1)
@@ -283,6 +294,8 @@
 #define CPUID_EXT2_FFXSR   (1 << 25)
 #define CPUID_EXT2_LM      (1 << 29)
 
+#define CPUID_EXT3_SVM     (1 << 2)
+
 #define EXCP00_DIVZ	0
 #define EXCP01_SSTP	1
 #define EXCP02_NMI	2
@@ -489,6 +502,16 @@ typedef struct CPUX86State {
     uint32_t sysenter_eip;
     uint64_t efer;
     uint64_t star;
+
+    struct CPUX86State *vm_hsave; // FIXME: should point to target memory
+    target_phys_addr_t vm_vmcb;
+    uint64_t intercept;
+    uint16_t intercept_cr_read;
+    uint16_t intercept_cr_write;
+    uint16_t intercept_dr_read;
+    uint16_t intercept_dr_write;
+    uint32_t intercept_exceptions;
+
 #ifdef TARGET_X86_64
     target_ulong lstar;
     target_ulong cstar;
target-i386/op.c +88 -3

140 lines not on this page · raw message

target-i386/helper.c +804 -57

999 lines not on this page · raw message

target-i386/svm.h new file +331 -0

331 lines not on this page · raw message

cpu-exec.c +38 -3

79 lines not on this page · raw message

target-i386/exec.h +10 -0
Index: qemu/target-i386/exec.h
===================================================================
@@ -501,6 +501,15 @@ void update_fp_status(void);
 void helper_hlt(void);
 void helper_monitor(void);
 void helper_mwait(void);
+void helper_vmrun(target_ulong addr);
+void helper_vmmcall(void);
+void helper_vmload(target_ulong addr);
+void helper_vmsave(target_ulong addr);
+void helper_stgi(void);
+void helper_clgi(void);
+void helper_skinit(void);
+void helper_invlpga(void);
+void vmexit(uint64_t exit_code, uint64_t exit_info_1);
 
 extern const uint8_t parity_table[256];
 extern const uint8_t rclw_table[32];
@@ -588,3 +597,4 @@ static inline int cpu_halted(CPUState *e
     }
     return EXCP_HALTED;
 }
+
exec.c +4 -0
Index: qemu/exec.c
===================================================================
@@ -1281,6 +1281,10 @@ void cpu_abort(CPUState *env, const char
     vfprintf(stderr, fmt, ap);
     fprintf(stderr, "\n");
 #ifdef TARGET_I386
+    if(env->hflags & HF_SVM_MASK) { // most probably the virtual machine should not
+	                            // be shut down but rather caught by the VMM
+        vmexit(SVM_EXIT_SHUTDOWN, 0);
+    }
     cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
 #else
     cpu_dump_state(env, stderr, fprintf, 0);
#1 lore raw
Quoted 1 line · Alexander Graf

- All interceptions (well, maybe I did oversee one or two)

Nice work! For better performance, you should do the op.c checks statically at translation time (if possible).

#2 lore raw
Quoted 10 lines · Blue Swirl
Quoted 2 lines · Alexander Graf

- All interceptions (well, maybe I did oversee one or two)

Nice work! For better performance, you should do the op.c checks statically at translation time (if possible).

Thanks. I thought about that first as well, but can't. The information if an intercept should occur is defined in the VMCB, which is passed as argument on VMRUN (so whenever one enters the VM). This means that the very same TB can be executed with completely different intercepts, which means I have to fall back to runtime detection in op.c.

I thought about moving some functionality from helper.c to op.c. Does that improve anything?

#4 lore raw
In reply to Alexander Graf
Quoted 8 lines · Alexander Graf

Hi,

this patch adds support for SVM (the virtual machine extension on amd64) to qemu's x86_64 target. It still needs cleanup (splitting, indentation, etc) and lacks some basic functionality but maybe someone will find interest in it as it is already.

Obviously this is a boon for hypervisor developers! I'm looking forward to using qemu to debug the tricky parts of kvm.

Hopefully a VT implementation will turn up as well.

Signature · 1 line
error compiling committee.c: too many arguments to function
#3 lore raw
In reply to Alexander Graf
Quoted 14 lines · Alexander Graf
Quoted 12 lines · Blue Swirl
Quoted 3 lines · Alexander Graf

- All interceptions (well, maybe I did oversee one or two)

Nice work! For better performance, you should do the op.c checks statically at translation time (if possible).

Quoted 6 lines

Thanks. I thought about that first as well, but can't. The information if an intercept should occur is defined in the VMCB, which is passed as argument on VMRUN (so whenever one enters the VM). This means that the very same TB can be executed with completely different intercepts, which means I have to fall back to runtime detection in op.c.

You can have the intercept vector be a part of the TB lookup key. So, if the same code is executed natively, or with different intercept vectors, it gets a different TB. Qemu already does this for a number of things like cpu operating mode, cs base, etc.

Signature · 1 line
error compiling committee.c: too many arguments to function
#5 lore raw
In reply to Alexander Graf
Quoted 40 lines · Alexander Graf

Hi,

this patch adds support for SVM (the virtual machine extension on amd64) to qemu's x86_64 target. It still needs cleanup (splitting, indentation, etc) and lacks some basic functionality but maybe someone will find interest in it as it is already.

In kvm real and protected modes work flawlessly as far as I can tell (minix and 32-bit linux worked).
Long mode seems to work quite ok as well, though I am not able to get a Linux kernel booted up (MenuetOS works).

What does work?

- VMRUN, VMLOAD, VMSAVE, VMEXIT, STGI, CLGI
- Event injection
- All interceptions (well, maybe I did oversee one or two)
- Context switching to the VM and back to the VMM

What is missing?

- According to the SVM specification NPTs are optional, so I did not include them (yet)
- Everything related to device virtualisation
- The "Secure" part of the extension (would need TPM emulation for that)
- Debugging support (maybe it does work, I actually have never tried to debug a kvm virtualised machine)
- I included a dirty hack to update EIP on every instruction.
- TSC_OFFSET
- ASID support
- Sanity checks
- Task switch and Ferr_Freeze Intercepts
- VMMCALL
- SMM support
- SVM-Lock

I hope this is useful to someone.
I am going to continue to refine this patch until it implements all of the SVM specification.

Quoted 7 lines

Comments as well as patches are greatly appreciated.

Thanks,

Alexander Graf

This is a reworked version of the same patch, where I can now boot into a x86_64 Linux kernel.
I rewrote all the access functions for the VMCB, so this time everything should work just fine on BE-machines. As suggested I moved the injection detection to translate.c, so the non-virtualized machine should be as fast as before (w/o svm support), while the virtual one got a speed boost from that as well.
I removed the EIP hack and set EIP every time an interception occurs, so unlike the previous version this patch really should have no negative effect on speed any more.

If any of the people on this list using SVM (kvm developers, maybe xen developers) could have a deep look into this I'd be really thankful.

Thanks,

Alexander Graf

target-i386/helper2.c +12 -3
Index: qemu/target-i386/helper2.c
===================================================================
@@ -27,8 +27,9 @@
 
 #include "cpu.h"
 #include "exec-all.h"
+#include "svm.h"
 
-//#define DEBUG_MMU
+// #define DEBUG_MMU
 
 #ifdef USE_CODE_COPY
 #include <asm/ldt.h>
@@ -111,6 +112,7 @@ CPUX86State *cpu_x86_init(void)
                                CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
                                CPUID_PAT);
         env->pat = 0x0007040600070406ULL;
+        env->cpuid_ext3_features = CPUID_EXT3_SVM;
         env->cpuid_ext_features = CPUID_EXT_SSE3;
         env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
         env->cpuid_features |= CPUID_APIC;
@@ -131,7 +133,7 @@ CPUX86State *cpu_x86_init(void)
         /* currently not enabled for std i386 because not fully tested */
         env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
         env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
-        env->cpuid_xlevel = 0x80000008;
+        env->cpuid_xlevel = 0x8000000a;
 
         /* these features are needed for Win64 and aren't fully implemented */
         env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
@@ -160,6 +162,7 @@ void cpu_reset(CPUX86State *env)
 #ifdef CONFIG_SOFTMMU
     env->hflags |= HF_SOFTMMU_MASK;
 #endif
+    env->hflags |= HF_GIF_MASK;
 
     cpu_x86_update_cr0(env, 0x60000010);
     env->a20_mask = 0xffffffff;
@@ -863,7 +866,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State
  do_fault_protect:
     error_code = PG_ERROR_P_MASK;
  do_fault:
-    env->cr[2] = addr;
     error_code |= (is_write << PG_ERROR_W_BIT);
     if (is_user)
         error_code |= PG_ERROR_U_MASK;
@@ -871,8 +873,15 @@ int cpu_x86_handle_mmu_fault(CPUX86State
         (env->efer & MSR_EFER_NXE) && 
         (env->cr[4] & CR4_PAE_MASK))
         error_code |= PG_ERROR_I_D_MASK;
+    if(INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) {
+        stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr);
+    } else {
+        env->cr[2] = addr;
+    }
     env->error_code = error_code;
     env->exception_index = EXCP0E_PAGE;
+    if(env->hflags & HF_SVM_MASK) // the VMM will handle this
+        return 2;
     return 1;
 }
 
target-i386/translate.c +143 -9

399 lines not on this page · raw message

target-i386/cpu.h +23 -0
Index: qemu/target-i386/cpu.h
===================================================================
@@ -46,6 +46,8 @@
 
 #include "softfloat.h"
 
+#include "svm.h"
+
 #if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(__APPLE__)
 #define USE_CODE_COPY
 #endif
@@ -84,6 +86,7 @@
 #define DESC_AVL_MASK   (1 << 20)
 #define DESC_P_MASK     (1 << 15)
 #define DESC_DPL_SHIFT  13
+#define DESC_DPL_MASK   (1 << DESC_DPL_SHIFT)
 #define DESC_S_MASK     (1 << 12)
 #define DESC_TYPE_SHIFT 8
 #define DESC_A_MASK     (1 << 8)
@@ -149,6 +152,9 @@
 #define HF_VM_SHIFT         17 /* must be same as eflags */
 #define HF_HALTED_SHIFT     18 /* CPU halted */
 #define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+#define HF_SVM_SHIFT        20 /* CPU in SVM mode */
+#define HF_GIF_SHIFT        21 /* if set CPU takes interrupts */
+#define HF_HIF_SHIFT        22 /* shadow copy of IF_MASK when in SVM */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
@@ -166,6 +172,9 @@
 #define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
 #define HF_HALTED_MASK       (1 << HF_HALTED_SHIFT)
 #define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+#define HF_SVM_MASK          (1 << HF_SVM_SHIFT)
+#define HF_GIF_MASK          (1 << HF_GIF_SHIFT)
+#define HF_HIF_MASK          (1 << HF_HIF_SHIFT)
 
 #define CR0_PE_MASK  (1 << 0)
 #define CR0_MP_MASK  (1 << 1)
@@ -249,6 +258,8 @@
 #define MSR_GSBASE                      0xc0000101
 #define MSR_KERNELGSBASE                0xc0000102
 
+#define MSR_VM_HSAVE_PA                 0xc0010117
+
 /* cpuid_features bits */
 #define CPUID_FP87 (1 << 0)
 #define CPUID_VME  (1 << 1)
@@ -283,6 +294,8 @@
 #define CPUID_EXT2_FFXSR   (1 << 25)
 #define CPUID_EXT2_LM      (1 << 29)
 
+#define CPUID_EXT3_SVM     (1 << 2)
+
 #define EXCP00_DIVZ	0
 #define EXCP01_SSTP	1
 #define EXCP02_NMI	2
@@ -489,6 +502,16 @@ typedef struct CPUX86State {
     uint32_t sysenter_eip;
     uint64_t efer;
     uint64_t star;
+
+    target_phys_addr_t vm_hsave;
+    target_phys_addr_t vm_vmcb;
+    uint64_t intercept;
+    uint16_t intercept_cr_read;
+    uint16_t intercept_cr_write;
+    uint16_t intercept_dr_read;
+    uint16_t intercept_dr_write;
+    uint32_t intercept_exceptions;
+
 #ifdef TARGET_X86_64
     target_ulong lstar;
     target_ulong cstar;
target-i386/op.c +71 -0

80 lines not on this page · raw message

target-i386/helper.c +649 -16

767 lines not on this page · raw message

target-i386/svm.h new file +359 -0

359 lines not on this page · raw message

cpu-exec.c +37 -4

85 lines not on this page · raw message

target-i386/exec.h +10 -0
Index: qemu/target-i386/exec.h
===================================================================
@@ -501,6 +501,15 @@ void update_fp_status(void);
 void helper_hlt(void);
 void helper_monitor(void);
 void helper_mwait(void);
+void helper_vmrun(target_ulong addr);
+void helper_vmmcall(void);
+void helper_vmload(target_ulong addr);
+void helper_vmsave(target_ulong addr);
+void helper_stgi(void);
+void helper_clgi(void);
+void helper_skinit(void);
+void helper_invlpga(void);
+void vmexit(uint64_t exit_code, uint64_t exit_info_1);
 
 extern const uint8_t parity_table[256];
 extern const uint8_t rclw_table[32];
@@ -588,3 +597,4 @@ static inline int cpu_halted(CPUState *e
     }
     return EXCP_HALTED;
 }
+
exec.c +4 -0
Index: qemu/exec.c
===================================================================
@@ -1281,6 +1281,10 @@ void cpu_abort(CPUState *env, const char
     vfprintf(stderr, fmt, ap);
     fprintf(stderr, "\n");
 #ifdef TARGET_I386
+    if(env->hflags & HF_SVM_MASK) { // most probably the virtual machine should not
+	                            // be shut down but rather caught by the VMM
+        vmexit(SVM_EXIT_SHUTDOWN, 0);
+    }
     cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
 #else
     cpu_dump_state(env, stderr, fprintf, 0);
exec-all.h +1 -0
Index: qemu/exec-all.h
===================================================================
@@ -166,6 +166,7 @@ static inline int tlb_set_page(CPUState 
 typedef struct TranslationBlock {
     target_ulong pc;   /* simulated PC corresponding to this block (EIP + CS base) */
     target_ulong cs_base; /* CS base for this block */
+    uint64_t intercept; /* SVM intercept vector */
     unsigned int flags; /* flags defining in which context the code was generated */
     uint16_t size;      /* size of target code for this block (1 <=
                            size <= TARGET_PAGE_SIZE) */
#6 lore raw
Quoted 12 lines

This is a reworked version of the same patch, where I can now boot into a x86_64 Linux kernel.
I rewrote all the access functions for the VMCB, so this time everything should work just fine on BE-machines. As suggested I moved the injection detection to translate.c, so the non-virtualized machine should be as fast as before (w/o svm support), while the virtual one got a speed boost from that as well.
I removed the EIP hack and set EIP every time an interception occurs, so unlike the previous version this patch really should have no negative effect on speed any more.

Quoted 2 lines

If any of the people on this list using SVM (kvm developers, maybe xen developers) could have a deep look into this I'd be really thankful.

Some notes:

- Saving and restoring CC_SRC and CC_DST is not correct as they do not belong to the real processor state. You must save and restore eflags correctly instead.

- Avoid using macros when inline functions suffice.

Regards,

Fabrice.

#7 lore raw

Alexander Graf:
Excuse me, but it is a bit unclear what you did.

Several questions arise:
a. Qemu now is able to emulate SVM on non-SVM old 32-bit processors ? -or-
b. Qemu now is able to emulate SVM on SVM processors ?
c. Qemu now is able to emulate SVM on VT processors ?
d. How fast it works ? (theoretically, or benchmark results )

Anyway it's nice to hear about this feature.

Signature · 1 line
-Alexey Eremenko "Technologov"
#8 lore raw
Quoted 16 lines · Alexey Eremenko

Alexander Graf:
Excuse me, but it is a bit unclear what you did.

Several questions arise:
a. Qemu now is able to emulate SVM on non-SVM old 32-bit processors ? -or-
b. Qemu now is able to emulate SVM on SVM processors ?
c. Qemu now is able to emulate SVM on VT processors ?
d. How fast it works ? (theoretically, or benchmark results )

Anyway it's nice to hear about this feature.

Signature · 1 line
-Alexey Eremenko "Technologov"

Hi Alexey,

I implemented SVM in the qemu emulator (not kqemu, not kvm, but the real emulator), so you can use SVM in qemu on _any_ platform qemu runs on - even on PowerPC.

Basically concerning speed I did not do any benchmarks, but as far as I can tell the ratio real machine:kvm and qemu:kvm are about the same. So the virtual machine is about 5-10% slower compared to the emulated machine.

Hope I could clarify this,

Alexander Graf

#9 lore raw

Hello...

Quoted 3 lines

I implemented SVM in the qemu emulator (not kqemu, not kvm, but the real emulator), so you can use SVM in qemu on _any_ platform qemu runs on - even on PowerPC.

basically, I wanna say thanks for your effort on implementing SVM support for Qemu. It helps user who doesn't have Pacifica enabled processor to test software how a software behaves in such environment.

It also serves as yet another example on how hack Qemu. Bravo! I hope this patch will be merged soon.

regards,

Mulyadi