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
|
/*
* 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, /* MOV R14, R15 */
};
void
cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
{
volatile ulong instr[2];
void *pcaddr;
void (*fp)(ulong);
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;
pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
cachedwbse(pcaddr, sizeof instr);
cacheiinv();
fp = (void (*)(ulong))pcaddr;
(*fp)(val);
coherence();
}
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)
{
volatile ulong instr[2];
void *pcaddr;
ulong (*fp)(void);
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;
pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
cachedwbse(pcaddr, sizeof instr);
cacheiinv();
fp = (ulong (*)(void))pcaddr;
return (*fp)();
}
ulong
cprdsc(int op1, int crn, int crm, int op2)
{
return cprd(CpSC, op1, crn, crm, op2);
}
/* floating point */
ulong
fprd(int fpreg)
{
volatile ulong instr[2];
void *pcaddr;
ulong (*fp)(void);
fpreg &= 017;
/*
* VMRS. return value will be in R0, which is convenient.
* Rt will be R0.
*/
instr[0] = 0xeef00a10 | fpreg << 16 | 0 << 12;
instr[1] = Retinst;
coherence();
pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
cachedwbse(pcaddr, sizeof instr);
cacheiinv();
fp = (ulong (*)(void))pcaddr;
return (*fp)();
}
void
fpwr(int fpreg, ulong val)
{
volatile ulong instr[2];
void *pcaddr;
void (*fp)(ulong);
fpreg &= 017;
/* VMSR. Rt will be R0. */
instr[0] = 0xeee00a10 | fpreg << 16 | 0 << 12;
instr[1] = Retinst;
coherence();
pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
cachedwbse(pcaddr, sizeof instr);
cacheiinv();
fp = (void (*)(ulong))pcaddr;
(*fp)(val);
coherence();
}
|