1 /*
2 * arm co-processors
3 * CP15 (system control) is the one that gets used the most in practice.
4 */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11
12 #include "arm.h"
13
14 #define MAP2PCSPACE(va, pc) ((uintptr)(va) & ~KSEGM | (pc) & KSEGM)
15
16 enum {
17 /* alternates: 0xe12fff1e BX (R14); last e is R14 */
18 /* 0xe28ef000 B 0(R14); second e is R14 (ken) */
19 Retinst = 0xe1a0f00e, /* MOV R14, R15 */
20 };
21
22 void
cpwr(int cp,int op1,int crn,int crm,int op2,ulong val)23 cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
24 {
25 volatile ulong instr[2];
26 void *pcaddr;
27 void (*fp)(ulong);
28
29 op1 &= 7;
30 op2 &= 7;
31 crn &= 017;
32 crm &= 017;
33 cp &= 017;
34 /* MCR. Rt will be R0. */
35 instr[0] = 0xee000010 |
36 op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
37 instr[1] = Retinst;
38
39 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
40 cachedwbse(pcaddr, sizeof instr);
41 cacheiinv();
42
43 fp = (void (*)(ulong))pcaddr;
44 (*fp)(val);
45 coherence();
46 }
47
48 void
cpwrsc(int op1,int crn,int crm,int op2,ulong val)49 cpwrsc(int op1, int crn, int crm, int op2, ulong val)
50 {
51 cpwr(CpSC, op1, crn, crm, op2, val);
52 }
53
54 ulong
cprd(int cp,int op1,int crn,int crm,int op2)55 cprd(int cp, int op1, int crn, int crm, int op2)
56 {
57 volatile ulong instr[2];
58 void *pcaddr;
59 ulong (*fp)(void);
60
61 op1 &= 7;
62 op2 &= 7;
63 crn &= 017;
64 crm &= 017;
65 /*
66 * MRC. return value will be in R0, which is convenient.
67 * Rt will be R0.
68 */
69 instr[0] = 0xee100010 |
70 op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
71 instr[1] = Retinst;
72
73 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
74 cachedwbse(pcaddr, sizeof instr);
75 cacheiinv();
76
77 fp = (ulong (*)(void))pcaddr;
78 return (*fp)();
79 }
80
81 ulong
cprdsc(int op1,int crn,int crm,int op2)82 cprdsc(int op1, int crn, int crm, int op2)
83 {
84 return cprd(CpSC, op1, crn, crm, op2);
85 }
86
87 /* floating point */
88
89 ulong
fprd(int fpreg)90 fprd(int fpreg)
91 {
92 volatile ulong instr[2];
93 void *pcaddr;
94 ulong (*fp)(void);
95
96 fpreg &= 017;
97 /*
98 * VMRS. return value will be in R0, which is convenient.
99 * Rt will be R0.
100 */
101 instr[0] = 0xeef00a10 | fpreg << 16 | 0 << 12;
102 instr[1] = Retinst;
103 coherence();
104
105 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
106 cachedwbse(pcaddr, sizeof instr);
107 cacheiinv();
108
109 fp = (ulong (*)(void))pcaddr;
110 return (*fp)();
111 }
112
113 void
fpwr(int fpreg,ulong val)114 fpwr(int fpreg, ulong val)
115 {
116 volatile ulong instr[2];
117 void *pcaddr;
118 void (*fp)(ulong);
119
120 fpreg &= 017;
121 /* VMSR. Rt will be R0. */
122 instr[0] = 0xeee00a10 | fpreg << 16 | 0 << 12;
123 instr[1] = Retinst;
124 coherence();
125
126 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
127 cachedwbse(pcaddr, sizeof instr);
128 cacheiinv();
129
130 fp = (void (*)(ulong))pcaddr;
131 (*fp)(val);
132 coherence();
133 }
134