mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[HVM][MMIO] Emulate more instructions: or/and/xor with byte width,
and load string (LODS) instructions. Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com> Signed-off-by: Yunfeng zhao <yunfeng.zhao@intel.com> Signed-off-by: Xin Li <xin.b.li@intel.com>
This commit is contained in:
1 parent
104f354554
commit
a47f6548d9
3 files changed
+70
-23
No files matched your search
@@ -507,6 +507,13 @@ static void hvm_mmio_assist(struct vcpu *v, struct cpu_user_regs *regs,
|
||||
regs->ecx -= p->count;
|
||||
break;
|
||||
|
||||
case INSTR_LODS:
|
||||
sign = p->df ? -1 : 1;
|
||||
regs->esi += sign * p->count * p->size;
|
||||
if (mmio_opp->flags & REPZ)
|
||||
regs->ecx -= p->count;
|
||||
break;
|
||||
|
||||
case INSTR_AND:
|
||||
if (src & REGISTER) {
|
||||
index = operand_index(src);
|
||||
|
||||
+59
-20
@@ -364,6 +364,12 @@ static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *i
|
||||
}
|
||||
|
||||
switch (*opcode) {
|
||||
case 0x0A: /* or r8, m8 */
|
||||
instr->instr = INSTR_OR;
|
||||
instr->op_size = BYTE;
|
||||
GET_OP_SIZE_FOR_BYTE(size_reg);
|
||||
return mem_reg(size_reg, opcode, instr, rex);
|
||||
|
||||
case 0x0B: /* or m32/16, r32/16 */
|
||||
instr->instr = INSTR_OR;
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
@@ -380,6 +386,12 @@ static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *i
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
return reg_mem(instr->op_size, opcode, instr, rex);
|
||||
|
||||
case 0x22: /* and m8, r8 */
|
||||
instr->instr = INSTR_AND;
|
||||
instr->op_size = BYTE;
|
||||
GET_OP_SIZE_FOR_BYTE(size_reg);
|
||||
return mem_reg(size_reg, opcode, instr, rex);
|
||||
|
||||
case 0x23: /* and m32/16, r32/16 */
|
||||
instr->instr = INSTR_AND;
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
@@ -396,6 +408,12 @@ static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *i
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
return reg_mem(instr->op_size, opcode, instr, rex);
|
||||
|
||||
case 0x32: /* xor m8, r8*/
|
||||
instr->instr = INSTR_XOR;
|
||||
instr->op_size = BYTE;
|
||||
GET_OP_SIZE_FOR_BYTE(size_reg);
|
||||
return mem_reg(size_reg, opcode, instr, rex);
|
||||
|
||||
case 0x39: /* cmp r32/16, m32/16 */
|
||||
instr->instr = INSTR_CMP;
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
@@ -516,6 +534,16 @@ static int hvm_decode(int realmode, unsigned char *opcode, struct instruction *i
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
return DECODE_success;
|
||||
|
||||
case 0xAC: /* lodsb */
|
||||
instr->instr = INSTR_LODS;
|
||||
instr->op_size = BYTE;
|
||||
return DECODE_success;
|
||||
|
||||
case 0xAD: /* lodsw/lodsl */
|
||||
instr->instr = INSTR_LODS;
|
||||
GET_OP_SIZE_FOR_NONEBYTE(instr->op_size);
|
||||
return DECODE_success;
|
||||
|
||||
case 0xC6:
|
||||
if (((opcode[1] >> 3) & 7) == 0) { /* mov $imm8, m8 */
|
||||
instr->instr = INSTR_MOV;
|
||||
@@ -906,6 +934,17 @@ void handle_mmio(unsigned long va, unsigned long gpa)
|
||||
GET_REPEAT_COUNT(), mmio_inst.op_size, regs->eax, IOREQ_WRITE, 0);
|
||||
break;
|
||||
|
||||
case INSTR_LODS:
|
||||
/*
|
||||
* Since the source is always in (contiguous) mmio space we don't
|
||||
* need to break it up into pages.
|
||||
*/
|
||||
mmio_opp->flags = mmio_inst.flags;
|
||||
mmio_opp->instr = mmio_inst.instr;
|
||||
send_mmio_req(IOREQ_TYPE_COPY, gpa,
|
||||
GET_REPEAT_COUNT(), mmio_inst.op_size, 0, IOREQ_READ, 0);
|
||||
break;
|
||||
|
||||
case INSTR_OR:
|
||||
mmio_operands(IOREQ_TYPE_OR, gpa, &mmio_inst, mmio_opp, regs);
|
||||
break;
|
||||
@@ -954,26 +993,26 @@ void handle_mmio(unsigned long va, unsigned long gpa)
|
||||
mmio_opp->instr = mmio_inst.instr;
|
||||
mmio_opp->operand[0] = mmio_inst.operand[0]; /* source */
|
||||
mmio_opp->operand[1] = mmio_inst.operand[1]; /* destination */
|
||||
if (mmio_inst.operand[0] & REGISTER) {
|
||||
long value;
|
||||
unsigned long operand = mmio_inst.operand[0];
|
||||
value = get_reg_value(operand_size(operand),
|
||||
operand_index(operand), 0,
|
||||
mmio_opp->inst_decoder_regs);
|
||||
/* send the request and wait for the value */
|
||||
send_mmio_req(IOREQ_TYPE_XCHG, gpa, 1,
|
||||
mmio_inst.op_size, value, IOREQ_WRITE, 0);
|
||||
} else {
|
||||
/* the destination is a register */
|
||||
long value;
|
||||
unsigned long operand = mmio_inst.operand[1];
|
||||
value = get_reg_value(operand_size(operand),
|
||||
operand_index(operand), 0,
|
||||
mmio_opp->inst_decoder_regs);
|
||||
/* send the request and wait for the value */
|
||||
send_mmio_req(IOREQ_TYPE_XCHG, gpa, 1,
|
||||
mmio_inst.op_size, value, IOREQ_WRITE, 0);
|
||||
}
|
||||
if ( mmio_inst.operand[0] & REGISTER ) {
|
||||
long value;
|
||||
unsigned long operand = mmio_inst.operand[0];
|
||||
value = get_reg_value(operand_size(operand),
|
||||
operand_index(operand), 0,
|
||||
mmio_opp->inst_decoder_regs);
|
||||
/* send the request and wait for the value */
|
||||
send_mmio_req(IOREQ_TYPE_XCHG, gpa, 1,
|
||||
mmio_inst.op_size, value, IOREQ_WRITE, 0);
|
||||
} else {
|
||||
/* the destination is a register */
|
||||
long value;
|
||||
unsigned long operand = mmio_inst.operand[1];
|
||||
value = get_reg_value(operand_size(operand),
|
||||
operand_index(operand), 0,
|
||||
mmio_opp->inst_decoder_regs);
|
||||
/* send the request and wait for the value */
|
||||
send_mmio_req(IOREQ_TYPE_XCHG, gpa, 1,
|
||||
mmio_inst.op_size, value, IOREQ_WRITE, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -64,9 +64,10 @@
|
||||
#define INSTR_MOVZX 8
|
||||
#define INSTR_MOVSX 9
|
||||
#define INSTR_STOS 10
|
||||
#define INSTR_TEST 11
|
||||
#define INSTR_BT 12
|
||||
#define INSTR_XCHG 13
|
||||
#define INSTR_LODS 11
|
||||
#define INSTR_TEST 12
|
||||
#define INSTR_BT 13
|
||||
#define INSTR_XCHG 14
|
||||
|
||||
struct instruction {
|
||||
__s8 instr; /* instruction type */
|
||||
|
||||