1 /*
2 * Copyright(c) 2021-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include <setjmp.h>
25 #include <signal.h>
26
27 int err;
28
29 #include "hex_test.h"
30
satub(int32_t src,int32_t * p,bool * ovf_result)31 static int32_t satub(int32_t src, int32_t *p, bool *ovf_result)
32 {
33 int32_t result;
34 uint32_t usr;
35
36 /*
37 * This instruction can set bit 0 (OVF/overflow) in usr
38 * Clear the bit first, then return that bit to the caller
39 *
40 * We also store the src into *p in the same packet, so we
41 * can ensure the overflow doesn't get set when an exception
42 * is generated.
43 */
44 asm volatile("r2 = usr\n\t"
45 "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
46 "usr = r2\n\t"
47 "{\n\t"
48 " %0 = satub(%2)\n\t"
49 " memw(%3) = %2\n\t"
50 "}\n\t"
51 "%1 = usr\n\t"
52 : "=r"(result), "=r"(usr)
53 : "r"(src), "r"(p)
54 : "r2", "usr", "memory");
55 *ovf_result = (usr & 1);
56 return result;
57 }
58
read_usr_overflow(void)59 bool read_usr_overflow(void)
60 {
61 uint32_t usr;
62 asm volatile("%0 = usr\n\t" : "=r"(usr));
63 return usr & 1;
64 }
65
get_usr_overflow(uint32_t usr)66 bool get_usr_overflow(uint32_t usr)
67 {
68 return usr & 1;
69 }
70
get_usr_fp_invalid(uint32_t usr)71 bool get_usr_fp_invalid(uint32_t usr)
72 {
73 return (usr >> 1) & 1;
74 }
75
get_usr_lpcfg(uint32_t usr)76 int32_t get_usr_lpcfg(uint32_t usr)
77 {
78 return (usr >> 8) & 0x3;
79 }
80
81 jmp_buf jmp_env;
82 bool usr_overflow;
83
sig_segv(int sig,siginfo_t * info,void * puc)84 static void sig_segv(int sig, siginfo_t *info, void *puc)
85 {
86 usr_overflow = read_usr_overflow();
87 longjmp(jmp_env, 1);
88 }
89
test_packet(void)90 static void test_packet(void)
91 {
92 int32_t convres;
93 int32_t satres;
94 uint32_t usr;
95
96 asm("r2 = usr\n\t"
97 "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
98 "r2 = clrbit(r2, #1)\n\t" /* clear FP invalid bit */
99 "usr = r2\n\t"
100 "{\n\t"
101 " %0 = convert_sf2uw(%3):chop\n\t"
102 " %1 = satb(%4)\n\t"
103 "}\n\t"
104 "%2 = usr\n\t"
105 : "=r"(convres), "=r"(satres), "=r"(usr)
106 : "r"(0x6a051b86), "r"(0x0410eec0)
107 : "r2", "usr");
108
109 check32(convres, 0xffffffff);
110 check32(satres, 0x7f);
111 check32(get_usr_overflow(usr), true);
112 check32(get_usr_fp_invalid(usr), true);
113
114 asm("r2 = usr\n\t"
115 "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
116 "usr = r2\n\t"
117 "%2 = r2\n\t"
118 "p3 = sp3loop0(1f, #1)\n\t"
119 "1:\n\t"
120 "{\n\t"
121 " %0 = satb(%2)\n\t"
122 "}:endloop0\n\t"
123 "%1 = usr\n\t"
124 : "=r"(satres), "=r"(usr)
125 : "r"(0x0410eec0)
126 : "r2", "usr", "p3", "sa0", "lc0");
127
128 check32(satres, 0x7f);
129 check32(get_usr_overflow(usr), true);
130 check32(get_usr_lpcfg(usr), 2);
131 }
132
main()133 int main()
134 {
135 struct sigaction act;
136 bool ovf;
137
138 /* SIGSEGV test */
139 act.sa_sigaction = sig_segv;
140 sigemptyset(&act.sa_mask);
141 act.sa_flags = SA_SIGINFO;
142 sigaction(SIGSEGV, &act, NULL);
143 if (setjmp(jmp_env) == 0) {
144 satub(300, 0, &ovf);
145 }
146
147 act.sa_handler = SIG_DFL;
148 sigemptyset(&act.sa_mask);
149 act.sa_flags = 0;
150
151 check32(usr_overflow, false);
152
153 test_packet();
154
155 puts(err ? "FAIL" : "PASS");
156 return err ? EXIT_FAILURE : EXIT_SUCCESS;
157 }
158