[PATCH] KVM: AMD SVM: 32-bit host support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Anthony Liguori <[email protected]>

This patch enables kvm support for 32-bit AMD SVM hosts.

Signed-off-by: Anthony Liguori <[email protected]>
Signed-off-by: Avi Kivity <[email protected]>

Index: linux-2.6/drivers/kvm/kvm_svm.h
===================================================================
--- linux-2.6.orig/drivers/kvm/kvm_svm.h
+++ linux-2.6/drivers/kvm/kvm_svm.h
@@ -9,11 +9,13 @@
 #include "kvm.h"
 
 static const u32 host_save_msrs[] = {
+#ifdef __x86_64__
 	MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
+	MSR_FS_BASE, MSR_GS_BASE,
+#endif
 	MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
 	MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP,
 	MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/
-	MSR_FS_BASE, MSR_GS_BASE,
 };
 
 #define NR_HOST_SAVE_MSRS (sizeof(host_save_msrs) / sizeof(*host_save_msrs))
Index: linux-2.6/drivers/kvm/svm.c
===================================================================
--- linux-2.6.orig/drivers/kvm/svm.c
+++ linux-2.6/drivers/kvm/svm.c
@@ -39,16 +39,28 @@ MODULE_LICENSE("GPL");
 #define SEG_TYPE_LDT 2
 #define SEG_TYPE_BUSY_TSS16 3
 
+#define KVM_EFER_LMA (1 << 10)
+#define KVM_EFER_LME (1 << 8)
+
 unsigned long iopm_base;
 unsigned long msrpm_base;
 
+struct kvm_ldttss_desc {
+	u16 limit0;
+	u16 base0;
+	unsigned base1 : 8, type : 5, dpl : 2, p : 1;
+	unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
+	u32 base3;
+	u32 zero1;
+} __attribute__((packed));
+
 struct svm_cpu_data {
 	int cpu;
 
 	uint64_t asid_generation;
 	uint32_t max_asid;
 	uint32_t next_asid;
-	struct ldttss_desc *tss_desc;
+	struct kvm_ldttss_desc *tss_desc;
 
 	struct page *save_area;
 };
@@ -156,7 +168,7 @@ static inline void write_dr7(unsigned lo
 
 static inline int svm_is_long_mode(struct kvm_vcpu *vcpu)
 {
-	return vcpu->svm->vmcb->save.efer & EFER_LMA;
+	return vcpu->svm->vmcb->save.efer & KVM_EFER_LMA;
 }
 
 static inline void force_new_asid(struct kvm_vcpu *vcpu)
@@ -171,8 +183,8 @@ static inline void flush_guest_tlb(struc
 
 static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
-	if (!(efer & EFER_LMA))
-		efer &= ~EFER_LME;
+	if (!(efer & KVM_EFER_LMA))
+		efer &= ~KVM_EFER_LME;
 
 	vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
 	vcpu->shadow_efer = efer;
@@ -275,7 +287,11 @@ static void svm_hardware_enable(void *ga
 
 	struct svm_cpu_data *svm_data;
 	uint64_t efer;
+#ifdef __x86_64__
 	struct desc_ptr gdt_descr;
+#else
+	struct Xgt_desc_struct gdt_descr;
+#endif
 	struct desc_struct *gdt;
 	int me = raw_smp_processor_id();
 
@@ -297,7 +313,7 @@ static void svm_hardware_enable(void *ga
 
 	asm volatile ( "sgdt %0" : "=m"(gdt_descr) );
 	gdt = (struct desc_struct *)gdt_descr.address;
-	svm_data->tss_desc = (struct ldttss_desc *)(gdt + GDT_ENTRY_TSS);
+	svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
 
 	rdmsrl(MSR_EFER, efer);
 	wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK);
@@ -381,6 +397,7 @@ static __init int svm_hardware_setup(voi
 	memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
 	msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT;
 
+#ifdef __x86_64__
 	set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1);
 	set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1);
 	set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1);
@@ -388,6 +405,7 @@ static __init int svm_hardware_setup(voi
 	set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1);
 	set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1);
 	set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1);
+#endif
 	set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1);
 	set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1);
 	set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1);
@@ -687,15 +705,15 @@ static void svm_set_gdt(struct kvm_vcpu 
 static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
 #ifdef __x86_64__
-	if (vcpu->shadow_efer & EFER_LME) {
+	if (vcpu->shadow_efer & KVM_EFER_LME) {
 		if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
-			vcpu->shadow_efer |= EFER_LMA;
-			vcpu->svm->vmcb->save.efer |= EFER_LMA | EFER_LME;
+			vcpu->shadow_efer |= KVM_EFER_LMA;
+			vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
 		}
 
 		if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) {
-			vcpu->shadow_efer &= ~EFER_LMA;
-			vcpu->svm->vmcb->save.efer &= ~(EFER_LMA | EFER_LME);
+			vcpu->shadow_efer &= ~KVM_EFER_LMA;
+			vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
 		}
 	}
 #endif
@@ -1079,6 +1097,7 @@ static int svm_get_msr(struct kvm_vcpu *
 	case MSR_IA32_APICBASE:
 		*data = vcpu->apic_base;
 		break;
+#ifdef __x86_64__
 	case MSR_STAR:
 		*data = vcpu->svm->vmcb->save.star;
 		break;
@@ -1088,6 +1107,13 @@ static int svm_get_msr(struct kvm_vcpu *
 	case MSR_CSTAR:
 		*data = vcpu->svm->vmcb->save.cstar;
 		break;
+	case MSR_KERNEL_GS_BASE:
+		*data = vcpu->svm->vmcb->save.kernel_gs_base;
+		break;
+	case MSR_SYSCALL_MASK:
+		*data = vcpu->svm->vmcb->save.sfmask;
+		break;
+#endif
 	case MSR_IA32_SYSENTER_CS:
 		*data = vcpu->svm->vmcb->save.sysenter_cs;
 		break;
@@ -1097,12 +1123,6 @@ static int svm_get_msr(struct kvm_vcpu *
 	case MSR_IA32_SYSENTER_ESP:
 		*data = vcpu->svm->vmcb->save.sysenter_esp;
 		break;
-	case MSR_KERNEL_GS_BASE:
-		*data = vcpu->svm->vmcb->save.kernel_gs_base;
-		break;
-	case MSR_SYSCALL_MASK:
-		*data = vcpu->svm->vmcb->save.sfmask;
-		break;
 	default:
 		printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", ecx);
 		return 1;
@@ -1152,6 +1172,7 @@ static int svm_set_msr(struct kvm_vcpu *
 	case MSR_IA32_APICBASE:
 		vcpu->apic_base = data;
 		break;
+#ifdef __x86_64___
 	case MSR_STAR:
 		vcpu->svm->vmcb->save.star = data;
 		break;
@@ -1161,6 +1182,13 @@ static int svm_set_msr(struct kvm_vcpu *
 	case MSR_CSTAR:
 		vcpu->svm->vmcb->save.cstar = data;
 		break;
+	case MSR_KERNEL_GS_BASE:
+		vcpu->svm->vmcb->save.kernel_gs_base = data;
+		break;
+	case MSR_SYSCALL_MASK:
+		vcpu->svm->vmcb->save.sfmask = data;
+		break;
+#endif
 	case MSR_IA32_SYSENTER_CS:
 		vcpu->svm->vmcb->save.sysenter_cs = data;
 		break;
@@ -1170,12 +1198,6 @@ static int svm_set_msr(struct kvm_vcpu *
 	case MSR_IA32_SYSENTER_ESP:
 		vcpu->svm->vmcb->save.sysenter_esp = data;
 		break;
-	case MSR_KERNEL_GS_BASE:
-		vcpu->svm->vmcb->save.kernel_gs_base = data;
-		break;
-	case MSR_SYSCALL_MASK:
-		vcpu->svm->vmcb->save.sfmask = data;
-		break;
 	default:
 		printk(KERN_ERR "kvm: unhandled wrmsr: %x\n", ecx);
 		return 1;
@@ -1323,6 +1345,7 @@ static void kvm_reput_irq(struct kvm_vcp
 
 static void save_db_regs(unsigned long *db_regs)
 {
+#ifdef __x86_64__
 	asm ("mov %%dr0, %%rax \n\t"
 	     "mov %%rax, %[dr0] \n\t"
 	     "mov %%dr1, %%rax \n\t"
@@ -1336,6 +1359,21 @@ static void save_db_regs(unsigned long *
 	       [dr2] "=m"(db_regs[2]),
 	       [dr3] "=m"(db_regs[3])
 	     : : "rax");
+#else
+	asm ("mov %%dr0, %%eax \n\t"
+	     "mov %%eax, %[dr0] \n\t"
+	     "mov %%dr1, %%eax \n\t"
+	     "mov %%eax, %[dr1] \n\t"
+	     "mov %%dr2, %%eax \n\t"
+	     "mov %%eax, %[dr2] \n\t"
+	     "mov %%dr3, %%eax \n\t"
+	     "mov %%eax, %[dr3] \n\t"
+	     : [dr0] "=m"(db_regs[0]),
+	       [dr1] "=m"(db_regs[1]),
+	       [dr2] "=m"(db_regs[2]),
+	       [dr3] "=m"(db_regs[3])
+	     : : "eax");
+#endif
 }
 
 static void load_db_regs(unsigned long *db_regs)
@@ -1349,7 +1387,11 @@ static void load_db_regs(unsigned long *
 	       [dr1] "r"(db_regs[1]),
 	       [dr2] "r"(db_regs[2]),
 	       [dr3] "r"(db_regs[3])
+#ifdef __x86_64__
 	     : "rax");
+#else
+	     : "eax");
+#endif
 }
 
 static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1414,6 +1456,7 @@ again:
 		"mov %c[rbp](%[vcpu]), %%ebp \n\t"
 #endif
 
+#ifdef __x86_64__
 		/* Enter guest mode */
 		"push %%rax \n\t"
 		"mov %c[svm](%[vcpu]), %%rax \n\t"
@@ -1422,6 +1465,16 @@ again:
 		SVM_VMRUN "\n\t"
 		SVM_VMSAVE "\n\t"
 		"pop %%rax \n\t"
+#else
+		/* Enter guest mode */
+		"push %%eax \n\t"
+		"mov %c[svm](%[vcpu]), %%eax \n\t"
+		"mov %c[vmcb](%%eax), %%eax \n\t"
+		SVM_VMLOAD "\n\t"
+		SVM_VMRUN "\n\t"
+		SVM_VMSAVE "\n\t"
+		"pop %%eax \n\t"
+#endif
 
 		/* Save guest registers, load host registers */
 #ifdef __x86_64__
@@ -1445,12 +1498,12 @@ again:
 		"pop  %%rbp; pop  %%rdi; pop  %%rsi;"
 		"pop  %%rdx; pop  %%rcx; pop  %%rbx; \n\t"
 #else
-		"mov %%ebx, %c[rbx](%3) \n\t"
-		"mov %%ecx, %c[rcx](%3) \n\t"
-		"mov %%edx, %c[rdx](%3) \n\t"
-		"mov %%esi, %c[rsi](%3) \n\t"
-		"mov %%edi, %c[rdi](%3) \n\t"
-		"mov %%ebp, %c[rbp](%3) \n\t"
+		"mov %%ebx, %c[rbx](%[vcpu]) \n\t"
+		"mov %%ecx, %c[rcx](%[vcpu]) \n\t"
+		"mov %%edx, %c[rdx](%[vcpu]) \n\t"
+		"mov %%esi, %c[rsi](%[vcpu]) \n\t"
+		"mov %%edi, %c[rdi](%[vcpu]) \n\t"
+		"mov %%ebp, %c[rbp](%[vcpu]) \n\t"
 
 		"pop  %%ebp; pop  %%edi; pop  %%esi;"
 		"pop  %%edx; pop  %%ecx; pop  %%ebx; \n\t"
Index: linux-2.6/drivers/kvm/Kconfig
===================================================================
--- linux-2.6.orig/drivers/kvm/Kconfig
+++ linux-2.6/drivers/kvm/Kconfig
@@ -27,7 +27,7 @@ config KVM_INTEL
 
 config KVM_AMD
 	tristate "KVM for AMD processors support"
-	depends on KVM && X86_64
+	depends on KVM
 	---help---
 	  Provides support for KVM on AMD processors equipped with the AMD-V
 	  (SVM) extensions.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux