1 /*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 /* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
26
27 /* Needed early for CONFIG_BSD etc. */
28 #include "config-host.h"
29 #include "sysemu/sysemu.h"
30 #include "sysemu/cpus.h"
31 #include "qemu/thread.h"
32
33 #include "exec/address-spaces.h" // debug, can be removed later
34
35 #include "uc_priv.h"
36
37 static bool cpu_can_run(CPUState *cpu);
38 static void cpu_handle_guest_debug(CPUState *cpu);
39 static int tcg_cpu_exec(struct uc_struct *uc, CPUArchState *env);
40 static bool tcg_exec_all(struct uc_struct* uc);
41 static int qemu_tcg_init_vcpu(CPUState *cpu);
42 static void qemu_tcg_cpu_loop(struct uc_struct *uc);
43
vm_start(struct uc_struct * uc)44 int vm_start(struct uc_struct* uc)
45 {
46 if (resume_all_vcpus(uc)) {
47 return -1;
48 }
49 return 0;
50 }
51
cpu_is_stopped(CPUState * cpu)52 bool cpu_is_stopped(CPUState *cpu)
53 {
54 return cpu->stopped;
55 }
56
run_on_cpu(CPUState * cpu,void (* func)(void * data),void * data)57 void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
58 {
59 func(data);
60 }
61
resume_all_vcpus(struct uc_struct * uc)62 int resume_all_vcpus(struct uc_struct *uc)
63 {
64 CPUState *cpu = uc->cpu;
65 // Fix call multiple time (vu).
66 // We have to check whether this is the second time, then reset all CPU.
67 if (!cpu->created) {
68 cpu->created = true;
69 cpu->halted = 0;
70 if (qemu_init_vcpu(cpu))
71 return -1;
72 }
73
74 cpu->exit_request = 0;
75
76 //qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
77 cpu_resume(cpu);
78 qemu_tcg_cpu_loop(uc);
79
80 return 0;
81 }
82
qemu_init_vcpu(CPUState * cpu)83 int qemu_init_vcpu(CPUState *cpu)
84 {
85 cpu->nr_cores = smp_cores;
86 cpu->nr_threads = smp_threads;
87 cpu->stopped = true;
88
89 if (tcg_enabled(cpu->uc))
90 return qemu_tcg_init_vcpu(cpu);
91
92 return 0;
93 }
94
qemu_tcg_cpu_loop(struct uc_struct * uc)95 static void qemu_tcg_cpu_loop(struct uc_struct *uc)
96 {
97 CPUState *cpu = uc->cpu;
98
99 //qemu_tcg_init_cpu_signals();
100
101 cpu->created = true;
102
103 while (1) {
104 if (tcg_exec_all(uc))
105 break;
106 }
107
108 cpu->created = false;
109 }
110
qemu_tcg_init_vcpu(CPUState * cpu)111 static int qemu_tcg_init_vcpu(CPUState *cpu)
112 {
113 tcg_cpu_address_space_init(cpu, cpu->as);
114
115 return 0;
116 }
117
tcg_cpu_exec(struct uc_struct * uc,CPUArchState * env)118 static int tcg_cpu_exec(struct uc_struct *uc, CPUArchState *env)
119 {
120 return cpu_exec(uc, env);
121 }
122
tcg_exec_all(struct uc_struct * uc)123 static bool tcg_exec_all(struct uc_struct* uc)
124 {
125 int r;
126 bool finish = false;
127 while (!uc->exit_request) {
128 CPUState *cpu = uc->cpu;
129 CPUArchState *env = cpu->env_ptr;
130
131 //qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
132 // (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
133 if (cpu_can_run(cpu)) {
134 uc->quit_request = false;
135 r = tcg_cpu_exec(uc, env);
136
137 // quit current TB but continue emulating?
138 if (uc->quit_request) {
139 // reset stop_request
140 uc->stop_request = false;
141 } else if (uc->stop_request) {
142 //printf(">>> got STOP request!!!\n");
143 finish = true;
144 break;
145 }
146
147 // save invalid memory access error & quit
148 if (env->invalid_error) {
149 // printf(">>> invalid memory accessed, STOP = %u!!!\n", env->invalid_error);
150 uc->invalid_addr = env->invalid_addr;
151 uc->invalid_error = env->invalid_error;
152 finish = true;
153 break;
154 }
155
156 // printf(">>> stop with r = %x, HLT=%x\n", r, EXCP_HLT);
157 if (r == EXCP_DEBUG) {
158 cpu_handle_guest_debug(cpu);
159 break;
160 }
161 if (r == EXCP_HLT) {
162 //printf(">>> got HLT!!!\n");
163 finish = true;
164 break;
165 }
166 } else if (cpu->stop || cpu->stopped) {
167 // printf(">>> got stopped!!!\n");
168 break;
169 }
170 }
171 uc->exit_request = 0;
172
173 return finish;
174 }
175
cpu_can_run(CPUState * cpu)176 static bool cpu_can_run(CPUState *cpu)
177 {
178 if (cpu->stop) {
179 return false;
180 }
181 if (cpu_is_stopped(cpu)) {
182 return false;
183 }
184 return true;
185 }
186
cpu_handle_guest_debug(CPUState * cpu)187 static void cpu_handle_guest_debug(CPUState *cpu)
188 {
189 cpu->stopped = true;
190 }
191
192 #if 0
193 #ifndef _WIN32
194 static void qemu_tcg_init_cpu_signals(void)
195 {
196 sigset_t set;
197 struct sigaction sigact;
198
199 memset(&sigact, 0, sizeof(sigact));
200 sigact.sa_handler = cpu_signal;
201 sigaction(SIG_IPI, &sigact, NULL);
202
203 sigemptyset(&set);
204 sigaddset(&set, SIG_IPI);
205 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
206 }
207 #else /* _WIN32 */
208 static void qemu_tcg_init_cpu_signals(void)
209 {
210 }
211 #endif /* _WIN32 */
212 #endif
213
214