Module Name: src Committed By: maxv Date: Sun Oct 13 17:32:15 UTC 2019
Modified Files: src/lib/libnvmm: libnvmm_x86.c src/tests/lib/libnvmm: h_mem_assist.c h_mem_assist_asm.S Log Message: Fix incorrect parsing: the R/M field uses a special GPR map when the address size is 16 bits, regardless of the actual operating mode. With this special map there can be two registers referenced at once, and also disp16-only. Implement this special behavior, and add associated tests. While here simplify a few things. With this in place, the Windows 95 installer initializes correctly. Part of PR/54611. To generate a diff of this commit: cvs rdiff -u -r1.31 -r1.32 src/lib/libnvmm/libnvmm_x86.c cvs rdiff -u -r1.11 -r1.12 src/tests/lib/libnvmm/h_mem_assist.c cvs rdiff -u -r1.6 -r1.7 src/tests/lib/libnvmm/h_mem_assist_asm.S 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.31 src/lib/libnvmm/libnvmm_x86.c:1.32 --- src/lib/libnvmm/libnvmm_x86.c:1.31 Sat Jun 8 07:27:44 2019 +++ src/lib/libnvmm/libnvmm_x86.c Sun Oct 13 17:32:15 2019 @@ -1,7 +1,7 @@ -/* $NetBSD: libnvmm_x86.c,v 1.31 2019/06/08 07:27:44 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.32 2019/10/13 17:32:15 maxv Exp $ */ /* - * Copyright (c) 2018 The NetBSD Foundation, Inc. + * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -441,6 +441,12 @@ nvmm_gva_to_gpa(struct nvmm_machine *mac /* -------------------------------------------------------------------------- */ +#define DISASSEMBLER_BUG() \ + do { \ + errno = EINVAL; \ + return -1; \ + } while (0); + static inline bool is_long_mode(struct nvmm_x64_state *state) { @@ -928,10 +934,16 @@ struct x86_reg { uint64_t mask; }; +struct x86_dualreg { + int reg1; + int reg2; +}; + enum x86_disp_type { DISP_NONE, DISP_0, DISP_1, + DISP_2, DISP_4 }; @@ -940,35 +952,6 @@ struct x86_disp { uint64_t data; /* 4 bytes, but can be sign-extended */ }; -enum REGMODRM__Mod { - MOD_DIS0, /* also, register indirect */ - MOD_DIS1, - MOD_DIS4, - MOD_REG -}; - -enum REGMODRM__Reg { - REG_000, /* these fields are indexes to the register map */ - REG_001, - REG_010, - REG_011, - REG_100, - REG_101, - REG_110, - REG_111 -}; - -enum REGMODRM__Rm { - RM_000, /* reg */ - RM_001, /* reg */ - RM_010, /* reg */ - RM_011, /* reg */ - RM_RSP_SIB, /* reg or SIB, depending on the MOD */ - RM_RBP_DISP32, /* reg or displacement-only (= RIP-relative on amd64) */ - RM_110, - RM_111 -}; - struct x86_regmodrm { uint8_t mod:2; uint8_t reg:3; @@ -988,6 +971,7 @@ struct x86_sib { enum x86_store_type { STORE_NONE, STORE_REG, + STORE_DUALREG, STORE_IMM, STORE_SIB, STORE_DMO @@ -997,6 +981,7 @@ struct x86_store { enum x86_store_type type; union { const struct x86_reg *reg; + struct x86_dualreg dualreg; struct x86_immediate imm; struct x86_sib sib; uint64_t dmo; @@ -1761,6 +1746,18 @@ static const struct x86_reg gpr_map[2][8 } }; +/* [enc] */ +static const int gpr_dual_reg1_rm[8] __cacheline_aligned = { + [0b000] = NVMM_X64_GPR_RBX, /* BX (+SI) */ + [0b001] = NVMM_X64_GPR_RBX, /* BX (+DI) */ + [0b010] = NVMM_X64_GPR_RBP, /* BP (+SI) */ + [0b011] = NVMM_X64_GPR_RBP, /* BP (+DI) */ + [0b100] = NVMM_X64_GPR_RSI, /* SI */ + [0b101] = NVMM_X64_GPR_RDI, /* DI */ + [0b110] = NVMM_X64_GPR_RBP, /* BP */ + [0b111] = NVMM_X64_GPR_RBX, /* BX */ +}; + static int node_overflow(struct x86_decode_fsm *fsm, struct x86_instr *instr) { @@ -1957,8 +1954,12 @@ node_disp(struct x86_decode_fsm *fsm, st if (instr->strm->disp.type == DISP_1) { n = 1; - } else { /* DISP4 */ + } else if (instr->strm->disp.type == DISP_2) { + n = 2; + } else if (instr->strm->disp.type == DISP_4) { n = 4; + } else { + DISASSEMBLER_BUG(); } if (fsm_read(fsm, (uint8_t *)&data, n) == -1) { @@ -1980,6 +1981,47 @@ node_disp(struct x86_decode_fsm *fsm, st return 0; } +/* + * Special node to handle 16bit addressing encoding, which can reference two + * registers at once. + */ +static int +node_dual(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + int reg1, reg2; + + reg1 = gpr_dual_reg1_rm[instr->regmodrm.rm]; + + if (instr->regmodrm.rm == 0b000 || + instr->regmodrm.rm == 0b010) { + reg2 = NVMM_X64_GPR_RSI; + } else if (instr->regmodrm.rm == 0b001 || + instr->regmodrm.rm == 0b011) { + reg2 = NVMM_X64_GPR_RDI; + } else { + DISASSEMBLER_BUG(); + } + + instr->strm->type = STORE_DUALREG; + instr->strm->u.dualreg.reg1 = reg1; + instr->strm->u.dualreg.reg2 = reg2; + + if (instr->strm->disp.type == DISP_NONE) { + DISASSEMBLER_BUG(); + } else if (instr->strm->disp.type == DISP_0) { + /* Indirect register addressing mode */ + if (instr->opcode->immediate) { + fsm_advance(fsm, 1, node_immediate); + } else { + fsm_advance(fsm, 1, NULL); + } + } else { + fsm_advance(fsm, 1, node_disp); + } + + return 0; +} + static const struct x86_reg * get_register_idx(struct x86_instr *instr, uint8_t index) { @@ -2053,7 +2095,9 @@ node_sib(struct x86_decode_fsm *fsm, str instr->strm->u.sib.bas = get_register_bas(instr, base); /* May have a displacement, or an immediate */ - if (instr->strm->disp.type == DISP_1 || instr->strm->disp.type == DISP_4) { + if (instr->strm->disp.type == DISP_1 || + instr->strm->disp.type == DISP_2 || + instr->strm->disp.type == DISP_4) { fsm_advance(fsm, 1, node_disp); } else if (opcode->immediate) { fsm_advance(fsm, 1, node_immediate); @@ -2106,35 +2150,58 @@ get_register_rm(struct x86_instr *instr, static inline bool has_sib(struct x86_instr *instr) { - return (instr->regmodrm.mod != 3 && instr->regmodrm.rm == 4); + return (instr->address_size != 2 && /* no SIB in 16bit addressing */ + instr->regmodrm.mod != 0b11 && + instr->regmodrm.rm == 0b100); } static inline bool is_rip_relative(struct x86_decode_fsm *fsm, struct x86_instr *instr) { - return (fsm->is64bit && instr->strm->disp.type == DISP_0 && - instr->regmodrm.rm == RM_RBP_DISP32); + return (fsm->is64bit && /* RIP-relative only in 64bit mode */ + instr->regmodrm.mod == 0b00 && + instr->regmodrm.rm == 0b101); } static inline bool is_disp32_only(struct x86_decode_fsm *fsm, struct x86_instr *instr) { - return (!fsm->is64bit && instr->strm->disp.type == DISP_0 && - instr->regmodrm.rm == RM_RBP_DISP32); + return (!fsm->is64bit && /* no disp32-only in 64bit mode */ + instr->address_size != 2 && /* no disp32-only in 16bit addressing */ + instr->regmodrm.mod == 0b00 && + instr->regmodrm.rm == 0b101); +} + +static inline bool +is_disp16_only(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + return (instr->address_size == 2 && /* disp16-only only in 16bit addr */ + instr->regmodrm.mod == 0b00 && + instr->regmodrm.rm == 0b110); +} + +static inline bool +is_dual(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + return (instr->address_size == 2 && + instr->regmodrm.mod != 0b11 && + instr->regmodrm.rm <= 0b011); } static enum x86_disp_type get_disp_type(struct x86_instr *instr) { switch (instr->regmodrm.mod) { - case MOD_DIS0: /* indirect */ + case 0b00: /* indirect */ return DISP_0; - case MOD_DIS1: /* indirect+1 */ + case 0b01: /* indirect+1 */ return DISP_1; - case MOD_DIS4: /* indirect+4 */ + case 0b10: /* indirect+{2,4} */ + if (__predict_false(instr->address_size == 2)) { + return DISP_2; + } return DISP_4; - case MOD_REG: /* direct */ - default: /* gcc */ + case 0b11: /* direct */ return DISP_NONE; } } @@ -2225,6 +2292,21 @@ node_regmodrm(struct x86_decode_fsm *fsm return 0; } + if (__predict_false(is_disp16_only(fsm, instr))) { + /* Overwrites RM */ + strm->type = STORE_REG; + strm->u.reg = NULL; + strm->disp.type = DISP_2; + fsm_advance(fsm, 1, node_disp); + return 0; + } + + if (__predict_false(is_dual(fsm, instr))) { + /* Overwrites RM */ + fsm_advance(fsm, 0, node_dual); + return 0; + } + reg = get_register_rm(instr, opcode); if (reg == NULL) { return -1; @@ -2864,10 +2946,14 @@ store_to_gva(struct nvmm_x64_state *stat } } else if (store->type == STORE_REG) { if (store->u.reg == NULL) { - /* The base is null. Happens with disp32-only. */ + /* The base is null. Happens with disp32-only and + * disp16-only. */ } else { gva = gpr_read_address(instr, state, store->u.reg->num); } + } else if (store->type == STORE_DUALREG) { + gva = gpr_read_address(instr, state, store->u.dualreg.reg1) + + gpr_read_address(instr, state, store->u.dualreg.reg2); } else { gva = store->u.dmo; } @@ -3021,12 +3107,6 @@ assist_mem_double(struct nvmm_machine *m return 0; } -#define DISASSEMBLER_BUG() \ - do { \ - errno = EINVAL; \ - return -1; \ - } while (0); - static int assist_mem_single(struct nvmm_machine *mach, struct nvmm_x64_state *state, struct x86_instr *instr, struct nvmm_exit *exit) @@ -3052,6 +3132,12 @@ assist_mem_single(struct nvmm_machine *m mem.write = true; } break; + case STORE_DUALREG: + if (instr->src.disp.type == DISP_NONE) { + DISASSEMBLER_BUG(); + } + mem.write = false; + break; case STORE_IMM: mem.write = true; break; Index: src/tests/lib/libnvmm/h_mem_assist.c diff -u src/tests/lib/libnvmm/h_mem_assist.c:1.11 src/tests/lib/libnvmm/h_mem_assist.c:1.12 --- src/tests/lib/libnvmm/h_mem_assist.c:1.11 Sat Jun 8 07:27:44 2019 +++ src/tests/lib/libnvmm/h_mem_assist.c Sun Oct 13 17:32:15 2019 @@ -1,7 +1,7 @@ -/* $NetBSD: h_mem_assist.c,v 1.11 2019/06/08 07:27:44 maxv Exp $ */ +/* $NetBSD: h_mem_assist.c,v 1.12 2019/10/13 17:32:15 maxv Exp $ */ /* - * Copyright (c) 2018 The NetBSD Foundation, Inc. + * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -51,6 +51,147 @@ static uint8_t mmiobuf[PAGE_SIZE]; static uint8_t *instbuf; +/* -------------------------------------------------------------------------- */ + +static void +mem_callback(struct nvmm_mem *mem) +{ + size_t off; + + if (mem->gpa < 0x1000 || mem->gpa + mem->size > 0x1000 + PAGE_SIZE) { + printf("Out of page\n"); + exit(-1); + } + + off = mem->gpa - 0x1000; + + printf("-> gpa = %p\n", (void *)mem->gpa); + + if (mem->write) { + memcpy(mmiobuf + off, mem->data, mem->size); + } else { + memcpy(mem->data, mmiobuf + off, mem->size); + } +} + +static int +handle_memory(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) +{ + int ret; + + ret = nvmm_assist_mem(mach, vcpu); + if (ret == -1) { + err(errno, "nvmm_assist_mem"); + } + + return 0; +} + +static void +run_machine(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) +{ + struct nvmm_exit *exit = vcpu->exit; + + while (1) { + if (nvmm_vcpu_run(mach, vcpu) == -1) + err(errno, "nvmm_vcpu_run"); + + switch (exit->reason) { + case NVMM_EXIT_NONE: + break; + + case NVMM_EXIT_MSR: + /* Stop here. */ + return; + + case NVMM_EXIT_MEMORY: + handle_memory(mach, vcpu); + break; + + case NVMM_EXIT_SHUTDOWN: + printf("Shutting down!\n"); + return; + + default: + printf("Invalid!\n"); + return; + } + } +} + +static struct nvmm_callbacks callbacks = { + .io = NULL, + .mem = mem_callback +}; + +/* -------------------------------------------------------------------------- */ + +struct test { + const char *name; + uint8_t *code_begin; + uint8_t *code_end; + uint64_t wanted; + uint64_t off; +}; + +static void +run_test(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu, + const struct test *test) +{ + uint64_t *res; + size_t size; + + size = (size_t)test->code_end - (size_t)test->code_begin; + + memset(mmiobuf, 0, PAGE_SIZE); + memcpy(instbuf, test->code_begin, size); + + run_machine(mach, vcpu); + + res = (uint64_t *)(mmiobuf + test->off); + if (*res == test->wanted) { + printf("Test '%s' passed\n", test->name); + } else { + printf("Test '%s' failed, wanted 0x%lx, got 0x%lx\n", test->name, + test->wanted, *res); + } +} + +/* -------------------------------------------------------------------------- */ + +extern uint8_t test1_begin, test1_end; +extern uint8_t test2_begin, test2_end; +extern uint8_t test3_begin, test3_end; +extern uint8_t test4_begin, test4_end; +extern uint8_t test5_begin, test5_end; +extern uint8_t test6_begin, test6_end; +extern uint8_t test7_begin, test7_end; +extern uint8_t test8_begin, test8_end; +extern uint8_t test9_begin, test9_end; +extern uint8_t test10_begin, test10_end; +extern uint8_t test11_begin, test11_end; +extern uint8_t test12_begin, test12_end; +extern uint8_t test13_begin, test13_end; +extern uint8_t test14_begin, test14_end; + +static const struct test tests64[] = { + { "test1 - MOV", &test1_begin, &test1_end, 0x3004 }, + { "test2 - OR", &test2_begin, &test2_end, 0x16FF }, + { "test3 - AND", &test3_begin, &test3_end, 0x1FC0 }, + { "test4 - XOR", &test4_begin, &test4_end, 0x10CF }, + { "test5 - Address Sizes", &test5_begin, &test5_end, 0x1F00 }, + { "test6 - DMO", &test6_begin, &test6_end, 0xFFAB }, + { "test7 - STOS", &test7_begin, &test7_end, 0x00123456 }, + { "test8 - LODS", &test8_begin, &test8_end, 0x12345678 }, + { "test9 - MOVS", &test9_begin, &test9_end, 0x12345678 }, + { "test10 - MOVZXB", &test10_begin, &test10_end, 0x00000078 }, + { "test11 - MOVZXW", &test11_begin, &test11_end, 0x00005678 }, + { "test12 - CMP", &test12_begin, &test12_end, 0x00000001 }, + { "test13 - SUB", &test13_begin, &test13_end, 0x0000000F0000A0FF }, + { "test14 - TEST", &test14_begin, &test14_end, 0x00000001 }, + { NULL, NULL, NULL, -1 } +}; + static void init_seg(struct nvmm_x64_state_seg *seg, int type, int sel) { @@ -68,7 +209,7 @@ init_seg(struct nvmm_x64_state_seg *seg, } static void -reset_machine(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) +reset_machine64(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) { struct nvmm_x64_state *state = vcpu->state; @@ -120,7 +261,7 @@ reset_machine(struct nvmm_machine *mach, } static void -map_pages(struct nvmm_machine *mach) +map_pages64(struct nvmm_machine *mach) { pt_entry_t *L4, *L3, *L2, *L1; int ret; @@ -192,157 +333,99 @@ map_pages(struct nvmm_machine *mach) L1[0x1000 / PAGE_SIZE] = PTE_P | PTE_W | 0x1000; } -/* -------------------------------------------------------------------------- */ - +/* + * 0x1000: MMIO address, unmapped + * 0x2000: Instructions, mapped + * 0x3000: L4 + * 0x4000: L3 + * 0x5000: L2 + * 0x6000: L1 + */ static void -mem_callback(struct nvmm_mem *mem) +test_vm64(void) { - size_t off; - - if (mem->gpa < 0x1000 || mem->gpa + mem->size > 0x1000 + PAGE_SIZE) { - printf("Out of page\n"); - exit(-1); - } - - off = mem->gpa - 0x1000; - - printf("-> gpa = %p\n", (void *)mem->gpa); - - if (mem->write) { - memcpy(mmiobuf + off, mem->data, mem->size); - } else { - memcpy(mem->data, mmiobuf + off, mem->size); - } -} + struct nvmm_machine mach; + struct nvmm_vcpu vcpu; + size_t i; -static int -handle_memory(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) -{ - int ret; + if (nvmm_machine_create(&mach) == -1) + err(errno, "nvmm_machine_create"); + if (nvmm_vcpu_create(&mach, 0, &vcpu) == -1) + err(errno, "nvmm_vcpu_create"); + nvmm_machine_configure(&mach, NVMM_MACH_CONF_CALLBACKS, &callbacks); + map_pages64(&mach); - ret = nvmm_assist_mem(mach, vcpu); - if (ret == -1) { - err(errno, "nvmm_assist_mem"); + for (i = 0; tests64[i].name != NULL; i++) { + reset_machine64(&mach, &vcpu); + run_test(&mach, &vcpu, &tests64[i]); } - return 0; -} - -static void -run_machine(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) -{ - struct nvmm_exit *exit = vcpu->exit; - - while (1) { - if (nvmm_vcpu_run(mach, vcpu) == -1) - err(errno, "nvmm_vcpu_run"); - - switch (exit->reason) { - case NVMM_EXIT_NONE: - break; - - case NVMM_EXIT_MSR: - /* Stop here. */ - return; - - case NVMM_EXIT_MEMORY: - handle_memory(mach, vcpu); - break; - - case NVMM_EXIT_SHUTDOWN: - printf("Shutting down!\n"); - return; - - default: - printf("Invalid!\n"); - return; - } - } + if (nvmm_machine_destroy(&mach) == -1) + err(errno, "nvmm_machine_destroy"); } /* -------------------------------------------------------------------------- */ -struct test { - const char *name; - uint8_t *code_begin; - uint8_t *code_end; - uint64_t wanted; +extern uint8_t test_16bit_1_begin, test_16bit_1_end; +extern uint8_t test_16bit_2_begin, test_16bit_2_end; +extern uint8_t test_16bit_3_begin, test_16bit_3_end; +extern uint8_t test_16bit_4_begin, test_16bit_4_end; +extern uint8_t test_16bit_5_begin, test_16bit_5_end; + +static const struct test tests16[] = { + { "16bit test1 - MOV single", &test_16bit_1_begin, &test_16bit_1_end, + 0x023, 0x10f1 - 0x1000 }, + { "16bit test2 - MOV dual", &test_16bit_2_begin, &test_16bit_2_end, + 0x123, 0x10f3 - 0x1000 }, + { "16bit test3 - MOV dual+disp", &test_16bit_3_begin, &test_16bit_3_end, + 0x678, 0x10f1 - 0x1000 }, + { "16bit test4 - Mixed", &test_16bit_4_begin, &test_16bit_4_end, + 0x1011, 0x10f6 - 0x1000 }, + { "16bit test5 - disp16-only", &test_16bit_5_begin, &test_16bit_5_end, + 0x12, 0x1234 - 0x1000 }, + { NULL, NULL, NULL, -1, -1 } }; static void -run_test(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu, - const struct test *test) +reset_machine16(struct nvmm_machine *mach, struct nvmm_vcpu *vcpu) { - uint64_t *res; - size_t size; - - size = (size_t)test->code_end - (size_t)test->code_begin; - - reset_machine(mach, vcpu); + struct nvmm_x64_state *state = vcpu->state; - memset(mmiobuf, 0, PAGE_SIZE); - memcpy(instbuf, test->code_begin, size); + if (nvmm_vcpu_getstate(mach, vcpu, NVMM_X64_STATE_ALL) == -1) + err(errno, "nvmm_vcpu_setstate"); - run_machine(mach, vcpu); + state->segs[NVMM_X64_SEG_CS].base = 0; + state->segs[NVMM_X64_SEG_CS].limit = 0xFFFFFFFF; + state->gprs[NVMM_X64_GPR_RIP] = 0x2000; - res = (uint64_t *)mmiobuf; - if (*res == test->wanted) { - printf("Test '%s' passed\n", test->name); - } else { - printf("Test '%s' failed, wanted 0x%lx, got 0x%lx\n", test->name, - test->wanted, *res); - } + if (nvmm_vcpu_setstate(mach, vcpu, NVMM_X64_STATE_ALL) == -1) + err(errno, "nvmm_vcpu_setstate"); } -/* -------------------------------------------------------------------------- */ - -extern uint8_t test1_begin, test1_end; -extern uint8_t test2_begin, test2_end; -extern uint8_t test3_begin, test3_end; -extern uint8_t test4_begin, test4_end; -extern uint8_t test5_begin, test5_end; -extern uint8_t test6_begin, test6_end; -extern uint8_t test7_begin, test7_end; -extern uint8_t test8_begin, test8_end; -extern uint8_t test9_begin, test9_end; -extern uint8_t test10_begin, test10_end; -extern uint8_t test11_begin, test11_end; -extern uint8_t test12_begin, test12_end; -extern uint8_t test13_begin, test13_end; -extern uint8_t test14_begin, test14_end; +static void +map_pages16(struct nvmm_machine *mach) +{ + int ret; -static const struct test tests[] = { - { "test1 - MOV", &test1_begin, &test1_end, 0x3004 }, - { "test2 - OR", &test2_begin, &test2_end, 0x16FF }, - { "test3 - AND", &test3_begin, &test3_end, 0x1FC0 }, - { "test4 - XOR", &test4_begin, &test4_end, 0x10CF }, - { "test5 - Address Sizes", &test5_begin, &test5_end, 0x1F00 }, - { "test6 - DMO", &test6_begin, &test6_end, 0xFFAB }, - { "test7 - STOS", &test7_begin, &test7_end, 0x00123456 }, - { "test8 - LODS", &test8_begin, &test8_end, 0x12345678 }, - { "test9 - MOVS", &test9_begin, &test9_end, 0x12345678 }, - { "test10 - MOVZXB", &test10_begin, &test10_end, 0x00000078 }, - { "test11 - MOVZXW", &test11_begin, &test11_end, 0x00005678 }, - { "test12 - CMP", &test12_begin, &test12_end, 0x00000001 }, - { "test13 - SUB", &test13_begin, &test13_end, 0x0000000F0000A0FF }, - { "test14 - TEST", &test14_begin, &test14_end, 0x00000001 }, - { NULL, NULL, NULL, -1 } -}; + instbuf = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, + -1, 0); + if (instbuf == MAP_FAILED) + err(errno, "mmap"); -static struct nvmm_callbacks callbacks = { - .io = NULL, - .mem = mem_callback -}; + if (nvmm_hva_map(mach, (uintptr_t)instbuf, PAGE_SIZE) == -1) + err(errno, "nvmm_hva_map"); + ret = nvmm_gpa_map(mach, (uintptr_t)instbuf, 0x2000, PAGE_SIZE, + PROT_READ|PROT_EXEC); + if (ret == -1) + err(errno, "nvmm_gpa_map"); +} /* * 0x1000: MMIO address, unmapped * 0x2000: Instructions, mapped - * 0x3000: L4 - * 0x4000: L3 - * 0x5000: L2 - * 0x6000: L1 */ -int main(int argc, char *argv[]) +static void +test_vm16(void) { struct nvmm_machine mach; struct nvmm_vcpu vcpu; @@ -353,11 +436,22 @@ int main(int argc, char *argv[]) if (nvmm_vcpu_create(&mach, 0, &vcpu) == -1) err(errno, "nvmm_vcpu_create"); nvmm_machine_configure(&mach, NVMM_MACH_CONF_CALLBACKS, &callbacks); - map_pages(&mach); + map_pages16(&mach); - for (i = 0; tests[i].name != NULL; i++) { - run_test(&mach, &vcpu, &tests[i]); + for (i = 0; tests16[i].name != NULL; i++) { + reset_machine16(&mach, &vcpu); + run_test(&mach, &vcpu, &tests16[i]); } + if (nvmm_machine_destroy(&mach) == -1) + err(errno, "nvmm_machine_destroy"); +} + +/* -------------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + test_vm64(); + test_vm16(); return 0; } Index: src/tests/lib/libnvmm/h_mem_assist_asm.S diff -u src/tests/lib/libnvmm/h_mem_assist_asm.S:1.6 src/tests/lib/libnvmm/h_mem_assist_asm.S:1.7 --- src/tests/lib/libnvmm/h_mem_assist_asm.S:1.6 Tue Mar 19 19:23:39 2019 +++ src/tests/lib/libnvmm/h_mem_assist_asm.S Sun Oct 13 17:32:15 2019 @@ -1,7 +1,7 @@ -/* $NetBSD: h_mem_assist_asm.S,v 1.6 2019/03/19 19:23:39 maxv Exp $ */ +/* $NetBSD: h_mem_assist_asm.S,v 1.7 2019/10/13 17:32:15 maxv Exp $ */ /* - * Copyright (c) 2018 The NetBSD Foundation, Inc. + * Copyright (c) 2018-2019 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -293,3 +293,73 @@ test14_begin: movq $0,(%rax) TEST_END test14_end: + +/* -------------------------------------------------------------------------- */ + + .globl test_16bit_1_begin, test_16bit_1_end + .globl test_16bit_2_begin, test_16bit_2_end + .globl test_16bit_3_begin, test_16bit_3_end + .globl test_16bit_4_begin, test_16bit_4_end + .globl test_16bit_5_begin, test_16bit_5_end + +#define TEST16_END \ + rdmsr + + .code16 + + .align 64 +test_16bit_1_begin: + movw $0x10f1,%bx + movw $0x123,%dx + + movb %dl,(%bx) + + TEST16_END +test_16bit_1_end: + + .align 64 +test_16bit_2_begin: + movw $0x10f1,%bx + movw $2,%di + movw $0x123,%dx + + movw %dx,(%bx,%di) + + TEST16_END +test_16bit_2_end: + + .align 64 +test_16bit_3_begin: + movw $0x10f1,%bp + movw $2,%si + movw $0x678,%dx + + movw %dx,-2(%bp,%si) + + TEST16_END +test_16bit_3_end: + + .align 64 +test_16bit_4_begin: + movw $0x10f0,%bp + movw $2,%si + movw $2+4+4,%di + movw $0xFFFF,%dx + movl $0x0001,%eax + movl $0x0010,%ebx + movl $0x1000,%ecx + + movw %dx,4(%bp,%si) /* 16bit opr 16bit adr */ + andl %eax,4(%bp,%si) /* 32bit opr 16bit adr */ + orw %bx,4(%ebp,%esi) /* 16bit opr 32bit adr */ + orl %ecx,-4(%bp,%di) /* 32bit opr 16bit adr, negative */ + + TEST16_END +test_16bit_4_end: + + .align 64 +test_16bit_5_begin: + movb $0x12,0x1234 + + TEST16_END +test_16bit_5_end: