blob: a7a81fbab5d39eb45c20bcebd0011604d60a1c3c [file] [log] [blame]
Thaminda Edirisooriyab0945832015-08-26 15:28:04 -07001/*
2 * Early initialization code for riscv virtual memory
3 *
4 * Copyright 2015 Google Inc.
5 *
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
9 * the License.
10 *
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.
Thaminda Edirisooriyab0945832015-08-26 15:28:04 -070015 */
16
17#include <vm.h>
18#include <arch/encoding.h>
19#include <atomic.h>
20#include <stdint.h>
21#include <console/console.h>
22
23pte_t* root_page_table;
24
25void 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);
30}
31
Thaminda Edirisooriyab0945832015-08-26 15:28:04 -070032void flush_tlb(void)
33{
34 asm volatile("sfence.vm");
35}
36
37size_t pte_ppn(pte_t pte)
38{
39 return pte >> PTE_PPN_SHIFT;
40}
41
42pte_t ptd_create(uintptr_t ppn)
43{
44 return (ppn << PTE_PPN_SHIFT) | PTE_V | PTE_TYPE_TABLE;
45}
46
47pte_t pte_create(uintptr_t ppn, int prot, int user)
48{
49 pte_t pte = (ppn << PTE_PPN_SHIFT) | PTE_V;
50 if (prot & PROT_WRITE) pte |= PTE_TYPE_URW_SRW;
51 if (prot & PROT_EXEC) pte |= PTE_TYPE_URX_SRX;
52 if (!user) pte |= PTE_TYPE_SR;
53 return pte;
54}
55
56void init_vm(uintptr_t virtMemStart, uintptr_t physMemStart, uintptr_t pageTableStart) {
57 pte_t* sbi_pt = (pte_t*) pageTableStart;
58 memset(sbi_pt, 0, RISCV_PGSIZE);
59 // need to leave room for sbi page
60 uintptr_t memorySize = 0x7F000000; // 0xFFF... - 0xFFFFFFFF81000000 - RISCV_PGSIZE
61
62 // middle page table
63 pte_t* middle_pt = (void*)sbi_pt + RISCV_PGSIZE;
64 size_t num_middle_pts = 2; // 3 level page table, 39 bit virtual address space for now
65
66 // root page table
67 pte_t* root_pt = (void*)middle_pt + num_middle_pts * RISCV_PGSIZE;
68 memset(middle_pt, 0, (num_middle_pts + 1) * RISCV_PGSIZE); // 0's out middle_pt and root_pt
69 for (size_t i = 0; i < num_middle_pts; i++)
70 root_pt[(1<<RISCV_PGLEVEL_BITS)-num_middle_pts+i] = ptd_create(((uintptr_t)middle_pt >> RISCV_PGSHIFT) + i);
71
72 // fill the middle page table
73 for (uintptr_t vaddr = virtMemStart, paddr = physMemStart; paddr < memorySize; vaddr += SUPERPAGE_SIZE, paddr += SUPERPAGE_SIZE) {
74 int l2_shift = RISCV_PGLEVEL_BITS + RISCV_PGSHIFT;
75 size_t l2_idx = (virtMemStart >> l2_shift) & ((1 << RISCV_PGLEVEL_BITS)-1);
76 l2_idx += ((vaddr - virtMemStart) >> l2_shift);
77 middle_pt[l2_idx] = pte_create(paddr >> RISCV_PGSHIFT, PROT_READ|PROT_WRITE|PROT_EXEC, 0);
78 }
79
80 // map SBI at top of vaddr space
81 uintptr_t num_sbi_pages = 1; // only need to map a single page for sbi interface
82 uintptr_t sbiStartAddress = 0x2000; // the start of the sbi mapping
83 uintptr_t sbiAddr = sbiStartAddress;
84 for (uintptr_t i = 0; i < num_sbi_pages; i++) {
85 uintptr_t idx = (1 << RISCV_PGLEVEL_BITS) - num_sbi_pages + i;
86 sbi_pt[idx] = pte_create(sbiAddr >> RISCV_PGSHIFT, PROT_READ|PROT_EXEC, 0);
87 sbiAddr += RISCV_PGSIZE;
88 }
89 pte_t* sbi_pte = middle_pt + ((num_middle_pts << RISCV_PGLEVEL_BITS)-1);
90 *sbi_pte = ptd_create((uintptr_t)sbi_pt >> RISCV_PGSHIFT);
91
92 mb();
93 root_page_table = root_pt;
94 write_csr(sptbr, root_pt);
95}
96
97void initVirtualMemory(void) {
98 printk(BIOS_DEBUG, "Initializing virtual memory...\n");
99 uintptr_t physicalStart = 0x1000000; // TODO: Figure out how to grab this from cbfs
100 uintptr_t virtualStart = 0xffffffff81000000;
Thaminda Edirisooriya08c10a92015-09-10 10:58:58 -0700101 uintptr_t pageTableStart = 0x1400000;
Thaminda Edirisooriyab0945832015-08-26 15:28:04 -0700102 init_vm(virtualStart, physicalStart, pageTableStart);
103 mb();
104 printk(BIOS_DEBUG, "Finished initializing virtual memory, starting walk...\n");
105 walk_page_table();
106}
107
108void mstatus_init(void)
109{
110 // supervisor support is required
111
112 uintptr_t ms = 0;
113 ms = INSERT_FIELD(ms, MSTATUS_PRV, PRV_M);
114 ms = INSERT_FIELD(ms, MSTATUS_PRV1, PRV_S);
115 ms = INSERT_FIELD(ms, MSTATUS_PRV2, PRV_U);
116 ms = INSERT_FIELD(ms, MSTATUS_IE2, 1);
117 ms = INSERT_FIELD(ms, MSTATUS_VM, VM_CHOICE);
118 ms = INSERT_FIELD(ms, MSTATUS_FS, 3);
119 ms = INSERT_FIELD(ms, MSTATUS_XS, 3);
120 write_csr(mstatus, ms);
121 ms = read_csr(mstatus);
122
123 if (EXTRACT_FIELD(ms, MSTATUS_VM) != VM_CHOICE) {
124 printk(BIOS_DEBUG, "we don't have virtual memory...\n");
125 } else {
126 printk(BIOS_DEBUG, "-----------------------------\n");
127 printk(BIOS_DEBUG, "virtual memory status enabled\n");
128 printk(BIOS_DEBUG, "-----------------------------\n");
129 }
130
131 clear_csr(mip, MIP_MSIP);
132 set_csr(mie, MIP_MSIP);
133}