blob: a7131379807f6e3f16a272d729d5052ef02181a8 [file] [log] [blame]
Alexander Graf14ade102013-09-03 20:12:10 +01001/*
2 * AArch64 translation
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24
25#include "cpu.h"
26#include "tcg-op.h"
27#include "qemu/log.h"
28#include "translate.h"
29#include "qemu/host-utils.h"
30
Peter Maydell089a8d92013-12-03 15:26:18 +000031#include "exec/gen-icount.h"
32
Alexander Graf14ade102013-09-03 20:12:10 +010033#include "helper.h"
34#define GEN_HELPER 1
35#include "helper.h"
36
37static TCGv_i64 cpu_X[32];
38static TCGv_i64 cpu_pc;
39static TCGv_i32 pstate;
40
41static const char *regnames[] = {
42 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
43 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
44 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
45 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
46};
47
48/* initialize TCG globals. */
49void a64_translate_init(void)
50{
51 int i;
52
53 cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
54 offsetof(CPUARMState, pc),
55 "pc");
56 for (i = 0; i < 32; i++) {
57 cpu_X[i] = tcg_global_mem_new_i64(TCG_AREG0,
58 offsetof(CPUARMState, xregs[i]),
59 regnames[i]);
60 }
61
62 pstate = tcg_global_mem_new_i32(TCG_AREG0,
63 offsetof(CPUARMState, pstate),
64 "pstate");
65}
66
67void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
68 fprintf_function cpu_fprintf, int flags)
69{
70 ARMCPU *cpu = ARM_CPU(cs);
71 CPUARMState *env = &cpu->env;
Peter Maydell6cd096b2013-11-26 17:21:48 +000072 uint32_t psr = pstate_read(env);
Alexander Graf14ade102013-09-03 20:12:10 +010073 int i;
74
75 cpu_fprintf(f, "PC=%016"PRIx64" SP=%016"PRIx64"\n",
76 env->pc, env->xregs[31]);
77 for (i = 0; i < 31; i++) {
78 cpu_fprintf(f, "X%02d=%016"PRIx64, i, env->xregs[i]);
79 if ((i % 4) == 3) {
80 cpu_fprintf(f, "\n");
81 } else {
82 cpu_fprintf(f, " ");
83 }
84 }
Peter Maydell6cd096b2013-11-26 17:21:48 +000085 cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
86 psr,
87 psr & PSTATE_N ? 'N' : '-',
88 psr & PSTATE_Z ? 'Z' : '-',
89 psr & PSTATE_C ? 'C' : '-',
90 psr & PSTATE_V ? 'V' : '-');
Alexander Graf14ade102013-09-03 20:12:10 +010091 cpu_fprintf(f, "\n");
92}
93
94void gen_a64_set_pc_im(uint64_t val)
95{
96 tcg_gen_movi_i64(cpu_pc, val);
97}
98
99static void gen_exception(int excp)
100{
101 TCGv_i32 tmp = tcg_temp_new_i32();
102 tcg_gen_movi_i32(tmp, excp);
103 gen_helper_exception(cpu_env, tmp);
104 tcg_temp_free_i32(tmp);
105}
106
107static void gen_exception_insn(DisasContext *s, int offset, int excp)
108{
109 gen_a64_set_pc_im(s->pc - offset);
110 gen_exception(excp);
Peter Maydell089a8d92013-12-03 15:26:18 +0000111 s->is_jmp = DISAS_EXC;
112}
113
114static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
115{
116 /* No direct tb linking with singlestep or deterministic io */
117 if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
118 return false;
119 }
120
121 /* Only link tbs from inside the same guest page */
122 if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
123 return false;
124 }
125
126 return true;
127}
128
129static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
130{
131 TranslationBlock *tb;
132
133 tb = s->tb;
134 if (use_goto_tb(s, n, dest)) {
135 tcg_gen_goto_tb(n);
136 gen_a64_set_pc_im(dest);
137 tcg_gen_exit_tb((tcg_target_long)tb + n);
138 s->is_jmp = DISAS_TB_JUMP;
139 } else {
140 gen_a64_set_pc_im(dest);
141 if (s->singlestep_enabled) {
142 gen_exception(EXCP_DEBUG);
143 }
144 tcg_gen_exit_tb(0);
145 s->is_jmp = DISAS_JUMP;
146 }
Alexander Graf14ade102013-09-03 20:12:10 +0100147}
148
149static void real_unallocated_encoding(DisasContext *s)
150{
151 fprintf(stderr, "Unknown instruction: %#x\n", s->insn);
152 gen_exception_insn(s, 4, EXCP_UDEF);
153}
154
155#define unallocated_encoding(s) do { \
156 fprintf(stderr, "unallocated encoding at line: %d\n", __LINE__); \
157 real_unallocated_encoding(s); \
158 } while (0)
159
Peter Maydell089a8d92013-12-03 15:26:18 +0000160static void disas_a64_insn(CPUARMState *env, DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +0100161{
162 uint32_t insn;
163
164 insn = arm_ldl_code(env, s->pc, s->bswap_code);
165 s->insn = insn;
166 s->pc += 4;
167
168 switch ((insn >> 24) & 0x1f) {
169 default:
170 unallocated_encoding(s);
171 break;
172 }
Peter Maydell089a8d92013-12-03 15:26:18 +0000173}
Alexander Graf14ade102013-09-03 20:12:10 +0100174
Peter Maydell089a8d92013-12-03 15:26:18 +0000175void gen_intermediate_code_internal_a64(ARMCPU *cpu,
176 TranslationBlock *tb,
177 bool search_pc)
178{
179 CPUState *cs = CPU(cpu);
180 CPUARMState *env = &cpu->env;
181 DisasContext dc1, *dc = &dc1;
182 CPUBreakpoint *bp;
183 uint16_t *gen_opc_end;
184 int j, lj;
185 target_ulong pc_start;
186 target_ulong next_page_start;
187 int num_insns;
188 int max_insns;
189
190 pc_start = tb->pc;
191
192 dc->tb = tb;
193
194 gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
195
196 dc->is_jmp = DISAS_NEXT;
197 dc->pc = pc_start;
198 dc->singlestep_enabled = cs->singlestep_enabled;
199 dc->condjmp = 0;
200
201 dc->aarch64 = 1;
202 dc->thumb = 0;
203 dc->bswap_code = 0;
204 dc->condexec_mask = 0;
205 dc->condexec_cond = 0;
206#if !defined(CONFIG_USER_ONLY)
207 dc->user = 0;
208#endif
209 dc->vfp_enabled = 0;
210 dc->vec_len = 0;
211 dc->vec_stride = 0;
212
213 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
214 lj = -1;
215 num_insns = 0;
216 max_insns = tb->cflags & CF_COUNT_MASK;
217 if (max_insns == 0) {
218 max_insns = CF_COUNT_MASK;
219 }
220
221 gen_tb_start();
222
223 tcg_clear_temp_count();
224
225 do {
226 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
227 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
228 if (bp->pc == dc->pc) {
229 gen_exception_insn(dc, 0, EXCP_DEBUG);
230 /* Advance PC so that clearing the breakpoint will
231 invalidate this TB. */
232 dc->pc += 2;
233 goto done_generating;
234 }
235 }
236 }
237
238 if (search_pc) {
239 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
240 if (lj < j) {
241 lj++;
242 while (lj < j) {
243 tcg_ctx.gen_opc_instr_start[lj++] = 0;
244 }
245 }
246 tcg_ctx.gen_opc_pc[lj] = dc->pc;
247 tcg_ctx.gen_opc_instr_start[lj] = 1;
248 tcg_ctx.gen_opc_icount[lj] = num_insns;
249 }
250
251 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
252 gen_io_start();
253 }
254
255 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
256 tcg_gen_debug_insn_start(dc->pc);
257 }
258
259 disas_a64_insn(env, dc);
260
261 if (tcg_check_temp_count()) {
262 fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
263 dc->pc);
264 }
265
266 /* Translation stops when a conditional branch is encountered.
267 * Otherwise the subsequent code could get translated several times.
268 * Also stop translation when a page boundary is reached. This
269 * ensures prefetch aborts occur at the right place.
270 */
271 num_insns++;
272 } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
273 !cs->singlestep_enabled &&
274 !singlestep &&
275 dc->pc < next_page_start &&
276 num_insns < max_insns);
277
278 if (tb->cflags & CF_LAST_IO) {
279 gen_io_end();
280 }
281
282 if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
283 /* Note that this means single stepping WFI doesn't halt the CPU.
284 * For conditional branch insns this is harmless unreachable code as
285 * gen_goto_tb() has already handled emitting the debug exception
286 * (and thus a tb-jump is not possible when singlestepping).
287 */
288 assert(dc->is_jmp != DISAS_TB_JUMP);
289 if (dc->is_jmp != DISAS_JUMP) {
290 gen_a64_set_pc_im(dc->pc);
291 }
292 gen_exception(EXCP_DEBUG);
293 } else {
294 switch (dc->is_jmp) {
295 case DISAS_NEXT:
296 gen_goto_tb(dc, 1, dc->pc);
297 break;
298 default:
299 case DISAS_JUMP:
300 case DISAS_UPDATE:
301 /* indicate that the hash table must be used to find the next TB */
302 tcg_gen_exit_tb(0);
303 break;
304 case DISAS_TB_JUMP:
305 case DISAS_EXC:
306 case DISAS_SWI:
307 break;
308 case DISAS_WFI:
309 /* This is a special case because we don't want to just halt the CPU
310 * if trying to debug across a WFI.
311 */
312 gen_helper_wfi(cpu_env);
313 break;
314 }
315 }
316
317done_generating:
318 gen_tb_end(tb, num_insns);
319 *tcg_ctx.gen_opc_ptr = INDEX_op_end;
320
321#ifdef DEBUG_DISAS
322 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
323 qemu_log("----------------\n");
324 qemu_log("IN: %s\n", lookup_symbol(pc_start));
325 log_target_disas(env, pc_start, dc->pc - pc_start,
326 dc->thumb | (dc->bswap_code << 1));
327 qemu_log("\n");
328 }
329#endif
330 if (search_pc) {
331 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
332 lj++;
333 while (lj <= j) {
334 tcg_ctx.gen_opc_instr_start[lj++] = 0;
335 }
336 } else {
337 tb->size = dc->pc - pc_start;
338 tb->icount = num_insns;
Alexander Graf14ade102013-09-03 20:12:10 +0100339 }
340}