diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-03-18 09:20:16 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:16:14 -0400 |
commit | 2dafc6c234b6064189405f42e1602e9a0abe5a44 (patch) | |
tree | 43ac5a6ead7a4fad9627d500b9e91a69e8ad7e8b /arch/x86/kvm/x86.c | |
parent | aca06a83071e4e4c9150751db7ea6a46240734fc (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.c | 130 |
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 | ||
3061 | static 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 | |||
3067 | void 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 | |||
3061 | gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error) | 3073 | gpa_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 | ||
3141 | static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes, | 3153 | static 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 | ||
3187 | static 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 | |||
3194 | static 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 | ||
3172 | static int emulator_read_emulated(unsigned long addr, | 3201 | static 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 | ||
3516 | static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu) | ||
3517 | { | ||
3518 | kvm_x86_ops->get_gdt(vcpu, dt); | ||
3519 | } | ||
3520 | |||
3521 | static 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 | |||
3547 | static 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 | |||
3575 | static 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 | |||
3583 | static 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 | |||
3487 | static struct x86_emulate_ops emulate_ops = { | 3593 | static 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 | ||
4652 | void 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 | |||
4658 | void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) | 4764 | void 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 | ||
4729 | static 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 | |||
4735 | static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector, | 4835 | static 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 | { |