| @@ -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 | |
1045 | struct x86_opcode { | | 1045 | struct 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 | |
1064 | struct x86_group_entry { | | 1065 | struct 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 | */ |
| | | 1900 | static int |
| | | 1901 | node_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 | */ |
1877 | static int | | 1927 | static int |
1878 | node_stlo(struct x86_decode_fsm *fsm, struct x86_instr *instr) | | 1928 | node_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 | |
2480 | static int | | 2532 | static int |
2481 | node_secondary_opcode(struct x86_decode_fsm *fsm, struct x86_instr *instr) | | 2533 | node_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) \ |
2661 | static uint##sz##_t \ | | 2721 | static uint##sz##_t \ |
2662 | exec_##instr##sz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags) \ | | 2722 | exec_##instr##sz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags) \ |
2663 | { \ | | 2723 | { \ |