Fri Oct 30 21:06:13 2020 UTC ()
Implement missing (REPE) CMPS instruction support in NVMMs x86_decode().

In apparently rare cases the (REPE) CMPS instruction can trigger an memory
assist. NVMM wouldn't recognize the instruction and thus couldn't assist and
Qemu would abort.


(reinoud)
diff -r1.40 -r1.41 src/lib/libnvmm/libnvmm_x86.c

cvs diff -r1.40 -r1.41 src/lib/libnvmm/libnvmm_x86.c (expand / switch to unified diff)

--- src/lib/libnvmm/libnvmm_x86.c 2020/09/05 07:22:25 1.40
+++ src/lib/libnvmm/libnvmm_x86.c 2020/10/30 21:06:13 1.41
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: libnvmm_x86.c,v 1.40 2020/09/05 07:22:25 maxv Exp $ */ 1/* $NetBSD: libnvmm_x86.c,v 1.41 2020/10/30 21:06:13 reinoud Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net 4 * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is part of the NVMM hypervisor. 7 * This code is part of the NVMM hypervisor.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
@@ -1041,26 +1041,27 @@ struct x86_decode_fsm { @@ -1041,26 +1041,27 @@ struct x86_decode_fsm {
1041 uint8_t *buf; 1041 uint8_t *buf;
1042 uint8_t *end; 1042 uint8_t *end;
1043}; 1043};
1044 1044
1045struct x86_opcode { 1045struct x86_opcode {
1046 bool valid:1; 1046 bool valid:1;
1047 bool regmodrm:1; 1047 bool regmodrm:1;
1048 bool regtorm:1; 1048 bool regtorm:1;
1049 bool dmo:1; 1049 bool dmo:1;
1050 bool todmo:1; 1050 bool todmo:1;
1051 bool movs:1; 1051 bool movs:1;
1052 bool stos:1; 1052 bool stos:1;
1053 bool lods:1; 1053 bool lods:1;
 1054 bool cmps:1;
1054 bool szoverride:1; 1055 bool szoverride:1;
1055 bool group1:1; 1056 bool group1:1;
1056 bool group3:1; 1057 bool group3:1;
1057 bool group11:1; 1058 bool group11:1;
1058 bool immediate:1; 1059 bool immediate:1;
1059 uint8_t defsize; 1060 uint8_t defsize;
1060 uint8_t flags; 1061 uint8_t flags;
1061 const struct x86_emul *emul; 1062 const struct x86_emul *emul;
1062}; 1063};
1063 1064
1064struct x86_group_entry { 1065struct x86_group_entry {
1065 const struct x86_emul *emul; 1066 const struct x86_emul *emul;
1066}; 1067};
@@ -1453,26 +1454,46 @@ static const struct x86_opcode primary_o @@ -1453,26 +1454,46 @@ static const struct x86_opcode primary_o
1453 .defsize = OPSIZE_BYTE, 1454 .defsize = OPSIZE_BYTE,
1454 .emul = &x86_emul_movs 1455 .emul = &x86_emul_movs
1455 }, 1456 },
1456 [0xA5] = { 1457 [0xA5] = {
1457 /* Yv, Xv */ 1458 /* Yv, Xv */
1458 .valid = true, 1459 .valid = true,
1459 .movs = true, 1460 .movs = true,
1460 .szoverride = true, 1461 .szoverride = true,
1461 .defsize = -1, 1462 .defsize = -1,
1462 .emul = &x86_emul_movs 1463 .emul = &x86_emul_movs
1463 }, 1464 },
1464 1465
1465 /* 1466 /*
 1467 * CMPS
 1468 */
 1469 [0xA6] = {
 1470 /* Yb, Xb */
 1471 .valid = true,
 1472 .cmps = true,
 1473 .szoverride = false,
 1474 .defsize = OPSIZE_BYTE,
 1475 .emul = &x86_emul_cmp
 1476 },
 1477 [0xA7] = {
 1478 /* Yv, Xv */
 1479 .valid = true,
 1480 .cmps = true,
 1481 .szoverride = true,
 1482 .defsize = -1,
 1483 .emul = &x86_emul_cmp
 1484 },
 1485
 1486 /*
1466 * STOS 1487 * STOS
1467 */ 1488 */
1468 [0xAA] = { 1489 [0xAA] = {
1469 /* Yb, AL */ 1490 /* Yb, AL */
1470 .valid = true, 1491 .valid = true,
1471 .stos = true, 1492 .stos = true,
1472 .szoverride = false, 1493 .szoverride = false,
1473 .defsize = OPSIZE_BYTE, 1494 .defsize = OPSIZE_BYTE,
1474 .emul = &x86_emul_stos 1495 .emul = &x86_emul_stos
1475 }, 1496 },
1476 [0xAB] = { 1497 [0xAB] = {
1477 /* Yv, rAX */ 1498 /* Yv, rAX */
1478 .valid = true, 1499 .valid = true,
@@ -1861,26 +1882,55 @@ node_movs(struct x86_decode_fsm *fsm, st @@ -1861,26 +1882,55 @@ node_movs(struct x86_decode_fsm *fsm, st
1861 1882
1862 /* ES:RDI, force ES */ 1883 /* ES:RDI, force ES */
1863 instr->dst.type = STORE_REG; 1884 instr->dst.type = STORE_REG;
1864 instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1]; 1885 instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1];
1865 instr->dst.disp.type = DISP_0; 1886 instr->dst.disp.type = DISP_0;
1866 instr->dst.hardseg = NVMM_X64_SEG_ES; 1887 instr->dst.hardseg = NVMM_X64_SEG_ES;
1867 1888
1868 fsm_advance(fsm, 0, NULL); 1889 fsm_advance(fsm, 0, NULL);
1869 1890
1870 return 0; 1891 return 0;
1871} 1892}
1872 1893
1873/* 1894/*
 1895 * Special node, for CMPS. Fake two displacements of zero on the source and
 1896 * destination registers.
 1897 * XXX coded as clone of movs as its similar in register usage
 1898 * XXX might be merged with node_movs()
 1899 */
 1900static int
 1901node_cmps(struct x86_decode_fsm *fsm, struct x86_instr *instr)
 1902{
 1903 size_t adrsize;
 1904
 1905 adrsize = instr->address_size;
 1906
 1907 /* DS:RSI */
 1908 instr->src.type = STORE_REG;
 1909 instr->src.u.reg = &gpr_map__special[1][2][adrsize-1];
 1910 instr->src.disp.type = DISP_0;
 1911
 1912 /* ES:RDI, force ES */
 1913 instr->dst.type = STORE_REG;
 1914 instr->dst.u.reg = &gpr_map__special[1][3][adrsize-1];
 1915 instr->dst.disp.type = DISP_0;
 1916 instr->dst.hardseg = NVMM_X64_SEG_ES;
 1917
 1918 fsm_advance(fsm, 0, NULL);
 1919
 1920 return 0;
 1921}
 1922
 1923/*
1874 * Special node, for STOS and LODS. Fake a displacement of zero on the 1924 * Special node, for STOS and LODS. Fake a displacement of zero on the
1875 * destination register. 1925 * destination register.
1876 */ 1926 */
1877static int 1927static int
1878node_stlo(struct x86_decode_fsm *fsm, struct x86_instr *instr) 1928node_stlo(struct x86_decode_fsm *fsm, struct x86_instr *instr)
1879{ 1929{
1880 const struct x86_opcode *opcode = instr->opcode; 1930 const struct x86_opcode *opcode = instr->opcode;
1881 struct x86_store *stlo, *streg; 1931 struct x86_store *stlo, *streg;
1882 size_t adrsize, regsize; 1932 size_t adrsize, regsize;
1883 1933
1884 adrsize = instr->address_size; 1934 adrsize = instr->address_size;
1885 regsize = instr->operand_size; 1935 regsize = instr->operand_size;
1886 1936
@@ -2460,26 +2510,28 @@ node_primary_opcode(struct x86_decode_fs @@ -2460,26 +2510,28 @@ node_primary_opcode(struct x86_decode_fs
2460 /* Zero-extend to 64 bits. */ 2510 /* Zero-extend to 64 bits. */
2461 instr->zeroextend_mask = ~size_to_mask(4); 2511 instr->zeroextend_mask = ~size_to_mask(4);
2462 } 2512 }
2463 2513
2464 if (opcode->regmodrm) { 2514 if (opcode->regmodrm) {
2465 fsm_advance(fsm, 1, node_regmodrm); 2515 fsm_advance(fsm, 1, node_regmodrm);
2466 } else if (opcode->dmo) { 2516 } else if (opcode->dmo) {
2467 /* Direct-Memory Offsets */ 2517 /* Direct-Memory Offsets */
2468 fsm_advance(fsm, 1, node_dmo); 2518 fsm_advance(fsm, 1, node_dmo);
2469 } else if (opcode->stos || opcode->lods) { 2519 } else if (opcode->stos || opcode->lods) {
2470 fsm_advance(fsm, 1, node_stlo); 2520 fsm_advance(fsm, 1, node_stlo);
2471 } else if (opcode->movs) { 2521 } else if (opcode->movs) {
2472 fsm_advance(fsm, 1, node_movs); 2522 fsm_advance(fsm, 1, node_movs);
 2523 } else if (opcode->cmps) {
 2524 fsm_advance(fsm, 1, node_cmps);
2473 } else { 2525 } else {
2474 return -1; 2526 return -1;
2475 } 2527 }
2476 2528
2477 return 0; 2529 return 0;
2478} 2530}
2479 2531
2480static int 2532static int
2481node_secondary_opcode(struct x86_decode_fsm *fsm, struct x86_instr *instr) 2533node_secondary_opcode(struct x86_decode_fsm *fsm, struct x86_instr *instr)
2482{ 2534{
2483 const struct x86_opcode *opcode; 2535 const struct x86_opcode *opcode;
2484 uint8_t byte; 2536 uint8_t byte;
2485 2537
@@ -2636,28 +2688,36 @@ x86_decode(uint8_t *inst_bytes, size_t i @@ -2636,28 +2688,36 @@ x86_decode(uint8_t *inst_bytes, size_t i
2636 instr->src.hardseg = -1; 2688 instr->src.hardseg = -1;
2637 instr->dst.hardseg = -1; 2689 instr->dst.hardseg = -1;
2638 2690
2639 fsm.is64bit = is_64bit(state); 2691 fsm.is64bit = is_64bit(state);
2640 fsm.is32bit = is_32bit(state); 2692 fsm.is32bit = is_32bit(state);
2641 fsm.is16bit = is_16bit(state); 2693 fsm.is16bit = is_16bit(state);
2642 2694
2643 fsm.fn = node_legacy_prefix; 2695 fsm.fn = node_legacy_prefix;
2644 fsm.buf = inst_bytes; 2696 fsm.buf = inst_bytes;
2645 fsm.end = inst_bytes + inst_len; 2697 fsm.end = inst_bytes + inst_len;
2646 2698
2647 while (fsm.fn != NULL) { 2699 while (fsm.fn != NULL) {
2648 ret = (*fsm.fn)(&fsm, instr); 2700 ret = (*fsm.fn)(&fsm, instr);
2649 if (ret == -1) 2701 if (ret == -1) {
 2702 printf("\nNVMM: %s missing support for instruction " \
 2703 "with max length %ld : [ ", __func__,
 2704 inst_len);
 2705 for (uint i = 0; i < inst_len; i++)
 2706 printf("%02x ", inst_bytes[i]);
 2707 printf("], please report to NetBSD!\n\n");
 2708 fflush(stdout);
2650 return -1; 2709 return -1;
 2710 }
2651 } 2711 }
2652 2712
2653 instr->len = fsm.buf - inst_bytes; 2713 instr->len = fsm.buf - inst_bytes;
2654 2714
2655 return 0; 2715 return 0;
2656} 2716}
2657 2717
2658/* -------------------------------------------------------------------------- */ 2718/* -------------------------------------------------------------------------- */
2659 2719
2660#define EXEC_INSTR(sz, instr) \ 2720#define EXEC_INSTR(sz, instr) \
2661static uint##sz##_t \ 2721static uint##sz##_t \
2662exec_##instr##sz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags) \ 2722exec_##instr##sz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags) \
2663{ \ 2723{ \