Statistics
| Branch: | Revision:

root / target-i386 / svm_helper.c @ a8170e5e

History | View | Annotate | Download (26.6 kB)

1
/*
2
 *  x86 SVM helpers
3
 *
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include "cpu.h"
21
#include "cpu-all.h"
22
#include "helper.h"
23

    
24
#if !defined(CONFIG_USER_ONLY)
25
#include "softmmu_exec.h"
26
#endif /* !defined(CONFIG_USER_ONLY) */
27

    
28
/* Secure Virtual Machine helpers */
29

    
30
#if defined(CONFIG_USER_ONLY)
31

    
32
void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
33
{
34
}
35

    
36
void helper_vmmcall(CPUX86State *env)
37
{
38
}
39

    
40
void helper_vmload(CPUX86State *env, int aflag)
41
{
42
}
43

    
44
void helper_vmsave(CPUX86State *env, int aflag)
45
{
46
}
47

    
48
void helper_stgi(CPUX86State *env)
49
{
50
}
51

    
52
void helper_clgi(CPUX86State *env)
53
{
54
}
55

    
56
void helper_skinit(CPUX86State *env)
57
{
58
}
59

    
60
void helper_invlpga(CPUX86State *env, int aflag)
61
{
62
}
63

    
64
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
65
{
66
}
67

    
68
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1)
69
{
70
}
71

    
72
void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
73
                                      uint64_t param)
74
{
75
}
76

    
77
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
78
                                   uint64_t param)
79
{
80
}
81

    
82
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
83
                         uint32_t next_eip_addend)
84
{
85
}
86
#else
87

    
88
static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
89
                                const SegmentCache *sc)
90
{
91
    stw_phys(addr + offsetof(struct vmcb_seg, selector),
92
             sc->selector);
93
    stq_phys(addr + offsetof(struct vmcb_seg, base),
94
             sc->base);
95
    stl_phys(addr + offsetof(struct vmcb_seg, limit),
96
             sc->limit);
97
    stw_phys(addr + offsetof(struct vmcb_seg, attrib),
98
             ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
99
}
100

    
101
static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
102
                                SegmentCache *sc)
103
{
104
    unsigned int flags;
105

    
106
    sc->selector = lduw_phys(addr + offsetof(struct vmcb_seg, selector));
107
    sc->base = ldq_phys(addr + offsetof(struct vmcb_seg, base));
108
    sc->limit = ldl_phys(addr + offsetof(struct vmcb_seg, limit));
109
    flags = lduw_phys(addr + offsetof(struct vmcb_seg, attrib));
110
    sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
111
}
112

    
113
static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
114
                                      int seg_reg)
115
{
116
    SegmentCache sc1, *sc = &sc1;
117

    
118
    svm_load_seg(env, addr, sc);
119
    cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
120
                           sc->base, sc->limit, sc->flags);
121
}
122

    
123
void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
124
{
125
    target_ulong addr;
126
    uint32_t event_inj;
127
    uint32_t int_ctl;
128

    
129
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0);
130

    
131
    if (aflag == 2) {
132
        addr = EAX;
133
    } else {
134
        addr = (uint32_t)EAX;
135
    }
136

    
137
    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
138

    
139
    env->vm_vmcb = addr;
140

    
141
    /* save the current CPU state in the hsave page */
142
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
143
             env->gdt.base);
144
    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
145
             env->gdt.limit);
146

    
147
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
148
             env->idt.base);
149
    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
150
             env->idt.limit);
151

    
152
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
153
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
154
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
155
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
156
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
157
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
158

    
159
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
160
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags),
161
             cpu_compute_eflags(env));
162

    
163
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es),
164
                 &env->segs[R_ES]);
165
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
166
                 &env->segs[R_CS]);
167
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
168
                 &env->segs[R_SS]);
169
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
170
                 &env->segs[R_DS]);
171

    
172
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
173
             EIP + next_eip_addend);
174
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
175
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
176

    
177
    /* load the interception bitmaps so we do not need to access the
178
       vmcb in svm mode */
179
    env->intercept = ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
180
                                                      control.intercept));
181
    env->intercept_cr_read = lduw_phys(env->vm_vmcb +
182
                                       offsetof(struct vmcb,
183
                                                control.intercept_cr_read));
184
    env->intercept_cr_write = lduw_phys(env->vm_vmcb +
185
                                        offsetof(struct vmcb,
186
                                                 control.intercept_cr_write));
187
    env->intercept_dr_read = lduw_phys(env->vm_vmcb +
188
                                       offsetof(struct vmcb,
189
                                                control.intercept_dr_read));
190
    env->intercept_dr_write = lduw_phys(env->vm_vmcb +
191
                                        offsetof(struct vmcb,
192
                                                 control.intercept_dr_write));
193
    env->intercept_exceptions = ldl_phys(env->vm_vmcb +
194
                                         offsetof(struct vmcb,
195
                                                  control.intercept_exceptions
196
                                                  ));
197

    
198
    /* enable intercepts */
199
    env->hflags |= HF_SVMI_MASK;
200

    
201
    env->tsc_offset = ldq_phys(env->vm_vmcb +
202
                               offsetof(struct vmcb, control.tsc_offset));
203

    
204
    env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
205
                                                      save.gdtr.base));
206
    env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
207
                                                      save.gdtr.limit));
208

    
209
    env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
210
                                                      save.idtr.base));
211
    env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
212
                                                      save.idtr.limit));
213

    
214
    /* clear exit_info_2 so we behave like the real hardware */
215
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
216

    
217
    cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
218
                                                             save.cr0)));
219
    cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
220
                                                             save.cr4)));
221
    cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
222
                                                             save.cr3)));
223
    env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
224
    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
225
    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
226
    if (int_ctl & V_INTR_MASKING_MASK) {
227
        env->v_tpr = int_ctl & V_TPR_MASK;
228
        env->hflags2 |= HF2_VINTR_MASK;
229
        if (env->eflags & IF_MASK) {
230
            env->hflags2 |= HF2_HIF_MASK;
231
        }
232
    }
233

    
234
    cpu_load_efer(env,
235
                  ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
236
    env->eflags = 0;
237
    cpu_load_eflags(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
238
                                                          save.rflags)),
239
                    ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
240
    CC_OP = CC_OP_EFLAGS;
241

    
242
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
243
                       R_ES);
244
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
245
                       R_CS);
246
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
247
                       R_SS);
248
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
249
                       R_DS);
250

    
251
    EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
252
    env->eip = EIP;
253
    ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
254
    EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
255
    env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
256
    env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
257
    cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb,
258
                                                           save.cpl)));
259

    
260
    /* FIXME: guest state consistency checks */
261

    
262
    switch (ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
263
    case TLB_CONTROL_DO_NOTHING:
264
        break;
265
    case TLB_CONTROL_FLUSH_ALL_ASID:
266
        /* FIXME: this is not 100% correct but should work for now */
267
        tlb_flush(env, 1);
268
        break;
269
    }
270

    
271
    env->hflags2 |= HF2_GIF_MASK;
272

    
273
    if (int_ctl & V_IRQ_MASK) {
274
        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
275
    }
276

    
277
    /* maybe we need to inject an event */
278
    event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
279
                                                 control.event_inj));
280
    if (event_inj & SVM_EVTINJ_VALID) {
281
        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
282
        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
283
        uint32_t event_inj_err = ldl_phys(env->vm_vmcb +
284
                                          offsetof(struct vmcb,
285
                                                   control.event_inj_err));
286

    
287
        qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
288
        /* FIXME: need to implement valid_err */
289
        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
290
        case SVM_EVTINJ_TYPE_INTR:
291
            env->exception_index = vector;
292
            env->error_code = event_inj_err;
293
            env->exception_is_int = 0;
294
            env->exception_next_eip = -1;
295
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
296
            /* XXX: is it always correct? */
297
            do_interrupt_x86_hardirq(env, vector, 1);
298
            break;
299
        case SVM_EVTINJ_TYPE_NMI:
300
            env->exception_index = EXCP02_NMI;
301
            env->error_code = event_inj_err;
302
            env->exception_is_int = 0;
303
            env->exception_next_eip = EIP;
304
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
305
            cpu_loop_exit(env);
306
            break;
307
        case SVM_EVTINJ_TYPE_EXEPT:
308
            env->exception_index = vector;
309
            env->error_code = event_inj_err;
310
            env->exception_is_int = 0;
311
            env->exception_next_eip = -1;
312
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
313
            cpu_loop_exit(env);
314
            break;
315
        case SVM_EVTINJ_TYPE_SOFT:
316
            env->exception_index = vector;
317
            env->error_code = event_inj_err;
318
            env->exception_is_int = 1;
319
            env->exception_next_eip = EIP;
320
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
321
            cpu_loop_exit(env);
322
            break;
323
        }
324
        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index,
325
                      env->error_code);
326
    }
327
}
328

    
329
void helper_vmmcall(CPUX86State *env)
330
{
331
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0);
332
    raise_exception(env, EXCP06_ILLOP);
333
}
334

    
335
void helper_vmload(CPUX86State *env, int aflag)
336
{
337
    target_ulong addr;
338

    
339
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
340

    
341
    if (aflag == 2) {
342
        addr = EAX;
343
    } else {
344
        addr = (uint32_t)EAX;
345
    }
346

    
347
    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx
348
                  "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
349
                  addr, ldq_phys(addr + offsetof(struct vmcb,
350
                                                          save.fs.base)),
351
                  env->segs[R_FS].base);
352

    
353
    svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
354
    svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
355
    svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
356
    svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
357

    
358
#ifdef TARGET_X86_64
359
    env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb,
360
                                                 save.kernel_gs_base));
361
    env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
362
    env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
363
    env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
364
#endif
365
    env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
366
    env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
367
    env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb,
368
                                                 save.sysenter_esp));
369
    env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb,
370
                                                 save.sysenter_eip));
371
}
372

    
373
void helper_vmsave(CPUX86State *env, int aflag)
374
{
375
    target_ulong addr;
376

    
377
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
378

    
379
    if (aflag == 2) {
380
        addr = EAX;
381
    } else {
382
        addr = (uint32_t)EAX;
383
    }
384

    
385
    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx
386
                  "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
387
                  addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
388
                  env->segs[R_FS].base);
389

    
390
    svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
391
                 &env->segs[R_FS]);
392
    svm_save_seg(env, addr + offsetof(struct vmcb, save.gs),
393
                 &env->segs[R_GS]);
394
    svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
395
                 &env->tr);
396
    svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr),
397
                 &env->ldt);
398

    
399
#ifdef TARGET_X86_64
400
    stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base),
401
             env->kernelgsbase);
402
    stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
403
    stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
404
    stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
405
#endif
406
    stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
407
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
408
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp),
409
             env->sysenter_esp);
410
    stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip),
411
             env->sysenter_eip);
412
}
413

    
414
void helper_stgi(CPUX86State *env)
415
{
416
    cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0);
417
    env->hflags2 |= HF2_GIF_MASK;
418
}
419

    
420
void helper_clgi(CPUX86State *env)
421
{
422
    cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0);
423
    env->hflags2 &= ~HF2_GIF_MASK;
424
}
425

    
426
void helper_skinit(CPUX86State *env)
427
{
428
    cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0);
429
    /* XXX: not implemented */
430
    raise_exception(env, EXCP06_ILLOP);
431
}
432

    
433
void helper_invlpga(CPUX86State *env, int aflag)
434
{
435
    target_ulong addr;
436

    
437
    cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
438

    
439
    if (aflag == 2) {
440
        addr = EAX;
441
    } else {
442
        addr = (uint32_t)EAX;
443
    }
444

    
445
    /* XXX: could use the ASID to see if it is needed to do the
446
       flush */
447
    tlb_flush_page(env, addr);
448
}
449

    
450
void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
451
                                      uint64_t param)
452
{
453
    if (likely(!(env->hflags & HF_SVMI_MASK))) {
454
        return;
455
    }
456
    switch (type) {
457
    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
458
        if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
459
            helper_vmexit(env, type, param);
460
        }
461
        break;
462
    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
463
        if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
464
            helper_vmexit(env, type, param);
465
        }
466
        break;
467
    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
468
        if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
469
            helper_vmexit(env, type, param);
470
        }
471
        break;
472
    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
473
        if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
474
            helper_vmexit(env, type, param);
475
        }
476
        break;
477
    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
478
        if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
479
            helper_vmexit(env, type, param);
480
        }
481
        break;
482
    case SVM_EXIT_MSR:
483
        if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
484
            /* FIXME: this should be read in at vmrun (faster this way?) */
485
            uint64_t addr = ldq_phys(env->vm_vmcb +
486
                                     offsetof(struct vmcb,
487
                                              control.msrpm_base_pa));
488
            uint32_t t0, t1;
489

    
490
            switch ((uint32_t)ECX) {
491
            case 0 ... 0x1fff:
492
                t0 = (ECX * 2) % 8;
493
                t1 = (ECX * 2) / 8;
494
                break;
495
            case 0xc0000000 ... 0xc0001fff:
496
                t0 = (8192 + ECX - 0xc0000000) * 2;
497
                t1 = (t0 / 8);
498
                t0 %= 8;
499
                break;
500
            case 0xc0010000 ... 0xc0011fff:
501
                t0 = (16384 + ECX - 0xc0010000) * 2;
502
                t1 = (t0 / 8);
503
                t0 %= 8;
504
                break;
505
            default:
506
                helper_vmexit(env, type, param);
507
                t0 = 0;
508
                t1 = 0;
509
                break;
510
            }
511
            if (ldub_phys(addr + t1) & ((1 << param) << t0)) {
512
                helper_vmexit(env, type, param);
513
            }
514
        }
515
        break;
516
    default:
517
        if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
518
            helper_vmexit(env, type, param);
519
        }
520
        break;
521
    }
522
}
523

    
524
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
525
                                   uint64_t param)
526
{
527
    helper_svm_check_intercept_param(env, type, param);
528
}
529

    
530
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
531
                         uint32_t next_eip_addend)
532
{
533
    if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
534
        /* FIXME: this should be read in at vmrun (faster this way?) */
535
        uint64_t addr = ldq_phys(env->vm_vmcb +
536
                                 offsetof(struct vmcb, control.iopm_base_pa));
537
        uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
538

    
539
        if (lduw_phys(addr + port / 8) & (mask << (port & 7))) {
540
            /* next EIP */
541
            stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
542
                     env->eip + next_eip_addend);
543
            helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16));
544
        }
545
    }
546
}
547

    
548
/* Note: currently only 32 bits of exit_code are used */
549
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
550
{
551
    uint32_t int_ctl;
552

    
553
    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
554
                  PRIx64 ", " TARGET_FMT_lx ")!\n",
555
                  exit_code, exit_info_1,
556
                  ldq_phys(env->vm_vmcb + offsetof(struct vmcb,
557
                                                   control.exit_info_2)),
558
                  EIP);
559

    
560
    if (env->hflags & HF_INHIBIT_IRQ_MASK) {
561
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state),
562
                 SVM_INTERRUPT_SHADOW_MASK);
563
        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
564
    } else {
565
        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
566
    }
567

    
568
    /* Save the VM state in the vmcb */
569
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
570
                 &env->segs[R_ES]);
571
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
572
                 &env->segs[R_CS]);
573
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
574
                 &env->segs[R_SS]);
575
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
576
                 &env->segs[R_DS]);
577

    
578
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
579
             env->gdt.base);
580
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
581
             env->gdt.limit);
582

    
583
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
584
             env->idt.base);
585
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
586
             env->idt.limit);
587

    
588
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
589
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
590
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
591
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
592
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
593

    
594
    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
595
    int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
596
    int_ctl |= env->v_tpr & V_TPR_MASK;
597
    if (env->interrupt_request & CPU_INTERRUPT_VIRQ) {
598
        int_ctl |= V_IRQ_MASK;
599
    }
600
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
601

    
602
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags),
603
             cpu_compute_eflags(env));
604
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip),
605
             env->eip);
606
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
607
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
608
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
609
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
610
    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl),
611
             env->hflags & HF_CPL_MASK);
612

    
613
    /* Reload the host state from vm_hsave */
614
    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
615
    env->hflags &= ~HF_SVMI_MASK;
616
    env->intercept = 0;
617
    env->intercept_exceptions = 0;
618
    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
619
    env->tsc_offset = 0;
620

    
621
    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb,
622
                                                       save.gdtr.base));
623
    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb,
624
                                                       save.gdtr.limit));
625

    
626
    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb,
627
                                                       save.idtr.base));
628
    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb,
629
                                                       save.idtr.limit));
630

    
631
    cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb,
632
                                                              save.cr0)) |
633
                       CR0_PE_MASK);
634
    cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb,
635
                                                              save.cr4)));
636
    cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb,
637
                                                              save.cr3)));
638
    /* we need to set the efer after the crs so the hidden flags get
639
       set properly */
640
    cpu_load_efer(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb,
641
                                                         save.efer)));
642
    env->eflags = 0;
643
    cpu_load_eflags(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb,
644
                                                           save.rflags)),
645
                    ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
646
    CC_OP = CC_OP_EFLAGS;
647

    
648
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
649
                       R_ES);
650
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
651
                       R_CS);
652
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
653
                       R_SS);
654
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
655
                       R_DS);
656

    
657
    EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
658
    ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
659
    EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
660

    
661
    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
662
    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
663

    
664
    /* other setups */
665
    cpu_x86_set_cpl(env, 0);
666
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
667
             exit_code);
668
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1),
669
             exit_info_1);
670

    
671
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
672
             ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
673
                                              control.event_inj)));
674
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
675
             ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
676
                                              control.event_inj_err)));
677
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
678

    
679
    env->hflags2 &= ~HF2_GIF_MASK;
680
    /* FIXME: Resets the current ASID register to zero (host ASID). */
681

    
682
    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
683

    
684
    /* Clears the TSC_OFFSET inside the processor. */
685

    
686
    /* If the host is in PAE mode, the processor reloads the host's PDPEs
687
       from the page table indicated the host's CR3. If the PDPEs contain
688
       illegal state, the processor causes a shutdown. */
689

    
690
    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
691
    env->cr[0] |= CR0_PE_MASK;
692
    env->eflags &= ~VM_MASK;
693

    
694
    /* Disables all breakpoints in the host DR7 register. */
695

    
696
    /* Checks the reloaded host state for consistency. */
697

    
698
    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
699
       host's code segment or non-canonical (in the case of long mode), a
700
       #GP fault is delivered inside the host. */
701

    
702
    /* remove any pending exception */
703
    env->exception_index = -1;
704
    env->error_code = 0;
705
    env->old_exception = -1;
706

    
707
    cpu_loop_exit(env);
708
}
709

    
710
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
711
{
712
    helper_vmexit(env, exit_code, exit_info_1);
713
}
714

    
715
#endif