diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 82c3b13e5d0a..3d07d9b1b815 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -382,6 +382,7 @@ struct kvm { struct kvm_pic *vpic; struct kvm_ioapic *vioapic; int round_robin_prev_vcpu; + unsigned int tss_addr; }; static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) @@ -467,6 +468,8 @@ struct kvm_x86_ops { void (*inject_pending_irq)(struct kvm_vcpu *vcpu); void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, struct kvm_run *run); + + int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); }; extern struct kvm_x86_ops *kvm_x86_ops; diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index a044856bd02b..50fd040b9ea9 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -2661,6 +2661,16 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu) return fd; } +static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr) +{ + int ret; + + if (addr > (unsigned int)(-3 * PAGE_SIZE)) + return -1; + ret = kvm_x86_ops->set_tss_addr(kvm, addr); + return ret; +} + /* * Creates some virtual cpus. Good luck creating more than one. */ @@ -2957,6 +2967,11 @@ static long kvm_vm_ioctl(struct file *filp, int r = -EINVAL; switch (ioctl) { + case KVM_SET_TSS_ADDR: + r = kvm_vm_ioctl_set_tss_addr(kvm, arg); + if (r < 0) + goto out; + break; case KVM_CREATE_VCPU: r = kvm_vm_ioctl_create_vcpu(kvm, arg); if (r < 0) @@ -3183,6 +3198,7 @@ static long kvm_dev_ioctl(struct file *filp, case KVM_CAP_HLT: case KVM_CAP_MMU_SHADOW_CACHE_CONTROL: case KVM_CAP_USER_MEMORY: + case KVM_CAP_SET_TSS_ADDR: r = 1; break; default: diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 953c111544e1..beb1e684b68a 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -1439,6 +1439,11 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu, control->intercept &= ~(1ULL << INTERCEPT_VINTR); } +static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) +{ + return 0; +} + static void save_db_regs(unsigned long *db_regs) { asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0])); @@ -1744,6 +1749,8 @@ static struct kvm_x86_ops svm_x86_ops = { .set_irq = svm_set_irq, .inject_pending_irq = svm_intr_assist, .inject_pending_vectors = do_interrupt_requests, + + .set_tss_addr = svm_set_tss_addr, }; static int __init svm_init(void) diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 768ea88beb45..46b29184a4d8 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -1105,8 +1105,12 @@ static void enter_pmode(struct kvm_vcpu *vcpu) static gva_t rmode_tss_base(struct kvm *kvm) { - gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3; - return base_gfn << PAGE_SHIFT; + if (!kvm->tss_addr) { + gfn_t base_gfn = kvm->memslots[0].base_gfn + + kvm->memslots[0].npages - 3; + return base_gfn << PAGE_SHIFT; + } + return kvm->tss_addr; } static void fix_rmode_seg(int seg, struct kvm_save_segment *save) @@ -1735,6 +1739,23 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu, vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); } +static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr) +{ + int ret; + struct kvm_userspace_memory_region tss_mem = { + .slot = 8, + .guest_phys_addr = addr, + .memory_size = PAGE_SIZE * 3, + .flags = 0, + }; + + ret = kvm_set_memory_region(kvm, &tss_mem, 0); + if (ret) + return ret; + kvm->tss_addr = addr; + return 0; +} + static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu) { struct kvm_guest_debug *dbg = &vcpu->guest_debug; @@ -2543,6 +2564,8 @@ static struct kvm_x86_ops vmx_x86_ops = { .set_irq = vmx_inject_irq, .inject_pending_irq = vmx_intr_assist, .inject_pending_vectors = do_interrupt_requests, + + .set_tss_addr = vmx_set_tss_addr, }; static int __init vmx_init(void) diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 971f465e26fa..71d33d62944f 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -358,6 +358,7 @@ struct kvm_signal_mask { #define KVM_CAP_HLT 1 #define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2 #define KVM_CAP_USER_MEMORY 3 +#define KVM_CAP_SET_TSS_ADDR 4 /* * ioctls for VM fds @@ -367,6 +368,7 @@ struct kvm_signal_mask { #define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45) #define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46,\ struct kvm_userspace_memory_region) +#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47) /* * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns * a vcpu fd.