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