Module Name: src
Committed By: maxv
Date: Mon Jan 7 18:13:34 UTC 2019
Modified Files:
src/lib/libnvmm: libnvmm_x86.c
Log Message:
Optimize the legpref node: omit BRN (we don't care and it's the same as
OVR_CS), inline the loops, sort the checks from most to least likely
prefix, and use a compact structure.
To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/lib/libnvmm/libnvmm_x86.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libnvmm/libnvmm_x86.c
diff -u src/lib/libnvmm/libnvmm_x86.c:1.12 src/lib/libnvmm/libnvmm_x86.c:1.13
--- src/lib/libnvmm/libnvmm_x86.c:1.12 Mon Jan 7 16:30:25 2019
+++ src/lib/libnvmm/libnvmm_x86.c Mon Jan 7 18:13:34 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: libnvmm_x86.c,v 1.12 2019/01/07 16:30:25 maxv Exp $ */
+/* $NetBSD: libnvmm_x86.c,v 1.13 2019/01/07 18:13:34 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -824,26 +824,25 @@ static void x86_emul_stos(struct nvmm_me
static void x86_emul_lods(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *);
static void x86_emul_movs(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *);
-enum x86_legpref {
- /* Group 1 */
- LEG_LOCK = 0,
- LEG_REPN, /* REPNE/REPNZ */
- LEG_REP, /* REP/REPE/REPZ */
- /* Group 2 */
- LEG_OVR_CS,
- LEG_OVR_SS,
- LEG_OVR_DS,
- LEG_OVR_ES,
- LEG_OVR_FS,
- LEG_OVR_GS,
- LEG_BRN_TAKEN,
- LEG_BRN_NTAKEN,
- /* Group 3 */
- LEG_OPR_OVR,
- /* Group 4 */
- LEG_ADR_OVR,
-
- NLEG
+/* Legacy prefixes. */
+#define LEG_LOCK 0xF0
+#define LEG_REPN 0xF2
+#define LEG_REP 0xF3
+#define LEG_OVR_CS 0x2E
+#define LEG_OVR_SS 0x36
+#define LEG_OVR_DS 0x3E
+#define LEG_OVR_ES 0x26
+#define LEG_OVR_FS 0x64
+#define LEG_OVR_GS 0x65
+#define LEG_OPR_OVR 0x66
+#define LEG_ADR_OVR 0x67
+
+struct x86_legpref {
+ bool opr_ovr:1;
+ bool adr_ovr:1;
+ bool rep:1;
+ bool repn:1;
+ int seg;
};
struct x86_rexpref {
@@ -940,7 +939,7 @@ struct x86_store {
struct x86_instr {
size_t len;
- bool legpref[NLEG];
+ struct x86_legpref legpref;
struct x86_rexpref rexpref;
size_t operand_size;
size_t address_size;
@@ -2133,13 +2132,13 @@ get_operand_size(struct x86_decode_fsm *
opsize = 8;
} else {
if (!fsm->is16bit) {
- if (instr->legpref[LEG_OPR_OVR]) {
+ if (instr->legpref.opr_ovr) {
opsize = 2;
} else {
opsize = 4;
}
} else { /* 16bit */
- if (instr->legpref[LEG_OPR_OVR]) {
+ if (instr->legpref.opr_ovr) {
opsize = 4;
} else {
opsize = 2;
@@ -2159,21 +2158,21 @@ static size_t
get_address_size(struct x86_decode_fsm *fsm, struct x86_instr *instr)
{
if (fsm->is64bit) {
- if (__predict_false(instr->legpref[LEG_ADR_OVR])) {
+ if (__predict_false(instr->legpref.adr_ovr)) {
return 4;
}
return 8;
}
if (fsm->is32bit) {
- if (__predict_false(instr->legpref[LEG_ADR_OVR])) {
+ if (__predict_false(instr->legpref.adr_ovr)) {
return 2;
}
return 4;
}
/* 16bit. */
- if (__predict_false(instr->legpref[LEG_ADR_OVR])) {
+ if (__predict_false(instr->legpref.adr_ovr)) {
return 4;
}
return 2;
@@ -2344,51 +2343,44 @@ node_rex_prefix(struct x86_decode_fsm *f
return 0;
}
-static const struct {
- uint8_t byte;
- int seg;
-} legpref_table[NLEG] = {
- /* Group 1 */
- [LEG_LOCK] = { 0xF0, -1 },
- [LEG_REPN] = { 0xF2, -1 },
- [LEG_REP] = { 0xF3, -1 },
- /* Group 2 */
- [LEG_OVR_CS] = { 0x2E, NVMM_X64_SEG_CS },
- [LEG_OVR_SS] = { 0x36, NVMM_X64_SEG_SS },
- [LEG_OVR_DS] = { 0x3E, NVMM_X64_SEG_DS },
- [LEG_OVR_ES] = { 0x26, NVMM_X64_SEG_ES },
- [LEG_OVR_FS] = { 0x64, NVMM_X64_SEG_FS },
- [LEG_OVR_GS] = { 0x65, NVMM_X64_SEG_GS },
- [LEG_BRN_TAKEN] = { 0x2E, -1 },
- [LEG_BRN_NTAKEN] = { 0x3E, -1 },
- /* Group 3 */
- [LEG_OPR_OVR] = { 0x66, -1 },
- /* Group 4 */
- [LEG_ADR_OVR] = { 0x67, -1 },
-};
-
static int
node_legacy_prefix(struct x86_decode_fsm *fsm, struct x86_instr *instr)
{
uint8_t byte;
- size_t i;
if (fsm_read(fsm, &byte, sizeof(byte)) == -1) {
return -1;
}
- for (i = 0; i < NLEG; i++) {
- if (byte == legpref_table[i].byte)
- break;
- }
-
- if (i == NLEG) {
- fsm->fn = node_rex_prefix;
+ if (byte == LEG_OPR_OVR) {
+ instr->legpref.opr_ovr = 1;
+ } else if (byte == LEG_OVR_DS) {
+ instr->legpref.seg = NVMM_X64_SEG_DS;
+ } else if (byte == LEG_OVR_ES) {
+ instr->legpref.seg = NVMM_X64_SEG_ES;
+ } else if (byte == LEG_REP) {
+ instr->legpref.rep = 1;
+ } else if (byte == LEG_OVR_GS) {
+ instr->legpref.seg = NVMM_X64_SEG_GS;
+ } else if (byte == LEG_OVR_FS) {
+ instr->legpref.seg = NVMM_X64_SEG_FS;
+ } else if (byte == LEG_ADR_OVR) {
+ instr->legpref.adr_ovr = 1;
+ } else if (byte == LEG_OVR_CS) {
+ instr->legpref.seg = NVMM_X64_SEG_CS;
+ } else if (byte == LEG_OVR_SS) {
+ instr->legpref.seg = NVMM_X64_SEG_SS;
+ } else if (byte == LEG_REPN) {
+ instr->legpref.repn = 1;
+ } else if (byte == LEG_LOCK) {
+ /* ignore */
} else {
- instr->legpref[i] = true;
- fsm_advance(fsm, 1, node_legacy_prefix);
+ /* not a legacy prefix */
+ fsm_advance(fsm, 0, node_rex_prefix);
+ return 0;
}
+ fsm_advance(fsm, 1, node_legacy_prefix);
return 0;
}
@@ -2400,6 +2392,7 @@ x86_decode(uint8_t *inst_bytes, size_t i
int ret;
memset(instr, 0, sizeof(*instr));
+ instr->legpref.seg = -1;
fsm.is64bit = is_64bit(state);
fsm.is32bit = is_32bit(state);
@@ -2660,16 +2653,8 @@ store_to_gva(struct nvmm_x64_state *stat
if (store->hardseg != 0) {
seg = store->hardseg;
} else {
- if (instr->legpref[LEG_OVR_CS]) {
- seg = NVMM_X64_SEG_CS;
- } else if (instr->legpref[LEG_OVR_SS]) {
- seg = NVMM_X64_SEG_SS;
- } else if (instr->legpref[LEG_OVR_ES]) {
- seg = NVMM_X64_SEG_ES;
- } else if (instr->legpref[LEG_OVR_FS]) {
- seg = NVMM_X64_SEG_FS;
- } else if (instr->legpref[LEG_OVR_GS]) {
- seg = NVMM_X64_SEG_GS;
+ if (__predict_false(instr->legpref.seg != -1)) {
+ seg = instr->legpref.seg;
} else {
seg = NVMM_X64_SEG_DS;
}
@@ -2688,7 +2673,7 @@ static int
fetch_segment(struct nvmm_machine *mach, struct nvmm_x64_state *state)
{
uint8_t inst_bytes[15], byte;
- size_t i, n, fetchsize;
+ size_t i, fetchsize;
gvaddr_t gva;
int ret, seg;
@@ -2707,17 +2692,33 @@ fetch_segment(struct nvmm_machine *mach,
return -1;
seg = NVMM_X64_SEG_DS;
- for (n = 0; n < fetchsize; n++) {
- byte = inst_bytes[n];
- for (i = 0; i < NLEG; i++) {
- if (byte != legpref_table[i].byte)
- continue;
- if (i >= LEG_OVR_CS && i <= LEG_OVR_GS)
- seg = legpref_table[i].seg;
- break;
- }
- if (i == NLEG) {
- break;
+ for (i = 0; i < fetchsize; i++) {
+ byte = inst_bytes[i];
+
+ if (byte == LEG_OVR_DS) {
+ seg = NVMM_X64_SEG_DS;
+ } else if (byte == LEG_OVR_ES) {
+ seg = NVMM_X64_SEG_ES;
+ } else if (byte == LEG_OVR_GS) {
+ seg = NVMM_X64_SEG_GS;
+ } else if (byte == LEG_OVR_FS) {
+ seg = NVMM_X64_SEG_FS;
+ } else if (byte == LEG_OVR_CS) {
+ seg = NVMM_X64_SEG_CS;
+ } else if (byte == LEG_OVR_SS) {
+ seg = NVMM_X64_SEG_SS;
+ } else if (byte == LEG_OPR_OVR) {
+ /* nothing */
+ } else if (byte == LEG_ADR_OVR) {
+ /* nothing */
+ } else if (byte == LEG_REP) {
+ /* nothing */
+ } else if (byte == LEG_REPN) {
+ /* nothing */
+ } else if (byte == LEG_LOCK) {
+ /* nothing */
+ } else {
+ return seg;
}
}
@@ -2901,7 +2902,7 @@ nvmm_assist_mem(struct nvmm_machine *mac
return -1;
}
- if (__predict_false(instr.legpref[LEG_REPN])) {
+ if (__predict_false(instr.legpref.repn)) {
errno = ENODEV;
return -1;
}
@@ -2916,7 +2917,7 @@ nvmm_assist_mem(struct nvmm_machine *mac
return -1;
}
- if (instr.legpref[LEG_REP]) {
+ if (instr.legpref.rep) {
cnt = rep_dec_apply(&state, instr.address_size);
if (cnt == 0) {
state.gprs[NVMM_X64_GPR_RIP] += instr.len;