1/*
2 * Copyright (c) 2024 CISPA Helmholtz Center for Information Security
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <zephyr/toolchain.h>
8
9GTEXT(_riscv_edge_case_cb_trigger_backward)
10
11/*
12 * Tests that jumping 256 bytes (the maximum) backwards
13 * using CB-type instruction is feasible
14 */
15SECTION_FUNC(TEXT, _riscv_edge_case_cb_trigger_backward)
16    /*
17     * tentative fail
18     * this needs precise alignment - need explicit compressed instructions
19     */
20    addi a0, zero, 0
21    c.j _do_jump
22
23_backward_jump_target:
24
25    /*
26     * we need to force RISC-V compressed instructions for alignment
27     * this directive is standard in RISC-V, i.e., not toolchain-specific
28     */
29    .option push
30    .option rvc
31
32    /* we made it to the correct target - success, return true */
33    c.addi a0, 0x1
34    /* explicit compressed return */
35    c.jr ra
36
37
38    /*
39     * we need a distance of 256 bytes between _do_jump and _backward_jump_target to trigger
40     * the edge case (max jump distance for c.beqz)
41     * _backward_jump_target itself needs 4 bytes (two compressed instructions)
42     * so we need to insert 252 additional padding bytes
43     * we pad with return instructions here, causing the test to return 0 (failure)
44     */
45    .rept 126
46        /* explicit compressed return - 2 bytes */
47        c.jr ra
48    .endr
49
50_do_jump:
51    /* jump precisely 256 bytes, the maximum distance, backwards */
52    c.beqz a0, _backward_jump_target
53
54    /*
55     * in case we erroneously jump FORWARD instead of backwards,
56     * the jump ends in the following return sled and we return 0
57     * this indicates test failure
58     * note that maximum distance for jump forwards is 254 bytes,
59     * which is also the size of this sled
60     */
61    .rept 127
62        /* explicit compressed return - 2 bytes */
63        c.jr ra
64    .endr
65
66    /* assembler can decide whether to emit compressed instructions */
67    .option pop
68
69GTEXT(_riscv_edge_case_cb_trigger_forward)
70
71/*
72 * Tests that jumping 256 bytes (the maximum) forwards
73 * using CB-type instruction is feasible
74 */
75SECTION_FUNC(TEXT, _riscv_edge_case_cb_trigger_forward)
76    j _test_start
77
78    /* we need to force RISC-V compressed instructions for alignment */
79    .option push
80    .option rvc
81
82    /*
83     * in case the relocation is incorrect and the c.beqz jumps BACKWARDS,
84     * e.g., after arithmetic overflow, we jump into the following return sled
85     * the return sled is 256 bytes long, covering the maximum backward jump
86     */
87    .rept 128
88        /* explicit compressed return - 2 bytes */
89        c.jr ra
90    .endr
91
92_test_start:
93    /* tentative fail */
94    addi a0, zero, 0
95
96    /*
97     * jump precisely 254 bytes, the maximum distance, forwards
98     * in case the relocation is applied incorrectly, we jump into the padding bytes
99     * this causes test failure
100     * we cannot jump too far forwards, 254 bytes is the maximum distance
101     */
102    c.beqz a0, _forward_jump_target
103
104    /*
105     * need to insert 252 padding bytes to pad to 254 byte jump
106     * we pad with return instructions here, causing the test to return 0 (failure)
107     */
108    .rept 126
109        /* explicit compressed return - 2 bytes */
110        c.jr ra
111    .endr
112
113    /* assembler can decide whether to emit compressed instructions */
114    .option pop
115
116_forward_jump_target:
117    /* we made it to the correct target - success, return true */
118    li a0, 1
119    /* should not be reached - causes return false */
120    ret
121