Statistics
| Branch: | Revision:

root / target-i386 / svm_helper.c @ 3523e4bd

History | View | Annotate | Download (27.1 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 "exec/cpu-all.h"
22
#include "helper.h"
23

    
24
#if !defined(CONFIG_USER_ONLY)
25
#include "exec/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 = env->regs[R_EAX];
133
    } else {
134
        addr = (uint32_t)env->regs[R_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
             env->eip + next_eip_addend);
174
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
175
    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_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
    env->eip = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
252

    
253
    env->regs[R_ESP] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
254
    env->regs[R_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
        CPUState *cs = CPU(x86_env_get_cpu(env));
275

    
276
        cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
277
    }
278

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

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

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

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

    
341
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
342

    
343
    if (aflag == 2) {
344
        addr = env->regs[R_EAX];
345
    } else {
346
        addr = (uint32_t)env->regs[R_EAX];
347
    }
348

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

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

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

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

    
379
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
380

    
381
    if (aflag == 2) {
382
        addr = env->regs[R_EAX];
383
    } else {
384
        addr = (uint32_t)env->regs[R_EAX];
385
    }
386

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

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

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

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

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

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

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

    
439
    cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
440

    
441
    if (aflag == 2) {
442
        addr = env->regs[R_EAX];
443
    } else {
444
        addr = (uint32_t)env->regs[R_EAX];
445
    }
446

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

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

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

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

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

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

    
550
/* Note: currently only 32 bits of exit_code are used */
551
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
552
{
553
    CPUState *cs = CPU(x86_env_get_cpu(env));
554
    uint32_t int_ctl;
555

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

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

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

    
581
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
582
             env->gdt.base);
583
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
584
             env->gdt.limit);
585

    
586
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
587
             env->idt.base);
588
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
589
             env->idt.limit);
590

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

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

    
605
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags),
606
             cpu_compute_eflags(env));
607
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip),
608
             env->eip);
609
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
610
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
611
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
612
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
613
    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl),
614
             env->hflags & HF_CPL_MASK);
615

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

    
624
    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb,
625
                                                       save.gdtr.base));
626
    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb,
627
                                                       save.gdtr.limit));
628

    
629
    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb,
630
                                                       save.idtr.base));
631
    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb,
632
                                                       save.idtr.limit));
633

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

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

    
660
    env->eip = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
661
    env->regs[R_ESP] = ldq_phys(env->vm_hsave +
662
                                offsetof(struct vmcb, save.rsp));
663
    env->regs[R_EAX] = ldq_phys(env->vm_hsave +
664
                                offsetof(struct vmcb, save.rax));
665

    
666
    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
667
    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
668

    
669
    /* other setups */
670
    cpu_x86_set_cpl(env, 0);
671
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
672
             exit_code);
673
    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1),
674
             exit_info_1);
675

    
676
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
677
             ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
678
                                              control.event_inj)));
679
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
680
             ldl_phys(env->vm_vmcb + offsetof(struct vmcb,
681
                                              control.event_inj_err)));
682
    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
683

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

    
687
    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
688

    
689
    /* Clears the TSC_OFFSET inside the processor. */
690

    
691
    /* If the host is in PAE mode, the processor reloads the host's PDPEs
692
       from the page table indicated the host's CR3. If the PDPEs contain
693
       illegal state, the processor causes a shutdown. */
694

    
695
    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
696
    env->cr[0] |= CR0_PE_MASK;
697
    env->eflags &= ~VM_MASK;
698

    
699
    /* Disables all breakpoints in the host DR7 register. */
700

    
701
    /* Checks the reloaded host state for consistency. */
702

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

    
707
    /* remove any pending exception */
708
    env->exception_index = -1;
709
    env->error_code = 0;
710
    env->old_exception = -1;
711

    
712
    cpu_loop_exit(env);
713
}
714

    
715
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
716
{
717
    helper_vmexit(env, exit_code, exit_info_1);
718
}
719

    
720
#endif