-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathriscv.h
273 lines (218 loc) · 6.64 KB
/
riscv.h
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#ifndef __ASSEMBLER__
// which hart (core) is this?
static inline uint64 r_mhartid() {
uint64 x;
asm volatile("csrr %0, mhartid" : "=r"(x));
return x;
}
// Machine Status Register, mstatus
#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
#define MSTATUS_MPP_M (3L << 11)
#define MSTATUS_MPP_S (1L << 11)
#define MSTATUS_MPP_U (0L << 11)
#define MSTATUS_MIE (1L << 3) // machine-mode interrupt enable.
static inline uint64 r_mstatus() {
uint64 x;
asm volatile("csrr %0, mstatus" : "=r"(x));
return x;
}
static inline void w_mstatus(uint64 x) {
asm volatile("csrw mstatus, %0" : : "r"(x));
}
// machine exception program counter, holds the
// instruction address to which a return from
// exception will go.
static inline void w_mepc(uint64 x) {
asm volatile("csrw mepc, %0" : : "r"(x));
}
// Supervisor Status Register, sstatus
#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
#define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable
#define SSTATUS_UIE (1L << 0) // User Interrupt Enable
static inline uint64 r_sstatus() {
uint64 x;
asm volatile("csrr %0, sstatus" : "=r"(x));
return x;
}
static inline void w_sstatus(uint64 x) {
asm volatile("csrw sstatus, %0" : : "r"(x));
}
// Supervisor Interrupt Pending
static inline uint64 r_sip() {
uint64 x;
asm volatile("csrr %0, sip" : "=r"(x));
return x;
}
static inline void w_sip(uint64 x) { asm volatile("csrw sip, %0" : : "r"(x)); }
// Supervisor Interrupt Enable
#define SIE_SEIE (1L << 9) // external
#define SIE_STIE (1L << 5) // timer
#define SIE_SSIE (1L << 1) // software
static inline uint64 r_sie() {
uint64 x;
asm volatile("csrr %0, sie" : "=r"(x));
return x;
}
static inline void w_sie(uint64 x) { asm volatile("csrw sie, %0" : : "r"(x)); }
// Machine-mode Interrupt Enable
#define MIE_MEIE (1L << 11) // external
#define MIE_MTIE (1L << 7) // timer
#define MIE_MSIE (1L << 3) // software
static inline uint64 r_mie() {
uint64 x;
asm volatile("csrr %0, mie" : "=r"(x));
return x;
}
static inline void w_mie(uint64 x) { asm volatile("csrw mie, %0" : : "r"(x)); }
// supervisor exception program counter, holds the
// instruction address to which a return from
// exception will go.
static inline void w_sepc(uint64 x) {
asm volatile("csrw sepc, %0" : : "r"(x));
}
static inline uint64 r_sepc() {
uint64 x;
asm volatile("csrr %0, sepc" : "=r"(x));
return x;
}
// Machine Exception Delegation
static inline uint64 r_medeleg() {
uint64 x;
asm volatile("csrr %0, medeleg" : "=r"(x));
return x;
}
static inline void w_medeleg(uint64 x) {
asm volatile("csrw medeleg, %0" : : "r"(x));
}
// Machine Interrupt Delegation
static inline uint64 r_mideleg() {
uint64 x;
asm volatile("csrr %0, mideleg" : "=r"(x));
return x;
}
static inline void w_mideleg(uint64 x) {
asm volatile("csrw mideleg, %0" : : "r"(x));
}
// Supervisor Trap-Vector Base Address
// low two bits are mode.
static inline void w_stvec(uint64 x) {
asm volatile("csrw stvec, %0" : : "r"(x));
}
static inline uint64 r_stvec() {
uint64 x;
asm volatile("csrr %0, stvec" : "=r"(x));
return x;
}
// Machine-mode interrupt vector
static inline void w_mtvec(uint64 x) {
asm volatile("csrw mtvec, %0" : : "r"(x));
}
// Physical Memory Protection
static inline void w_pmpcfg0(uint64 x) {
asm volatile("csrw pmpcfg0, %0" : : "r"(x));
}
static inline void w_pmpaddr0(uint64 x) {
asm volatile("csrw pmpaddr0, %0" : : "r"(x));
}
// use riscv's sv39 page table scheme.
#define SATP_SV39 (8L << 60)
#define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12))
// supervisor address translation and protection;
// holds the address of the page table.
static inline void w_satp(uint64 x) {
asm volatile("csrw satp, %0" : : "r"(x));
}
static inline uint64 r_satp() {
uint64 x;
asm volatile("csrr %0, satp" : "=r"(x));
return x;
}
static inline void w_mscratch(uint64 x) {
asm volatile("csrw mscratch, %0" : : "r"(x));
}
// Supervisor Trap Cause
static inline uint64 r_scause() {
uint64 x;
asm volatile("csrr %0, scause" : "=r"(x));
return x;
}
// Supervisor Trap Value
static inline uint64 r_stval() {
uint64 x;
asm volatile("csrr %0, stval" : "=r"(x));
return x;
}
// Machine-mode Counter-Enable
static inline void w_mcounteren(uint64 x) {
asm volatile("csrw mcounteren, %0" : : "r"(x));
}
static inline uint64 r_mcounteren() {
uint64 x;
asm volatile("csrr %0, mcounteren" : "=r"(x));
return x;
}
// machine-mode cycle counter
static inline uint64 r_time() {
uint64 x;
asm volatile("csrr %0, time" : "=r"(x));
return x;
}
// enable device interrupts
static inline void intr_on() { w_sstatus(r_sstatus() | SSTATUS_SIE); }
// disable device interrupts
static inline void intr_off() { w_sstatus(r_sstatus() & ~SSTATUS_SIE); }
// are device interrupts enabled?
static inline int intr_get() {
uint64 x = r_sstatus();
return (x & SSTATUS_SIE) != 0;
}
static inline uint64 r_sp() {
uint64 x;
asm volatile("mv %0, sp" : "=r"(x));
return x;
}
// read and write tp, the thread pointer, which xv6 uses to hold
// this core's hartid (core number), the index into cpus[].
static inline uint64 r_tp() {
uint64 x;
asm volatile("mv %0, tp" : "=r"(x));
return x;
}
static inline void w_tp(uint64 x) { asm volatile("mv tp, %0" : : "r"(x)); }
static inline uint64 r_ra() {
uint64 x;
asm volatile("mv %0, ra" : "=r"(x));
return x;
}
// flush the TLB.
static inline void sfence_vma() {
// the zero, zero means flush all TLB entries.
asm volatile("sfence.vma zero, zero");
}
typedef uint64 pte_t;
typedef uint64 *pagetable_t; // 512 PTEs
#endif // __ASSEMBLER__
#define PGSIZE 4096 // bytes per page
#define PGSHIFT 12 // bits of offset within a page
#define PGROUNDUP(sz) (((sz) + PGSIZE - 1) & ~(PGSIZE - 1))
#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE - 1))
#define PTE_V (1L << 0) // valid
#define PTE_R (1L << 1)
#define PTE_W (1L << 2)
#define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access
// shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
#define PTE2PA(pte) (((pte) >> 10) << 12)
#define PTE_FLAGS(pte) ((pte)&0x3FF)
// extract the three 9-bit page table indices from a virtual address.
#define PXMASK 0x1FF // 9 bits
#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
#define PX(level, va) ((((uint64)(va)) >> PXSHIFT(level)) & PXMASK)
// one beyond the highest possible virtual address.
// MAXVA is actually one bit less than the max allowed by
// Sv39, to avoid having to sign-extend virtual addresses
// that have the high bit set.
#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))