1
From 89f9fb84d3bbee4cae1706a4ea73f2a0af8e55b6 Mon Sep 17 00:00:00 2001
2
From: Peter Maydell <peter.maydell@linaro.org>
3
Date: Sat, 4 Jan 2014 22:15:45 +0000
4
Subject: [PATCH 064/158] target-arm: A64: Implement MRS/MSR/SYS/SYSL
6
The AArch64 equivalent of the traditional AArch32
7
cp15 coprocessor registers is the set of instructions
8
MRS/MSR/SYS/SYSL, which cover between them both true
9
system registers and the "operations with side effects"
10
such as cache maintenance which in AArch32 are mixed
11
in with other cp15 registers. Implement these instructions
12
to look in the cpregs hashtable for the register or
15
Since we don't yet populate the cpregs hashtable with
16
any registers with the "AA64" bit set, everything will
17
still UNDEF at this point.
19
MSR/MRS is the first user of is_jmp = DISAS_UPDATE, so
20
fix an infelicity in its handling where the main loop
21
was requiring the caller to do the update of PC rather
22
than just doing it itself.
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Reviewed-by: Richard Henderson <rth@twiddle.net>
27
target-arm/translate-a64.c | 112 +++++++++++++++++++++++++++++++++------------
28
1 file changed, 82 insertions(+), 30 deletions(-)
30
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
31
index e35d2f3..7a9ee82 100644
32
--- a/target-arm/translate-a64.c
33
+++ b/target-arm/translate-a64.c
34
@@ -733,28 +733,88 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
35
unsupported_encoding(s, insn);
39
-static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
40
- unsigned int op1, unsigned int op2,
41
+/* C5.6.129 MRS - move from system register
42
+ * C5.6.131 MSR (register) - move to system register
45
+ * These are all essentially the same insn in 'read' and 'write'
46
+ * versions, with varying op0 fields.
48
+static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
49
+ unsigned int op0, unsigned int op1, unsigned int op2,
50
unsigned int crn, unsigned int crm, unsigned int rt)
52
- unsupported_encoding(s, insn);
54
+ const ARMCPRegInfo *ri;
57
-/* C5.6.129 MRS - move from system register */
58
-static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
59
- unsigned int op1, unsigned int op2,
60
- unsigned int crn, unsigned int crm, unsigned int rt)
62
- unsupported_encoding(s, insn);
64
+ ri = get_arm_cp_reginfo(s->cp_regs,
65
+ ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
66
+ crn, crm, op0, op1, op2));
68
-/* C5.6.131 MSR (register) - move to system register */
69
-static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
70
- unsigned int op1, unsigned int op2,
71
- unsigned int crn, unsigned int crm, unsigned int rt)
73
- unsupported_encoding(s, insn);
75
+ /* Unknown register */
76
+ unallocated_encoding(s);
80
+ /* Check access permissions */
81
+ if (!cp_access_ok(s->current_pl, ri, isread)) {
82
+ unallocated_encoding(s);
86
+ /* Handle special cases first */
87
+ switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
94
+ if (use_icount && (ri->type & ARM_CP_IO)) {
98
+ tcg_rt = cpu_reg(s, rt);
101
+ if (ri->type & ARM_CP_CONST) {
102
+ tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
103
+ } else if (ri->readfn) {
105
+ gen_a64_set_pc_im(s->pc - 4);
106
+ tmpptr = tcg_const_ptr(ri);
107
+ gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr);
108
+ tcg_temp_free_ptr(tmpptr);
110
+ tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
113
+ if (ri->type & ARM_CP_CONST) {
114
+ /* If not forbidden by access permissions, treat as WI */
116
+ } else if (ri->writefn) {
118
+ gen_a64_set_pc_im(s->pc - 4);
119
+ tmpptr = tcg_const_ptr(ri);
120
+ gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt);
121
+ tcg_temp_free_ptr(tmpptr);
123
+ tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
127
+ if (use_icount && (ri->type & ARM_CP_IO)) {
128
+ /* I/O operations must end the TB here (whether read or write) */
130
+ s->is_jmp = DISAS_UPDATE;
131
+ } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
132
+ /* We default to ending the TB on a coprocessor register write,
133
+ * but allow this to be suppressed by the register definition
134
+ * (usually only necessary to work around guest bugs).
136
+ s->is_jmp = DISAS_UPDATE;
141
@@ -795,17 +855,7 @@ static void disas_system(DisasContext *s, uint32_t insn)
148
- handle_sys(s, insn, l, op1, op2, crn, crm, rt);
149
- } else if (l) { /* op0 > 1 */
150
- /* C5.6.129 MRS - move from system register */
151
- handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
153
- /* C5.6.131 MSR (register) - move to system register */
154
- handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
156
+ handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
159
/* C3.2.3 Exception generation
160
@@ -3098,8 +3148,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
161
gen_goto_tb(dc, 1, dc->pc);
166
+ gen_a64_set_pc_im(dc->pc);
169
/* indicate that the hash table must be used to find the next TB */