1 /*
2  *  RISC-V CPU init and loop
3  *
4  *  Copyright (c) 2019 Mark Corbin
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef TARGET_ARCH_CPU_H
21 #define TARGET_ARCH_CPU_H
22 
23 #include "target_arch.h"
24 #include "signal-common.h"
25 
26 #define TARGET_DEFAULT_CPU_MODEL "max"
27 
28 static inline void target_cpu_init(CPURISCVState *env,
29         struct target_pt_regs *regs)
30 {
31     int i;
32 
33     for (i = 1; i < 32; i++) {
34         env->gpr[i] = regs->regs[i];
35     }
36 
37     env->pc = regs->sepc;
38 }
39 
40 static inline void target_cpu_loop(CPURISCVState *env)
41 {
42     CPUState *cs = env_cpu(env);
43     int trapnr;
44     abi_long ret;
45     unsigned int syscall_num;
46     int32_t signo, code;
47 
48     for (;;) {
49         cpu_exec_start(cs);
50         trapnr = cpu_exec(cs);
51         cpu_exec_end(cs);
52         process_queued_cpu_work(cs);
53 
54         signo = 0;
55 
56         switch (trapnr) {
57         case EXCP_INTERRUPT:
58             /* just indicate that signals should be handled asap */
59             break;
60         case EXCP_ATOMIC:
61             cpu_exec_step_atomic(cs);
62             break;
63         case RISCV_EXCP_U_ECALL:
64             syscall_num = env->gpr[xT0];
65             env->pc += TARGET_INSN_SIZE;
66             /* Compare to cpu_fetch_syscall_args() in riscv/riscv/trap.c */
67             if (TARGET_FREEBSD_NR___syscall == syscall_num ||
68                 TARGET_FREEBSD_NR_syscall == syscall_num) {
69                 ret = do_freebsd_syscall(env,
70                                          env->gpr[xA0],
71                                          env->gpr[xA1],
72                                          env->gpr[xA2],
73                                          env->gpr[xA3],
74                                          env->gpr[xA4],
75                                          env->gpr[xA5],
76                                          env->gpr[xA6],
77                                          env->gpr[xA7],
78                                          0);
79             } else {
80                 ret = do_freebsd_syscall(env,
81                                          syscall_num,
82                                          env->gpr[xA0],
83                                          env->gpr[xA1],
84                                          env->gpr[xA2],
85                                          env->gpr[xA3],
86                                          env->gpr[xA4],
87                                          env->gpr[xA5],
88                                          env->gpr[xA6],
89                                          env->gpr[xA7]
90                     );
91             }
92 
93             /*
94              * Compare to cpu_set_syscall_retval() in
95              * riscv/riscv/vm_machdep.c
96              */
97             if (ret >= 0) {
98                 env->gpr[xA0] = ret;
99                 env->gpr[xT0] = 0;
100             } else if (ret == -TARGET_ERESTART) {
101                 env->pc -= TARGET_INSN_SIZE;
102             } else if (ret != -TARGET_EJUSTRETURN) {
103                 env->gpr[xA0] = -ret;
104                 env->gpr[xT0] = 1;
105             }
106             break;
107         case RISCV_EXCP_ILLEGAL_INST:
108             signo = TARGET_SIGILL;
109             code = TARGET_ILL_ILLOPC;
110             break;
111         case RISCV_EXCP_BREAKPOINT:
112             signo = TARGET_SIGTRAP;
113             code = TARGET_TRAP_BRKPT;
114             break;
115         case EXCP_DEBUG:
116             signo = TARGET_SIGTRAP;
117             code = TARGET_TRAP_BRKPT;
118             break;
119         default:
120             fprintf(stderr, "qemu: unhandled CPU exception "
121                 "0x%x - aborting\n", trapnr);
122             cpu_dump_state(cs, stderr, 0);
123             abort();
124         }
125 
126         if (signo) {
127             force_sig_fault(signo, code, env->pc);
128         }
129 
130         process_pending_signals(env);
131     }
132 }
133 
134 static inline void target_cpu_clone_regs(CPURISCVState *env, target_ulong newsp)
135 {
136     if (newsp) {
137         env->gpr[xSP] = newsp;
138     }
139 
140     env->gpr[xA0] = 0;
141     env->gpr[xT0] = 0;
142 }
143 
144 static inline void target_cpu_reset(CPUArchState *env)
145 {
146 }
147 
148 #endif /* TARGET_ARCH_CPU_H */
149