xref: /openbmc/qemu/tests/tcg/hexagon/overflow.c (revision cc67f28e)
1 /*
2  *  Copyright(c) 2021 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 <unistd.h>
21 #include <sys/types.h>
22 #include <fcntl.h>
23 #include <setjmp.h>
24 #include <signal.h>
25 
26 
27 int err;
28 
29 static void __check(const char *filename, int line, int x, int expect)
30 {
31     if (x != expect) {
32         printf("ERROR %s:%d - %d != %d\n",
33                filename, line, x, expect);
34         err++;
35     }
36 }
37 
38 #define check(x, expect) __check(__FILE__, __LINE__, (x), (expect))
39 
40 static int satub(int src, int *p, int *ovf_result)
41 {
42     int result;
43     int usr;
44 
45     /*
46      * This instruction can set bit 0 (OVF/overflow) in usr
47      * Clear the bit first, then return that bit to the caller
48      *
49      * We also store the src into *p in the same packet, so we
50      * can ensure the overflow doesn't get set when an exception
51      * is generated.
52      */
53     asm volatile("r2 = usr\n\t"
54                  "r2 = clrbit(r2, #0)\n\t"        /* clear overflow bit */
55                  "usr = r2\n\t"
56                  "{\n\t"
57                  "    %0 = satub(%2)\n\t"
58                  "    memw(%3) = %2\n\t"
59                  "}\n\t"
60                  "%1 = usr\n\t"
61                  : "=r"(result), "=r"(usr)
62                  : "r"(src), "r"(p)
63                  : "r2", "usr", "memory");
64   *ovf_result = (usr & 1);
65   return result;
66 }
67 
68 int read_usr_overflow(void)
69 {
70     int result;
71     asm volatile("%0 = usr\n\t" : "=r"(result));
72     return result & 1;
73 }
74 
75 
76 jmp_buf jmp_env;
77 int usr_overflow;
78 
79 static void sig_segv(int sig, siginfo_t *info, void *puc)
80 {
81     usr_overflow = read_usr_overflow();
82     longjmp(jmp_env, 1);
83 }
84 
85 int main()
86 {
87     struct sigaction act;
88     int ovf;
89 
90     /* SIGSEGV test */
91     act.sa_sigaction = sig_segv;
92     sigemptyset(&act.sa_mask);
93     act.sa_flags = SA_SIGINFO;
94     sigaction(SIGSEGV, &act, NULL);
95     if (setjmp(jmp_env) == 0) {
96         satub(300, 0, &ovf);
97     }
98 
99     act.sa_handler = SIG_DFL;
100     sigemptyset(&act.sa_mask);
101     act.sa_flags = 0;
102 
103     check(usr_overflow, 0);
104 
105     puts(err ? "FAIL" : "PASS");
106     return err ? EXIT_FAILURE : EXIT_SUCCESS;
107 }
108