xref: /OK3568_Linux_fs/kernel/tools/perf/arch/x86/tests/insn-x86.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/types.h>
3*4882a593Smuzhiyun #include "../../../../arch/x86/include/asm/insn.h"
4*4882a593Smuzhiyun #include <string.h>
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include "debug.h"
7*4882a593Smuzhiyun #include "tests/tests.h"
8*4882a593Smuzhiyun #include "arch-tests.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "intel-pt-decoder/intel-pt-insn-decoder.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun struct test_data {
13*4882a593Smuzhiyun 	u8 data[MAX_INSN_SIZE];
14*4882a593Smuzhiyun 	int expected_length;
15*4882a593Smuzhiyun 	int expected_rel;
16*4882a593Smuzhiyun 	const char *expected_op_str;
17*4882a593Smuzhiyun 	const char *expected_branch_str;
18*4882a593Smuzhiyun 	const char *asm_rep;
19*4882a593Smuzhiyun };
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun struct test_data test_data_32[] = {
22*4882a593Smuzhiyun #include "insn-x86-dat-32.c"
23*4882a593Smuzhiyun 	{{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee             \trdpkru"},
24*4882a593Smuzhiyun 	{{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef             \twrpkru"},
25*4882a593Smuzhiyun 	{{0}, 0, 0, NULL, NULL, NULL},
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun struct test_data test_data_64[] = {
29*4882a593Smuzhiyun #include "insn-x86-dat-64.c"
30*4882a593Smuzhiyun 	{{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee             \trdpkru"},
31*4882a593Smuzhiyun 	{{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef             \twrpkru"},
32*4882a593Smuzhiyun 	{{0}, 0, 0, NULL, NULL, NULL},
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
get_op(const char * op_str)35*4882a593Smuzhiyun static int get_op(const char *op_str)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct val_data {
38*4882a593Smuzhiyun 		const char *name;
39*4882a593Smuzhiyun 		int val;
40*4882a593Smuzhiyun 	} vals[] = {
41*4882a593Smuzhiyun 		{"other",   INTEL_PT_OP_OTHER},
42*4882a593Smuzhiyun 		{"call",    INTEL_PT_OP_CALL},
43*4882a593Smuzhiyun 		{"ret",     INTEL_PT_OP_RET},
44*4882a593Smuzhiyun 		{"jcc",     INTEL_PT_OP_JCC},
45*4882a593Smuzhiyun 		{"jmp",     INTEL_PT_OP_JMP},
46*4882a593Smuzhiyun 		{"loop",    INTEL_PT_OP_LOOP},
47*4882a593Smuzhiyun 		{"iret",    INTEL_PT_OP_IRET},
48*4882a593Smuzhiyun 		{"int",     INTEL_PT_OP_INT},
49*4882a593Smuzhiyun 		{"syscall", INTEL_PT_OP_SYSCALL},
50*4882a593Smuzhiyun 		{"sysret",  INTEL_PT_OP_SYSRET},
51*4882a593Smuzhiyun 		{NULL, 0},
52*4882a593Smuzhiyun 	};
53*4882a593Smuzhiyun 	struct val_data *val;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	if (!op_str || !strlen(op_str))
56*4882a593Smuzhiyun 		return 0;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	for (val = vals; val->name; val++) {
59*4882a593Smuzhiyun 		if (!strcmp(val->name, op_str))
60*4882a593Smuzhiyun 			return val->val;
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	pr_debug("Failed to get op\n");
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	return -1;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
get_branch(const char * branch_str)68*4882a593Smuzhiyun static int get_branch(const char *branch_str)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	struct val_data {
71*4882a593Smuzhiyun 		const char *name;
72*4882a593Smuzhiyun 		int val;
73*4882a593Smuzhiyun 	} vals[] = {
74*4882a593Smuzhiyun 		{"no_branch",     INTEL_PT_BR_NO_BRANCH},
75*4882a593Smuzhiyun 		{"indirect",      INTEL_PT_BR_INDIRECT},
76*4882a593Smuzhiyun 		{"conditional",   INTEL_PT_BR_CONDITIONAL},
77*4882a593Smuzhiyun 		{"unconditional", INTEL_PT_BR_UNCONDITIONAL},
78*4882a593Smuzhiyun 		{NULL, 0},
79*4882a593Smuzhiyun 	};
80*4882a593Smuzhiyun 	struct val_data *val;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (!branch_str || !strlen(branch_str))
83*4882a593Smuzhiyun 		return 0;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	for (val = vals; val->name; val++) {
86*4882a593Smuzhiyun 		if (!strcmp(val->name, branch_str))
87*4882a593Smuzhiyun 			return val->val;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	pr_debug("Failed to get branch\n");
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	return -1;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
test_data_item(struct test_data * dat,int x86_64)95*4882a593Smuzhiyun static int test_data_item(struct test_data *dat, int x86_64)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct intel_pt_insn intel_pt_insn;
98*4882a593Smuzhiyun 	struct insn insn;
99*4882a593Smuzhiyun 	int op, branch;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	insn_init(&insn, dat->data, MAX_INSN_SIZE, x86_64);
102*4882a593Smuzhiyun 	insn_get_length(&insn);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (!insn_complete(&insn)) {
105*4882a593Smuzhiyun 		pr_debug("Failed to decode: %s\n", dat->asm_rep);
106*4882a593Smuzhiyun 		return -1;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (insn.length != dat->expected_length) {
110*4882a593Smuzhiyun 		pr_debug("Failed to decode length (%d vs expected %d): %s\n",
111*4882a593Smuzhiyun 			 insn.length, dat->expected_length, dat->asm_rep);
112*4882a593Smuzhiyun 		return -1;
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	op = get_op(dat->expected_op_str);
116*4882a593Smuzhiyun 	branch = get_branch(dat->expected_branch_str);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (intel_pt_get_insn(dat->data, MAX_INSN_SIZE, x86_64, &intel_pt_insn)) {
119*4882a593Smuzhiyun 		pr_debug("Intel PT failed to decode: %s\n", dat->asm_rep);
120*4882a593Smuzhiyun 		return -1;
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if ((int)intel_pt_insn.op != op) {
124*4882a593Smuzhiyun 		pr_debug("Failed to decode 'op' value (%d vs expected %d): %s\n",
125*4882a593Smuzhiyun 			 intel_pt_insn.op, op, dat->asm_rep);
126*4882a593Smuzhiyun 		return -1;
127*4882a593Smuzhiyun 	}
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if ((int)intel_pt_insn.branch != branch) {
130*4882a593Smuzhiyun 		pr_debug("Failed to decode 'branch' value (%d vs expected %d): %s\n",
131*4882a593Smuzhiyun 			 intel_pt_insn.branch, branch, dat->asm_rep);
132*4882a593Smuzhiyun 		return -1;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (intel_pt_insn.rel != dat->expected_rel) {
136*4882a593Smuzhiyun 		pr_debug("Failed to decode 'rel' value (%#x vs expected %#x): %s\n",
137*4882a593Smuzhiyun 			 intel_pt_insn.rel, dat->expected_rel, dat->asm_rep);
138*4882a593Smuzhiyun 		return -1;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	pr_debug("Decoded ok: %s\n", dat->asm_rep);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
test_data_set(struct test_data * dat_set,int x86_64)146*4882a593Smuzhiyun static int test_data_set(struct test_data *dat_set, int x86_64)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct test_data *dat;
149*4882a593Smuzhiyun 	int ret = 0;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	for (dat = dat_set; dat->expected_length; dat++) {
152*4882a593Smuzhiyun 		if (test_data_item(dat, x86_64))
153*4882a593Smuzhiyun 			ret = -1;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return ret;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun  * test__insn_x86 - test x86 instruction decoder - new instructions.
161*4882a593Smuzhiyun  *
162*4882a593Smuzhiyun  * This function implements a test that decodes a selection of instructions and
163*4882a593Smuzhiyun  * checks the results.  The Intel PT function that further categorizes
164*4882a593Smuzhiyun  * instructions (i.e. intel_pt_get_insn()) is also checked.
165*4882a593Smuzhiyun  *
166*4882a593Smuzhiyun  * The instructions are originally in insn-x86-dat-src.c which has been
167*4882a593Smuzhiyun  * processed by scripts gen-insn-x86-dat.sh and gen-insn-x86-dat.awk to produce
168*4882a593Smuzhiyun  * insn-x86-dat-32.c and insn-x86-dat-64.c which are included into this program.
169*4882a593Smuzhiyun  * i.e. to add new instructions to the test, edit insn-x86-dat-src.c, run the
170*4882a593Smuzhiyun  * gen-insn-x86-dat.sh script, make perf, and then run the test.
171*4882a593Smuzhiyun  *
172*4882a593Smuzhiyun  * If the test passes %0 is returned, otherwise %-1 is returned.  Use the
173*4882a593Smuzhiyun  * verbose (-v) option to see all the instructions and whether or not they
174*4882a593Smuzhiyun  * decoded successfully.
175*4882a593Smuzhiyun  */
test__insn_x86(struct test * test __maybe_unused,int subtest __maybe_unused)176*4882a593Smuzhiyun int test__insn_x86(struct test *test __maybe_unused, int subtest __maybe_unused)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	int ret = 0;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (test_data_set(test_data_32, 0))
181*4882a593Smuzhiyun 		ret = -1;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (test_data_set(test_data_64, 1))
184*4882a593Smuzhiyun 		ret = -1;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return ret;
187*4882a593Smuzhiyun }
188