2 * Early initialization code for riscv virtual memory
4 * Copyright 2015 Google Inc.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14 * GNU General Public License for more details.
18 #include <arch/encoding.h>
21 #include <console/console.h>
23 pte_t
* root_page_table
;
25 void walk_page_table(void) {
26 // TODO: implement a full walk to make sure memory was set up
27 //const size_t pte_per_page = RISCV_PGSIZE/sizeof(void*);
28 pte_t
* t
= root_page_table
;
29 printk(BIOS_DEBUG
, "root_page_table: %p\n", t
);
32 void enter_supervisor(void) {
33 // enter supervisor mode
34 asm volatile("la t0, 1f; csrw mepc, t0; eret; 1:" ::: "t0");
39 asm volatile("sfence.vm");
42 size_t pte_ppn(pte_t pte
)
44 return pte
>> PTE_PPN_SHIFT
;
47 pte_t
ptd_create(uintptr_t ppn
)
49 return (ppn
<< PTE_PPN_SHIFT
) | PTE_V
| PTE_TYPE_TABLE
;
52 pte_t
pte_create(uintptr_t ppn
, int prot
, int user
)
54 pte_t pte
= (ppn
<< PTE_PPN_SHIFT
) | PTE_V
;
55 if (prot
& PROT_WRITE
) pte
|= PTE_TYPE_URW_SRW
;
56 if (prot
& PROT_EXEC
) pte
|= PTE_TYPE_URX_SRX
;
57 if (!user
) pte
|= PTE_TYPE_SR
;
61 void init_vm(uintptr_t virtMemStart
, uintptr_t physMemStart
, uintptr_t pageTableStart
) {
62 pte_t
* sbi_pt
= (pte_t
*) pageTableStart
;
63 memset(sbi_pt
, 0, RISCV_PGSIZE
);
64 // need to leave room for sbi page
65 uintptr_t memorySize
= 0x7F000000; // 0xFFF... - 0xFFFFFFFF81000000 - RISCV_PGSIZE
68 pte_t
* middle_pt
= (void*)sbi_pt
+ RISCV_PGSIZE
;
69 size_t num_middle_pts
= 2; // 3 level page table, 39 bit virtual address space for now
72 pte_t
* root_pt
= (void*)middle_pt
+ num_middle_pts
* RISCV_PGSIZE
;
73 memset(middle_pt
, 0, (num_middle_pts
+ 1) * RISCV_PGSIZE
); // 0's out middle_pt and root_pt
74 for (size_t i
= 0; i
< num_middle_pts
; i
++)
75 root_pt
[(1<<RISCV_PGLEVEL_BITS
)-num_middle_pts
+i
] = ptd_create(((uintptr_t)middle_pt
>> RISCV_PGSHIFT
) + i
);
77 // fill the middle page table
78 for (uintptr_t vaddr
= virtMemStart
, paddr
= physMemStart
; paddr
< memorySize
; vaddr
+= SUPERPAGE_SIZE
, paddr
+= SUPERPAGE_SIZE
) {
79 int l2_shift
= RISCV_PGLEVEL_BITS
+ RISCV_PGSHIFT
;
80 size_t l2_idx
= (virtMemStart
>> l2_shift
) & ((1 << RISCV_PGLEVEL_BITS
)-1);
81 l2_idx
+= ((vaddr
- virtMemStart
) >> l2_shift
);
82 middle_pt
[l2_idx
] = pte_create(paddr
>> RISCV_PGSHIFT
, PROT_READ
|PROT_WRITE
|PROT_EXEC
, 0);
85 // map SBI at top of vaddr space
86 uintptr_t num_sbi_pages
= 1; // only need to map a single page for sbi interface
87 uintptr_t sbiStartAddress
= 0x2000; // the start of the sbi mapping
88 uintptr_t sbiAddr
= sbiStartAddress
;
89 for (uintptr_t i
= 0; i
< num_sbi_pages
; i
++) {
90 uintptr_t idx
= (1 << RISCV_PGLEVEL_BITS
) - num_sbi_pages
+ i
;
91 sbi_pt
[idx
] = pte_create(sbiAddr
>> RISCV_PGSHIFT
, PROT_READ
|PROT_EXEC
, 0);
92 sbiAddr
+= RISCV_PGSIZE
;
94 pte_t
* sbi_pte
= middle_pt
+ ((num_middle_pts
<< RISCV_PGLEVEL_BITS
)-1);
95 *sbi_pte
= ptd_create((uintptr_t)sbi_pt
>> RISCV_PGSHIFT
);
98 root_page_table
= root_pt
;
99 write_csr(sptbr
, root_pt
);
102 void initVirtualMemory(void) {
103 printk(BIOS_DEBUG
, "Initializing virtual memory...\n");
104 uintptr_t physicalStart
= 0x1000000; // TODO: Figure out how to grab this from cbfs
105 uintptr_t virtualStart
= 0xffffffff81000000;
106 uintptr_t pageTableStart
= 0x1400000;
107 init_vm(virtualStart
, physicalStart
, pageTableStart
);
109 printk(BIOS_DEBUG
, "Finished initializing virtual memory, starting walk...\n");
113 void mstatus_init(void)
115 // supervisor support is required
118 ms
= INSERT_FIELD(ms
, MSTATUS_PRV
, PRV_M
);
119 ms
= INSERT_FIELD(ms
, MSTATUS_PRV1
, PRV_S
);
120 ms
= INSERT_FIELD(ms
, MSTATUS_PRV2
, PRV_U
);
121 ms
= INSERT_FIELD(ms
, MSTATUS_IE2
, 1);
122 ms
= INSERT_FIELD(ms
, MSTATUS_VM
, VM_CHOICE
);
123 ms
= INSERT_FIELD(ms
, MSTATUS_FS
, 3);
124 ms
= INSERT_FIELD(ms
, MSTATUS_XS
, 3);
125 write_csr(mstatus
, ms
);
126 ms
= read_csr(mstatus
);
128 if (EXTRACT_FIELD(ms
, MSTATUS_VM
) != VM_CHOICE
) {
129 printk(BIOS_DEBUG
, "we don't have virtual memory...\n");
131 printk(BIOS_DEBUG
, "-----------------------------\n");
132 printk(BIOS_DEBUG
, "virtual memory status enabled\n");
133 printk(BIOS_DEBUG
, "-----------------------------\n");
136 clear_csr(mip
, MIP_MSIP
);
137 set_csr(mie
, MIP_MSIP
);