1 /*
2 * xen/arch/arm/arm64/vcpreg.c
3 *
4 * Emulate co-processor registers trapped.
5 *
6 * Copyright (c) 2011 Citrix Systems.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 #include <xen/sched.h>
20
21 #include <asm/cpregs.h>
22 #include <asm/current.h>
23 #include <asm/regs.h>
24 #include <asm/traps.h>
25 #include <asm/vtimer.h>
26
do_cp15_32(struct cpu_user_regs * regs,const union hsr hsr)27 void do_cp15_32(struct cpu_user_regs *regs, const union hsr hsr)
28 {
29 const struct hsr_cp32 cp32 = hsr.cp32;
30 int regidx = cp32.reg;
31 struct vcpu *v = current;
32
33 if ( !check_conditional_instr(regs, hsr) )
34 {
35 advance_pc(regs, hsr);
36 return;
37 }
38
39 switch ( hsr.bits & HSR_CP32_REGS_MASK )
40 {
41 /*
42 * !CNTHCTL_EL2.EL1PCEN / !CNTHCTL.PL1PCEN
43 *
44 * ARMv7 (DDI 0406C.b): B4.1.22
45 * ARMv8 (DDI 0487A.d): D1-1510 Table D1-60
46 */
47 case HSR_CPREG32(CNTP_CTL):
48 case HSR_CPREG32(CNTP_TVAL):
49 if ( !vtimer_emulate(regs, hsr) )
50 return inject_undef_exception(regs, hsr);
51 break;
52
53 /*
54 * HCR_EL2.TACR / HCR.TAC
55 *
56 * ARMv7 (DDI 0406C.b): B1.14.6
57 * ARMv8 (DDI 0487A.d): G6.2.1
58 */
59 case HSR_CPREG32(ACTLR):
60 if ( psr_mode_is_user(regs) )
61 return inject_undef_exception(regs, hsr);
62 if ( cp32.read )
63 set_user_reg(regs, regidx, v->arch.actlr);
64 break;
65
66 /*
67 * MDCR_EL2.TPM
68 *
69 * ARMv7 (DDI 0406C.b): B1.14.17
70 * ARMv8 (DDI 0487A.d): D1-1511 Table D1-61
71 *
72 * Unhandled:
73 * PMEVCNTR<n>
74 * PMEVTYPER<n>
75 * PMCCFILTR
76 *
77 * MDCR_EL2.TPMCR
78 *
79 * ARMv7 (DDI 0406C.b): B1.14.17
80 * ARMv8 (DDI 0487A.d): D1-1511 Table D1-62
81 *
82 * NB: Both MDCR_EL2.TPM and MDCR_EL2.TPMCR cause trapping of PMCR.
83 */
84 /* We could trap ID_DFR0 and tell the guest we don't support
85 * performance monitoring, but Linux doesn't check the ID_DFR0.
86 * Therefore it will read PMCR.
87 *
88 * We tell the guest we have 0 counters. Unfortunately we must
89 * always support PMCCNTR (the cyle counter): we just RAZ/WI for all
90 * PM register, which doesn't crash the kernel at least
91 */
92 case HSR_CPREG32(PMUSERENR):
93 /* RO at EL0. RAZ/WI at EL1 */
94 if ( psr_mode_is_user(regs) )
95 return handle_ro_raz(regs, regidx, cp32.read, hsr, 0);
96 else
97 return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
98 case HSR_CPREG32(PMINTENSET):
99 case HSR_CPREG32(PMINTENCLR):
100 /* EL1 only, however MDCR_EL2.TPM==1 means EL0 may trap here also. */
101 return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
102 case HSR_CPREG32(PMCR):
103 case HSR_CPREG32(PMCNTENSET):
104 case HSR_CPREG32(PMCNTENCLR):
105 case HSR_CPREG32(PMOVSR):
106 case HSR_CPREG32(PMSWINC):
107 case HSR_CPREG32(PMSELR):
108 case HSR_CPREG32(PMCEID0):
109 case HSR_CPREG32(PMCEID1):
110 case HSR_CPREG32(PMCCNTR):
111 case HSR_CPREG32(PMXEVTYPER):
112 case HSR_CPREG32(PMXEVCNTR):
113 case HSR_CPREG32(PMOVSSET):
114 /*
115 * Accessible at EL0 only if PMUSERENR_EL0.EN is set. We
116 * emulate that register as 0 above.
117 */
118 return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
119
120 /*
121 * HCR_EL2.TIDCP
122 *
123 * ARMv7 (DDI 0406C.b): B1.14.3
124 * ARMv8 (DDI 0487A.d): D1-1501 Table D1-43
125 *
126 * - CRn==c9, opc1=={0-7}, CRm=={c0-c2, c5-c8}, opc2=={0-7}
127 * (Cache and TCM lockdown registers)
128 * - CRn==c10, opc1=={0-7}, CRm=={c0, c1, c4, c8}, opc2=={0-7}
129 * (VMSA CP15 c10 registers)
130 * - CRn==c11, opc1=={0-7}, CRm=={c0-c8, c15}, opc2=={0-7}
131 * (VMSA CP15 c11 registers)
132 *
133 * CPTR_EL2.T{0..9,12..13}
134 *
135 * ARMv7 (DDI 0406C.b): B1.14.12
136 * ARMv8 (DDI 0487A.d): N/A
137 *
138 * - All accesses to coprocessors 0..9 and 12..13
139 *
140 * HSTR_EL2.T15
141 *
142 * ARMv7 (DDI 0406C.b): B1.14.14
143 * ARMv8 (DDI 0487A.d): D1-1507 Table D1-55
144 *
145 * - All accesses to cp15, c15 registers.
146 *
147 * And all other unknown registers.
148 */
149 default:
150 gdprintk(XENLOG_ERR,
151 "%s p15, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n",
152 cp32.read ? "mrc" : "mcr",
153 cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc);
154 gdprintk(XENLOG_ERR, "unhandled 32-bit CP15 access %#x\n",
155 hsr.bits & HSR_CP32_REGS_MASK);
156 inject_undef_exception(regs, hsr);
157 return;
158 }
159 advance_pc(regs, hsr);
160 }
161
do_cp15_64(struct cpu_user_regs * regs,const union hsr hsr)162 void do_cp15_64(struct cpu_user_regs *regs, const union hsr hsr)
163 {
164 if ( !check_conditional_instr(regs, hsr) )
165 {
166 advance_pc(regs, hsr);
167 return;
168 }
169
170 switch ( hsr.bits & HSR_CP64_REGS_MASK )
171 {
172 /*
173 * !CNTHCTL_EL2.EL1PCEN / !CNTHCTL.PL1PCEN
174 *
175 * ARMv7 (DDI 0406C.b): B4.1.22
176 * ARMv8 (DDI 0487A.d): D1-1510 Table D1-60
177 */
178 case HSR_CPREG64(CNTP_CVAL):
179 if ( !vtimer_emulate(regs, hsr) )
180 return inject_undef_exception(regs, hsr);
181 break;
182
183 /*
184 * HCR_EL2.FMO or HCR_EL2.IMO
185 *
186 * GIC Architecture Specification (IHI 0069C): Section 4.6.3
187 */
188 case HSR_CPREG64(ICC_SGI1R):
189 case HSR_CPREG64(ICC_ASGI1R):
190 case HSR_CPREG64(ICC_SGI0R):
191 if ( !vgic_emulate(regs, hsr) )
192 return inject_undef_exception(regs, hsr);
193 break;
194
195 /*
196 * CPTR_EL2.T{0..9,12..13}
197 *
198 * ARMv7 (DDI 0406C.b): B1.14.12
199 * ARMv8 (DDI 0487A.d): N/A
200 *
201 * - All accesses to coprocessors 0..9 and 12..13
202 *
203 * HSTR_EL2.T15
204 *
205 * ARMv7 (DDI 0406C.b): B1.14.14
206 * ARMv8 (DDI 0487A.d): D1-1507 Table D1-55
207 *
208 * - All accesses to cp15, c15 registers.
209 *
210 * And all other unknown registers.
211 */
212 default:
213 {
214 const struct hsr_cp64 cp64 = hsr.cp64;
215
216 gdprintk(XENLOG_ERR,
217 "%s p15, %d, r%d, r%d, cr%d @ 0x%"PRIregister"\n",
218 cp64.read ? "mrrc" : "mcrr",
219 cp64.op1, cp64.reg1, cp64.reg2, cp64.crm, regs->pc);
220 gdprintk(XENLOG_ERR, "unhandled 64-bit CP15 access %#x\n",
221 hsr.bits & HSR_CP64_REGS_MASK);
222 inject_undef_exception(regs, hsr);
223 return;
224 }
225 }
226 advance_pc(regs, hsr);
227 }
228
do_cp14_32(struct cpu_user_regs * regs,const union hsr hsr)229 void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr)
230 {
231 const struct hsr_cp32 cp32 = hsr.cp32;
232 int regidx = cp32.reg;
233 struct domain *d = current->domain;
234
235 if ( !check_conditional_instr(regs, hsr) )
236 {
237 advance_pc(regs, hsr);
238 return;
239 }
240
241 switch ( hsr.bits & HSR_CP32_REGS_MASK )
242 {
243 /*
244 * MDCR_EL2.TDOSA
245 *
246 * ARMv7 (DDI 0406C.b): B1.14.15
247 * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
248 *
249 * Unhandled:
250 * DBGOSLSR
251 * DBGPRCR
252 */
253 case HSR_CPREG32(DBGOSLAR):
254 return handle_wo_wi(regs, regidx, cp32.read, hsr, 1);
255 case HSR_CPREG32(DBGOSDLR):
256 return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
257
258 /*
259 * MDCR_EL2.TDA
260 *
261 * ARMv7 (DDI 0406C.b): B1.14.15
262 * ARMv8 (DDI 0487A.d): D1-1510 Table D1-59
263 *
264 * Unhandled:
265 * DBGDCCINT
266 * DBGDTRRXint
267 * DBGDTRTXint
268 * DBGWFAR
269 * DBGDTRTXext
270 * DBGDTRRXext,
271 * DBGBXVR<n>
272 * DBGCLAIMSET
273 * DBGCLAIMCLR
274 * DBGAUTHSTATUS
275 * DBGDEVID
276 * DBGDEVID1
277 * DBGDEVID2
278 * DBGOSECCR
279 */
280 case HSR_CPREG32(DBGDIDR):
281 {
282 uint32_t val;
283
284 /*
285 * Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis
286 * is set to 0, which we emulated below.
287 */
288 if ( !cp32.read )
289 return inject_undef_exception(regs, hsr);
290
291 /* Implement the minimum requirements:
292 * - Number of watchpoints: 1
293 * - Number of breakpoints: 2
294 * - Version: ARMv7 v7.1
295 * - Variant and Revision bits match MDIR
296 */
297 val = (1 << 24) | (5 << 16);
298 val |= ((d->arch.vpidr >> 20) & 0xf) | (d->arch.vpidr & 0xf);
299 set_user_reg(regs, regidx, val);
300
301 break;
302 }
303
304 case HSR_CPREG32(DBGDSCRINT):
305 /*
306 * Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis
307 * is set to 0, which we emulated below.
308 */
309 return handle_ro_raz(regs, regidx, cp32.read, hsr, 1);
310
311 case HSR_CPREG32(DBGDSCREXT):
312 /*
313 * Implement debug status and control register as RAZ/WI.
314 * The OS won't use Hardware debug if MDBGen not set.
315 */
316 return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
317
318 case HSR_CPREG32(DBGVCR):
319 case HSR_CPREG32(DBGBVR0):
320 case HSR_CPREG32(DBGBCR0):
321 case HSR_CPREG32(DBGWVR0):
322 case HSR_CPREG32(DBGWCR0):
323 case HSR_CPREG32(DBGBVR1):
324 case HSR_CPREG32(DBGBCR1):
325 return handle_raz_wi(regs, regidx, cp32.read, hsr, 1);
326
327 /*
328 * CPTR_EL2.TTA
329 *
330 * ARMv7 (DDI 0406C.b): B1.14.16
331 * ARMv8 (DDI 0487A.d): D1-1507 Table D1-54
332 *
333 * - All implemented trace registers.
334 *
335 * MDCR_EL2.TDRA
336 *
337 * ARMv7 (DDI 0406C.b): B1.14.15
338 * ARMv8 (DDI 0487A.d): D1-1508 Table D1-57
339 *
340 * Unhandled:
341 * DBGDRAR (32-bit accesses)
342 * DBGDSAR (32-bit accesses)
343 *
344 * And all other unknown registers.
345 */
346 default:
347 gdprintk(XENLOG_ERR,
348 "%s p14, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n",
349 cp32.read ? "mrc" : "mcr",
350 cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc);
351 gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#x\n",
352 hsr.bits & HSR_CP32_REGS_MASK);
353 inject_undef_exception(regs, hsr);
354 return;
355 }
356
357 advance_pc(regs, hsr);
358 }
359
do_cp14_64(struct cpu_user_regs * regs,const union hsr hsr)360 void do_cp14_64(struct cpu_user_regs *regs, const union hsr hsr)
361 {
362 const struct hsr_cp64 cp64 = hsr.cp64;
363
364 if ( !check_conditional_instr(regs, hsr) )
365 {
366 advance_pc(regs, hsr);
367 return;
368 }
369
370 /*
371 * CPTR_EL2.TTA
372 *
373 * ARMv7 (DDI 0406C.b): B1.14.16
374 * ARMv8 (DDI 0487A.d): D1-1507 Table D1-54
375 *
376 * - All implemented trace registers.
377 *
378 * MDCR_EL2.TDRA
379 *
380 * ARMv7 (DDI 0406C.b): B1.14.15
381 * ARMv8 (DDI 0487A.d): D1-1508 Table D1-57
382 *
383 * Unhandled:
384 * DBGDRAR (64-bit accesses)
385 * DBGDSAR (64-bit accesses)
386 *
387 * And all other unknown registers.
388 */
389 gdprintk(XENLOG_ERR,
390 "%s p14, %d, r%d, r%d, cr%d @ 0x%"PRIregister"\n",
391 cp64.read ? "mrrc" : "mcrr",
392 cp64.op1, cp64.reg1, cp64.reg2, cp64.crm, regs->pc);
393 gdprintk(XENLOG_ERR, "unhandled 64-bit CP14 access %#x\n",
394 hsr.bits & HSR_CP64_REGS_MASK);
395 inject_undef_exception(regs, hsr);
396 }
397
do_cp14_dbg(struct cpu_user_regs * regs,const union hsr hsr)398 void do_cp14_dbg(struct cpu_user_regs *regs, const union hsr hsr)
399 {
400 struct hsr_cp64 cp64 = hsr.cp64;
401
402 if ( !check_conditional_instr(regs, hsr) )
403 {
404 advance_pc(regs, hsr);
405 return;
406 }
407
408 /*
409 * MDCR_EL2.TDOSA
410 *
411 * ARMv7 (DDI 0406C.b): B1.14.15
412 * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
413 *
414 * Unhandled:
415 * DBGDTRTXint
416 * DBGDTRRXint
417 *
418 * And all other unknown registers.
419 */
420 gdprintk(XENLOG_ERR,
421 "%s p14, %d, r%d, r%d, cr%d @ 0x%"PRIregister"\n",
422 cp64.read ? "mrrc" : "mcrr",
423 cp64.op1, cp64.reg1, cp64.reg2, cp64.crm, regs->pc);
424 gdprintk(XENLOG_ERR, "unhandled 64-bit CP14 DBG access %#x\n",
425 hsr.bits & HSR_CP64_REGS_MASK);
426
427 inject_undef_exception(regs, hsr);
428 }
429
do_cp(struct cpu_user_regs * regs,const union hsr hsr)430 void do_cp(struct cpu_user_regs *regs, const union hsr hsr)
431 {
432 const struct hsr_cp cp = hsr.cp;
433
434 if ( !check_conditional_instr(regs, hsr) )
435 {
436 advance_pc(regs, hsr);
437 return;
438 }
439
440 ASSERT(!cp.tas); /* We don't trap SIMD instruction */
441 gdprintk(XENLOG_ERR, "unhandled CP%d access\n", cp.coproc);
442 inject_undef_exception(regs, hsr);
443 }
444
445 /*
446 * Local variables:
447 * mode: C
448 * c-file-style: "BSD"
449 * c-basic-offset: 4
450 * indent-tabs-mode: nil
451 * End:
452 */
453