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

#include "cpu.h"
21
#include "exec/cpu-all.h"
22
#include "exec/helper-proto.h"
B
Blue Swirl 已提交
23

B
Blue Swirl 已提交
24
#if !defined(CONFIG_USER_ONLY)
25
#include "exec/softmmu_exec.h"
B
Blue Swirl 已提交
26 27
#endif /* !defined(CONFIG_USER_ONLY) */

B
Blue Swirl 已提交
28 29 30 31
/* Secure Virtual Machine helpers */

#if defined(CONFIG_USER_ONLY)

B
Blue Swirl 已提交
32
void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
B
Blue Swirl 已提交
33 34 35
{
}

B
Blue Swirl 已提交
36
void helper_vmmcall(CPUX86State *env)
B
Blue Swirl 已提交
37 38 39
{
}

B
Blue Swirl 已提交
40
void helper_vmload(CPUX86State *env, int aflag)
B
Blue Swirl 已提交
41 42 43
{
}

B
Blue Swirl 已提交
44
void helper_vmsave(CPUX86State *env, int aflag)
B
Blue Swirl 已提交
45 46 47
{
}

B
Blue Swirl 已提交
48
void helper_stgi(CPUX86State *env)
B
Blue Swirl 已提交
49 50 51
{
}

B
Blue Swirl 已提交
52
void helper_clgi(CPUX86State *env)
B
Blue Swirl 已提交
53 54 55
{
}

B
Blue Swirl 已提交
56
void helper_skinit(CPUX86State *env)
B
Blue Swirl 已提交
57 58 59
{
}

B
Blue Swirl 已提交
60
void helper_invlpga(CPUX86State *env, int aflag)
B
Blue Swirl 已提交
61 62 63
{
}

B
Blue Swirl 已提交
64
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
B
Blue Swirl 已提交
65 66 67 68 69 70 71
{
}

void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1)
{
}

B
Blue Swirl 已提交
72 73
void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
                                      uint64_t param)
B
Blue Swirl 已提交
74 75 76 77 78 79 80 81
{
}

void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
                                   uint64_t param)
{
}

B
Blue Swirl 已提交
82
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
B
Blue Swirl 已提交
83 84 85 86 87
                         uint32_t next_eip_addend)
{
}
#else

A
Avi Kivity 已提交
88
static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
B
Blue Swirl 已提交
89 90
                                const SegmentCache *sc)
{
91 92
    CPUState *cs = CPU(x86_env_get_cpu(env));

93
    stw_phys(cs->as, addr + offsetof(struct vmcb_seg, selector),
B
Blue Swirl 已提交
94
             sc->selector);
95
    stq_phys(cs->as, addr + offsetof(struct vmcb_seg, base),
B
Blue Swirl 已提交
96
             sc->base);
97
    stl_phys(cs->as, addr + offsetof(struct vmcb_seg, limit),
B
Blue Swirl 已提交
98
             sc->limit);
99
    stw_phys(cs->as, addr + offsetof(struct vmcb_seg, attrib),
B
Blue Swirl 已提交
100 101 102
             ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
}

A
Avi Kivity 已提交
103
static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
B
Blue Swirl 已提交
104
                                SegmentCache *sc)
B
Blue Swirl 已提交
105
{
106
    CPUState *cs = CPU(x86_env_get_cpu(env));
B
Blue Swirl 已提交
107 108
    unsigned int flags;

109 110
    sc->selector = lduw_phys(cs->as,
                             addr + offsetof(struct vmcb_seg, selector));
111
    sc->base = ldq_phys(cs->as, addr + offsetof(struct vmcb_seg, base));
112
    sc->limit = ldl_phys(cs->as, addr + offsetof(struct vmcb_seg, limit));
113
    flags = lduw_phys(cs->as, addr + offsetof(struct vmcb_seg, attrib));
B
Blue Swirl 已提交
114 115 116
    sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
}

A
Avi Kivity 已提交
117
static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
B
Blue Swirl 已提交
118
                                      int seg_reg)
B
Blue Swirl 已提交
119 120 121
{
    SegmentCache sc1, *sc = &sc1;

B
Blue Swirl 已提交
122
    svm_load_seg(env, addr, sc);
B
Blue Swirl 已提交
123 124 125 126
    cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
                           sc->base, sc->limit, sc->flags);
}

B
Blue Swirl 已提交
127
void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
B
Blue Swirl 已提交
128
{
129
    CPUState *cs = CPU(x86_env_get_cpu(env));
B
Blue Swirl 已提交
130 131 132 133
    target_ulong addr;
    uint32_t event_inj;
    uint32_t int_ctl;

B
Blue Swirl 已提交
134
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0);
B
Blue Swirl 已提交
135 136

    if (aflag == 2) {
L
liguang 已提交
137
        addr = env->regs[R_EAX];
B
Blue Swirl 已提交
138
    } else {
L
liguang 已提交
139
        addr = (uint32_t)env->regs[R_EAX];
B
Blue Swirl 已提交
140 141 142 143 144 145 146
    }

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

    env->vm_vmcb = addr;

    /* save the current CPU state in the hsave page */
147
    stq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base),
B
Blue Swirl 已提交
148
             env->gdt.base);
149
    stl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit),
B
Blue Swirl 已提交
150 151
             env->gdt.limit);

152
    stq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.idtr.base),
B
Blue Swirl 已提交
153
             env->idt.base);
154
    stl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit),
B
Blue Swirl 已提交
155 156
             env->idt.limit);

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);

    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.rflags),
B
Blue Swirl 已提交
174 175
             cpu_compute_eflags(env));

B
Blue Swirl 已提交
176
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es),
B
Blue Swirl 已提交
177
                 &env->segs[R_ES]);
B
Blue Swirl 已提交
178
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
B
Blue Swirl 已提交
179
                 &env->segs[R_CS]);
B
Blue Swirl 已提交
180
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
B
Blue Swirl 已提交
181
                 &env->segs[R_SS]);
B
Blue Swirl 已提交
182
    svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
B
Blue Swirl 已提交
183 184
                 &env->segs[R_DS]);

185
    stq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.rip),
L
liguang 已提交
186
             env->eip + next_eip_addend);
187 188 189 190
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
    stq_phys(cs->as,
             env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
B
Blue Swirl 已提交
191 192 193

    /* load the interception bitmaps so we do not need to access the
       vmcb in svm mode */
194
    env->intercept = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
195
                                                      control.intercept));
196
    env->intercept_cr_read = lduw_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
197 198
                                       offsetof(struct vmcb,
                                                control.intercept_cr_read));
199
    env->intercept_cr_write = lduw_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
200 201
                                        offsetof(struct vmcb,
                                                 control.intercept_cr_write));
202
    env->intercept_dr_read = lduw_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
203 204
                                       offsetof(struct vmcb,
                                                control.intercept_dr_read));
205
    env->intercept_dr_write = lduw_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
206 207
                                        offsetof(struct vmcb,
                                                 control.intercept_dr_write));
208
    env->intercept_exceptions = ldl_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
209 210 211 212 213 214 215
                                         offsetof(struct vmcb,
                                                  control.intercept_exceptions
                                                  ));

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

216
    env->tsc_offset = ldq_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
217 218
                               offsetof(struct vmcb, control.tsc_offset));

219
    env->gdt.base  = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
220
                                                      save.gdtr.base));
221
    env->gdt.limit = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
222 223
                                                      save.gdtr.limit));

224
    env->idt.base  = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
225
                                                      save.idtr.base));
226
    env->idt.limit = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
227 228 229
                                                      save.idtr.limit));

    /* clear exit_info_2 so we behave like the real hardware */
230 231
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
B
Blue Swirl 已提交
232

233 234
    cpu_x86_update_cr0(env, ldq_phys(cs->as,
                                     env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
235
                                                             save.cr0)));
236 237
    cpu_x86_update_cr4(env, ldq_phys(cs->as,
                                     env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
238
                                                             save.cr4)));
239 240
    cpu_x86_update_cr3(env, ldq_phys(cs->as,
                                     env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
241
                                                             save.cr3)));
242 243
    env->cr[2] = ldq_phys(cs->as,
                          env->vm_vmcb + offsetof(struct vmcb, save.cr2));
244 245
    int_ctl = ldl_phys(cs->as,
                       env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
B
Blue Swirl 已提交
246 247 248 249 250 251 252 253 254 255
    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
    if (int_ctl & V_INTR_MASKING_MASK) {
        env->v_tpr = int_ctl & V_TPR_MASK;
        env->hflags2 |= HF2_VINTR_MASK;
        if (env->eflags & IF_MASK) {
            env->hflags2 |= HF2_HIF_MASK;
        }
    }

    cpu_load_efer(env,
256 257
                  ldq_phys(cs->as,
                           env->vm_vmcb + offsetof(struct vmcb, save.efer)));
B
Blue Swirl 已提交
258
    env->eflags = 0;
259 260
    cpu_load_eflags(env, ldq_phys(cs->as,
                                  env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
261 262 263
                                                          save.rflags)),
                    ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));

B
Blue Swirl 已提交
264 265 266 267 268 269 270 271
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
                       R_ES);
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
                       R_CS);
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
                       R_SS);
    svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
                       R_DS);
B
Blue Swirl 已提交
272

273 274 275 276 277 278 279 280 281 282 283
    env->eip = ldq_phys(cs->as,
                        env->vm_vmcb + offsetof(struct vmcb, save.rip));

    env->regs[R_ESP] = ldq_phys(cs->as,
                                env->vm_vmcb + offsetof(struct vmcb, save.rsp));
    env->regs[R_EAX] = ldq_phys(cs->as,
                                env->vm_vmcb + offsetof(struct vmcb, save.rax));
    env->dr[7] = ldq_phys(cs->as,
                          env->vm_vmcb + offsetof(struct vmcb, save.dr7));
    env->dr[6] = ldq_phys(cs->as,
                          env->vm_vmcb + offsetof(struct vmcb, save.dr6));
B
Blue Swirl 已提交
284 285 286

    /* FIXME: guest state consistency checks */

287 288
    switch (ldub_phys(cs->as,
                      env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
B
Blue Swirl 已提交
289 290 291 292
    case TLB_CONTROL_DO_NOTHING:
        break;
    case TLB_CONTROL_FLUSH_ALL_ASID:
        /* FIXME: this is not 100% correct but should work for now */
293
        tlb_flush(cs, 1);
B
Blue Swirl 已提交
294 295 296 297 298 299
        break;
    }

    env->hflags2 |= HF2_GIF_MASK;

    if (int_ctl & V_IRQ_MASK) {
300 301 302
        CPUState *cs = CPU(x86_env_get_cpu(env));

        cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
B
Blue Swirl 已提交
303 304 305
    }

    /* maybe we need to inject an event */
306
    event_inj = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
307 308 309 310
                                                 control.event_inj));
    if (event_inj & SVM_EVTINJ_VALID) {
        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
311
        uint32_t event_inj_err = ldl_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
312 313 314 315 316 317 318
                                          offsetof(struct vmcb,
                                                   control.event_inj_err));

        qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
        /* FIXME: need to implement valid_err */
        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
        case SVM_EVTINJ_TYPE_INTR:
319
            cs->exception_index = vector;
B
Blue Swirl 已提交
320 321 322 323 324 325 326 327
            env->error_code = event_inj_err;
            env->exception_is_int = 0;
            env->exception_next_eip = -1;
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
            /* XXX: is it always correct? */
            do_interrupt_x86_hardirq(env, vector, 1);
            break;
        case SVM_EVTINJ_TYPE_NMI:
328
            cs->exception_index = EXCP02_NMI;
B
Blue Swirl 已提交
329 330
            env->error_code = event_inj_err;
            env->exception_is_int = 0;
L
liguang 已提交
331
            env->exception_next_eip = env->eip;
B
Blue Swirl 已提交
332
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
333
            cpu_loop_exit(cs);
B
Blue Swirl 已提交
334 335
            break;
        case SVM_EVTINJ_TYPE_EXEPT:
336
            cs->exception_index = vector;
B
Blue Swirl 已提交
337 338 339 340
            env->error_code = event_inj_err;
            env->exception_is_int = 0;
            env->exception_next_eip = -1;
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
341
            cpu_loop_exit(cs);
B
Blue Swirl 已提交
342 343
            break;
        case SVM_EVTINJ_TYPE_SOFT:
344
            cs->exception_index = vector;
B
Blue Swirl 已提交
345 346
            env->error_code = event_inj_err;
            env->exception_is_int = 1;
L
liguang 已提交
347
            env->exception_next_eip = env->eip;
B
Blue Swirl 已提交
348
            qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
349
            cpu_loop_exit(cs);
B
Blue Swirl 已提交
350 351
            break;
        }
352
        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index,
B
Blue Swirl 已提交
353 354 355 356
                      env->error_code);
    }
}

B
Blue Swirl 已提交
357
void helper_vmmcall(CPUX86State *env)
B
Blue Swirl 已提交
358
{
B
Blue Swirl 已提交
359
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0);
B
Blue Swirl 已提交
360 361 362
    raise_exception(env, EXCP06_ILLOP);
}

B
Blue Swirl 已提交
363
void helper_vmload(CPUX86State *env, int aflag)
B
Blue Swirl 已提交
364
{
365
    CPUState *cs = CPU(x86_env_get_cpu(env));
B
Blue Swirl 已提交
366 367
    target_ulong addr;

B
Blue Swirl 已提交
368
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
B
Blue Swirl 已提交
369 370

    if (aflag == 2) {
L
liguang 已提交
371
        addr = env->regs[R_EAX];
B
Blue Swirl 已提交
372
    } else {
L
liguang 已提交
373
        addr = (uint32_t)env->regs[R_EAX];
B
Blue Swirl 已提交
374 375 376 377
    }

    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx
                  "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
378
                  addr, ldq_phys(cs->as, addr + offsetof(struct vmcb,
B
Blue Swirl 已提交
379
                                                          save.fs.base)),
B
Blue Swirl 已提交
380 381
                  env->segs[R_FS].base);

B
Blue Swirl 已提交
382 383 384 385
    svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
    svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
    svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
    svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
B
Blue Swirl 已提交
386 387

#ifdef TARGET_X86_64
388
    env->kernelgsbase = ldq_phys(cs->as, addr + offsetof(struct vmcb,
B
Blue Swirl 已提交
389
                                                 save.kernel_gs_base));
390 391 392
    env->lstar = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.lstar));
    env->cstar = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.cstar));
    env->fmask = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.sfmask));
B
Blue Swirl 已提交
393
#endif
394 395 396 397
    env->star = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.star));
    env->sysenter_cs = ldq_phys(cs->as,
                                addr + offsetof(struct vmcb, save.sysenter_cs));
    env->sysenter_esp = ldq_phys(cs->as, addr + offsetof(struct vmcb,
B
Blue Swirl 已提交
398
                                                 save.sysenter_esp));
399
    env->sysenter_eip = ldq_phys(cs->as, addr + offsetof(struct vmcb,
B
Blue Swirl 已提交
400 401 402
                                                 save.sysenter_eip));
}

B
Blue Swirl 已提交
403
void helper_vmsave(CPUX86State *env, int aflag)
B
Blue Swirl 已提交
404
{
405
    CPUState *cs = CPU(x86_env_get_cpu(env));
B
Blue Swirl 已提交
406 407
    target_ulong addr;

B
Blue Swirl 已提交
408
    cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
B
Blue Swirl 已提交
409 410

    if (aflag == 2) {
L
liguang 已提交
411
        addr = env->regs[R_EAX];
B
Blue Swirl 已提交
412
    } else {
L
liguang 已提交
413
        addr = (uint32_t)env->regs[R_EAX];
B
Blue Swirl 已提交
414 415 416 417
    }

    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx
                  "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
418 419
                  addr, ldq_phys(cs->as,
                                 addr + offsetof(struct vmcb, save.fs.base)),
B
Blue Swirl 已提交
420 421
                  env->segs[R_FS].base);

B
Blue Swirl 已提交
422
    svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
B
Blue Swirl 已提交
423
                 &env->segs[R_FS]);
B
Blue Swirl 已提交
424
    svm_save_seg(env, addr + offsetof(struct vmcb, save.gs),
B
Blue Swirl 已提交
425
                 &env->segs[R_GS]);
B
Blue Swirl 已提交
426
    svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
B
Blue Swirl 已提交
427
                 &env->tr);
B
Blue Swirl 已提交
428
    svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr),
B
Blue Swirl 已提交
429 430 431
                 &env->ldt);

#ifdef TARGET_X86_64
432
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.kernel_gs_base),
B
Blue Swirl 已提交
433
             env->kernelgsbase);
434 435 436
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.lstar), env->lstar);
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.cstar), env->cstar);
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.sfmask), env->fmask);
B
Blue Swirl 已提交
437
#endif
438 439 440 441
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.star), env->star);
    stq_phys(cs->as,
             addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.sysenter_esp),
B
Blue Swirl 已提交
442
             env->sysenter_esp);
443
    stq_phys(cs->as, addr + offsetof(struct vmcb, save.sysenter_eip),
B
Blue Swirl 已提交
444 445 446
             env->sysenter_eip);
}

B
Blue Swirl 已提交
447
void helper_stgi(CPUX86State *env)
B
Blue Swirl 已提交
448
{
B
Blue Swirl 已提交
449
    cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0);
B
Blue Swirl 已提交
450 451 452
    env->hflags2 |= HF2_GIF_MASK;
}

B
Blue Swirl 已提交
453
void helper_clgi(CPUX86State *env)
B
Blue Swirl 已提交
454
{
B
Blue Swirl 已提交
455
    cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0);
B
Blue Swirl 已提交
456 457 458
    env->hflags2 &= ~HF2_GIF_MASK;
}

B
Blue Swirl 已提交
459
void helper_skinit(CPUX86State *env)
B
Blue Swirl 已提交
460
{
B
Blue Swirl 已提交
461
    cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0);
B
Blue Swirl 已提交
462 463 464 465
    /* XXX: not implemented */
    raise_exception(env, EXCP06_ILLOP);
}

B
Blue Swirl 已提交
466
void helper_invlpga(CPUX86State *env, int aflag)
B
Blue Swirl 已提交
467
{
468
    X86CPU *cpu = x86_env_get_cpu(env);
B
Blue Swirl 已提交
469 470
    target_ulong addr;

B
Blue Swirl 已提交
471
    cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
B
Blue Swirl 已提交
472 473

    if (aflag == 2) {
L
liguang 已提交
474
        addr = env->regs[R_EAX];
B
Blue Swirl 已提交
475
    } else {
L
liguang 已提交
476
        addr = (uint32_t)env->regs[R_EAX];
B
Blue Swirl 已提交
477 478 479 480
    }

    /* XXX: could use the ASID to see if it is needed to do the
       flush */
481
    tlb_flush_page(CPU(cpu), addr);
B
Blue Swirl 已提交
482 483
}

B
Blue Swirl 已提交
484 485
void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
                                      uint64_t param)
B
Blue Swirl 已提交
486
{
487
    CPUState *cs = CPU(x86_env_get_cpu(env));
488

B
Blue Swirl 已提交
489 490 491 492 493 494
    if (likely(!(env->hflags & HF_SVMI_MASK))) {
        return;
    }
    switch (type) {
    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
        if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
B
Blue Swirl 已提交
495
            helper_vmexit(env, type, param);
B
Blue Swirl 已提交
496 497 498 499
        }
        break;
    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
        if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
B
Blue Swirl 已提交
500
            helper_vmexit(env, type, param);
B
Blue Swirl 已提交
501 502 503 504
        }
        break;
    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
        if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
B
Blue Swirl 已提交
505
            helper_vmexit(env, type, param);
B
Blue Swirl 已提交
506 507 508 509
        }
        break;
    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
        if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
B
Blue Swirl 已提交
510
            helper_vmexit(env, type, param);
B
Blue Swirl 已提交
511 512 513 514
        }
        break;
    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
        if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
B
Blue Swirl 已提交
515
            helper_vmexit(env, type, param);
B
Blue Swirl 已提交
516 517 518 519 520
        }
        break;
    case SVM_EXIT_MSR:
        if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) {
            /* FIXME: this should be read in at vmrun (faster this way?) */
521
            uint64_t addr = ldq_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
522 523 524 525
                                     offsetof(struct vmcb,
                                              control.msrpm_base_pa));
            uint32_t t0, t1;

L
liguang 已提交
526
            switch ((uint32_t)env->regs[R_ECX]) {
B
Blue Swirl 已提交
527
            case 0 ... 0x1fff:
L
liguang 已提交
528 529
                t0 = (env->regs[R_ECX] * 2) % 8;
                t1 = (env->regs[R_ECX] * 2) / 8;
B
Blue Swirl 已提交
530 531
                break;
            case 0xc0000000 ... 0xc0001fff:
L
liguang 已提交
532
                t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2;
B
Blue Swirl 已提交
533 534 535 536
                t1 = (t0 / 8);
                t0 %= 8;
                break;
            case 0xc0010000 ... 0xc0011fff:
L
liguang 已提交
537
                t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2;
B
Blue Swirl 已提交
538 539 540 541
                t1 = (t0 / 8);
                t0 %= 8;
                break;
            default:
B
Blue Swirl 已提交
542
                helper_vmexit(env, type, param);
B
Blue Swirl 已提交
543 544 545 546
                t0 = 0;
                t1 = 0;
                break;
            }
547
            if (ldub_phys(cs->as, addr + t1) & ((1 << param) << t0)) {
B
Blue Swirl 已提交
548
                helper_vmexit(env, type, param);
B
Blue Swirl 已提交
549 550 551 552 553
            }
        }
        break;
    default:
        if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
B
Blue Swirl 已提交
554
            helper_vmexit(env, type, param);
B
Blue Swirl 已提交
555 556 557 558 559
        }
        break;
    }
}

B
Blue Swirl 已提交
560
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
B
Blue Swirl 已提交
561 562
                                   uint64_t param)
{
B
Blue Swirl 已提交
563
    helper_svm_check_intercept_param(env, type, param);
B
Blue Swirl 已提交
564 565
}

B
Blue Swirl 已提交
566
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
B
Blue Swirl 已提交
567 568
                         uint32_t next_eip_addend)
{
569 570
    CPUState *cs = CPU(x86_env_get_cpu(env));

B
Blue Swirl 已提交
571 572
    if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) {
        /* FIXME: this should be read in at vmrun (faster this way?) */
573
        uint64_t addr = ldq_phys(cs->as, env->vm_vmcb +
B
Blue Swirl 已提交
574 575 576
                                 offsetof(struct vmcb, control.iopm_base_pa));
        uint16_t mask = (1 << ((param >> 4) & 7)) - 1;

577
        if (lduw_phys(cs->as, addr + port / 8) & (mask << (port & 7))) {
L
liguang 已提交
578
            /* next env->eip */
579 580
            stq_phys(cs->as,
                     env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
B
Blue Swirl 已提交
581
                     env->eip + next_eip_addend);
B
Blue Swirl 已提交
582
            helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16));
B
Blue Swirl 已提交
583 584 585 586 587
        }
    }
}

/* Note: currently only 32 bits of exit_code are used */
B
Blue Swirl 已提交
588
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
B
Blue Swirl 已提交
589
{
590
    CPUState *cs = CPU(x86_env_get_cpu(env));
B
Blue Swirl 已提交
591 592 593 594 595
    uint32_t int_ctl;

    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
                  PRIx64 ", " TARGET_FMT_lx ")!\n",
                  exit_code, exit_info_1,
596
                  ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
597
                                                   control.exit_info_2)),
L
liguang 已提交
598
                  env->eip);
B
Blue Swirl 已提交
599 600

    if (env->hflags & HF_INHIBIT_IRQ_MASK) {
601 602
        stl_phys(cs->as,
                 env->vm_vmcb + offsetof(struct vmcb, control.int_state),
B
Blue Swirl 已提交
603 604 605
                 SVM_INTERRUPT_SHADOW_MASK);
        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
    } else {
606 607
        stl_phys(cs->as,
                 env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
B
Blue Swirl 已提交
608 609 610
    }

    /* Save the VM state in the vmcb */
B
Blue Swirl 已提交
611
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
B
Blue Swirl 已提交
612
                 &env->segs[R_ES]);
B
Blue Swirl 已提交
613
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
B
Blue Swirl 已提交
614
                 &env->segs[R_CS]);
B
Blue Swirl 已提交
615
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
B
Blue Swirl 已提交
616
                 &env->segs[R_SS]);
B
Blue Swirl 已提交
617
    svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
B
Blue Swirl 已提交
618 619
                 &env->segs[R_DS]);

620
    stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
B
Blue Swirl 已提交
621
             env->gdt.base);
622
    stl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit),
B
Blue Swirl 已提交
623 624
             env->gdt.limit);

625
    stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base),
B
Blue Swirl 已提交
626
             env->idt.base);
627
    stl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit),
B
Blue Swirl 已提交
628 629
             env->idt.limit);

630 631 632 633 634 635 636 637 638 639
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
B
Blue Swirl 已提交
640

641 642
    int_ctl = ldl_phys(cs->as,
                       env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
B
Blue Swirl 已提交
643 644
    int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
    int_ctl |= env->v_tpr & V_TPR_MASK;
645
    if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
B
Blue Swirl 已提交
646 647
        int_ctl |= V_IRQ_MASK;
    }
648 649
    stl_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
B
Blue Swirl 已提交
650

651
    stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.rflags),
B
Blue Swirl 已提交
652
             cpu_compute_eflags(env));
653
    stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.rip),
B
Blue Swirl 已提交
654
             env->eip);
655 656 657 658 659 660 661 662
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
    stq_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
663
    stb_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.cpl),
B
Blue Swirl 已提交
664 665 666 667 668 669 670
             env->hflags & HF_CPL_MASK);

    /* Reload the host state from vm_hsave */
    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
    env->hflags &= ~HF_SVMI_MASK;
    env->intercept = 0;
    env->intercept_exceptions = 0;
671
    cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
B
Blue Swirl 已提交
672 673
    env->tsc_offset = 0;

674
    env->gdt.base  = ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
675
                                                       save.gdtr.base));
676
    env->gdt.limit = ldl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
677 678
                                                       save.gdtr.limit));

679
    env->idt.base  = ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
680
                                                       save.idtr.base));
681
    env->idt.limit = ldl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
682 683
                                                       save.idtr.limit));

684 685
    cpu_x86_update_cr0(env, ldq_phys(cs->as,
                                     env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
686 687
                                                              save.cr0)) |
                       CR0_PE_MASK);
688 689
    cpu_x86_update_cr4(env, ldq_phys(cs->as,
                                     env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
690
                                                              save.cr4)));
691 692
    cpu_x86_update_cr3(env, ldq_phys(cs->as,
                                     env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
693 694 695
                                                              save.cr3)));
    /* we need to set the efer after the crs so the hidden flags get
       set properly */
696
    cpu_load_efer(env, ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
697 698
                                                         save.efer)));
    env->eflags = 0;
699 700
    cpu_load_eflags(env, ldq_phys(cs->as,
                                  env->vm_hsave + offsetof(struct vmcb,
B
Blue Swirl 已提交
701
                                                           save.rflags)),
702 703
                    ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
                      VM_MASK));
B
Blue Swirl 已提交
704

B
Blue Swirl 已提交
705 706 707 708 709 710 711 712
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
                       R_ES);
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
                       R_CS);
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
                       R_SS);
    svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
                       R_DS);
B
Blue Swirl 已提交
713

714 715 716
    env->eip = ldq_phys(cs->as,
                        env->vm_hsave + offsetof(struct vmcb, save.rip));
    env->regs[R_ESP] = ldq_phys(cs->as, env->vm_hsave +
717
                                offsetof(struct vmcb, save.rsp));
718
    env->regs[R_EAX] = ldq_phys(cs->as, env->vm_hsave +
719
                                offsetof(struct vmcb, save.rax));
B
Blue Swirl 已提交
720

721 722 723 724
    env->dr[6] = ldq_phys(cs->as,
                          env->vm_hsave + offsetof(struct vmcb, save.dr6));
    env->dr[7] = ldq_phys(cs->as,
                          env->vm_hsave + offsetof(struct vmcb, save.dr7));
B
Blue Swirl 已提交
725 726

    /* other setups */
727
    stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, control.exit_code),
B
Blue Swirl 已提交
728
             exit_code);
729
    stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1),
B
Blue Swirl 已提交
730 731
             exit_info_1);

732 733
    stl_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
734
             ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
735
                                              control.event_inj)));
736 737
    stl_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
738
             ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb,
B
Blue Swirl 已提交
739
                                              control.event_inj_err)));
740 741
    stl_phys(cs->as,
             env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
B
Blue Swirl 已提交
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762

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

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

    /* Clears the TSC_OFFSET inside the processor. */

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

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

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

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

    /* remove any pending exception */
763
    cs->exception_index = -1;
B
Blue Swirl 已提交
764 765 766
    env->error_code = 0;
    env->old_exception = -1;

767
    cpu_loop_exit(cs);
B
Blue Swirl 已提交
768 769
}

B
Blue Swirl 已提交
770
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
B
Blue Swirl 已提交
771
{
B
Blue Swirl 已提交
772
    helper_vmexit(env, exit_code, exit_info_1);
B
Blue Swirl 已提交
773 774 775
}

#endif