master
c 199 lines 4.97 KB
Raw
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * LoongArch emulation helpers for CSRs
4 *
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
6 */
7
8 #include "qemu/osdep.h"
9 #include "qemu/log.h"
10 #include "qemu/main-loop.h"
11 #include "cpu.h"
12 #include "internals.h"
13 #include "qemu/host-utils.h"
14 #include "exec/helper-proto.h"
15 #include "exec/cputlb.h"
16 #include "accel/tcg/cpu-ldst.h"
17 #include "hw/core/irq.h"
18 #include "cpu-csr.h"
19 #include "cpu-mmu.h"
20
21 target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val)
22 {
23 CPUSysState *sys = env_sys(env);
24 int64_t old_v = sys->CSR_STLBPS;
25
26 /*
27 * The real hardware only supports the min tlb_ps is 12
28 * tlb_ps=0 may cause undefined-behavior.
29 */
30 uint8_t tlb_ps = FIELD_EX64(val, CSR_STLBPS, PS);
31 if (!check_ps(env, tlb_ps)) {
32 qemu_log_mask(LOG_GUEST_ERROR,
33 "Attempted set ps %d\n", tlb_ps);
34 } else {
35 /* Only update PS field, reserved bit keeps zero */
36 val = FIELD_DP64(val, CSR_STLBPS, RESERVE, 0);
37 sys->CSR_STLBPS = val;
38 }
39
40 return old_v;
41 }
42
43 target_ulong helper_csrrd_pgd(CPULoongArchState *env)
44 {
45 int64_t v;
46 CPUSysState *sys = env_sys(env);
47
48 if (sys->CSR_TLBRERA & 0x1) {
49 v = sys->CSR_TLBRBADV;
50 } else {
51 v = sys->CSR_BADV;
52 }
53
54 if ((v >> 63) & 0x1) {
55 v = sys->CSR_PGDH;
56 } else {
57 v = sys->CSR_PGDL;
58 }
59
60 return v;
61 }
62
63 target_ulong helper_csrrd_cpuid(CPULoongArchState *env)
64 {
65 LoongArchCPU *lac = env_archcpu(env);
66 CPUSysState *sys = env_sys(env);
67
68 sys->CSR_CPUID = CPU(lac)->cpu_index;
69
70 return sys->CSR_CPUID;
71 }
72
73 target_ulong helper_csrrd_tval(CPULoongArchState *env)
74 {
75 LoongArchCPU *cpu = env_archcpu(env);
76
77 return cpu_loongarch_get_constant_timer_ticks(cpu);
78 }
79
80 target_ulong helper_csrrd_msgir(CPULoongArchState *env)
81 {
82 int irq, new;
83 CPUSysState *sys = env_sys(env);
84
85 irq = find_first_bit((unsigned long *)sys->CSR_MSGIS, 256);
86 if (irq < 256) {
87 clear_bit(irq, (unsigned long *)sys->CSR_MSGIS);
88 new = find_first_bit((unsigned long *)sys->CSR_MSGIS, 256);
89 if (new < 256) {
90 return irq;
91 }
92
93 sys->CSR_ESTAT = FIELD_DP64(sys->CSR_ESTAT, CSR_ESTAT, MSGINT, 0);
94 } else {
95 /* bit 31 set 1 for no invalid irq */
96 irq = BIT(31);
97 }
98
99 return irq;
100 }
101
102 target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
103 {
104 CPUSysState *sys = env_sys(env);
105 int64_t old_v = sys->CSR_ESTAT;
106
107 /* Only IS[1:0] can be written */
108 sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 0, 2, val);
109 /*
110 * Software interrupts (SWI0/SWI1) are latched in CSR.ESTAT.IS[1:0].
111 * Make sure the CPU interrupt request state tracks the pending bits,
112 * matching the behavior of loongarch_cpu_set_irq().
113 */
114 if (sys->CSR_ESTAT != old_v) {
115 bql_lock();
116 loongarch_cpu_update_irq(env_archcpu(env), old_v);
117 bql_unlock();
118 }
119
120 return old_v;
121 }
122
123 target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val)
124 {
125 CPUSysState *sys = env_sys(env);
126 int64_t old_v = sys->CSR_ASID;
127
128 /* Only ASID filed of CSR_ASID can be written */
129 sys->CSR_ASID = deposit64(sys->CSR_ASID, 0, 10, val);
130 if (old_v != sys->CSR_ASID) {
131 tlb_flush(env_cpu(env));
132 }
133 return old_v;
134 }
135
136 target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val)
137 {
138 LoongArchCPU *cpu = env_archcpu(env);
139 CPUSysState *sys = env_sys(env);
140 int64_t old_v = sys->CSR_TCFG;
141
142 cpu_loongarch_store_constant_timer_config(cpu, val);
143
144 return old_v;
145 }
146
147 target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
148 {
149 LoongArchCPU *cpu = env_archcpu(env);
150 int64_t old_v = 0;
151
152 if (val & 0x1) {
153 bql_lock();
154 loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0);
155 bql_unlock();
156 }
157 return old_v;
158 }
159
160 target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val)
161 {
162 uint8_t shift, ptbase;
163 CPUSysState *sys = env_sys(env);
164 int64_t old_v = sys->CSR_PWCL;
165
166 /*
167 * The real hardware only supports 64bit PTE width now, 128bit or others
168 * treated as illegal.
169 */
170 shift = FIELD_EX64(val, CSR_PWCL, PTEWIDTH);
171 ptbase = FIELD_EX64(val, CSR_PWCL, PTBASE);
172 if (shift) {
173 qemu_log_mask(LOG_GUEST_ERROR,
174 "Attempted set pte width with %d bit\n", 64 << shift);
175 val = FIELD_DP64(val, CSR_PWCL, PTEWIDTH, 0);
176 }
177 if (!check_ps(env, ptbase)) {
178 qemu_log_mask(LOG_GUEST_ERROR,
179 "Attempted set ptbase 2^%d\n", ptbase);
180 }
181 sys->CSR_PWCL = val;
182 return old_v;
183 }
184
185 target_ulong helper_csrwr_pwch(CPULoongArchState *env, target_ulong val)
186 {
187 uint8_t has_ptw;
188 CPUSysState *sys = env_sys(env);
189 int64_t old_v = sys->CSR_PWCH;
190
191 val = FIELD_DP64(val, CSR_PWCH, RESERVE, 0);
192 has_ptw = FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW);
193 if (!has_ptw) {
194 val = FIELD_DP64(val, CSR_PWCH, HPTW_EN, 0);
195 }
196
197 sys->CSR_PWCH = val;
198 return old_v;
199 }