1// SPDX-License-Identifier: GPL-2.0
2
3#include <linux/bpf.h>
4#include <bpf/bpf_helpers.h>
5#include "bpf_misc.h"
6
7#if (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \
8     (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && __clang_major__ >= 18
9
10SEC("socket")
11__description("MOV32SX, S8")
12__success __success_unpriv __retval(0x23)
13__naked void mov32sx_s8(void)
14{
15	asm volatile ("					\
16	w0 = 0xff23;					\
17	w0 = (s8)w0;					\
18	exit;						\
19"	::: __clobber_all);
20}
21
22SEC("socket")
23__description("MOV32SX, S16")
24__success __success_unpriv __retval(0xFFFFff23)
25__naked void mov32sx_s16(void)
26{
27	asm volatile ("					\
28	w0 = 0xff23;					\
29	w0 = (s16)w0;					\
30	exit;						\
31"	::: __clobber_all);
32}
33
34SEC("socket")
35__description("MOV64SX, S8")
36__success __success_unpriv __retval(-2)
37__naked void mov64sx_s8(void)
38{
39	asm volatile ("					\
40	r0 = 0x1fe;					\
41	r0 = (s8)r0;					\
42	exit;						\
43"	::: __clobber_all);
44}
45
46SEC("socket")
47__description("MOV64SX, S16")
48__success __success_unpriv __retval(0xf23)
49__naked void mov64sx_s16(void)
50{
51	asm volatile ("					\
52	r0 = 0xf0f23;					\
53	r0 = (s16)r0;					\
54	exit;						\
55"	::: __clobber_all);
56}
57
58SEC("socket")
59__description("MOV64SX, S32")
60__success __success_unpriv __retval(-1)
61__naked void mov64sx_s32(void)
62{
63	asm volatile ("					\
64	r0 = 0xfffffffe;				\
65	r0 = (s32)r0;					\
66	r0 >>= 1;					\
67	exit;						\
68"	::: __clobber_all);
69}
70
71SEC("socket")
72__description("MOV32SX, S8, range_check")
73__success __success_unpriv __retval(1)
74__naked void mov32sx_s8_range(void)
75{
76	asm volatile ("					\
77	call %[bpf_get_prandom_u32];			\
78	w1 = (s8)w0;					\
79	/* w1 with s8 range */				\
80	if w1 s> 0x7f goto l0_%=;			\
81	if w1 s< -0x80 goto l0_%=;			\
82	r0 = 1;						\
83l1_%=:							\
84	exit;						\
85l0_%=:							\
86	r0 = 2;						\
87	goto l1_%=;					\
88"	:
89	: __imm(bpf_get_prandom_u32)
90	: __clobber_all);
91}
92
93SEC("socket")
94__description("MOV32SX, S16, range_check")
95__success __success_unpriv __retval(1)
96__naked void mov32sx_s16_range(void)
97{
98	asm volatile ("					\
99	call %[bpf_get_prandom_u32];			\
100	w1 = (s16)w0;					\
101	/* w1 with s16 range */				\
102	if w1 s> 0x7fff goto l0_%=;			\
103	if w1 s< -0x80ff goto l0_%=;			\
104	r0 = 1;						\
105l1_%=:							\
106	exit;						\
107l0_%=:							\
108	r0 = 2;						\
109	goto l1_%=;					\
110"	:
111	: __imm(bpf_get_prandom_u32)
112	: __clobber_all);
113}
114
115SEC("socket")
116__description("MOV32SX, S16, range_check 2")
117__success __success_unpriv __retval(1)
118__naked void mov32sx_s16_range_2(void)
119{
120	asm volatile ("					\
121	r1 = 65535;					\
122	w2 = (s16)w1;					\
123	r2 >>= 1;					\
124	if r2 != 0x7fffFFFF goto l0_%=;			\
125	r0 = 1;						\
126l1_%=:							\
127	exit;						\
128l0_%=:							\
129	r0 = 0;						\
130	goto l1_%=;					\
131"	:
132	: __imm(bpf_get_prandom_u32)
133	: __clobber_all);
134}
135
136SEC("socket")
137__description("MOV64SX, S8, range_check")
138__success __success_unpriv __retval(1)
139__naked void mov64sx_s8_range(void)
140{
141	asm volatile ("					\
142	call %[bpf_get_prandom_u32];			\
143	r1 = (s8)r0;					\
144	/* r1 with s8 range */				\
145	if r1 s> 0x7f goto l0_%=;			\
146	if r1 s< -0x80 goto l0_%=;			\
147	r0 = 1;						\
148l1_%=:							\
149	exit;						\
150l0_%=:							\
151	r0 = 2;						\
152	goto l1_%=;					\
153"	:
154	: __imm(bpf_get_prandom_u32)
155	: __clobber_all);
156}
157
158SEC("socket")
159__description("MOV64SX, S16, range_check")
160__success __success_unpriv __retval(1)
161__naked void mov64sx_s16_range(void)
162{
163	asm volatile ("					\
164	call %[bpf_get_prandom_u32];			\
165	r1 = (s16)r0;					\
166	/* r1 with s16 range */				\
167	if r1 s> 0x7fff goto l0_%=;			\
168	if r1 s< -0x8000 goto l0_%=;			\
169	r0 = 1;						\
170l1_%=:							\
171	exit;						\
172l0_%=:							\
173	r0 = 2;						\
174	goto l1_%=;					\
175"	:
176	: __imm(bpf_get_prandom_u32)
177	: __clobber_all);
178}
179
180SEC("socket")
181__description("MOV64SX, S32, range_check")
182__success __success_unpriv __retval(1)
183__naked void mov64sx_s32_range(void)
184{
185	asm volatile ("					\
186	call %[bpf_get_prandom_u32];			\
187	r1 = (s32)r0;					\
188	/* r1 with s32 range */				\
189	if r1 s> 0x7fffffff goto l0_%=;			\
190	if r1 s< -0x80000000 goto l0_%=;		\
191	r0 = 1;						\
192l1_%=:							\
193	exit;						\
194l0_%=:							\
195	r0 = 2;						\
196	goto l1_%=;					\
197"	:
198	: __imm(bpf_get_prandom_u32)
199	: __clobber_all);
200}
201
202SEC("socket")
203__description("MOV64SX, S16, R10 Sign Extension")
204__failure __msg("R1 type=scalar expected=fp, pkt, pkt_meta, map_key, map_value, mem, ringbuf_mem, buf, trusted_ptr_")
205__failure_unpriv __msg_unpriv("R10 sign-extension part of pointer")
206__naked void mov64sx_s16_r10(void)
207{
208	asm volatile ("					\
209	r1 = 553656332;					\
210	*(u32 *)(r10 - 8) = r1; 			\
211	r1 = (s16)r10;					\
212	r1 += -8;					\
213	r2 = 3;						\
214	if r2 <= r1 goto l0_%=;				\
215l0_%=:							\
216	call %[bpf_trace_printk];			\
217	r0 = 0;						\
218	exit;						\
219"	:
220	: __imm(bpf_trace_printk)
221	: __clobber_all);
222}
223
224#else
225
226SEC("socket")
227__description("cpuv4 is not supported by compiler or jit, use a dummy test")
228__success
229int dummy_test(void)
230{
231	return 0;
232}
233
234#endif
235
236char _license[] SEC("license") = "GPL";
237