Dear folks, I've reworked the patch using the feedback I got from Maxime and had to refactor some minor parts in the other code. I'm in the process of writing the test-cases now but would like feedback for this solution in the meantime. It ought now give a proper REPE memory assist implementation. It could use some minor enhancements still though. With regards, Reinoud
Index: libnvmm_x86.c =================================================================== RCS file: /cvsroot/src/lib/libnvmm/libnvmm_x86.c,v retrieving revision 1.42 diff -u -p -r1.42 libnvmm_x86.c --- libnvmm_x86.c 31 Oct 2020 15:44:01 -0000 1.42 +++ libnvmm_x86.c 31 Oct 2020 22:55:45 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.42 2020/10/31 15:44:01 reinoud Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.41 2020/10/30 21:06:13 reinoud Exp $ */ /* * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net @@ -869,7 +869,6 @@ static void x86_func_test(struct nvmm_vc static void x86_func_mov(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *); static void x86_func_stos(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *); static void x86_func_lods(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *); -static void x86_func_movs(struct nvmm_vcpu *, struct nvmm_mem *, uint64_t *); static const struct x86_emul x86_emul_or = { .readreg = true, @@ -919,10 +918,6 @@ static const struct x86_emul x86_emul_lo .func = x86_func_lods }; -static const struct x86_emul x86_emul_movs = { - .func = x86_func_movs -}; - /* Legacy prefixes. */ #define LEG_LOCK 0xF0 #define LEG_REPN 0xF2 @@ -1051,6 +1046,7 @@ struct x86_opcode { bool movs:1; bool stos:1; bool lods:1; + bool cmps:1; bool szoverride:1; bool group1:1; bool group3:1; @@ -1451,7 +1447,7 @@ static const struct x86_opcode primary_o .movs = true, .szoverride = false, .defsize = OPSIZE_BYTE, - .emul = &x86_emul_movs + .emul = NULL }, [0xA5] = { /* Yv, Xv */ @@ -1459,7 +1455,27 @@ static const struct x86_opcode primary_o .movs = true, .szoverride = true, .defsize = -1, - .emul = &x86_emul_movs + .emul = NULL + }, + + /* + * CMPS + */ + [0xA6] = { + /* Yb, Xb */ + .valid = true, + .cmps = true, + .szoverride = false, + .defsize = OPSIZE_BYTE, + .emul = NULL + }, + [0xA7] = { + /* Yv, Xv */ + .valid = true, + .cmps = true, + .szoverride = true, + .defsize = -1, + .emul = NULL }, /* @@ -1871,6 +1887,35 @@ node_movs(struct x86_decode_fsm *fsm, st } /* + * Special node, for CMPS. Fake two displacements of zero on the source and + * destination registers. + * XXX coded as clone of movs as its similar in register usage + * XXX might be merged with node_movs() + */ +static int +node_cmps(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + size_t adrsize; + + adrsize = instr->address_size; + + /* DS:RSI */ + instr->src.type = STORE_REG; + instr->src.u.reg = &gpr_map__special[1][2][adrsize-1]; + instr->src.disp.type = DISP_0; + + /* ES:RDI, force ES */ + instr->dst.type = STORE_REG; + instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1]; + instr->dst.disp.type = DISP_0; + instr->dst.hardseg = NVMM_X64_SEG_ES; + + fsm_advance(fsm, 0, NULL); + + return 0; +} + +/* * Special node, for STOS and LODS. Fake a displacement of zero on the * destination register. */ @@ -2470,6 +2515,8 @@ node_primary_opcode(struct x86_decode_fs fsm_advance(fsm, 1, node_stlo); } else if (opcode->movs) { fsm_advance(fsm, 1, node_movs); + } else if (opcode->cmps) { + fsm_advance(fsm, 1, node_cmps); } else { return -1; } @@ -2966,23 +3013,6 @@ x86_func_lods(struct nvmm_vcpu *vcpu, st } } -static void -x86_func_movs(struct nvmm_vcpu *vcpu, struct nvmm_mem *mem, uint64_t *gprs) -{ - /* - * Special instruction: double memory operand. Don't call the cb, - * because the storage has already been performed earlier. - */ - - if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) { - gprs[NVMM_X64_GPR_RSI] -= mem->size; - gprs[NVMM_X64_GPR_RDI] -= mem->size; - } else { - gprs[NVMM_X64_GPR_RSI] += mem->size; - gprs[NVMM_X64_GPR_RDI] += mem->size; - } -} - /* -------------------------------------------------------------------------- */ static inline uint64_t @@ -3145,17 +3175,18 @@ fetch_instruction(struct nvmm_machine *m } static int -assist_mem_double(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu, +assist_mem_movs(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu, struct x86_instr *instr) { struct nvmm_x64_state *state = vcpu->state; - struct nvmm_mem mem; + uint64_t *gprs; uint8_t data[8]; gvaddr_t gva; size_t size; int ret; size = instr->operand_size; + gprs = state->gprs; /* Source. */ ret = store_to_gva(state, instr, &instr->src, &gva, size); @@ -3173,8 +3204,72 @@ assist_mem_double(struct nvmm_machine *m if (ret == -1) return -1; - mem.size = size; - (*instr->emul->func)(vcpu, &mem, state->gprs); + /* + * Inlined x86_func_movs() call + * (*instr->emul->func)(vcpu, &mem, state->gprs); + */ + + if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) { + gprs[NVMM_X64_GPR_RSI] -= size; + gprs[NVMM_X64_GPR_RDI] -= size; + } else { + gprs[NVMM_X64_GPR_RSI] += size; + gprs[NVMM_X64_GPR_RDI] += size; + } + + return 0; +} + +static int +assist_mem_cmps(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu, + struct x86_instr *instr) +{ + struct nvmm_x64_state *state = vcpu->state; + uint64_t *gprs, op1, op2, fl; + uint8_t data1[8], data2[8]; + gvaddr_t gva; + size_t size; + int ret; + + size = instr->operand_size; + gprs = state->gprs; + + /* Source 1. */ + ret = store_to_gva(state, instr, &instr->src, &gva, size); + if (ret == -1) + return -1; + ret = read_guest_memory(mach, vcpu, gva, data1, size); + if (ret == -1) + return -1; + + /* Source 2. */ + ret = store_to_gva(state, instr, &instr->dst, &gva, size); + if (ret == -1) + return -1; + ret = read_guest_memory(mach, vcpu, gva, data2, size); + if (ret == -1) + return -1; + + /* + * Inlined x86_func_cmps() call + * (*instr->emul->func)(vcpu, &mem, state->gprs); + */ + + /* Perform the CMP. */ + op1 = *((uint64_t *) data1); + op2 = *((uint64_t *) data2); + exec_sub(op1, op2, &fl, size); + + gprs[NVMM_X64_GPR_RFLAGS] &= ~PSL_SUB_MASK; + gprs[NVMM_X64_GPR_RFLAGS] |= (fl & PSL_SUB_MASK); + + if (gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) { + gprs[NVMM_X64_GPR_RSI] -= size; + gprs[NVMM_X64_GPR_RDI] -= size; + } else { + gprs[NVMM_X64_GPR_RSI] += size; + gprs[NVMM_X64_GPR_RDI] += size; + } return 0; } @@ -3349,7 +3444,9 @@ nvmm_assist_mem(struct nvmm_machine *mac } if (instr.opcode->movs) { - ret = assist_mem_double(mach, vcpu, &instr); + ret = assist_mem_movs(mach, vcpu, &instr); + } else if (instr.opcode->cmps) { + ret = assist_mem_cmps(mach, vcpu, &instr); } else { ret = assist_mem_single(mach, vcpu, &instr); }
Attachment:
signature.asc
Description: PGP signature