1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <linux/compiler.h> |
4 | #include <linux/bits.h> |
5 | #include <string.h> |
6 | #include <cpuid.h> |
7 | #include <sched.h> |
8 | |
9 | #include "intel-pt-decoder/intel-pt-pkt-decoder.h" |
10 | |
11 | #include "debug.h" |
12 | #include "tests/tests.h" |
13 | #include "arch-tests.h" |
14 | #include "cpumap.h" |
15 | |
16 | /** |
17 | * struct test_data - Test data. |
18 | * @len: number of bytes to decode |
19 | * @bytes: bytes to decode |
20 | * @ctx: packet context to decode |
21 | * @packet: expected packet |
22 | * @new_ctx: expected new packet context |
23 | * @ctx_unchanged: the packet context must not change |
24 | */ |
25 | static const struct test_data { |
26 | int len; |
27 | u8 bytes[INTEL_PT_PKT_MAX_SZ]; |
28 | enum intel_pt_pkt_ctx ctx; |
29 | struct intel_pt_pkt packet; |
30 | enum intel_pt_pkt_ctx new_ctx; |
31 | int ctx_unchanged; |
32 | } data[] = { |
33 | /* Padding Packet */ |
34 | {1, {0}, 0, {INTEL_PT_PAD, 0, 0}, 0, 1 }, |
35 | /* Short Taken/Not Taken Packet */ |
36 | {1, {4}, 0, {INTEL_PT_TNT, 1, 0}, 0, 0 }, |
37 | {1, {6}, 0, {INTEL_PT_TNT, 1, 0x20ULL << 58}, 0, 0 }, |
38 | {1, {0x80}, 0, {INTEL_PT_TNT, 6, 0}, 0, 0 }, |
39 | {1, {0xfe}, 0, {INTEL_PT_TNT, 6, 0x3fULL << 58}, 0, 0 }, |
40 | /* Long Taken/Not Taken Packet */ |
41 | {8, {0x02, 0xa3, 2}, 0, {INTEL_PT_TNT, 1, 0xa302ULL << 47}, 0, 0 }, |
42 | {8, {0x02, 0xa3, 3}, 0, {INTEL_PT_TNT, 1, 0x1a302ULL << 47}, 0, 0 }, |
43 | {8, {0x02, 0xa3, 0, 0, 0, 0, 0, 0x80}, 0, {INTEL_PT_TNT, 47, 0xa302ULL << 1}, 0, 0 }, |
44 | {8, {0x02, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, {INTEL_PT_TNT, 47, 0xffffffffffffa302ULL << 1}, 0, 0 }, |
45 | /* Target IP Packet */ |
46 | {1, {0x0d}, 0, {INTEL_PT_TIP, 0, 0}, 0, 0 }, |
47 | {3, {0x2d, 1, 2}, 0, {INTEL_PT_TIP, 1, 0x201}, 0, 0 }, |
48 | {5, {0x4d, 1, 2, 3, 4}, 0, {INTEL_PT_TIP, 2, 0x4030201}, 0, 0 }, |
49 | {7, {0x6d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP, 3, 0x60504030201}, 0, 0 }, |
50 | {7, {0x8d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP, 4, 0x60504030201}, 0, 0 }, |
51 | {9, {0xcd, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_TIP, 6, 0x807060504030201}, 0, 0 }, |
52 | /* Packet Generation Enable */ |
53 | {1, {0x11}, 0, {INTEL_PT_TIP_PGE, 0, 0}, 0, 0 }, |
54 | {3, {0x31, 1, 2}, 0, {INTEL_PT_TIP_PGE, 1, 0x201}, 0, 0 }, |
55 | {5, {0x51, 1, 2, 3, 4}, 0, {INTEL_PT_TIP_PGE, 2, 0x4030201}, 0, 0 }, |
56 | {7, {0x71, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGE, 3, 0x60504030201}, 0, 0 }, |
57 | {7, {0x91, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGE, 4, 0x60504030201}, 0, 0 }, |
58 | {9, {0xd1, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_TIP_PGE, 6, 0x807060504030201}, 0, 0 }, |
59 | /* Packet Generation Disable */ |
60 | {1, {0x01}, 0, {INTEL_PT_TIP_PGD, 0, 0}, 0, 0 }, |
61 | {3, {0x21, 1, 2}, 0, {INTEL_PT_TIP_PGD, 1, 0x201}, 0, 0 }, |
62 | {5, {0x41, 1, 2, 3, 4}, 0, {INTEL_PT_TIP_PGD, 2, 0x4030201}, 0, 0 }, |
63 | {7, {0x61, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGD, 3, 0x60504030201}, 0, 0 }, |
64 | {7, {0x81, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_TIP_PGD, 4, 0x60504030201}, 0, 0 }, |
65 | {9, {0xc1, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_TIP_PGD, 6, 0x807060504030201}, 0, 0 }, |
66 | /* Flow Update Packet */ |
67 | {1, {0x1d}, 0, {INTEL_PT_FUP, 0, 0}, 0, 0 }, |
68 | {3, {0x3d, 1, 2}, 0, {INTEL_PT_FUP, 1, 0x201}, 0, 0 }, |
69 | {5, {0x5d, 1, 2, 3, 4}, 0, {INTEL_PT_FUP, 2, 0x4030201}, 0, 0 }, |
70 | {7, {0x7d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_FUP, 3, 0x60504030201}, 0, 0 }, |
71 | {7, {0x9d, 1, 2, 3, 4, 5, 6}, 0, {INTEL_PT_FUP, 4, 0x60504030201}, 0, 0 }, |
72 | {9, {0xdd, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_FUP, 6, 0x807060504030201}, 0, 0 }, |
73 | /* Paging Information Packet */ |
74 | {8, {0x02, 0x43, 2, 4, 6, 8, 10, 12}, 0, {INTEL_PT_PIP, 0, 0xC0A08060402}, 0, 0 }, |
75 | {8, {0x02, 0x43, 3, 4, 6, 8, 10, 12}, 0, {INTEL_PT_PIP, 0, 0xC0A08060403}, 0, 0 }, |
76 | /* Mode Exec Packet */ |
77 | {2, {0x99, 0x00}, 0, {INTEL_PT_MODE_EXEC, 0, 16}, 0, 0 }, |
78 | {2, {0x99, 0x01}, 0, {INTEL_PT_MODE_EXEC, 1, 64}, 0, 0 }, |
79 | {2, {0x99, 0x02}, 0, {INTEL_PT_MODE_EXEC, 2, 32}, 0, 0 }, |
80 | {2, {0x99, 0x04}, 0, {INTEL_PT_MODE_EXEC, 4, 16}, 0, 0 }, |
81 | {2, {0x99, 0x05}, 0, {INTEL_PT_MODE_EXEC, 5, 64}, 0, 0 }, |
82 | {2, {0x99, 0x06}, 0, {INTEL_PT_MODE_EXEC, 6, 32}, 0, 0 }, |
83 | /* Mode TSX Packet */ |
84 | {2, {0x99, 0x20}, 0, {INTEL_PT_MODE_TSX, 0, 0}, 0, 0 }, |
85 | {2, {0x99, 0x21}, 0, {INTEL_PT_MODE_TSX, 0, 1}, 0, 0 }, |
86 | {2, {0x99, 0x22}, 0, {INTEL_PT_MODE_TSX, 0, 2}, 0, 0 }, |
87 | /* Trace Stop Packet */ |
88 | {2, {0x02, 0x83}, 0, {INTEL_PT_TRACESTOP, 0, 0}, 0, 0 }, |
89 | /* Core:Bus Ratio Packet */ |
90 | {4, {0x02, 0x03, 0x12, 0}, 0, {INTEL_PT_CBR, 0, 0x12}, 0, 1 }, |
91 | /* Timestamp Counter Packet */ |
92 | {8, {0x19, 1, 2, 3, 4, 5, 6, 7}, 0, {INTEL_PT_TSC, 0, 0x7060504030201}, 0, 1 }, |
93 | /* Mini Time Counter Packet */ |
94 | {2, {0x59, 0x12}, 0, {INTEL_PT_MTC, 0, 0x12}, 0, 1 }, |
95 | /* TSC / MTC Alignment Packet */ |
96 | {7, {0x02, 0x73}, 0, {INTEL_PT_TMA, 0, 0}, 0, 1 }, |
97 | {7, {0x02, 0x73, 1, 2}, 0, {INTEL_PT_TMA, 0, 0x201}, 0, 1 }, |
98 | {7, {0x02, 0x73, 0, 0, 0, 0xff, 1}, 0, {INTEL_PT_TMA, 0x1ff, 0}, 0, 1 }, |
99 | {7, {0x02, 0x73, 0x80, 0xc0, 0, 0xff, 1}, 0, {INTEL_PT_TMA, 0x1ff, 0xc080}, 0, 1 }, |
100 | /* Cycle Count Packet */ |
101 | {1, {0x03}, 0, {INTEL_PT_CYC, 0, 0}, 0, 1 }, |
102 | {1, {0x0b}, 0, {INTEL_PT_CYC, 0, 1}, 0, 1 }, |
103 | {1, {0xfb}, 0, {INTEL_PT_CYC, 0, 0x1f}, 0, 1 }, |
104 | {2, {0x07, 2}, 0, {INTEL_PT_CYC, 0, 0x20}, 0, 1 }, |
105 | {2, {0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0xfff}, 0, 1 }, |
106 | {3, {0x07, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x1000}, 0, 1 }, |
107 | {3, {0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x7ffff}, 0, 1 }, |
108 | {4, {0x07, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x80000}, 0, 1 }, |
109 | {4, {0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x3ffffff}, 0, 1 }, |
110 | {5, {0x07, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x4000000}, 0, 1 }, |
111 | {5, {0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x1ffffffff}, 0, 1 }, |
112 | {6, {0x07, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x200000000}, 0, 1 }, |
113 | {6, {0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0xffffffffff}, 0, 1 }, |
114 | {7, {0x07, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x10000000000}, 0, 1 }, |
115 | {7, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x7fffffffffff}, 0, 1 }, |
116 | {8, {0x07, 1, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x800000000000}, 0, 1 }, |
117 | {8, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x3fffffffffffff}, 0, 1 }, |
118 | {9, {0x07, 1, 1, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x40000000000000}, 0, 1 }, |
119 | {9, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}, 0, {INTEL_PT_CYC, 0, 0x1fffffffffffffff}, 0, 1 }, |
120 | {10, {0x07, 1, 1, 1, 1, 1, 1, 1, 1, 2}, 0, {INTEL_PT_CYC, 0, 0x2000000000000000}, 0, 1 }, |
121 | {10, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe}, 0, {INTEL_PT_CYC, 0, 0xffffffffffffffff}, 0, 1 }, |
122 | /* Virtual-Machine Control Structure Packet */ |
123 | {7, {0x02, 0xc8, 1, 2, 3, 4, 5}, 0, {INTEL_PT_VMCS, 5, 0x504030201}, 0, 0 }, |
124 | /* Overflow Packet */ |
125 | {2, {0x02, 0xf3}, 0, {INTEL_PT_OVF, 0, 0}, 0, 0 }, |
126 | {2, {0x02, 0xf3}, INTEL_PT_BLK_4_CTX, {INTEL_PT_OVF, 0, 0}, 0, 0 }, |
127 | {2, {0x02, 0xf3}, INTEL_PT_BLK_8_CTX, {INTEL_PT_OVF, 0, 0}, 0, 0 }, |
128 | /* Packet Stream Boundary*/ |
129 | {16, {0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82}, 0, {INTEL_PT_PSB, 0, 0}, 0, 0 }, |
130 | {16, {0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82}, INTEL_PT_BLK_4_CTX, {INTEL_PT_PSB, 0, 0}, 0, 0 }, |
131 | {16, {0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82}, INTEL_PT_BLK_8_CTX, {INTEL_PT_PSB, 0, 0}, 0, 0 }, |
132 | /* PSB End Packet */ |
133 | {2, {0x02, 0x23}, 0, {INTEL_PT_PSBEND, 0, 0}, 0, 0 }, |
134 | /* Maintenance Packet */ |
135 | {11, {0x02, 0xc3, 0x88, 1, 2, 3, 4, 5, 6, 7}, 0, {INTEL_PT_MNT, 0, 0x7060504030201}, 0, 1 }, |
136 | /* Write Data to PT Packet */ |
137 | {6, {0x02, 0x12, 1, 2, 3, 4}, 0, {INTEL_PT_PTWRITE, 0, 0x4030201}, 0, 0 }, |
138 | {10, {0x02, 0x32, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_PTWRITE, 1, 0x807060504030201}, 0, 0 }, |
139 | {6, {0x02, 0x92, 1, 2, 3, 4}, 0, {INTEL_PT_PTWRITE_IP, 0, 0x4030201}, 0, 0 }, |
140 | {10, {0x02, 0xb2, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_PTWRITE_IP, 1, 0x807060504030201}, 0, 0 }, |
141 | /* Execution Stop Packet */ |
142 | {2, {0x02, 0x62}, 0, {INTEL_PT_EXSTOP, 0, 0}, 0, 1 }, |
143 | {2, {0x02, 0xe2}, 0, {INTEL_PT_EXSTOP_IP, 0, 0}, 0, 1 }, |
144 | /* Monitor Wait Packet */ |
145 | {10, {0x02, 0xc2}, 0, {INTEL_PT_MWAIT, 0, 0}, 0, 0 }, |
146 | {10, {0x02, 0xc2, 1, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_MWAIT, 0, 0x807060504030201}, 0, 0 }, |
147 | {10, {0x02, 0xc2, 0xff, 2, 3, 4, 7, 6, 7, 8}, 0, {INTEL_PT_MWAIT, 0, 0x8070607040302ff}, 0, 0 }, |
148 | /* Power Entry Packet */ |
149 | {4, {0x02, 0x22}, 0, {INTEL_PT_PWRE, 0, 0}, 0, 1 }, |
150 | {4, {0x02, 0x22, 1, 2}, 0, {INTEL_PT_PWRE, 0, 0x0201}, 0, 1 }, |
151 | {4, {0x02, 0x22, 0x80, 0x34}, 0, {INTEL_PT_PWRE, 0, 0x3480}, 0, 1 }, |
152 | {4, {0x02, 0x22, 0x00, 0x56}, 0, {INTEL_PT_PWRE, 0, 0x5600}, 0, 1 }, |
153 | /* Power Exit Packet */ |
154 | {7, {0x02, 0xa2}, 0, {INTEL_PT_PWRX, 0, 0}, 0, 1 }, |
155 | {7, {0x02, 0xa2, 1, 2, 3, 4, 5}, 0, {INTEL_PT_PWRX, 0, 0x504030201}, 0, 1 }, |
156 | {7, {0x02, 0xa2, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, {INTEL_PT_PWRX, 0, 0xffffffffff}, 0, 1 }, |
157 | /* Block Begin Packet */ |
158 | {3, {0x02, 0x63, 0x00}, 0, {INTEL_PT_BBP, 0, 0}, INTEL_PT_BLK_8_CTX, 0 }, |
159 | {3, {0x02, 0x63, 0x80}, 0, {INTEL_PT_BBP, 1, 0}, INTEL_PT_BLK_4_CTX, 0 }, |
160 | {3, {0x02, 0x63, 0x1f}, 0, {INTEL_PT_BBP, 0, 0x1f}, INTEL_PT_BLK_8_CTX, 0 }, |
161 | {3, {0x02, 0x63, 0x9f}, 0, {INTEL_PT_BBP, 1, 0x1f}, INTEL_PT_BLK_4_CTX, 0 }, |
162 | /* 4-byte Block Item Packet */ |
163 | {5, {0x04}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0, 0}, INTEL_PT_BLK_4_CTX, 0 }, |
164 | {5, {0xfc}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0x1f, 0}, INTEL_PT_BLK_4_CTX, 0 }, |
165 | {5, {0x04, 1, 2, 3, 4}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0, 0x04030201}, INTEL_PT_BLK_4_CTX, 0 }, |
166 | {5, {0xfc, 1, 2, 3, 4}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BIP, 0x1f, 0x04030201}, INTEL_PT_BLK_4_CTX, 0 }, |
167 | /* 8-byte Block Item Packet */ |
168 | {9, {0x04}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0, 0}, INTEL_PT_BLK_8_CTX, 0 }, |
169 | {9, {0xfc}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0x1f, 0}, INTEL_PT_BLK_8_CTX, 0 }, |
170 | {9, {0x04, 1, 2, 3, 4, 5, 6, 7, 8}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0, 0x0807060504030201}, INTEL_PT_BLK_8_CTX, 0 }, |
171 | {9, {0xfc, 1, 2, 3, 4, 5, 6, 7, 8}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BIP, 0x1f, 0x0807060504030201}, INTEL_PT_BLK_8_CTX, 0 }, |
172 | /* Block End Packet */ |
173 | {2, {0x02, 0x33}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BEP, 0, 0}, 0, 0 }, |
174 | {2, {0x02, 0xb3}, INTEL_PT_BLK_4_CTX, {INTEL_PT_BEP_IP, 0, 0}, 0, 0 }, |
175 | {2, {0x02, 0x33}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BEP, 0, 0}, 0, 0 }, |
176 | {2, {0x02, 0xb3}, INTEL_PT_BLK_8_CTX, {INTEL_PT_BEP_IP, 0, 0}, 0, 0 }, |
177 | /* Control Flow Event Packet */ |
178 | {4, {0x02, 0x13, 0x01, 0x03}, 0, {INTEL_PT_CFE, 1, 3}, 0, 0 }, |
179 | {4, {0x02, 0x13, 0x81, 0x03}, 0, {INTEL_PT_CFE_IP, 1, 3}, 0, 0 }, |
180 | {4, {0x02, 0x13, 0x1f, 0x00}, 0, {INTEL_PT_CFE, 0x1f, 0}, 0, 0 }, |
181 | {4, {0x02, 0x13, 0x9f, 0xff}, 0, {INTEL_PT_CFE_IP, 0x1f, 0xff}, 0, 0 }, |
182 | /* */ |
183 | {11, {0x02, 0x53, 0x09, 1, 2, 3, 4, 5, 6, 7}, 0, {INTEL_PT_EVD, 0x09, 0x7060504030201}, 0, 0 }, |
184 | {11, {0x02, 0x53, 0x3f, 2, 3, 4, 5, 6, 7, 8}, 0, {INTEL_PT_EVD, 0x3f, 0x8070605040302}, 0, 0 }, |
185 | /* Terminator */ |
186 | {0, {0}, 0, {0, 0, 0}, 0, 0 }, |
187 | }; |
188 | |
189 | static int dump_packet(const struct intel_pt_pkt *packet, const u8 *bytes, int len) |
190 | { |
191 | char desc[INTEL_PT_PKT_DESC_MAX]; |
192 | int ret, i; |
193 | |
194 | for (i = 0; i < len; i++) |
195 | pr_debug(" %02x" , bytes[i]); |
196 | for (; i < INTEL_PT_PKT_MAX_SZ; i++) |
197 | pr_debug(" " ); |
198 | pr_debug(" " ); |
199 | ret = intel_pt_pkt_desc(packet, desc, INTEL_PT_PKT_DESC_MAX); |
200 | if (ret < 0) { |
201 | pr_debug("intel_pt_pkt_desc failed!\n" ); |
202 | return TEST_FAIL; |
203 | } |
204 | pr_debug("%s\n" , desc); |
205 | |
206 | return TEST_OK; |
207 | } |
208 | |
209 | static void decoding_failed(const struct test_data *d) |
210 | { |
211 | pr_debug("Decoding failed!\n" ); |
212 | pr_debug("Decoding: " ); |
213 | dump_packet(packet: &d->packet, bytes: d->bytes, len: d->len); |
214 | } |
215 | |
216 | static int fail(const struct test_data *d, struct intel_pt_pkt *packet, int len, |
217 | enum intel_pt_pkt_ctx new_ctx) |
218 | { |
219 | decoding_failed(d); |
220 | |
221 | if (len != d->len) |
222 | pr_debug("Expected length: %d Decoded length %d\n" , |
223 | d->len, len); |
224 | |
225 | if (packet->type != d->packet.type) |
226 | pr_debug("Expected type: %d Decoded type %d\n" , |
227 | d->packet.type, packet->type); |
228 | |
229 | if (packet->count != d->packet.count) |
230 | pr_debug("Expected count: %d Decoded count %d\n" , |
231 | d->packet.count, packet->count); |
232 | |
233 | if (packet->payload != d->packet.payload) |
234 | pr_debug("Expected payload: 0x%llx Decoded payload 0x%llx\n" , |
235 | (unsigned long long)d->packet.payload, |
236 | (unsigned long long)packet->payload); |
237 | |
238 | if (new_ctx != d->new_ctx) |
239 | pr_debug("Expected packet context: %d Decoded packet context %d\n" , |
240 | d->new_ctx, new_ctx); |
241 | |
242 | return TEST_FAIL; |
243 | } |
244 | |
245 | static int test_ctx_unchanged(const struct test_data *d, struct intel_pt_pkt *packet, |
246 | enum intel_pt_pkt_ctx ctx) |
247 | { |
248 | enum intel_pt_pkt_ctx old_ctx = ctx; |
249 | |
250 | intel_pt_upd_pkt_ctx(packet, &ctx); |
251 | |
252 | if (ctx != old_ctx) { |
253 | decoding_failed(d); |
254 | pr_debug("Packet context changed!\n" ); |
255 | return TEST_FAIL; |
256 | } |
257 | |
258 | return TEST_OK; |
259 | } |
260 | |
261 | static int test_one(const struct test_data *d) |
262 | { |
263 | struct intel_pt_pkt packet; |
264 | enum intel_pt_pkt_ctx ctx = d->ctx; |
265 | int ret; |
266 | |
267 | memset(&packet, 0xff, sizeof(packet)); |
268 | |
269 | /* Decode a packet */ |
270 | ret = intel_pt_get_packet(d->bytes, d->len, &packet, &ctx); |
271 | if (ret < 0 || ret > INTEL_PT_PKT_MAX_SZ) { |
272 | decoding_failed(d); |
273 | pr_debug("intel_pt_get_packet returned %d\n" , ret); |
274 | return TEST_FAIL; |
275 | } |
276 | |
277 | /* Some packets must always leave the packet context unchanged */ |
278 | if (d->ctx_unchanged) { |
279 | int err; |
280 | |
281 | err = test_ctx_unchanged(d, &packet, INTEL_PT_NO_CTX); |
282 | if (err) |
283 | return err; |
284 | err = test_ctx_unchanged(d, &packet, INTEL_PT_BLK_4_CTX); |
285 | if (err) |
286 | return err; |
287 | err = test_ctx_unchanged(d, &packet, INTEL_PT_BLK_8_CTX); |
288 | if (err) |
289 | return err; |
290 | } |
291 | |
292 | /* Compare to the expected values */ |
293 | if (ret != d->len || packet.type != d->packet.type || |
294 | packet.count != d->packet.count || |
295 | packet.payload != d->packet.payload || ctx != d->new_ctx) |
296 | return fail(d, packet: &packet, len: ret, new_ctx: ctx); |
297 | |
298 | pr_debug("Decoded ok:" ); |
299 | ret = dump_packet(packet: &d->packet, bytes: d->bytes, len: d->len); |
300 | |
301 | return ret; |
302 | } |
303 | |
304 | /* |
305 | * This test feeds byte sequences to the Intel PT packet decoder and checks the |
306 | * results. Changes to the packet context are also checked. |
307 | */ |
308 | int test__intel_pt_pkt_decoder(struct test_suite *test __maybe_unused, int subtest __maybe_unused) |
309 | { |
310 | const struct test_data *d = data; |
311 | int ret; |
312 | |
313 | for (d = data; d->len; d++) { |
314 | ret = test_one(d); |
315 | if (ret) |
316 | return ret; |
317 | } |
318 | |
319 | return TEST_OK; |
320 | } |
321 | |
322 | static int setaffinity(int cpu) |
323 | { |
324 | cpu_set_t cpu_set; |
325 | |
326 | CPU_ZERO(&cpu_set); |
327 | CPU_SET(cpu, &cpu_set); |
328 | if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set)) { |
329 | pr_debug("sched_setaffinity() failed for CPU %d\n" , cpu); |
330 | return -1; |
331 | } |
332 | return 0; |
333 | } |
334 | |
335 | #define INTEL_PT_ADDR_FILT_CNT_MASK GENMASK(2, 0) |
336 | #define INTEL_PT_SUBLEAF_CNT 2 |
337 | #define CPUID_REG_CNT 4 |
338 | |
339 | struct cpuid_result { |
340 | union { |
341 | struct { |
342 | unsigned int eax; |
343 | unsigned int ebx; |
344 | unsigned int ecx; |
345 | unsigned int edx; |
346 | }; |
347 | unsigned int reg[CPUID_REG_CNT]; |
348 | }; |
349 | }; |
350 | |
351 | struct pt_caps { |
352 | struct cpuid_result subleaf[INTEL_PT_SUBLEAF_CNT]; |
353 | }; |
354 | |
355 | static int get_pt_caps(int cpu, struct pt_caps *caps) |
356 | { |
357 | struct cpuid_result r; |
358 | int i; |
359 | |
360 | if (setaffinity(cpu)) |
361 | return -1; |
362 | |
363 | memset(caps, 0, sizeof(*caps)); |
364 | |
365 | for (i = 0; i < INTEL_PT_SUBLEAF_CNT; i++) { |
366 | __get_cpuid_count(20, i, &r.eax, &r.ebx, &r.ecx, &r.edx); |
367 | pr_debug("CPU %d CPUID leaf 20 subleaf %d\n" , cpu, i); |
368 | pr_debug("eax = 0x%08x\n" , r.eax); |
369 | pr_debug("ebx = 0x%08x\n" , r.ebx); |
370 | pr_debug("ecx = 0x%08x\n" , r.ecx); |
371 | pr_debug("edx = 0x%08x\n" , r.edx); |
372 | caps->subleaf[i] = r; |
373 | } |
374 | |
375 | return 0; |
376 | } |
377 | |
378 | static bool is_hydrid(void) |
379 | { |
380 | unsigned int eax, ebx, ecx, edx = 0; |
381 | bool result; |
382 | |
383 | __get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx); |
384 | result = edx & BIT(15); |
385 | pr_debug("Is %shybrid : CPUID leaf 7 subleaf 0 edx %#x (bit-15 indicates hybrid)\n" , |
386 | result ? "" : "not " , edx); |
387 | return result; |
388 | } |
389 | |
390 | static int compare_caps(int cpu, struct pt_caps *caps, struct pt_caps *caps0) |
391 | { |
392 | struct pt_caps mask = { /* Mask of bits to check*/ |
393 | .subleaf = { |
394 | [0] = { |
395 | .ebx = GENMASK(8, 0), |
396 | .ecx = GENMASK(3, 0), |
397 | }, |
398 | [1] = { |
399 | .eax = GENMASK(31, 16), |
400 | .ebx = GENMASK(31, 0), |
401 | } |
402 | } |
403 | }; |
404 | unsigned int m, reg, reg0; |
405 | int ret = 0; |
406 | int i, j; |
407 | |
408 | for (i = 0; i < INTEL_PT_SUBLEAF_CNT; i++) { |
409 | for (j = 0; j < CPUID_REG_CNT; j++) { |
410 | m = mask.subleaf[i].reg[j]; |
411 | reg = m & caps->subleaf[i].reg[j]; |
412 | reg0 = m & caps0->subleaf[i].reg[j]; |
413 | if ((reg & reg0) != reg0) { |
414 | pr_debug("CPU %d subleaf %d reg %d FAIL %#x vs %#x\n" , |
415 | cpu, i, j, reg, reg0); |
416 | ret = -1; |
417 | } |
418 | } |
419 | } |
420 | |
421 | m = INTEL_PT_ADDR_FILT_CNT_MASK; |
422 | reg = m & caps->subleaf[1].eax; |
423 | reg0 = m & caps0->subleaf[1].eax; |
424 | if (reg < reg0) { |
425 | pr_debug("CPU %d subleaf 1 reg 0 FAIL address filter count %#x vs %#x\n" , |
426 | cpu, reg, reg0); |
427 | ret = -1; |
428 | } |
429 | |
430 | if (!ret) |
431 | pr_debug("CPU %d OK\n" , cpu); |
432 | |
433 | return ret; |
434 | } |
435 | |
436 | int test__intel_pt_hybrid_compat(struct test_suite *test, int subtest) |
437 | { |
438 | int max_cpu = cpu__max_cpu().cpu; |
439 | struct pt_caps last_caps; |
440 | struct pt_caps caps0; |
441 | int ret = TEST_OK; |
442 | int cpu; |
443 | |
444 | if (!is_hydrid()) { |
445 | test->test_cases[subtest].skip_reason = "not hybrid" ; |
446 | return TEST_SKIP; |
447 | } |
448 | |
449 | if (get_pt_caps(0, &caps0)) |
450 | return TEST_FAIL; |
451 | |
452 | for (cpu = 1, last_caps = caps0; cpu < max_cpu; cpu++) { |
453 | struct pt_caps caps; |
454 | |
455 | if (get_pt_caps(cpu, caps: &caps)) { |
456 | pr_debug("CPU %d not found\n" , cpu); |
457 | continue; |
458 | } |
459 | if (!memcmp(&caps, &last_caps, sizeof(caps))) { |
460 | pr_debug("CPU %d same caps as previous CPU\n" , cpu); |
461 | continue; |
462 | } |
463 | if (compare_caps(cpu, &caps, &caps0)) |
464 | ret = TEST_FAIL; |
465 | last_caps = caps; |
466 | } |
467 | |
468 | return ret; |
469 | } |
470 | |