xv6, line by line
kernel/riscv.h

kernel/riscv.h

C header · 417 lines · annotated 100% · kernel · upstream

Included by 26 fileskernel/bio.c, kernel/console.c, kernel/exec.c, kernel/file.c, kernel/fs.c, kernel/kalloc.c, kernel/log.c, kernel/main.c, kernel/pipe.c, kernel/plic.c, kernel/printk.c, kernel/proc.c, kernel/sleeplock.c, kernel/spinlock.c, kernel/start.c, kernel/syscall.c, kernel/sysfile.c, kernel/sysproc.c, kernel/trampoline.S, kernel/trap.c, kernel/uart.c, kernel/virtio_disk.c, kernel/vm.c, user/grind.c, user/ulib.c, user/usertests.c
About this file

The kernel’s vocabulary for talking to the RISC-V hardware. C has no way to name a CSR (control and status register) or a special instruction, so this header wraps each one xv6 needs in a tiny function containing one line of inline assembly: r_sstatus reads sstatus, w_satp writes satp, sfence_vma flushes the TLB (translation lookaside buffer), and so on. Each is static inline, so a call compiles to the single instruction it wraps.

The second half defines the constants and macros of Sv39 paging, which kernel/vm.c is built on: the page size, the bits of a PTE (page-table entry), and the arithmetic that converts between physical addresses, PTEs and page-table indices.

The file is long but repetitive. Most of it is pairs of accessors, r_X() to read register X and w_X(v) to write it; the notes explain the pattern once (lines 3–10) and then say what each register is for and which bits xv6 uses.

Read before: kernel/start.c uses the machine-mode half. Read next: kernel/vm.c.

1#ifndef __ASSEMBLER__
3// which hart (core) is this?
4static inline uint64
6{
8 asm volatile("csrr %0, mhartid" : "=r"(x));
9 return x;
12// Machine Status Register, mstatus
14#define MSTATUS_MPP_MASK (3L << 11) // previous mode.
15#define MSTATUS_MPP_M (3L << 11)
16#define MSTATUS_MPP_S (1L << 11)
17#define MSTATUS_MPP_U (0L << 11)
19static inline uint64
23 asm volatile("csrr %0, mstatus" : "=r"(x));
24 return x;
27static inline void
30 asm volatile("csrw mstatus, %0" : : "r"(x));
33// machine exception program counter, holds the
34// instruction address to which a return from
35// exception will go.
36static inline void
39 asm volatile("csrw mepc, %0" : : "r"(x));
42// Supervisor Status Register, sstatus
44#define SSTATUS_SPP (1L << 8) // Previous mode, 1=Supervisor, 0=User
45#define SSTATUS_SPIE (1L << 5) // Supervisor Previous Interrupt Enable
46#define SSTATUS_UPIE (1L << 4) // User Previous Interrupt Enable
47#define SSTATUS_SIE (1L << 1) // Supervisor Interrupt Enable
48#define SSTATUS_UIE (1L << 0) // User Interrupt Enable
50static inline uint64
54 asm volatile("csrr %0, sstatus" : "=r"(x));
55 return x;
58static inline void
61 asm volatile("csrw sstatus, %0" : : "r"(x));
64static inline void
67 __asm__ __volatile__("csrs sstatus, %0" ::"rK"(x) : "memory");
70static inline void
73 __asm__ __volatile__("csrc sstatus, %0" ::"rK"(x) : "memory");
76static inline uint64
79 __asm__ __volatile__("csrrc %0, sstatus, %1" : "=r"(x) : "rK"(x) : "memory");
80 return x;
83// Supervisor Interrupt Pending
84static inline uint64
88 asm volatile("csrr %0, sip" : "=r"(x));
89 return x;
92static inline void
95 asm volatile("csrw sip, %0" : : "r"(x));
98// Supervisor Interrupt Enable
99#define SIE_SEIE (1L << 9) // external
100#define SIE_STIE (1L << 5) // timer
101static inline uint64
105 asm volatile("csrr %0, sie" : "=r"(x));
106 return x;
109static inline void
112 asm volatile("csrw sie, %0" : : "r"(x));
115// Machine-mode Interrupt Enable
116#define MIE_STIE (1L << 5) // supervisor timer
117static inline uint64
121 asm volatile("csrr %0, mie" : "=r"(x));
122 return x;
125static inline void
128 asm volatile("csrw mie, %0" : : "r"(x));
131// supervisor exception program counter, holds the
132// instruction address to which a return from
133// exception will go.
134static inline void
137 asm volatile("csrw sepc, %0" : : "r"(x));
140static inline uint64
144 asm volatile("csrr %0, sepc" : "=r"(x));
145 return x;
148// Machine Exception Delegation
149static inline uint64
153 asm volatile("csrr %0, medeleg" : "=r"(x));
154 return x;
157static inline void
160 asm volatile("csrw medeleg, %0" : : "r"(x));
163// Machine Interrupt Delegation
164static inline uint64
168 asm volatile("csrr %0, mideleg" : "=r"(x));
169 return x;
172static inline void
175 asm volatile("csrw mideleg, %0" : : "r"(x));
178// Supervisor Trap-Vector Base Address
179// low two bits are mode.
180static inline void
183 asm volatile("csrw stvec, %0" : : "r"(x));
186static inline uint64
190 asm volatile("csrr %0, stvec" : "=r"(x));
191 return x;
194// Supervisor Timer Comparison Register
195static inline uint64
199 // asm volatile("csrr %0, stimecmp" : "=r" (x) );
200 asm volatile("csrr %0, 0x14d" : "=r"(x));
201 return x;
204static inline void
207 // asm volatile("csrw stimecmp, %0" : : "r" (x));
208 asm volatile("csrw 0x14d, %0" : : "r"(x));
211// Machine Environment Configuration Register
213#define MENVCFG_STCE (1L << 63)
214#define MENVCFG_ADUE (1L << 61)
216static inline uint64
220 // asm volatile("csrr %0, menvcfg" : "=r" (x) );
221 asm volatile("csrr %0, 0x30a" : "=r"(x));
222 return x;
225static inline void
228 // asm volatile("csrw menvcfg, %0" : : "r" (x));
229 asm volatile("csrw 0x30a, %0" : : "r"(x));
232// Physical Memory Protection
233static inline void
236 asm volatile("csrw pmpcfg0, %0" : : "r"(x));
239static inline void
242 asm volatile("csrw pmpaddr0, %0" : : "r"(x));
245// use riscv's sv39 page table scheme.
246#define SATP_SV39 (8L << 60)
248#define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12))
250// supervisor address translation and protection;
251// holds the address of the page table.
252static inline void
255 asm volatile("csrw satp, %0" : : "r"(x));
258static inline uint64
262 asm volatile("csrr %0, satp" : "=r"(x));
263 return x;
266// Supervisor Trap Cause
267static inline uint64
271 asm volatile("csrr %0, scause" : "=r"(x));
272 return x;
275// Supervisor Trap Value
276static inline uint64
280 asm volatile("csrr %0, stval" : "=r"(x));
281 return x;
284// Machine-mode Counter-Enable
285static inline void
288 asm volatile("csrw mcounteren, %0" : : "r"(x));
291static inline uint64
295 asm volatile("csrr %0, mcounteren" : "=r"(x));
296 return x;
299// machine-mode cycle counter
300static inline uint64
304 asm volatile("csrr %0, time" : "=r"(x));
305 return x;
308// enable device interrupts
309static inline void
315// disable device interrupts
316static inline void
322// are device interrupts enabled?
323static inline int
327 return (x & SSTATUS_SIE) != 0;
330static inline uint64
334 asm volatile("mv %0, sp" : "=r"(x));
335 return x;
338// read and write tp, the thread pointer, which xv6 uses to hold
339// this core's hartid (core number), the index into cpus[].
340static inline uint64
344 asm volatile("mv %0, tp" : "=r"(x));
345 return x;
348static inline void
351 asm volatile("mv tp, %0" : : "r"(x));
354static inline uint64
358 asm volatile("mv %0, ra" : "=r"(x));
359 return x;
362// flush the TLB.
363static inline void
366 // the zero, zero means flush all TLB entries.
367 asm volatile("sfence.vma zero, zero" ::: "memory");
370// fence for memory-mapped IO
371static inline void
374 asm volatile("fence iorw, iorw" ::: "memory");
377// fence for icache
378static inline void
381 asm volatile("fence.i" ::: "memory");
384typedef uint64 pte_t;
385typedef uint64 *pagetable_t; // 512 PTEs
387#endif // __ASSEMBLER__
389#define PGSIZE 4096 // bytes per page
390#define PGSHIFT 12 // bits of offset within a page
392#define PGROUNDUP(sz) (((sz) + PGSIZE - 1) & ~(PGSIZE - 1))
393#define PGROUNDDOWN(a) (((a)) & ~(PGSIZE - 1))
395#define PTE_V (1L << 0) // valid
396#define PTE_R (1L << 1)
397#define PTE_W (1L << 2)
398#define PTE_X (1L << 3)
399#define PTE_U (1L << 4) // user can access
401// shift a physical address to the right place for a PTE.
402#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
404#define PTE2PA(pte) (((pte) >> 10) << 12)
406#define PTE_FLAGS(pte) ((pte) & 0x3FF)
408// extract the three 9-bit page table indices from a virtual address.
409#define PXMASK 0x1FF // 9 bits
410#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
411#define PX(level, va) ((((uint64)(va)) >> PXSHIFT(level)) & PXMASK)
413// one beyond the highest possible virtual address.
414// MAXVA is actually one bit less than the max allowed by
415// Sv39, to avoid having to sign-extend virtual addresses
416// that have the high bit set.
417#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))