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