~ubuntu-branches/ubuntu/utopic/qemu/utopic

« back to all changes in this revision

Viewing changes to debian/patches/arm64/0024-target-arm-Split-A64-from-A32-T32-gen_intermediate_c.patch

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn, Serge Hallyn, dann frazier
  • Date: 2014-01-10 12:19:08 UTC
  • Revision ID: package-import@ubuntu.com-20140110121908-6lsn06rypqbokbaf
Tags: 1.7.0+dfsg-2ubuntu6
[ Serge Hallyn ]
* add arm64 patchset from upstream.  The three arm virt patches previously
  pushed are in that set, so drop them.

[ dann frazier ]
* Add packaging for qemu-system-aarch64. This package is currently only
  available for arm64, as full software emulation is not yet supported.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From f96f1df1c9b50914fb618369b747fff4ae66b72e Mon Sep 17 00:00:00 2001
 
2
From: Peter Maydell <peter.maydell@linaro.org>
 
3
Date: Tue, 17 Dec 2013 19:42:31 +0000
 
4
Subject: [PATCH 24/49] target-arm: Split A64 from A32/T32
 
5
 gen_intermediate_code_internal()
 
6
 
 
7
The A32/T32 gen_intermediate_code_internal() is complicated because it
 
8
has to deal with:
 
9
 * conditionally executed instructions
 
10
 * Thumb IT blocks
 
11
 * kernel helper page
 
12
 * M profile exception-exit special casing
 
13
 
 
14
None of these apply to A64, so putting the "this is A64 so
 
15
call the A64 decoder" check in the middle of the A32/T32
 
16
loop is confusing and means the A64 decoder's handling of
 
17
things like conditional jump and singlestepping has to take
 
18
account of the conditional-execution jumps the main loop
 
19
might emit.
 
20
 
 
21
Refactor the code to give A64 its own gen_intermediate_code_internal
 
22
function instead.
 
23
 
 
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
 
25
Reviewed-by: Richard Henderson <rth@twiddle.net>
 
26
---
 
27
 target-arm/translate-a64.c | 209 +++++++++++++++++++++++++++++++++++++++++++--
 
28
 target-arm/translate.c     |  62 ++++++--------
 
29
 target-arm/translate.h     |  20 ++++-
 
30
 3 files changed, 246 insertions(+), 45 deletions(-)
 
31
 
 
32
Index: qemu/target-arm/translate-a64.c
 
33
===================================================================
 
34
--- qemu.orig/target-arm/translate-a64.c        2014-01-10 12:08:03.444166815 -0600
 
35
+++ qemu/target-arm/translate-a64.c     2014-01-10 12:08:03.436166815 -0600
 
36
@@ -28,6 +28,8 @@
 
37
 #include "translate.h"
 
38
 #include "qemu/host-utils.h"
 
39
 
 
40
+#include "exec/gen-icount.h"
 
41
+
 
42
 #include "helper.h"
 
43
 #define GEN_HELPER 1
 
44
 #include "helper.h"
 
45
@@ -106,7 +108,42 @@ static void gen_exception_insn(DisasCont
 
46
 {
 
47
     gen_a64_set_pc_im(s->pc - offset);
 
48
     gen_exception(excp);
 
49
-    s->is_jmp = DISAS_JUMP;
 
50
+    s->is_jmp = DISAS_EXC;
 
51
+}
 
52
+
 
53
+static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
 
54
+{
 
55
+    /* No direct tb linking with singlestep or deterministic io */
 
56
+    if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
 
57
+        return false;
 
58
+    }
 
59
+
 
60
+    /* Only link tbs from inside the same guest page */
 
61
+    if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
 
62
+        return false;
 
63
+    }
 
64
+
 
65
+    return true;
 
66
+}
 
67
+
 
68
+static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
 
69
+{
 
70
+    TranslationBlock *tb;
 
71
+
 
72
+    tb = s->tb;
 
73
+    if (use_goto_tb(s, n, dest)) {
 
74
+        tcg_gen_goto_tb(n);
 
75
+        gen_a64_set_pc_im(dest);
 
76
+        tcg_gen_exit_tb((tcg_target_long)tb + n);
 
77
+        s->is_jmp = DISAS_TB_JUMP;
 
78
+    } else {
 
79
+        gen_a64_set_pc_im(dest);
 
80
+        if (s->singlestep_enabled) {
 
81
+            gen_exception(EXCP_DEBUG);
 
82
+        }
 
83
+        tcg_gen_exit_tb(0);
 
84
+        s->is_jmp = DISAS_JUMP;
 
85
+    }
 
86
 }
 
87
 
 
88
 static void real_unallocated_encoding(DisasContext *s)
 
89
@@ -120,7 +157,7 @@ static void real_unallocated_encoding(Di
 
90
     real_unallocated_encoding(s); \
 
91
     } while (0)
 
92
 
 
93
-void disas_a64_insn(CPUARMState *env, DisasContext *s)
 
94
+static void disas_a64_insn(CPUARMState *env, DisasContext *s)
 
95
 {
 
96
     uint32_t insn;
 
97
 
 
98
@@ -133,9 +170,171 @@ void disas_a64_insn(CPUARMState *env, Di
 
99
         unallocated_encoding(s);
 
100
         break;
 
101
     }
 
102
+}
 
103
 
 
104
-    if (unlikely(s->singlestep_enabled) && (s->is_jmp == DISAS_TB_JUMP)) {
 
105
-        /* go through the main loop for single step */
 
106
-        s->is_jmp = DISAS_JUMP;
 
107
+void gen_intermediate_code_internal_a64(ARMCPU *cpu,
 
108
+                                        TranslationBlock *tb,
 
109
+                                        bool search_pc)
 
110
+{
 
111
+    CPUState *cs = CPU(cpu);
 
112
+    CPUARMState *env = &cpu->env;
 
113
+    DisasContext dc1, *dc = &dc1;
 
114
+    CPUBreakpoint *bp;
 
115
+    uint16_t *gen_opc_end;
 
116
+    int j, lj;
 
117
+    target_ulong pc_start;
 
118
+    target_ulong next_page_start;
 
119
+    int num_insns;
 
120
+    int max_insns;
 
121
+
 
122
+    pc_start = tb->pc;
 
123
+
 
124
+    dc->tb = tb;
 
125
+
 
126
+    gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
 
127
+
 
128
+    dc->is_jmp = DISAS_NEXT;
 
129
+    dc->pc = pc_start;
 
130
+    dc->singlestep_enabled = cs->singlestep_enabled;
 
131
+    dc->condjmp = 0;
 
132
+
 
133
+    dc->aarch64 = 1;
 
134
+    dc->thumb = 0;
 
135
+    dc->bswap_code = 0;
 
136
+    dc->condexec_mask = 0;
 
137
+    dc->condexec_cond = 0;
 
138
+#if !defined(CONFIG_USER_ONLY)
 
139
+    dc->user = 0;
 
140
+#endif
 
141
+    dc->vfp_enabled = 0;
 
142
+    dc->vec_len = 0;
 
143
+    dc->vec_stride = 0;
 
144
+
 
145
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
 
146
+    lj = -1;
 
147
+    num_insns = 0;
 
148
+    max_insns = tb->cflags & CF_COUNT_MASK;
 
149
+    if (max_insns == 0) {
 
150
+        max_insns = CF_COUNT_MASK;
 
151
+    }
 
152
+
 
153
+    gen_tb_start();
 
154
+
 
155
+    tcg_clear_temp_count();
 
156
+
 
157
+    do {
 
158
+        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
 
159
+            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
 
160
+                if (bp->pc == dc->pc) {
 
161
+                    gen_exception_insn(dc, 0, EXCP_DEBUG);
 
162
+                    /* Advance PC so that clearing the breakpoint will
 
163
+                       invalidate this TB.  */
 
164
+                    dc->pc += 2;
 
165
+                    goto done_generating;
 
166
+                }
 
167
+            }
 
168
+        }
 
169
+
 
170
+        if (search_pc) {
 
171
+            j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
 
172
+            if (lj < j) {
 
173
+                lj++;
 
174
+                while (lj < j) {
 
175
+                    tcg_ctx.gen_opc_instr_start[lj++] = 0;
 
176
+                }
 
177
+            }
 
178
+            tcg_ctx.gen_opc_pc[lj] = dc->pc;
 
179
+            tcg_ctx.gen_opc_instr_start[lj] = 1;
 
180
+            tcg_ctx.gen_opc_icount[lj] = num_insns;
 
181
+        }
 
182
+
 
183
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
 
184
+            gen_io_start();
 
185
+        }
 
186
+
 
187
+        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
 
188
+            tcg_gen_debug_insn_start(dc->pc);
 
189
+        }
 
190
+
 
191
+        disas_a64_insn(env, dc);
 
192
+
 
193
+        if (tcg_check_temp_count()) {
 
194
+            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
 
195
+                    dc->pc);
 
196
+        }
 
197
+
 
198
+        /* Translation stops when a conditional branch is encountered.
 
199
+         * Otherwise the subsequent code could get translated several times.
 
200
+         * Also stop translation when a page boundary is reached.  This
 
201
+         * ensures prefetch aborts occur at the right place.
 
202
+         */
 
203
+        num_insns++;
 
204
+    } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
 
205
+             !cs->singlestep_enabled &&
 
206
+             !singlestep &&
 
207
+             dc->pc < next_page_start &&
 
208
+             num_insns < max_insns);
 
209
+
 
210
+    if (tb->cflags & CF_LAST_IO) {
 
211
+        gen_io_end();
 
212
+    }
 
213
+
 
214
+    if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
 
215
+        /* Note that this means single stepping WFI doesn't halt the CPU.
 
216
+         * For conditional branch insns this is harmless unreachable code as
 
217
+         * gen_goto_tb() has already handled emitting the debug exception
 
218
+         * (and thus a tb-jump is not possible when singlestepping).
 
219
+         */
 
220
+        assert(dc->is_jmp != DISAS_TB_JUMP);
 
221
+        if (dc->is_jmp != DISAS_JUMP) {
 
222
+            gen_a64_set_pc_im(dc->pc);
 
223
+        }
 
224
+        gen_exception(EXCP_DEBUG);
 
225
+    } else {
 
226
+        switch (dc->is_jmp) {
 
227
+        case DISAS_NEXT:
 
228
+            gen_goto_tb(dc, 1, dc->pc);
 
229
+            break;
 
230
+        default:
 
231
+        case DISAS_JUMP:
 
232
+        case DISAS_UPDATE:
 
233
+            /* indicate that the hash table must be used to find the next TB */
 
234
+            tcg_gen_exit_tb(0);
 
235
+            break;
 
236
+        case DISAS_TB_JUMP:
 
237
+        case DISAS_EXC:
 
238
+        case DISAS_SWI:
 
239
+            break;
 
240
+        case DISAS_WFI:
 
241
+            /* This is a special case because we don't want to just halt the CPU
 
242
+             * if trying to debug across a WFI.
 
243
+             */
 
244
+            gen_helper_wfi(cpu_env);
 
245
+            break;
 
246
+        }
 
247
+    }
 
248
+
 
249
+done_generating:
 
250
+    gen_tb_end(tb, num_insns);
 
251
+    *tcg_ctx.gen_opc_ptr = INDEX_op_end;
 
252
+
 
253
+#ifdef DEBUG_DISAS
 
254
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
 
255
+        qemu_log("----------------\n");
 
256
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
 
257
+        log_target_disas(env, pc_start, dc->pc - pc_start,
 
258
+                         dc->thumb | (dc->bswap_code << 1));
 
259
+        qemu_log("\n");
 
260
+    }
 
261
+#endif
 
262
+    if (search_pc) {
 
263
+        j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
 
264
+        lj++;
 
265
+        while (lj <= j) {
 
266
+            tcg_ctx.gen_opc_instr_start[lj++] = 0;
 
267
+        }
 
268
+    } else {
 
269
+        tb->size = dc->pc - pc_start;
 
270
+        tb->icount = num_insns;
 
271
     }
 
272
 }
 
273
Index: qemu/target-arm/translate.c
 
274
===================================================================
 
275
--- qemu.orig/target-arm/translate.c    2014-01-10 12:07:58.348166701 -0600
 
276
+++ qemu/target-arm/translate.c 2014-01-10 12:14:18.576175248 -0600
 
277
@@ -50,18 +50,18 @@
 
278
 #include "translate.h"
 
279
 static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
 
280
 
 
281
-#if defined(CONFIG_USER_ONLY)
 
282
-#define IS_USER(s) 1
 
283
-#else
 
284
-#define IS_USER(s) (s->user)
 
285
-#endif
 
286
-
 
287
 /* These instructions trap after executing, so defer them until after the
 
288
    conditional execution state has been updated.  */
 
289
 #define DISAS_WFI 4
 
290
 #define DISAS_SWI 5
 
291
 #define DISAS_SMC 6
 
292
 
 
293
+#if defined(CONFIG_USER_ONLY)
 
294
+#define IS_USER(s) 1
 
295
+#else
 
296
+#define IS_USER(s) (s->user)
 
297
+#endif
 
298
+
 
299
 TCGv_ptr cpu_env;
 
300
 /* We reuse the same 64-bit temporaries for efficiency.  */
 
301
 static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
 
302
@@ -907,11 +907,7 @@ static inline void gen_smc(CPUARMState *
 
303
 
 
304
 static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
 
305
 {
 
306
-    if (s->aarch64) {
 
307
-        gen_a64_set_pc_im(val);
 
308
-    } else {
 
309
-        tcg_gen_movi_i32(cpu_R[15], val);
 
310
-    }
 
311
+    tcg_gen_movi_i32(cpu_R[15], val);
 
312
 }
 
313
 
 
314
 /* Force a TB lookup after an instruction that changes the CPU state.  */
 
315
@@ -10235,6 +10231,15 @@ static inline void gen_intermediate_code
 
316
     int max_insns;
 
317
 
 
318
     /* generate intermediate code */
 
319
+
 
320
+    /* The A64 decoder has its own top level loop, because it doesn't need
 
321
+     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
 
322
+     */
 
323
+    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
 
324
+        gen_intermediate_code_internal_a64(cpu, tb, search_pc);
 
325
+        return;
 
326
+    }
 
327
+
 
328
     pc_start = tb->pc;
 
329
 
 
330
     dc->tb = tb;
 
331
@@ -10246,31 +10251,18 @@ static inline void gen_intermediate_code
 
332
     dc->singlestep_enabled = cs->singlestep_enabled;
 
333
     dc->condjmp = 0;
 
334
 
 
335
-    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
 
336
-        dc->aarch64 = 1;
 
337
-        dc->thumb = 0;
 
338
-        dc->bswap_code = 0;
 
339
-        dc->condexec_mask = 0;
 
340
-        dc->condexec_cond = 0;
 
341
-#if !defined(CONFIG_USER_ONLY)
 
342
-        dc->user = 0;
 
343
-#endif
 
344
-        dc->vfp_enabled = 0;
 
345
-        dc->vec_len = 0;
 
346
-        dc->vec_stride = 0;
 
347
-    } else {
 
348
-        dc->aarch64 = 0;
 
349
-        dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
 
350
-        dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
 
351
-        dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
 
352
-        dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
 
353
+    dc->aarch64 = 0;
 
354
+    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
 
355
+    dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
 
356
+    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
 
357
+    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
 
358
 #if !defined(CONFIG_USER_ONLY)
 
359
-        dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
 
360
+    dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
 
361
 #endif
 
362
-        dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
 
363
-        dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
 
364
-        dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
 
365
-    }
 
366
+    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
 
367
+    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
 
368
+    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
 
369
+
 
370
     cpu_F0s = tcg_temp_new_i32();
 
371
     cpu_F1s = tcg_temp_new_i32();
 
372
     cpu_F0d = tcg_temp_new_i64();
 
373
@@ -10332,7 +10324,7 @@ static inline void gen_intermediate_code
 
374
     do {
 
375
 #ifdef CONFIG_USER_ONLY
 
376
         /* Intercept jump to the magic kernel page.  */
 
377
-        if (!dc->aarch64 && dc->pc >= 0xffff0000) {
 
378
+        if (dc->pc >= 0xffff0000) {
 
379
             /* We always get here via a jump, so know we are not in a
 
380
                conditional execution block.  */
 
381
             gen_exception(EXCP_KERNEL_TRAP);
 
382
@@ -10380,9 +10372,7 @@ static inline void gen_intermediate_code
 
383
             tcg_gen_debug_insn_start(dc->pc);
 
384
         }
 
385
 
 
386
-        if (dc->aarch64) {
 
387
-            disas_a64_insn(env, dc);
 
388
-        } else if (dc->thumb) {
 
389
+        if (dc->thumb) {
 
390
             disas_thumb_insn(env, dc);
 
391
             if (dc->condexec_mask) {
 
392
                 dc->condexec_cond = (dc->condexec_cond & 0xe)
 
393
@@ -10584,8 +10574,9 @@ void restore_state_to_opc(CPUARMState *e
 
394
 {
 
395
     if (is_a64(env)) {
 
396
         env->pc = tcg_ctx.gen_opc_pc[pc_pos];
 
397
+        env->condexec_bits = 0;
 
398
     } else {
 
399
         env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
 
400
+        env->condexec_bits = gen_opc_condexec_bits[pc_pos];
 
401
     }
 
402
-    env->condexec_bits = gen_opc_condexec_bits[pc_pos];
 
403
 }
 
404
Index: qemu/target-arm/translate.h
 
405
===================================================================
 
406
--- qemu.orig/target-arm/translate.h    2014-01-10 12:08:03.444166815 -0600
 
407
+++ qemu/target-arm/translate.h 2014-01-10 12:08:03.440166815 -0600
 
408
@@ -28,16 +28,32 @@ typedef struct DisasContext {
 
409
 
 
410
 extern TCGv_ptr cpu_env;
 
411
 
 
412
+/* target-specific extra values for is_jmp */
 
413
+/* These instructions trap after executing, so the A32/T32 decoder must
 
414
+ * defer them until after the conditional execution state has been updated.
 
415
+ * WFI also needs special handling when single-stepping.
 
416
+ */
 
417
+#define DISAS_WFI 4
 
418
+#define DISAS_SWI 5
 
419
+/* For instructions which unconditionally cause an exception we can skip
 
420
+ * emitting unreachable code at the end of the TB in the A64 decoder
 
421
+ */
 
422
+#define DISAS_EXC 6
 
423
+
 
424
 #ifdef TARGET_AARCH64
 
425
 void a64_translate_init(void);
 
426
-void disas_a64_insn(CPUARMState *env, DisasContext *s);
 
427
+void gen_intermediate_code_internal_a64(ARMCPU *cpu,
 
428
+                                        TranslationBlock *tb,
 
429
+                                        bool search_pc);
 
430
 void gen_a64_set_pc_im(uint64_t val);
 
431
 #else
 
432
 static inline void a64_translate_init(void)
 
433
 {
 
434
 }
 
435
 
 
436
-static inline void disas_a64_insn(CPUARMState *env, DisasContext *s)
 
437
+static inline void gen_intermediate_code_internal_a64(ARMCPU *cpu,
 
438
+                                                      TranslationBlock *tb,
 
439
+                                                      bool search_pc)
 
440
 {
 
441
 }
 
442