xref: /plan9-contrib/sys/src/9/kw/coproc.c (revision 84860c5d80372cab6c5e871d17f5695a8d0192c9)
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