aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2010-03-18 09:20:16 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:16:14 -0400
commit2dafc6c234b6064189405f42e1602e9a0abe5a44 (patch)
tree43ac5a6ead7a4fad9627d500b9e91a69e8ad7e8b /arch/x86/kvm/x86.c
parentaca06a83071e4e4c9150751db7ea6a46240734fc (diff)
KVM: x86 emulator: Provide more callbacks for x86 emulator.
Provide get_cached_descriptor(), set_cached_descriptor(), get_segment_selector(), set_segment_selector(), get_gdt(), write_std() callbacks. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c130
1 files changed, 115 insertions, 15 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0ecd37ac9d39..fbee8fbb33b5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3058,6 +3058,18 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
3058 return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v); 3058 return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
3059} 3059}
3060 3060
3061static void kvm_set_segment(struct kvm_vcpu *vcpu,
3062 struct kvm_segment *var, int seg)
3063{
3064 kvm_x86_ops->set_segment(vcpu, var, seg);
3065}
3066
3067void kvm_get_segment(struct kvm_vcpu *vcpu,
3068 struct kvm_segment *var, int seg)
3069{
3070 kvm_x86_ops->get_segment(vcpu, var, seg);
3071}
3072
3061gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error) 3073gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
3062{ 3074{
3063 u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; 3075 u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
@@ -3138,14 +3150,18 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
3138 return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error); 3150 return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
3139} 3151}
3140 3152
3141static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes, 3153static int kvm_write_guest_virt_helper(gva_t addr, void *val,
3142 struct kvm_vcpu *vcpu, u32 *error) 3154 unsigned int bytes,
3155 struct kvm_vcpu *vcpu, u32 access,
3156 u32 *error)
3143{ 3157{
3144 void *data = val; 3158 void *data = val;
3145 int r = X86EMUL_CONTINUE; 3159 int r = X86EMUL_CONTINUE;
3146 3160
3161 access |= PFERR_WRITE_MASK;
3162
3147 while (bytes) { 3163 while (bytes) {
3148 gpa_t gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error); 3164 gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
3149 unsigned offset = addr & (PAGE_SIZE-1); 3165 unsigned offset = addr & (PAGE_SIZE-1);
3150 unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); 3166 unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
3151 int ret; 3167 int ret;
@@ -3168,6 +3184,19 @@ out:
3168 return r; 3184 return r;
3169} 3185}
3170 3186
3187static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes,
3188 struct kvm_vcpu *vcpu, u32 *error)
3189{
3190 u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
3191 return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, access, error);
3192}
3193
3194static int kvm_write_guest_virt_system(gva_t addr, void *val,
3195 unsigned int bytes,
3196 struct kvm_vcpu *vcpu, u32 *error)
3197{
3198 return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error);
3199}
3171 3200
3172static int emulator_read_emulated(unsigned long addr, 3201static int emulator_read_emulated(unsigned long addr,
3173 void *val, 3202 void *val,
@@ -3484,12 +3513,95 @@ static int emulator_get_cpl(struct kvm_vcpu *vcpu)
3484 return kvm_x86_ops->get_cpl(vcpu); 3513 return kvm_x86_ops->get_cpl(vcpu);
3485} 3514}
3486 3515
3516static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
3517{
3518 kvm_x86_ops->get_gdt(vcpu, dt);
3519}
3520
3521static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
3522 struct kvm_vcpu *vcpu)
3523{
3524 struct kvm_segment var;
3525
3526 kvm_get_segment(vcpu, &var, seg);
3527
3528 if (var.unusable)
3529 return false;
3530
3531 if (var.g)
3532 var.limit >>= 12;
3533 set_desc_limit(desc, var.limit);
3534 set_desc_base(desc, (unsigned long)var.base);
3535 desc->type = var.type;
3536 desc->s = var.s;
3537 desc->dpl = var.dpl;
3538 desc->p = var.present;
3539 desc->avl = var.avl;
3540 desc->l = var.l;
3541 desc->d = var.db;
3542 desc->g = var.g;
3543
3544 return true;
3545}
3546
3547static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg,
3548 struct kvm_vcpu *vcpu)
3549{
3550 struct kvm_segment var;
3551
3552 /* needed to preserve selector */
3553 kvm_get_segment(vcpu, &var, seg);
3554
3555 var.base = get_desc_base(desc);
3556 var.limit = get_desc_limit(desc);
3557 if (desc->g)
3558 var.limit = (var.limit << 12) | 0xfff;
3559 var.type = desc->type;
3560 var.present = desc->p;
3561 var.dpl = desc->dpl;
3562 var.db = desc->d;
3563 var.s = desc->s;
3564 var.l = desc->l;
3565 var.g = desc->g;
3566 var.avl = desc->avl;
3567 var.present = desc->p;
3568 var.unusable = !var.present;
3569 var.padding = 0;
3570
3571 kvm_set_segment(vcpu, &var, seg);
3572 return;
3573}
3574
3575static u16 emulator_get_segment_selector(int seg, struct kvm_vcpu *vcpu)
3576{
3577 struct kvm_segment kvm_seg;
3578
3579 kvm_get_segment(vcpu, &kvm_seg, seg);
3580 return kvm_seg.selector;
3581}
3582
3583static void emulator_set_segment_selector(u16 sel, int seg,
3584 struct kvm_vcpu *vcpu)
3585{
3586 struct kvm_segment kvm_seg;
3587
3588 kvm_get_segment(vcpu, &kvm_seg, seg);
3589 kvm_seg.selector = sel;
3590 kvm_set_segment(vcpu, &kvm_seg, seg);
3591}
3592
3487static struct x86_emulate_ops emulate_ops = { 3593static struct x86_emulate_ops emulate_ops = {
3488 .read_std = kvm_read_guest_virt_system, 3594 .read_std = kvm_read_guest_virt_system,
3595 .write_std = kvm_write_guest_virt_system,
3489 .fetch = kvm_fetch_guest_virt, 3596 .fetch = kvm_fetch_guest_virt,
3490 .read_emulated = emulator_read_emulated, 3597 .read_emulated = emulator_read_emulated,
3491 .write_emulated = emulator_write_emulated, 3598 .write_emulated = emulator_write_emulated,
3492 .cmpxchg_emulated = emulator_cmpxchg_emulated, 3599 .cmpxchg_emulated = emulator_cmpxchg_emulated,
3600 .get_cached_descriptor = emulator_get_cached_descriptor,
3601 .set_cached_descriptor = emulator_set_cached_descriptor,
3602 .get_segment_selector = emulator_get_segment_selector,
3603 .set_segment_selector = emulator_set_segment_selector,
3604 .get_gdt = emulator_get_gdt,
3493 .get_cr = emulator_get_cr, 3605 .get_cr = emulator_get_cr,
3494 .set_cr = emulator_set_cr, 3606 .set_cr = emulator_set_cr,
3495 .cpl = emulator_get_cpl, 3607 .cpl = emulator_get_cpl,
@@ -4649,12 +4761,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
4649 return 0; 4761 return 0;
4650} 4762}
4651 4763
4652void kvm_get_segment(struct kvm_vcpu *vcpu,
4653 struct kvm_segment *var, int seg)
4654{
4655 kvm_x86_ops->get_segment(vcpu, var, seg);
4656}
4657
4658void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) 4764void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
4659{ 4765{
4660 struct kvm_segment cs; 4766 struct kvm_segment cs;
@@ -4726,12 +4832,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
4726 return 0; 4832 return 0;
4727} 4833}
4728 4834
4729static void kvm_set_segment(struct kvm_vcpu *vcpu,
4730 struct kvm_segment *var, int seg)
4731{
4732 kvm_x86_ops->set_segment(vcpu, var, seg);
4733}
4734
4735static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector, 4835static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
4736 struct kvm_segment *kvm_desct) 4836 struct kvm_segment *kvm_desct)
4737{ 4837{