📄 emulate.c
字号:
/* * emulate.c: handling SVM emulate instructions help. * Copyright (c) 2005 AMD Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */#include <xen/config.h>#include <xen/init.h>#include <xen/lib.h>#include <xen/trace.h>#include <asm/msr.h>#include <asm/hvm/hvm.h>#include <asm/hvm/support.h>#include <asm/hvm/svm/svm.h>#include <asm/hvm/svm/vmcb.h>#include <asm/hvm/svm/emulate.h>#define MAX_INST_LEN 15static unsigned int is_prefix(u8 opc){ switch ( opc ) { case 0x66: case 0x67: case 0x2E: case 0x3E: case 0x26: case 0x64: case 0x65: case 0x36: case 0xF0: case 0xF3: case 0xF2:#if __x86_64__ case 0x40 ... 0x4f:#endif /* __x86_64__ */ return 1; } return 0;}static unsigned long svm_rip2pointer(struct vcpu *v){ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; unsigned long p = vmcb->cs.base + guest_cpu_user_regs()->eip; if ( !(vmcb->cs.attr.fields.l && hvm_long_mode_enabled(v)) ) return (u32)p; /* mask to 32 bits */ return p;}/* First byte: Length. Following bytes: Opcode bytes. */#define MAKE_INSTR(nm, ...) static const u8 OPCODE_##nm[] = { __VA_ARGS__ }MAKE_INSTR(INVD, 2, 0x0f, 0x08);MAKE_INSTR(WBINVD, 2, 0x0f, 0x09);MAKE_INSTR(CPUID, 2, 0x0f, 0xa2);MAKE_INSTR(RDMSR, 2, 0x0f, 0x32);MAKE_INSTR(WRMSR, 2, 0x0f, 0x30);MAKE_INSTR(VMCALL, 3, 0x0f, 0x01, 0xd9);MAKE_INSTR(HLT, 1, 0xf4);MAKE_INSTR(INT3, 1, 0xcc);MAKE_INSTR(RDTSC, 2, 0x0f, 0x31);static const u8 *opc_bytes[INSTR_MAX_COUNT] = { [INSTR_INVD] = OPCODE_INVD, [INSTR_WBINVD] = OPCODE_WBINVD, [INSTR_CPUID] = OPCODE_CPUID, [INSTR_RDMSR] = OPCODE_RDMSR, [INSTR_WRMSR] = OPCODE_WRMSR, [INSTR_VMCALL] = OPCODE_VMCALL, [INSTR_HLT] = OPCODE_HLT, [INSTR_INT3] = OPCODE_INT3, [INSTR_RDTSC] = OPCODE_RDTSC};static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len){ uint32_t pfec = (v->arch.hvm_svm.vmcb->cpl == 3) ? PFEC_user_mode : 0; switch ( hvm_fetch_from_guest_virt(buf, addr, len, pfec) ) { case HVMCOPY_okay: return 1; case HVMCOPY_bad_gva_to_gfn: /* OK just to give up; we'll have injected #PF already */ return 0; case HVMCOPY_bad_gfn_to_mfn: default: /* Not OK: fetches from non-RAM pages are not supportable. */ gdprintk(XENLOG_WARNING, "Bad instruction fetch at %#lx (%#lx)\n", (unsigned long) guest_cpu_user_regs()->eip, addr); hvm_inject_exception(TRAP_gp_fault, 0, 0); return 0; }}int __get_instruction_length_from_list(struct vcpu *v, enum instruction_index *list, unsigned int list_count){ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; unsigned int i, j, inst_len = 0; enum instruction_index instr = 0; u8 buf[MAX_INST_LEN]; const u8 *opcode = NULL; unsigned long fetch_addr; unsigned int fetch_len; /* Fetch up to the next page break; we'll fetch from the next page * later if we have to. */ fetch_addr = svm_rip2pointer(v); fetch_len = min_t(unsigned int, MAX_INST_LEN, PAGE_SIZE - (fetch_addr & ~PAGE_MASK)); if ( !fetch(v, buf, fetch_addr, fetch_len) ) return 0; while ( (inst_len < MAX_INST_LEN) && is_prefix(buf[inst_len]) ) { inst_len++; if ( inst_len >= fetch_len ) { if ( !fetch(v, buf + fetch_len, fetch_addr + fetch_len, MAX_INST_LEN - fetch_len) ) return 0; fetch_len = MAX_INST_LEN; } } for ( j = 0; j < list_count; j++ ) { instr = list[j]; opcode = opc_bytes[instr]; for ( i = 0; (i < opcode[0]) && ((inst_len + i) < MAX_INST_LEN); i++ ) { if ( (inst_len + i) >= fetch_len ) { if ( !fetch(v, buf + fetch_len, fetch_addr + fetch_len, MAX_INST_LEN - fetch_len) ) return 0; fetch_len = MAX_INST_LEN; } if ( buf[inst_len+i] != opcode[i+1] ) goto mismatch; } goto done; mismatch: ; } gdprintk(XENLOG_WARNING, "%s: Mismatch between expected and actual instruction bytes: " "eip = %lx\n", __func__, (unsigned long)vmcb->rip); hvm_inject_exception(TRAP_gp_fault, 0, 0); return 0; done: inst_len += opcode[0]; ASSERT(inst_len <= MAX_INST_LEN); return inst_len;}/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -