aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c93
1 files changed, 30 insertions, 63 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index cd687395e4e7..27c6ece91da6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3267,54 +3267,6 @@ static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
3267 return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr); 3267 return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr);
3268} 3268}
3269 3269
3270static int load_tss_segment32(struct kvm_vcpu *vcpu,
3271 struct desc_struct *seg_desc,
3272 struct tss_segment_32 *tss)
3273{
3274 u32 base_addr;
3275
3276 base_addr = get_tss_base_addr(vcpu, seg_desc);
3277
3278 return kvm_read_guest(vcpu->kvm, base_addr, tss,
3279 sizeof(struct tss_segment_32));
3280}
3281
3282static int save_tss_segment32(struct kvm_vcpu *vcpu,
3283 struct desc_struct *seg_desc,
3284 struct tss_segment_32 *tss)
3285{
3286 u32 base_addr;
3287
3288 base_addr = get_tss_base_addr(vcpu, seg_desc);
3289
3290 return kvm_write_guest(vcpu->kvm, base_addr, tss,
3291 sizeof(struct tss_segment_32));
3292}
3293
3294static int load_tss_segment16(struct kvm_vcpu *vcpu,
3295 struct desc_struct *seg_desc,
3296 struct tss_segment_16 *tss)
3297{
3298 u32 base_addr;
3299
3300 base_addr = get_tss_base_addr(vcpu, seg_desc);
3301
3302 return kvm_read_guest(vcpu->kvm, base_addr, tss,
3303 sizeof(struct tss_segment_16));
3304}
3305
3306static int save_tss_segment16(struct kvm_vcpu *vcpu,
3307 struct desc_struct *seg_desc,
3308 struct tss_segment_16 *tss)
3309{
3310 u32 base_addr;
3311
3312 base_addr = get_tss_base_addr(vcpu, seg_desc);
3313
3314 return kvm_write_guest(vcpu->kvm, base_addr, tss,
3315 sizeof(struct tss_segment_16));
3316}
3317
3318static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg) 3270static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
3319{ 3271{
3320 struct kvm_segment kvm_seg; 3272 struct kvm_segment kvm_seg;
@@ -3472,20 +3424,26 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
3472} 3424}
3473 3425
3474static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector, 3426static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
3475 struct desc_struct *cseg_desc, 3427 u32 old_tss_base,
3476 struct desc_struct *nseg_desc) 3428 struct desc_struct *nseg_desc)
3477{ 3429{
3478 struct tss_segment_16 tss_segment_16; 3430 struct tss_segment_16 tss_segment_16;
3479 int ret = 0; 3431 int ret = 0;
3480 3432
3481 if (load_tss_segment16(vcpu, cseg_desc, &tss_segment_16)) 3433 if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
3434 sizeof tss_segment_16))
3482 goto out; 3435 goto out;
3483 3436
3484 save_state_to_tss16(vcpu, &tss_segment_16); 3437 save_state_to_tss16(vcpu, &tss_segment_16);
3485 save_tss_segment16(vcpu, cseg_desc, &tss_segment_16);
3486 3438
3487 if (load_tss_segment16(vcpu, nseg_desc, &tss_segment_16)) 3439 if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
3440 sizeof tss_segment_16))
3488 goto out; 3441 goto out;
3442
3443 if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
3444 &tss_segment_16, sizeof tss_segment_16))
3445 goto out;
3446
3489 if (load_state_from_tss16(vcpu, &tss_segment_16)) 3447 if (load_state_from_tss16(vcpu, &tss_segment_16))
3490 goto out; 3448 goto out;
3491 3449
@@ -3495,20 +3453,26 @@ out:
3495} 3453}
3496 3454
3497static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector, 3455static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
3498 struct desc_struct *cseg_desc, 3456 u32 old_tss_base,
3499 struct desc_struct *nseg_desc) 3457 struct desc_struct *nseg_desc)
3500{ 3458{
3501 struct tss_segment_32 tss_segment_32; 3459 struct tss_segment_32 tss_segment_32;
3502 int ret = 0; 3460 int ret = 0;
3503 3461
3504 if (load_tss_segment32(vcpu, cseg_desc, &tss_segment_32)) 3462 if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
3463 sizeof tss_segment_32))
3505 goto out; 3464 goto out;
3506 3465
3507 save_state_to_tss32(vcpu, &tss_segment_32); 3466 save_state_to_tss32(vcpu, &tss_segment_32);
3508 save_tss_segment32(vcpu, cseg_desc, &tss_segment_32);
3509 3467
3510 if (load_tss_segment32(vcpu, nseg_desc, &tss_segment_32)) 3468 if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
3469 sizeof tss_segment_32))
3470 goto out;
3471
3472 if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
3473 &tss_segment_32, sizeof tss_segment_32))
3511 goto out; 3474 goto out;
3475
3512 if (load_state_from_tss32(vcpu, &tss_segment_32)) 3476 if (load_state_from_tss32(vcpu, &tss_segment_32))
3513 goto out; 3477 goto out;
3514 3478
@@ -3523,16 +3487,20 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
3523 struct desc_struct cseg_desc; 3487 struct desc_struct cseg_desc;
3524 struct desc_struct nseg_desc; 3488 struct desc_struct nseg_desc;
3525 int ret = 0; 3489 int ret = 0;
3490 u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
3491 u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
3526 3492
3527 kvm_get_segment(vcpu, &tr_seg, VCPU_SREG_TR); 3493 old_tss_base = vcpu->arch.mmu.gva_to_gpa(vcpu, old_tss_base);
3528 3494
3495 /* FIXME: Handle errors. Failure to read either TSS or their
3496 * descriptors should generate a pagefault.
3497 */
3529 if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc)) 3498 if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
3530 goto out; 3499 goto out;
3531 3500
3532 if (load_guest_segment_descriptor(vcpu, tr_seg.selector, &cseg_desc)) 3501 if (load_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc))
3533 goto out; 3502 goto out;
3534 3503
3535
3536 if (reason != TASK_SWITCH_IRET) { 3504 if (reason != TASK_SWITCH_IRET) {
3537 int cpl; 3505 int cpl;
3538 3506
@@ -3550,8 +3518,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
3550 3518
3551 if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) { 3519 if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
3552 cseg_desc.type &= ~(1 << 1); //clear the B flag 3520 cseg_desc.type &= ~(1 << 1); //clear the B flag
3553 save_guest_segment_descriptor(vcpu, tr_seg.selector, 3521 save_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc);
3554 &cseg_desc);
3555 } 3522 }
3556 3523
3557 if (reason == TASK_SWITCH_IRET) { 3524 if (reason == TASK_SWITCH_IRET) {
@@ -3563,10 +3530,10 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
3563 kvm_x86_ops->cache_regs(vcpu); 3530 kvm_x86_ops->cache_regs(vcpu);
3564 3531
3565 if (nseg_desc.type & 8) 3532 if (nseg_desc.type & 8)
3566 ret = kvm_task_switch_32(vcpu, tss_selector, &cseg_desc, 3533 ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base,
3567 &nseg_desc); 3534 &nseg_desc);
3568 else 3535 else
3569 ret = kvm_task_switch_16(vcpu, tss_selector, &cseg_desc, 3536 ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base,
3570 &nseg_desc); 3537 &nseg_desc);
3571 3538
3572 if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) { 3539 if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {