aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorIzik Eidus <izike@qumranet.com>2008-03-24 17:14:53 -0400
committerAvi Kivity <avi@qumranet.com>2008-04-27 05:00:39 -0400
commit37817f2982d0f559f90cecc66e150dd9d2c2df05 (patch)
tree45114b5720d7a13bdbe48cc6a75dc6de03d6fcd2 /arch/x86/kvm/x86.c
parent2e4d2653497856b102c90153f970c9e344ba96c6 (diff)
KVM: x86: hardware task switching support
This emulates the x86 hardware task switch mechanism in software, as it is unsupported by either vmx or svm. It allows operating systems which use it, like freedos, to run as kvm guests. Signed-off-by: Izik Eidus <izike@qumranet.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 63afca1c295f..32d910044f85 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -18,6 +18,7 @@
18#include "irq.h" 18#include "irq.h"
19#include "mmu.h" 19#include "mmu.h"
20#include "i8254.h" 20#include "i8254.h"
21#include "tss.h"
21 22
22#include <linux/clocksource.h> 23#include <linux/clocksource.h>
23#include <linux/kvm.h> 24#include <linux/kvm.h>
@@ -3077,6 +3078,414 @@ static void set_segment(struct kvm_vcpu *vcpu,
3077 kvm_x86_ops->set_segment(vcpu, var, seg); 3078 kvm_x86_ops->set_segment(vcpu, var, seg);
3078} 3079}
3079 3080
3081static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
3082 struct kvm_segment *kvm_desct)
3083{
3084 kvm_desct->base = seg_desc->base0;
3085 kvm_desct->base |= seg_desc->base1 << 16;
3086 kvm_desct->base |= seg_desc->base2 << 24;
3087 kvm_desct->limit = seg_desc->limit0;
3088 kvm_desct->limit |= seg_desc->limit << 16;
3089 kvm_desct->selector = selector;
3090 kvm_desct->type = seg_desc->type;
3091 kvm_desct->present = seg_desc->p;
3092 kvm_desct->dpl = seg_desc->dpl;
3093 kvm_desct->db = seg_desc->d;
3094 kvm_desct->s = seg_desc->s;
3095 kvm_desct->l = seg_desc->l;
3096 kvm_desct->g = seg_desc->g;
3097 kvm_desct->avl = seg_desc->avl;
3098 if (!selector)
3099 kvm_desct->unusable = 1;
3100 else
3101 kvm_desct->unusable = 0;
3102 kvm_desct->padding = 0;
3103}
3104
3105static void get_segment_descritptor_dtable(struct kvm_vcpu *vcpu,
3106 u16 selector,
3107 struct descriptor_table *dtable)
3108{
3109 if (selector & 1 << 2) {
3110 struct kvm_segment kvm_seg;
3111
3112 get_segment(vcpu, &kvm_seg, VCPU_SREG_LDTR);
3113
3114 if (kvm_seg.unusable)
3115 dtable->limit = 0;
3116 else
3117 dtable->limit = kvm_seg.limit;
3118 dtable->base = kvm_seg.base;
3119 }
3120 else
3121 kvm_x86_ops->get_gdt(vcpu, dtable);
3122}
3123
3124/* allowed just for 8 bytes segments */
3125static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
3126 struct desc_struct *seg_desc)
3127{
3128 struct descriptor_table dtable;
3129 u16 index = selector >> 3;
3130
3131 get_segment_descritptor_dtable(vcpu, selector, &dtable);
3132
3133 if (dtable.limit < index * 8 + 7) {
3134 kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
3135 return 1;
3136 }
3137 return kvm_read_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
3138}
3139
3140/* allowed just for 8 bytes segments */
3141static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
3142 struct desc_struct *seg_desc)
3143{
3144 struct descriptor_table dtable;
3145 u16 index = selector >> 3;
3146
3147 get_segment_descritptor_dtable(vcpu, selector, &dtable);
3148
3149 if (dtable.limit < index * 8 + 7)
3150 return 1;
3151 return kvm_write_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
3152}
3153
3154static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
3155 struct desc_struct *seg_desc)
3156{
3157 u32 base_addr;
3158
3159 base_addr = seg_desc->base0;
3160 base_addr |= (seg_desc->base1 << 16);
3161 base_addr |= (seg_desc->base2 << 24);
3162
3163 return base_addr;
3164}
3165
3166static int load_tss_segment32(struct kvm_vcpu *vcpu,
3167 struct desc_struct *seg_desc,
3168 struct tss_segment_32 *tss)
3169{
3170 u32 base_addr;
3171
3172 base_addr = get_tss_base_addr(vcpu, seg_desc);
3173
3174 return kvm_read_guest(vcpu->kvm, base_addr, tss,
3175 sizeof(struct tss_segment_32));
3176}
3177
3178static int save_tss_segment32(struct kvm_vcpu *vcpu,
3179 struct desc_struct *seg_desc,
3180 struct tss_segment_32 *tss)
3181{
3182 u32 base_addr;
3183
3184 base_addr = get_tss_base_addr(vcpu, seg_desc);
3185
3186 return kvm_write_guest(vcpu->kvm, base_addr, tss,
3187 sizeof(struct tss_segment_32));
3188}
3189
3190static int load_tss_segment16(struct kvm_vcpu *vcpu,
3191 struct desc_struct *seg_desc,
3192 struct tss_segment_16 *tss)
3193{
3194 u32 base_addr;
3195
3196 base_addr = get_tss_base_addr(vcpu, seg_desc);
3197
3198 return kvm_read_guest(vcpu->kvm, base_addr, tss,
3199 sizeof(struct tss_segment_16));
3200}
3201
3202static int save_tss_segment16(struct kvm_vcpu *vcpu,
3203 struct desc_struct *seg_desc,
3204 struct tss_segment_16 *tss)
3205{
3206 u32 base_addr;
3207
3208 base_addr = get_tss_base_addr(vcpu, seg_desc);
3209
3210 return kvm_write_guest(vcpu->kvm, base_addr, tss,
3211 sizeof(struct tss_segment_16));
3212}
3213
3214static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
3215{
3216 struct kvm_segment kvm_seg;
3217
3218 get_segment(vcpu, &kvm_seg, seg);
3219 return kvm_seg.selector;
3220}
3221
3222static int load_segment_descriptor_to_kvm_desct(struct kvm_vcpu *vcpu,
3223 u16 selector,
3224 struct kvm_segment *kvm_seg)
3225{
3226 struct desc_struct seg_desc;
3227
3228 if (load_guest_segment_descriptor(vcpu, selector, &seg_desc))
3229 return 1;
3230 seg_desct_to_kvm_desct(&seg_desc, selector, kvm_seg);
3231 return 0;
3232}
3233
3234static int load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
3235 int type_bits, int seg)
3236{
3237 struct kvm_segment kvm_seg;
3238
3239 if (load_segment_descriptor_to_kvm_desct(vcpu, selector, &kvm_seg))
3240 return 1;
3241 kvm_seg.type |= type_bits;
3242
3243 if (seg != VCPU_SREG_SS && seg != VCPU_SREG_CS &&
3244 seg != VCPU_SREG_LDTR)
3245 if (!kvm_seg.s)
3246 kvm_seg.unusable = 1;
3247
3248 set_segment(vcpu, &kvm_seg, seg);
3249 return 0;
3250}
3251
3252static void save_state_to_tss32(struct kvm_vcpu *vcpu,
3253 struct tss_segment_32 *tss)
3254{
3255 tss->cr3 = vcpu->arch.cr3;
3256 tss->eip = vcpu->arch.rip;
3257 tss->eflags = kvm_x86_ops->get_rflags(vcpu);
3258 tss->eax = vcpu->arch.regs[VCPU_REGS_RAX];
3259 tss->ecx = vcpu->arch.regs[VCPU_REGS_RCX];
3260 tss->edx = vcpu->arch.regs[VCPU_REGS_RDX];
3261 tss->ebx = vcpu->arch.regs[VCPU_REGS_RBX];
3262 tss->esp = vcpu->arch.regs[VCPU_REGS_RSP];
3263 tss->ebp = vcpu->arch.regs[VCPU_REGS_RBP];
3264 tss->esi = vcpu->arch.regs[VCPU_REGS_RSI];
3265 tss->edi = vcpu->arch.regs[VCPU_REGS_RDI];
3266
3267 tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
3268 tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
3269 tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
3270 tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
3271 tss->fs = get_segment_selector(vcpu, VCPU_SREG_FS);
3272 tss->gs = get_segment_selector(vcpu, VCPU_SREG_GS);
3273 tss->ldt_selector = get_segment_selector(vcpu, VCPU_SREG_LDTR);
3274 tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
3275}
3276
3277static int load_state_from_tss32(struct kvm_vcpu *vcpu,
3278 struct tss_segment_32 *tss)
3279{
3280 kvm_set_cr3(vcpu, tss->cr3);
3281
3282 vcpu->arch.rip = tss->eip;
3283 kvm_x86_ops->set_rflags(vcpu, tss->eflags | 2);
3284
3285 vcpu->arch.regs[VCPU_REGS_RAX] = tss->eax;
3286 vcpu->arch.regs[VCPU_REGS_RCX] = tss->ecx;
3287 vcpu->arch.regs[VCPU_REGS_RDX] = tss->edx;
3288 vcpu->arch.regs[VCPU_REGS_RBX] = tss->ebx;
3289 vcpu->arch.regs[VCPU_REGS_RSP] = tss->esp;
3290 vcpu->arch.regs[VCPU_REGS_RBP] = tss->ebp;
3291 vcpu->arch.regs[VCPU_REGS_RSI] = tss->esi;
3292 vcpu->arch.regs[VCPU_REGS_RDI] = tss->edi;
3293
3294 if (load_segment_descriptor(vcpu, tss->ldt_selector, 0, VCPU_SREG_LDTR))
3295 return 1;
3296
3297 if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
3298 return 1;
3299
3300 if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
3301 return 1;
3302
3303 if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
3304 return 1;
3305
3306 if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
3307 return 1;
3308
3309 if (load_segment_descriptor(vcpu, tss->fs, 1, VCPU_SREG_FS))
3310 return 1;
3311
3312 if (load_segment_descriptor(vcpu, tss->gs, 1, VCPU_SREG_GS))
3313 return 1;
3314 return 0;
3315}
3316
3317static void save_state_to_tss16(struct kvm_vcpu *vcpu,
3318 struct tss_segment_16 *tss)
3319{
3320 tss->ip = vcpu->arch.rip;
3321 tss->flag = kvm_x86_ops->get_rflags(vcpu);
3322 tss->ax = vcpu->arch.regs[VCPU_REGS_RAX];
3323 tss->cx = vcpu->arch.regs[VCPU_REGS_RCX];
3324 tss->dx = vcpu->arch.regs[VCPU_REGS_RDX];
3325 tss->bx = vcpu->arch.regs[VCPU_REGS_RBX];
3326 tss->sp = vcpu->arch.regs[VCPU_REGS_RSP];
3327 tss->bp = vcpu->arch.regs[VCPU_REGS_RBP];
3328 tss->si = vcpu->arch.regs[VCPU_REGS_RSI];
3329 tss->di = vcpu->arch.regs[VCPU_REGS_RDI];
3330
3331 tss->es = get_segment_selector(vcpu, VCPU_SREG_ES);
3332 tss->cs = get_segment_selector(vcpu, VCPU_SREG_CS);
3333 tss->ss = get_segment_selector(vcpu, VCPU_SREG_SS);
3334 tss->ds = get_segment_selector(vcpu, VCPU_SREG_DS);
3335 tss->ldt = get_segment_selector(vcpu, VCPU_SREG_LDTR);
3336 tss->prev_task_link = get_segment_selector(vcpu, VCPU_SREG_TR);
3337}
3338
3339static int load_state_from_tss16(struct kvm_vcpu *vcpu,
3340 struct tss_segment_16 *tss)
3341{
3342 vcpu->arch.rip = tss->ip;
3343 kvm_x86_ops->set_rflags(vcpu, tss->flag | 2);
3344 vcpu->arch.regs[VCPU_REGS_RAX] = tss->ax;
3345 vcpu->arch.regs[VCPU_REGS_RCX] = tss->cx;
3346 vcpu->arch.regs[VCPU_REGS_RDX] = tss->dx;
3347 vcpu->arch.regs[VCPU_REGS_RBX] = tss->bx;
3348 vcpu->arch.regs[VCPU_REGS_RSP] = tss->sp;
3349 vcpu->arch.regs[VCPU_REGS_RBP] = tss->bp;
3350 vcpu->arch.regs[VCPU_REGS_RSI] = tss->si;
3351 vcpu->arch.regs[VCPU_REGS_RDI] = tss->di;
3352
3353 if (load_segment_descriptor(vcpu, tss->ldt, 0, VCPU_SREG_LDTR))
3354 return 1;
3355
3356 if (load_segment_descriptor(vcpu, tss->es, 1, VCPU_SREG_ES))
3357 return 1;
3358
3359 if (load_segment_descriptor(vcpu, tss->cs, 9, VCPU_SREG_CS))
3360 return 1;
3361
3362 if (load_segment_descriptor(vcpu, tss->ss, 1, VCPU_SREG_SS))
3363 return 1;
3364
3365 if (load_segment_descriptor(vcpu, tss->ds, 1, VCPU_SREG_DS))
3366 return 1;
3367 return 0;
3368}
3369
3370int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
3371 struct desc_struct *cseg_desc,
3372 struct desc_struct *nseg_desc)
3373{
3374 struct tss_segment_16 tss_segment_16;
3375 int ret = 0;
3376
3377 if (load_tss_segment16(vcpu, cseg_desc, &tss_segment_16))
3378 goto out;
3379
3380 save_state_to_tss16(vcpu, &tss_segment_16);
3381 save_tss_segment16(vcpu, cseg_desc, &tss_segment_16);
3382
3383 if (load_tss_segment16(vcpu, nseg_desc, &tss_segment_16))
3384 goto out;
3385 if (load_state_from_tss16(vcpu, &tss_segment_16))
3386 goto out;
3387
3388 ret = 1;
3389out:
3390 return ret;
3391}
3392
3393int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
3394 struct desc_struct *cseg_desc,
3395 struct desc_struct *nseg_desc)
3396{
3397 struct tss_segment_32 tss_segment_32;
3398 int ret = 0;
3399
3400 if (load_tss_segment32(vcpu, cseg_desc, &tss_segment_32))
3401 goto out;
3402
3403 save_state_to_tss32(vcpu, &tss_segment_32);
3404 save_tss_segment32(vcpu, cseg_desc, &tss_segment_32);
3405
3406 if (load_tss_segment32(vcpu, nseg_desc, &tss_segment_32))
3407 goto out;
3408 if (load_state_from_tss32(vcpu, &tss_segment_32))
3409 goto out;
3410
3411 ret = 1;
3412out:
3413 return ret;
3414}
3415
3416int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
3417{
3418 struct kvm_segment tr_seg;
3419 struct desc_struct cseg_desc;
3420 struct desc_struct nseg_desc;
3421 int ret = 0;
3422
3423 get_segment(vcpu, &tr_seg, VCPU_SREG_TR);
3424
3425 if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
3426 goto out;
3427
3428 if (load_guest_segment_descriptor(vcpu, tr_seg.selector, &cseg_desc))
3429 goto out;
3430
3431
3432 if (reason != TASK_SWITCH_IRET) {
3433 int cpl;
3434
3435 cpl = kvm_x86_ops->get_cpl(vcpu);
3436 if ((tss_selector & 3) > nseg_desc.dpl || cpl > nseg_desc.dpl) {
3437 kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
3438 return 1;
3439 }
3440 }
3441
3442 if (!nseg_desc.p || (nseg_desc.limit0 | nseg_desc.limit << 16) < 0x67) {
3443 kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc);
3444 return 1;
3445 }
3446
3447 if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
3448 cseg_desc.type &= ~(1 << 8); //clear the B flag
3449 save_guest_segment_descriptor(vcpu, tr_seg.selector,
3450 &cseg_desc);
3451 }
3452
3453 if (reason == TASK_SWITCH_IRET) {
3454 u32 eflags = kvm_x86_ops->get_rflags(vcpu);
3455 kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
3456 }
3457
3458 kvm_x86_ops->skip_emulated_instruction(vcpu);
3459 kvm_x86_ops->cache_regs(vcpu);
3460
3461 if (nseg_desc.type & 8)
3462 ret = kvm_task_switch_32(vcpu, tss_selector, &cseg_desc,
3463 &nseg_desc);
3464 else
3465 ret = kvm_task_switch_16(vcpu, tss_selector, &cseg_desc,
3466 &nseg_desc);
3467
3468 if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
3469 u32 eflags = kvm_x86_ops->get_rflags(vcpu);
3470 kvm_x86_ops->set_rflags(vcpu, eflags | X86_EFLAGS_NT);
3471 }
3472
3473 if (reason != TASK_SWITCH_IRET) {
3474 nseg_desc.type |= (1 << 8);
3475 save_guest_segment_descriptor(vcpu, tss_selector,
3476 &nseg_desc);
3477 }
3478
3479 kvm_x86_ops->set_cr0(vcpu, vcpu->arch.cr0 | X86_CR0_TS);
3480 seg_desct_to_kvm_desct(&nseg_desc, tss_selector, &tr_seg);
3481 tr_seg.type = 11;
3482 set_segment(vcpu, &tr_seg, VCPU_SREG_TR);
3483out:
3484 kvm_x86_ops->decache_regs(vcpu);
3485 return ret;
3486}
3487EXPORT_SYMBOL_GPL(kvm_task_switch);
3488
3080int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, 3489int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
3081 struct kvm_sregs *sregs) 3490 struct kvm_sregs *sregs)
3082{ 3491{