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