cavatools: initialize repository
[cavatools.git] / caveat / ecall.c
1 #include <unistd.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <sys/mman.h>
8 #include <sys/syscall.h>
9 #include <sys/utsname.h>
10 #include <math.h>
11 #include <string.h>
12
13 //#include "encoding.h"
14
15 //#define NO_FP_MACROS
16 #include "caveat_fp.h"
17 #include "arith.h"
18
19 #include "caveat.h"
20 #include "opcodes.h"
21 #include "insn.h"
22 #include "shmfifo.h"
23 #include "core.h"
24 #include "riscv-opc.h"
25 #include "ecall_nums.h"
26
27 //#define DEBUG
28
29
30 static Addr_t emulate_brk(Addr_t addr, struct pinfo_t* info)
31 {
32 Addr_t newbrk = addr;
33 if (addr < info->brk_min)
34 newbrk = info->brk_min;
35 else if (addr > info->brk_max)
36 newbrk = info->brk_max;
37
38 if (info->brk == 0)
39 info->brk = ROUNDUP(info->brk_min, RISCV_PGSIZE);
40
41 uintptr_t newbrk_page = ROUNDUP(newbrk, RISCV_PGSIZE);
42 if (info->brk > newbrk_page)
43 munmap((void*)newbrk_page, info->brk - newbrk_page);
44 else if (info->brk < newbrk_page)
45 assert(mmap((void*)info->brk, newbrk_page - info->brk, -1, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) == (void*)info->brk);
46 info->brk = newbrk_page;
47
48 return newbrk;
49 }
50
51
52 int proxy_ecall( struct core_t* cpu )
53 {
54 static long previous =0;
55 assert(insn(cpu->pc)->op_code == Op_ecall);
56 long rvnum = cpu->reg[17].l;
57 if (rvnum < 0 || rvnum >= rv_syscall_entries) {
58 no_mapping:
59 fprintf(stderr, "RISC-V system call %ld has no mapping to host system\n", rvnum);
60 fprintf(stderr, "Arguments(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
61 cpu->reg[10].l, cpu->reg[11].l, cpu->reg[12].l, cpu->reg[13].l, cpu->reg[14].l, cpu->reg[15].l);
62 abort();
63 }
64 long sysnum = rv_to_host[rvnum].sysnum;
65 #ifdef DEBUG
66 fprintf(stderr, "%10ld: %s[%ld:%ld](%lx, %lx, %lx, %lx, %lx, %lx)", cpu->counter.insn_executed-previous,
67 rv_to_host[rvnum].name, rvnum, sysnum,
68 cpu->reg[10].l, cpu->reg[11].l, cpu->reg[12].l, cpu->reg[13].l, cpu->reg[14].l, cpu->reg[15].l);
69 previous = cpu->counter.insn_executed;
70 #endif
71 switch (sysnum) {
72 case -1:
73 goto no_mapping;
74 case -2:
75 fprintf(stderr, "RISCV-V system call %s(#%ld) not supported on host system\n", rv_to_host[rvnum].name, sysnum);
76 abort();
77
78 #if 0
79 case 12: /* sys_brk */
80 cpu->reg[10].l = emulate_brk(cpu->reg[10].l, &current);
81 break;
82 #endif
83
84 case 60: /* sys_exit */
85 case 231: /* sys_exit_group */\
86 return 1;
87
88 case 13: /* sys_rt_sigaction */
89 fprintf(stderr, "Trying to call rt_sigaction, always succeed without error.\n");
90 cpu->reg[10].l = 0; // always succeed without error
91 break;
92
93 case 56: /* sys_clone */
94 abort();
95
96 case 96: /* gettimeofday */
97 #define PRETEND_MIPS 1000
98 #ifdef PRETEND_MIPS
99 {
100 struct timeval tv;
101 tv.tv_sec = (cpu->counter.insn_executed / PRETEND_MIPS) / 1000000;
102 tv.tv_usec = (cpu->counter.insn_executed / PRETEND_MIPS) % 1000000;
103 tv.tv_sec += cpu->counter.start_timeval.tv_sec;
104 tv.tv_usec += cpu->counter.start_timeval.tv_usec;
105 tv.tv_sec += tv.tv_usec / 1000000; // microseconds overflow
106 tv.tv_usec %= 1000000;
107 // fprintf(stderr, "gettimeofday(sec=%ld, usec=%4ld)\n", tv.tv_sec, tv.tv_usec);
108 memcpy(cpu->reg[10].p, &tv, sizeof tv);
109 cpu->reg[10].l = 0;
110 }
111 break;
112 #else
113 goto default_case;
114 #endif
115
116 case 3: /* sys_close */
117 if (cpu->reg[10].l <= 2) { // Don't close stdin, stdout, stderr
118 cpu->reg[10].l = 0;
119 break;
120 }
121 goto default_case;
122
123 default:
124 default_case:
125 cpu->reg[10].l = syscall(sysnum, cpu->reg[10].l, cpu->reg[11].l, cpu->reg[12].l, cpu->reg[13].l, cpu->reg[14].l, cpu->reg[15].l);
126 break;
127 }
128 #ifdef DEBUG
129 fprintf(stderr, " return %lx\n", cpu->reg[10].l);
130 #endif
131 return 0;
132 }
133
134
135 static void set_csr( struct core_t* cpu, int which, long val )
136 {
137 switch (which) {
138 case CSR_USTATUS:
139 cpu->state.ustatus = val;
140 return;
141 case CSR_FFLAGS:
142 cpu->state.fcsr.flags = val;
143 #ifdef SOFT_FP
144 softfloat_exceptionFlags = val;
145 #else
146 #endif
147 return;
148 case CSR_FRM:
149 cpu->state.fcsr.rmode = val;
150 break;
151 case CSR_FCSR:
152 cpu->state.fcsr_v = val;
153 break;
154 default:
155 fprintf(stderr, "Unsupported set_csr(%d, val=%lx)\n", which, val);
156 abort();
157 }
158 #ifdef SOFT_FP
159 softfloat_roundingMode = cpu->state.fcsr.rmode;
160 #else
161 fesetround(riscv_to_c_rm(cpu->state.fcsr.rmode));
162 #endif
163 }
164
165 static long get_csr( struct core_t* cpu, int which )
166 {
167 switch (which) {
168 case CSR_USTATUS:
169 return cpu->state.ustatus;
170 case CSR_FFLAGS:
171 #ifdef SOFT_FP
172 cpu->state.fcsr.flags = softfloat_exceptionFlags;
173 #else
174 #endif
175 return cpu->state.fcsr.flags;
176 case CSR_FRM:
177 return cpu->state.fcsr.rmode;
178 case CSR_FCSR:
179 return cpu->state.fcsr_v;
180 default:
181 fprintf(stderr, "Unsupported get_csr(%d)\n", which);
182 abort();
183 }
184 }
185
186 void proxy_csr( struct core_t* cpu, const struct insn_t* p, int which )
187 {
188 enum Opcode_t op = p->op_code;
189 int regop = op==Op_csrrw || op==Op_csrrs || op==Op_csrrc;
190 long old_val = 0;
191 long value = regop ? p->op_rs1 : p->op_constant>>12;
192 if (op==Op_csrrw || op==Op_csrrwi) {
193 if (p->op_rd != 0)
194 old_val = get_csr(cpu, which);
195 set_csr(cpu, which, value);
196 }
197 else {
198 old_val = get_csr(cpu, which);
199 if (regop || value != 0) {
200 if (op==Op_csrrs || op==Op_csrrsi)
201 value = old_val | value;
202 else
203 value = old_val & ~value;
204 set_csr(cpu, which, value);
205 }
206 }
207 cpu->reg[p->op_rd].l = old_val;
208 }