RISC-V port mostly links now
[akaros.git] / kern / arch / riscv / cboot.c
1 #include <multiboot.h>
2 #include <ros/memlayout.h>
3 #include <arch/arch.h>
4 #include <arch/mmu.h>
5 #include <string.h>
6 #include <assert.h>
7
8 static void
9 build_multiboot_info(multiboot_info_t* mbi)
10 {
11         long memsize_kb = mfpcr(PCR_MEMSIZE)*(PGSIZE/1024);
12         long basemem_kb = EXTPHYSMEM/1024;
13
14         memset(mbi, 0, sizeof(mbi));
15
16         mbi->flags = 0x00000001;
17         mbi->mem_lower = basemem_kb;
18         mbi->mem_upper = memsize_kb - basemem_kb;
19 }
20
21 #define KERNSIZE ((uintptr_t)(-KERNBASE))
22 #ifdef __riscv64
23 #define NL3PT ((KERNSIZE+L2PGSIZE-1)/L2PGSIZE)
24 pte_t l1pt[NPTENTRIES], l2pt[NPTENTRIES], l3pts[NL3PT][NPTENTRIES]
25       __attribute__((section("data"))) __attribute__((aligned(PGSIZE)));
26 #else
27 pte_t l1pt[NPTENTRIES]
28       __attribute__((section("data"))) __attribute__((aligned(PGSIZE)));
29 #endif
30
31 void
32 mmu_init()
33 {
34         pte_t* l1pt_phys = (pte_t*)((uint8_t*)l1pt - KERNBASE);
35         pte_t* l2pt_phys = (pte_t*)((uint8_t*)l2pt - KERNBASE);
36
37         // Retain the identity mapping [0,KERNSIZE]
38         for(uintptr_t i = 0; i < (KERNSIZE+L1PGSIZE-1)/L1PGSIZE; i++)
39                 l1pt_phys[i] = PTE(LA2PPN(i*L1PGSIZE), PTE_KERN_RW|PTE_E);
40
41         #ifdef __riscv64
42         // for rv64, we need to create an L1 and an L2 PT, and many L3 PTs.
43
44         // kernel can be mapped by a single L1 page
45         static_assert(KERNSIZE <= L1PGSIZE);
46         static_assert(KERNBASE % L3PGSIZE == 0);
47
48         // highest L1 page contains KERNBASE mapping
49         uintptr_t l1x = L1X(KERNBASE);
50         l1pt_phys[l1x] = PTD(l2pt);
51
52         for(uintptr_t i = 0; i < NL3PT; i++)
53         {
54                 uintptr_t l2x = L2X(KERNBASE + i*L2PGSIZE);
55                 l2pt_phys[l2x] = PTD(l3pts[l2x]);
56                 for(uintptr_t l3x = 0; l3x < NPTENTRIES; l3x++)
57                 {
58                         uintptr_t addr = PGADDR(l1x, l2x, l3x, 0, 0);
59                         if(addr >= KERNBASE)
60                                 l3pts[l2x][l3x] = PTE(LA2PPN(addr), PTE_KERN_RW | PTE_E);
61                 }
62         }
63
64         // KERNBASE mapping
65         l1pt_phys[NPTENTRIES-1] = PTD(l2pt_phys);
66         for(uintptr_t i = 0; i < (KERNSIZE+L2PGSIZE-1)/L2PGSIZE; i++)
67                 l2pt_phys[i] = PTD(l1pt_phys + i*NPTENTRIES);
68         
69   // Map the upper 2GB (0xFFFFFFFF80000000 and up) to alias the KERNBASE
70         // mapping.  We'll use this region to reference static/global variables
71         // more efficiently with a LUI/ADD pair, which can only reach addresses
72         // 0x00000000->0x7FFFF7FF and 0xFFFFFFFF80000000->0xFFFFFFFFFFFFF7FF.
73         // The alternative requires an 8-instruction sequence in the general case.
74   const uintptr_t start = 0xFFFFFFFF80000000;
75         static_assert(start % L2PGSIZE == 0);
76         for(uintptr_t va = start; va != 0; va += L2PGSIZE)
77           l2pt[L2X(va)] = PTE(LA2PPN(va-start), PTE_KERN_RW|PTE_E);
78         #else
79         // for rv32, just create the L1 page table.
80         static_assert(KERNBASE % L1PGSIZE == 0);
81
82         // KERNBASE mapping
83         for(uintptr_t pa = 0; pa < KERNSIZE; pa += L1PGSIZE)
84                 l1pt_phys[L1X(KERNBASE+pa)] = PTE(LA2PPN(pa), PTE_KERN_RW|PTE_E);
85         #endif
86
87         lcr3((uintptr_t)l1pt_phys);
88         mtpcr(PCR_SR, mfpcr(PCR_SR) | SR_VM);
89 }
90
91 static void
92 mmu_init_cleanup()
93 {
94         // after relocation, we no longer rely on the identity mapping
95         for(uintptr_t va = 0; va < KERNSIZE+L1PGSIZE-1; va += L1PGSIZE)
96                 l1pt[L1X(va)] = 0;
97         tlbflush();
98 }
99
100 void
101 cmain()
102 {
103         mmu_init_cleanup();
104
105         multiboot_info_t mbi;
106         build_multiboot_info(&mbi);
107
108         extern void kernel_init(multiboot_info_t *mboot_info);
109         // kernel_init expects a pre-relocation mbi address
110         kernel_init((multiboot_info_t*)((uint8_t*)&mbi - KERNBASE));
111 }