xref: /linux/tools/testing/selftests/bpf/progs/compute_live_registers.c (revision 0a91336e287ca2557fead5221d2c79e0effd034e)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/bpf.h>
4 #include <bpf/bpf_helpers.h>
5 #include "../../../include/linux/filter.h"
6 #include "bpf_arena_common.h"
7 #include "bpf_misc.h"
8 
9 struct {
10 	__uint(type, BPF_MAP_TYPE_ARRAY);
11 	__uint(max_entries, 1);
12 	__type(key, __u32);
13 	__type(value, __u64);
14 } test_map SEC(".maps");
15 
16 struct {
17 	__uint(type, BPF_MAP_TYPE_ARENA);
18 	__uint(map_flags, BPF_F_MMAPABLE);
19 	__uint(max_entries, 1);
20 } arena SEC(".maps");
21 
22 SEC("socket")
23 __log_level(2)
24 __msg(" 0: .......... (b7) r0 = 42")
25 __msg(" 1: 0......... (bf) r1 = r0")
26 __msg(" 2: .1........ (bf) r2 = r1")
27 __msg(" 3: ..2....... (bf) r3 = r2")
28 __msg(" 4: ...3...... (bf) r4 = r3")
29 __msg(" 5: ....4..... (bf) r5 = r4")
30 __msg(" 6: .....5.... (bf) r6 = r5")
31 __msg(" 7: ......6... (bf) r7 = r6")
32 __msg(" 8: .......7.. (bf) r8 = r7")
33 __msg(" 9: ........8. (bf) r9 = r8")
34 __msg("10: .........9 (bf) r0 = r9")
35 __msg("11: 0......... (95) exit")
assign_chain(void)36 __naked void assign_chain(void)
37 {
38 	asm volatile (
39 		"r0 = 42;"
40 		"r1 = r0;"
41 		"r2 = r1;"
42 		"r3 = r2;"
43 		"r4 = r3;"
44 		"r5 = r4;"
45 		"r6 = r5;"
46 		"r7 = r6;"
47 		"r8 = r7;"
48 		"r9 = r8;"
49 		"r0 = r9;"
50 		"exit;"
51 		::: __clobber_all);
52 }
53 
54 SEC("socket")
55 __log_level(2)
56 __msg("0: .......... (b7) r1 = 7")
57 __msg("1: .1........ (07) r1 += 7")
58 __msg("2: .......... (b7) r2 = 7")
59 __msg("3: ..2....... (b7) r3 = 42")
60 __msg("4: ..23...... (0f) r2 += r3")
61 __msg("5: .......... (b7) r0 = 0")
62 __msg("6: 0......... (95) exit")
arithmetics(void)63 __naked void arithmetics(void)
64 {
65 	asm volatile (
66 		"r1 = 7;"
67 		"r1 += 7;"
68 		"r2 = 7;"
69 		"r3 = 42;"
70 		"r2 += r3;"
71 		"r0 = 0;"
72 		"exit;"
73 		::: __clobber_all);
74 }
75 
76 #ifdef CAN_USE_BPF_ST
77 SEC("socket")
78 __log_level(2)
79 __msg("  1: .1........ (07) r1 += -8")
80 __msg("  2: .1........ (7a) *(u64 *)(r1 +0) = 7")
81 __msg("  3: .1........ (b7) r2 = 42")
82 __msg("  4: .12....... (7b) *(u64 *)(r1 +0) = r2")
83 __msg("  5: .12....... (7b) *(u64 *)(r1 +0) = r2")
84 __msg("  6: .......... (b7) r0 = 0")
store(void)85 __naked void store(void)
86 {
87 	asm volatile (
88 		"r1 = r10;"
89 		"r1 += -8;"
90 		"*(u64 *)(r1 +0) = 7;"
91 		"r2 = 42;"
92 		"*(u64 *)(r1 +0) = r2;"
93 		"*(u64 *)(r1 +0) = r2;"
94 		"r0 = 0;"
95 		"exit;"
96 		::: __clobber_all);
97 }
98 #endif
99 
100 SEC("socket")
101 __log_level(2)
102 __msg("1: ....4..... (07) r4 += -8")
103 __msg("2: ....4..... (79) r5 = *(u64 *)(r4 +0)")
104 __msg("3: ....45.... (07) r4 += -8")
load(void)105 __naked void load(void)
106 {
107 	asm volatile (
108 		"r4 = r10;"
109 		"r4 += -8;"
110 		"r5 = *(u64 *)(r4 +0);"
111 		"r4 += -8;"
112 		"r0 = r5;"
113 		"exit;"
114 		::: __clobber_all);
115 }
116 
117 SEC("socket")
118 __log_level(2)
119 __msg("0: .1........ (61) r2 = *(u32 *)(r1 +0)")
120 __msg("1: ..2....... (d4) r2 = le64 r2")
121 __msg("2: ..2....... (bf) r0 = r2")
endian(void)122 __naked void endian(void)
123 {
124 	asm volatile (
125 		"r2 = *(u32 *)(r1 +0);"
126 		"r2 = le64 r2;"
127 		"r0 = r2;"
128 		"exit;"
129 		::: __clobber_all);
130 }
131 
132 SEC("socket")
133 __log_level(2)
134 __msg(" 8: 0......... (b7) r1 = 1")
135 __msg(" 9: 01........ (db) r1 = atomic64_fetch_add((u64 *)(r0 +0), r1)")
136 __msg("10: 01........ (c3) lock *(u32 *)(r0 +0) += r1")
137 __msg("11: 01........ (db) r1 = atomic64_xchg((u64 *)(r0 +0), r1)")
138 __msg("12: 01........ (bf) r2 = r0")
139 __msg("13: .12....... (bf) r0 = r1")
140 __msg("14: 012....... (db) r0 = atomic64_cmpxchg((u64 *)(r2 +0), r0, r1)")
atomic(void)141 __naked void atomic(void)
142 {
143 	asm volatile (
144 		"r2 = r10;"
145 		"r2 += -8;"
146 		"r1 = 0;"
147 		"*(u64 *)(r2 +0) = r1;"
148 		"r1 = %[test_map] ll;"
149 		"call %[bpf_map_lookup_elem];"
150 		"if r0 == 0 goto 1f;"
151 		"r1 = 1;"
152 		"r1 = atomic_fetch_add((u64 *)(r0 +0), r1);"
153 		".8byte %[add_nofetch];" /* same as "lock *(u32 *)(r0 +0) += r1;" */
154 		"r1 = xchg_64(r0 + 0, r1);"
155 		"r2 = r0;"
156 		"r0 = r1;"
157 		"r0 = cmpxchg_64(r2 + 0, r0, r1);"
158 		"1: exit;"
159 		:
160 		: __imm(bpf_map_lookup_elem),
161 		  __imm_addr(test_map),
162 		  __imm_insn(add_nofetch, BPF_ATOMIC_OP(BPF_W, BPF_ADD, BPF_REG_0, BPF_REG_1, 0))
163 		: __clobber_all);
164 }
165 
166 #ifdef CAN_USE_LOAD_ACQ_STORE_REL
167 
168 SEC("socket")
169 __log_level(2)
170 __msg("2: .12....... (db) store_release((u64 *)(r2 -8), r1)")
171 __msg("3: .......... (bf) r3 = r10")
172 __msg("4: ...3...... (db) r4 = load_acquire((u64 *)(r3 -8))")
atomic_load_acq_store_rel(void)173 __naked void atomic_load_acq_store_rel(void)
174 {
175 	asm volatile (
176 		"r1 = 42;"
177 		"r2 = r10;"
178 		".8byte %[store_release_insn];" /* store_release((u64 *)(r2 - 8), r1); */
179 		"r3 = r10;"
180 		".8byte %[load_acquire_insn];" /* r4 = load_acquire((u64 *)(r3 + 0)); */
181 		"r0 = r4;"
182 		"exit;"
183 		:
184 		: __imm_insn(store_release_insn,
185 			     BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_2, BPF_REG_1, -8)),
186 		  __imm_insn(load_acquire_insn,
187 			     BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_4, BPF_REG_3, -8))
188 		: __clobber_all);
189 }
190 
191 #endif /* CAN_USE_LOAD_ACQ_STORE_REL */
192 
193 SEC("socket")
194 __log_level(2)
195 __msg("4: .12....7.. (85) call bpf_trace_printk#6")
196 __msg("5: 0......7.. (0f) r0 += r7")
regular_call(void)197 __naked void regular_call(void)
198 {
199 	asm volatile (
200 		"r7 = 1;"
201 		"r1 = r10;"
202 		"r1 += -8;"
203 		"r2 = 1;"
204 		"call %[bpf_trace_printk];"
205 		"r0 += r7;"
206 		"exit;"
207 		:
208 		: __imm(bpf_trace_printk)
209 		: __clobber_all);
210 }
211 
212 SEC("socket")
213 __log_level(2)
214 __msg("2: 012....... (25) if r1 > 0x7 goto pc+1")
215 __msg("3: ..2....... (bf) r0 = r2")
if1(void)216 __naked void if1(void)
217 {
218 	asm volatile (
219 		"r0 = 1;"
220 		"r2 = 2;"
221 		"if r1 > 0x7 goto +1;"
222 		"r0 = r2;"
223 		"exit;"
224 		::: __clobber_all);
225 }
226 
227 SEC("socket")
228 __log_level(2)
229 __msg("3: 0123...... (2d) if r1 > r3 goto pc+1")
230 __msg("4: ..2....... (bf) r0 = r2")
if2(void)231 __naked void if2(void)
232 {
233 	asm volatile (
234 		"r0 = 1;"
235 		"r2 = 2;"
236 		"r3 = 7;"
237 		"if r1 > r3 goto +1;"
238 		"r0 = r2;"
239 		"exit;"
240 		::: __clobber_all);
241 }
242 
243 /* Verifier misses that r2 is alive if jset is not handled properly */
244 SEC("socket")
245 __log_level(2)
246 __msg("2: 012....... (45) if r1 & 0x7 goto pc+1")
if3_jset_bug(void)247 __naked void if3_jset_bug(void)
248 {
249 	asm volatile (
250 		"r0 = 1;"
251 		"r2 = 2;"
252 		"if r1 & 0x7 goto +1;"
253 		"exit;"
254 		"r0 = r2;"
255 		"exit;"
256 		::: __clobber_all);
257 }
258 
259 SEC("socket")
260 __log_level(2)
261 __msg("0: .......... (b7) r1 = 0")
262 __msg("1: .1........ (b7) r2 = 7")
263 __msg("2: .12....... (25) if r1 > 0x7 goto pc+4")
264 __msg("3: .12....... (07) r1 += 1")
265 __msg("4: .12....... (27) r2 *= 2")
266 __msg("5: .12....... (05) goto pc+0")
267 __msg("6: .12....... (05) goto pc-5")
268 __msg("7: .......... (b7) r0 = 0")
269 __msg("8: 0......... (95) exit")
loop(void)270 __naked void loop(void)
271 {
272 	asm volatile (
273 		"r1 = 0;"
274 		"r2 = 7;"
275 		"if r1 > 0x7 goto +4;"
276 		"r1 += 1;"
277 		"r2 *= 2;"
278 		"goto +0;"
279 		"goto -5;"
280 		"r0 = 0;"
281 		"exit;"
282 		:
283 		: __imm(bpf_trace_printk)
284 		: __clobber_all);
285 }
286 
287 #ifdef CAN_USE_GOTOL
288 SEC("socket")
289 __log_level(2)
290 __msg("2: .123...... (25) if r1 > 0x7 goto pc+2")
291 __msg("3: ..2....... (bf) r0 = r2")
292 __msg("4: 0......... (06) gotol pc+1")
293 __msg("5: ...3...... (bf) r0 = r3")
294 __msg("6: 0......... (95) exit")
gotol(void)295 __naked void gotol(void)
296 {
297 	asm volatile (
298 		"r2 = 42;"
299 		"r3 = 24;"
300 		"if r1 > 0x7 goto +2;"
301 		"r0 = r2;"
302 		"gotol +1;"
303 		"r0 = r3;"
304 		"exit;"
305 		:
306 		: __imm(bpf_trace_printk)
307 		: __clobber_all);
308 }
309 #endif
310 
311 SEC("socket")
312 __log_level(2)
313 __msg("0: .......... (b7) r1 = 1")
314 __msg("1: .1........ (e5) may_goto pc+1")
315 __msg("2: .......... (05) goto pc-3")
316 __msg("3: .1........ (bf) r0 = r1")
317 __msg("4: 0......... (95) exit")
may_goto(void)318 __naked void may_goto(void)
319 {
320 	asm volatile (
321 	"1: r1 = 1;"
322 	".8byte %[may_goto];"
323 	"goto 1b;"
324 	"r0 = r1;"
325 	"exit;"
326 	:
327 	: __imm(bpf_get_smp_processor_id),
328 	  __imm_insn(may_goto, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, +1 /* offset */, 0))
329 	: __clobber_all);
330 }
331 
332 SEC("socket")
333 __log_level(2)
334 __msg("1: 0......... (18) r2 = 0x7")
335 __msg("3: 0.2....... (0f) r0 += r2")
ldimm64(void)336 __naked void ldimm64(void)
337 {
338 	asm volatile (
339 		"r0 = 0;"
340 		"r2 = 0x7 ll;"
341 		"r0 += r2;"
342 		"exit;"
343 		:
344 		:: __clobber_all);
345 }
346 
347 /* No rules specific for LD_ABS/LD_IND, default behaviour kicks in */
348 SEC("socket")
349 __log_level(2)
350 __msg("2: 0123456789 (30) r0 = *(u8 *)skb[42]")
351 __msg("3: 012.456789 (0f) r7 += r0")
352 __msg("4: 012.456789 (b7) r3 = 42")
353 __msg("5: 0123456789 (50) r0 = *(u8 *)skb[r3 + 0]")
354 __msg("6: 0......7.. (0f) r7 += r0")
ldabs(void)355 __naked void ldabs(void)
356 {
357 	asm volatile (
358 		"r6 = r1;"
359 		"r7 = 0;"
360 		"r0 = *(u8 *)skb[42];"
361 		"r7 += r0;"
362 		"r3 = 42;"
363 		".8byte %[ld_ind];" /* same as "r0 = *(u8 *)skb[r3];" */
364 		"r7 += r0;"
365 		"r0 = r7;"
366 		"exit;"
367 		:
368 		: __imm_insn(ld_ind, BPF_LD_IND(BPF_B, BPF_REG_3, 0))
369 		: __clobber_all);
370 }
371 
372 
373 #ifdef __BPF_FEATURE_ADDR_SPACE_CAST
374 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
375 __log_level(2)
376 __msg(" 6: .12345.... (85) call bpf_arena_alloc_pages")
377 __msg(" 7: 0......... (bf) r1 = addr_space_cast(r0, 0, 1)")
378 __msg(" 8: .1........ (b7) r2 = 42")
addr_space_cast(void)379 __naked void addr_space_cast(void)
380 {
381 	asm volatile (
382 		"r1 = %[arena] ll;"
383 		"r2 = 0;"
384 		"r3 = 1;"
385 		"r4 = 0;"
386 		"r5 = 0;"
387 		"call %[bpf_arena_alloc_pages];"
388 		"r1 = addr_space_cast(r0, 0, 1);"
389 		"r2 = 42;"
390 		"*(u64 *)(r1 +0) = r2;"
391 		"r0 = 0;"
392 		"exit;"
393 		:
394 		: __imm(bpf_arena_alloc_pages),
395 		  __imm_addr(arena)
396 		: __clobber_all);
397 }
398 #endif
399 
aux1(void)400 static __used __naked int aux1(void)
401 {
402 	asm volatile (
403 		"r0 = r1;"
404 		"r0 += r2;"
405 		"exit;"
406 		::: __clobber_all);
407 }
408 
409 SEC("socket")
410 __log_level(2)
411 __msg("0: ....45.... (b7) r1 = 1")
412 __msg("1: .1..45.... (b7) r2 = 2")
413 __msg("2: .12.45.... (b7) r3 = 3")
414 /* Conservative liveness for subprog parameters. */
415 __msg("3: .12345.... (85) call pc+2")
416 __msg("4: .......... (b7) r0 = 0")
417 __msg("5: 0......... (95) exit")
418 __msg("6: .12....... (bf) r0 = r1")
419 __msg("7: 0.2....... (0f) r0 += r2")
420 /* Conservative liveness for subprog return value. */
421 __msg("8: 0......... (95) exit")
subprog1(void)422 __naked void subprog1(void)
423 {
424 	asm volatile (
425 		"r1 = 1;"
426 		"r2 = 2;"
427 		"r3 = 3;"
428 		"call aux1;"
429 		"r0 = 0;"
430 		"exit;"
431 		::: __clobber_all);
432 }
433 
434 /* to retain debug info for BTF generation */
kfunc_root(void)435 void kfunc_root(void)
436 {
437 	bpf_arena_alloc_pages(0, 0, 0, 0, 0);
438 }
439 
440 char _license[] SEC("license") = "GPL";
441