📄 platform.c
字号:
/* * platform.c: handling x86 platform related MMIO instructions * * Copyright (c) 2004, Intel Corporation. * Copyright (c) 2005, International Business Machines 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/types.h>#include <xen/mm.h>#include <xen/domain_page.h>#include <asm/page.h>#include <xen/event.h>#include <xen/trace.h>#include <xen/sched.h>#include <asm/regs.h>#include <asm/x86_emulate.h>#include <asm/paging.h>#include <asm/hvm/hvm.h>#include <asm/hvm/support.h>#include <asm/hvm/io.h>#include <public/hvm/ioreq.h>#include <xen/lib.h>#include <xen/sched.h>#include <asm/current.h>#define DECODE_success 1#define DECODE_failure 0#define mk_operand(size_reg, index, seg, flag) \ (((size_reg) << 24) | ((index) << 16) | ((seg) << 8) | (flag))#if defined (__x86_64__)static inline long __get_reg_value(unsigned long reg, int size){ switch ( size ) { case BYTE_64: return (char)(reg & 0xFF); case WORD: return (short)(reg & 0xFFFF); case LONG: return (int)(reg & 0xFFFFFFFF); case QUAD: return (long)(reg); default: printk("Error: (__get_reg_value) Invalid reg size\n"); domain_crash_synchronous(); }}long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs){ if ( size == BYTE ) { switch ( index ) { case 0: /* %al */ return (char)(regs->rax & 0xFF); case 1: /* %cl */ return (char)(regs->rcx & 0xFF); case 2: /* %dl */ return (char)(regs->rdx & 0xFF); case 3: /* %bl */ return (char)(regs->rbx & 0xFF); case 4: /* %ah */ return (char)((regs->rax & 0xFF00) >> 8); case 5: /* %ch */ return (char)((regs->rcx & 0xFF00) >> 8); case 6: /* %dh */ return (char)((regs->rdx & 0xFF00) >> 8); case 7: /* %bh */ return (char)((regs->rbx & 0xFF00) >> 8); default: printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } /* NOTREACHED */ } switch ( index ) { case 0: return __get_reg_value(regs->rax, size); case 1: return __get_reg_value(regs->rcx, size); case 2: return __get_reg_value(regs->rdx, size); case 3: return __get_reg_value(regs->rbx, size); case 4: return __get_reg_value(regs->rsp, size); case 5: return __get_reg_value(regs->rbp, size); case 6: return __get_reg_value(regs->rsi, size); case 7: return __get_reg_value(regs->rdi, size); case 8: return __get_reg_value(regs->r8, size); case 9: return __get_reg_value(regs->r9, size); case 10: return __get_reg_value(regs->r10, size); case 11: return __get_reg_value(regs->r11, size); case 12: return __get_reg_value(regs->r12, size); case 13: return __get_reg_value(regs->r13, size); case 14: return __get_reg_value(regs->r14, size); case 15: return __get_reg_value(regs->r15, size); default: printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); }}#elif defined (__i386__)static inline long __get_reg_value(unsigned long reg, int size){ switch ( size ) { case WORD: return (short)(reg & 0xFFFF); case LONG: return (int)(reg & 0xFFFFFFFF); default: printk("Error: (__get_reg_value) Invalid reg size\n"); domain_crash_synchronous(); }}long get_reg_value(int size, int index, int seg, struct cpu_user_regs *regs){ if ( size == BYTE ) { switch ( index ) { case 0: /* %al */ return (char)(regs->eax & 0xFF); case 1: /* %cl */ return (char)(regs->ecx & 0xFF); case 2: /* %dl */ return (char)(regs->edx & 0xFF); case 3: /* %bl */ return (char)(regs->ebx & 0xFF); case 4: /* %ah */ return (char)((regs->eax & 0xFF00) >> 8); case 5: /* %ch */ return (char)((regs->ecx & 0xFF00) >> 8); case 6: /* %dh */ return (char)((regs->edx & 0xFF00) >> 8); case 7: /* %bh */ return (char)((regs->ebx & 0xFF00) >> 8); default: printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); } } switch ( index ) { case 0: return __get_reg_value(regs->eax, size); case 1: return __get_reg_value(regs->ecx, size); case 2: return __get_reg_value(regs->edx, size); case 3: return __get_reg_value(regs->ebx, size); case 4: return __get_reg_value(regs->esp, size); case 5: return __get_reg_value(regs->ebp, size); case 6: return __get_reg_value(regs->esi, size); case 7: return __get_reg_value(regs->edi, size); default: printk("Error: (get_reg_value) Invalid index value\n"); domain_crash_synchronous(); }}#endifstatic inline unsigned char *check_prefix(unsigned char *inst, struct hvm_io_op *mmio_op, unsigned char *ad_size, unsigned char *op_size, unsigned char *seg_sel, unsigned char *rex_p){ while ( 1 ) { switch ( *inst ) { /* rex prefix for em64t instructions */ case 0x40 ... 0x4f: *rex_p = *inst; break; case 0xf3: /* REPZ */ mmio_op->flags = REPZ; break; case 0xf2: /* REPNZ */ mmio_op->flags = REPNZ; break; case 0xf0: /* LOCK */ break; case 0x2e: /* CS */ case 0x36: /* SS */ case 0x3e: /* DS */ case 0x26: /* ES */ case 0x64: /* FS */ case 0x65: /* GS */ *seg_sel = *inst; break; case 0x66: /* 32bit->16bit */ *op_size = WORD; break; case 0x67: *ad_size = WORD; break; default: return inst; } inst++; }}static inline unsigned long get_immediate(int ad_size, const unsigned char *inst, int op_size){ int mod, reg, rm; unsigned long val = 0; int i; mod = (*inst >> 6) & 3; reg = (*inst >> 3) & 7; rm = *inst & 7; inst++; //skip ModR/M byte if ( ad_size != WORD && mod != 3 && rm == 4 ) { rm = *inst & 7; inst++; //skip SIB byte } switch ( mod ) { case 0: if ( ad_size == WORD ) { if ( rm == 6 ) inst = inst + 2; //disp16, skip 2 bytes } else { if ( rm == 5 ) inst = inst + 4; //disp32, skip 4 bytes } break; case 1: inst++; //disp8, skip 1 byte break; case 2: if ( ad_size == WORD ) inst = inst + 2; //disp16, skip 2 bytes else inst = inst + 4; //disp32, skip 4 bytes break; } if ( op_size == QUAD ) op_size = LONG; for ( i = 0; i < op_size; i++ ) { val |= (*inst++ & 0xff) << (8 * i); } return val;}static inline unsigned long get_immediate_sign_ext( int ad_size, const unsigned char *inst, int op_size){ unsigned long result = get_immediate(ad_size, inst, op_size); if ( op_size == BYTE ) return (int8_t)result; if ( op_size == WORD ) return (int16_t)result; return (int32_t)result;}static inline int get_index(const unsigned char *inst, unsigned char rex){ int mod, reg, rm; int rex_r, rex_b; mod = (*inst >> 6) & 3; reg = (*inst >> 3) & 7; rm = *inst & 7; rex_r = (rex >> 2) & 1; rex_b = rex & 1; //Only one operand in the instruction is register if ( mod == 3 ) { return (rm + (rex_b << 3)); } else { return (reg + (rex_r << 3)); } return 0;}static void init_instruction(struct hvm_io_op *mmio_op){ mmio_op->instr = 0; mmio_op->flags = 0; mmio_op->operand[0] = 0; mmio_op->operand[1] = 0; mmio_op->immediate = 0;}#define GET_OP_SIZE_FOR_BYTE(size_reg) \ do { \ if ( rex ) \ (size_reg) = BYTE_64; \ else \ (size_reg) = BYTE; \ } while( 0 )#define GET_OP_SIZE_FOR_NONEBYTE(op_size) \ do { \ if ( rex & 0x8 ) \ (op_size) = QUAD; \ else if ( (op_size) != WORD ) \ (op_size) = LONG; \ } while( 0 )/* * Decode mem,accumulator operands (as in <opcode> m8/m16/m32, al,ax,eax) */static inline int mem_acc(unsigned char size, struct hvm_io_op *mmio){ mmio->operand[0] = mk_operand(size, 0, 0, MEMORY); mmio->operand[1] = mk_operand(size, 0, 0, REGISTER); return DECODE_success;}/* * Decode accumulator,mem operands (as in <opcode> al,ax,eax, m8/m16/m32) */static inline int acc_mem(unsigned char size, struct hvm_io_op *mmio){ mmio->operand[0] = mk_operand(size, 0, 0, REGISTER); mmio->operand[1] = mk_operand(size, 0, 0, MEMORY); return DECODE_success;}/* * Decode mem,reg operands (as in <opcode> r32/16, m32/16) */static int mem_reg(unsigned char size, unsigned char *opcode, struct hvm_io_op *mmio_op, unsigned char rex){ int index = get_index(opcode + 1, rex); mmio_op->operand[0] = mk_operand(size, 0, 0, MEMORY); mmio_op->operand[1] = mk_operand(size, index, 0, REGISTER); return DECODE_success;}/* * Decode reg,mem operands (as in <opcode> m32/16, r32/16) */static int reg_mem(unsigned char size, unsigned char *opcode, struct hvm_io_op *mmio_op, unsigned char rex){ int index = get_index(opcode + 1, rex); mmio_op->operand[0] = mk_operand(size, index, 0, REGISTER); mmio_op->operand[1] = mk_operand(size, 0, 0, MEMORY); return DECODE_success;}static int mmio_decode(int address_bytes, unsigned char *opcode, struct hvm_io_op *mmio_op, unsigned char *ad_size, unsigned char *op_size, unsigned char *seg_sel){ unsigned char size_reg = 0; unsigned char rex = 0; int index; *ad_size = 0; *op_size = 0; *seg_sel = 0; init_instruction(mmio_op); opcode = check_prefix(opcode, mmio_op, ad_size, op_size, seg_sel, &rex); switch ( address_bytes ) { case 2: if ( *op_size == WORD ) *op_size = LONG; else if ( *op_size == LONG ) *op_size = WORD; else if ( *op_size == 0 ) *op_size = WORD; if ( *ad_size == WORD ) *ad_size = LONG; else if ( *ad_size == LONG ) *ad_size = WORD; else if ( *ad_size == 0 ) *ad_size = WORD; break; case 4: if ( *op_size == 0 ) *op_size = LONG; if ( *ad_size == 0 ) *ad_size = LONG; break;#ifdef __x86_64__ case 8: if ( *op_size == 0 ) *op_size = rex & 0x8 ? QUAD : LONG; if ( *ad_size == WORD ) *ad_size = LONG; else if ( *ad_size == 0 ) *ad_size = QUAD; break;#endif } /* the operands order in comments conforms to AT&T convention */ switch ( *opcode ) { case 0x00: /* add r8, m8 */ mmio_op->instr = INSTR_ADD; *op_size = BYTE; GET_OP_SIZE_FOR_BYTE(size_reg); return reg_mem(size_reg, opcode, mmio_op, rex); case 0x03: /* add m32/16, r32/16 */ mmio_op->instr = INSTR_ADD; GET_OP_SIZE_FOR_NONEBYTE(*op_size); return mem_reg(*op_size, opcode, mmio_op, rex); case 0x08: /* or r8, m8 */ mmio_op->instr = INSTR_OR; *op_size = BYTE; GET_OP_SIZE_FOR_BYTE(size_reg); return reg_mem(size_reg, opcode, mmio_op, rex); case 0x09: /* or r32/16, m32/16 */ mmio_op->instr = INSTR_OR; GET_OP_SIZE_FOR_NONEBYTE(*op_size); return reg_mem(*op_size, opcode, mmio_op, rex); case 0x0A: /* or m8, r8 */ mmio_op->instr = INSTR_OR; *op_size = BYTE; GET_OP_SIZE_FOR_BYTE(size_reg); return mem_reg(size_reg, opcode, mmio_op, rex); case 0x0B: /* or m32/16, r32/16 */ mmio_op->instr = INSTR_OR; GET_OP_SIZE_FOR_NONEBYTE(*op_size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -