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, /* MOVW R14, R15 */
20
21 Fpproc = 10, /* for vfp 3+; also 11 for doubles */
22 };
23
24 void
cpwr(int cp,int op1,int crn,int crm,int op2,ulong val)25 cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
26 {
27 int s;
28 volatile ulong instr[2];
29 void *pcaddr;
30 void (*fp)(ulong);
31
32 s = splhi();
33 op1 &= 7;
34 op2 &= 7;
35 crn &= 017;
36 crm &= 017;
37 cp &= 017;
38 /* MCR. Rt will be R0. */
39 instr[0] = 0xee000010 |
40 op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
41 instr[1] = Retinst;
42 coherence();
43
44 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
45 cachedwbse(pcaddr, sizeof instr);
46 cacheiinv();
47
48 fp = (void (*)(ulong))pcaddr;
49 (*fp)(val);
50 coherence();
51 splx(s);
52 }
53
54 void
cpwrsc(int op1,int crn,int crm,int op2,ulong val)55 cpwrsc(int op1, int crn, int crm, int op2, ulong val)
56 {
57 cpwr(CpSC, op1, crn, crm, op2, val);
58 }
59
60 ulong
cprd(int cp,int op1,int crn,int crm,int op2)61 cprd(int cp, int op1, int crn, int crm, int op2)
62 {
63 int s;
64 ulong res;
65 volatile ulong instr[2];
66 void *pcaddr;
67 ulong (*fp)(void);
68
69 s = splhi();
70 op1 &= 7;
71 op2 &= 7;
72 crn &= 017;
73 crm &= 017;
74 /*
75 * MRC. return value will be in R0, which is convenient.
76 * Rt will be R0.
77 */
78 instr[0] = 0xee100010 |
79 op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
80 instr[1] = Retinst;
81 coherence();
82
83 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
84 cachedwbse(pcaddr, sizeof instr);
85 cacheiinv();
86
87 fp = (ulong (*)(void))pcaddr;
88 res = (*fp)();
89 splx(s);
90 return res;
91 }
92
93 ulong
cprdsc(int op1,int crn,int crm,int op2)94 cprdsc(int op1, int crn, int crm, int op2)
95 {
96 return cprd(CpSC, op1, crn, crm, op2);
97 }
98
99 /* floating point */
100
101 ulong
fprd(int fpreg)102 fprd(int fpreg)
103 {
104 int s;
105 ulong res;
106 volatile ulong instr[2];
107 void *pcaddr;
108 ulong (*fp)(void);
109
110 s = splhi();
111 fpreg &= 017;
112 /*
113 * VMRS. return value will be in R0, which is convenient.
114 * Rt will be R0.
115 */
116 instr[0] = 0xeef00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
117 instr[1] = Retinst;
118 coherence();
119
120 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
121 cachedwbse(pcaddr, sizeof instr);
122 cacheiinv();
123
124 fp = (ulong (*)(void))pcaddr;
125 res = (*fp)();
126 splx(s);
127 return res;
128 }
129
130 void
fpwr(int fpreg,ulong val)131 fpwr(int fpreg, ulong val)
132 {
133 int s;
134 volatile ulong instr[2];
135 void *pcaddr;
136 void (*fp)(ulong);
137
138 s = splhi();
139 fpreg &= 017;
140 /* VMSR. Rt will be R0. */
141 instr[0] = 0xeee00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
142 instr[1] = Retinst;
143 coherence();
144
145 pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
146 cachedwbse(pcaddr, sizeof instr);
147 cacheiinv();
148
149 fp = (void (*)(ulong))pcaddr;
150 (*fp)(val);
151 coherence();
152 splx(s);
153 }
154