de473e4c6cf2337fe124d80e9c1e0906e1a82fc1
[akaros.git] / kern / arch / sparc / pmap.c
1 #ifdef __SHARC__
2 #pragma nosharc
3 #endif
4
5 #ifdef __DEPUTY__
6 #pragma nodeputy
7 #endif
8
9 #include <arch/mmu.h>
10 #include <ros/memlayout.h>
11 #include <pmap.h>
12 #include <string.h>
13 #include <kmalloc.h>
14
15 physaddr_t boot_cr3;
16 pde_t* boot_pgdir;
17 page_t* pages;
18 page_list_t page_free_list;
19
20 void
21 vm_init(void)
22 {
23         // we already set up our page tables before jumping
24         // into the kernel, so there's not much going on here
25
26         extern pde_t l1_page_table[NL1ENTRIES];
27         boot_pgdir = l1_page_table;
28         boot_cr3 = PADDR(boot_pgdir);
29 }
30
31 error_t
32 pagetable_remove(pde_t* l1pt, void* va)
33 {
34         panic("pagetable_remove doesn't work yet... -asw");
35         return 0;
36 }
37
38 pte_t*
39 pgdir_walk(pde_t* l1pt, const void*SNT va, int create)
40 {
41         pte_t *l1pte, *l2pt, *l2pte, *l3pt, *l3pte;
42         page_t* new_table;
43
44         l1pte = &l1pt[L1X(va)];
45         if(*l1pte & PTE_PTE)
46                 return l1pte;
47         if(!(*l1pte & PTE_PTD))
48         {
49                 int i, l1x_start, l2_tables_per_page;
50                 physaddr_t pa;
51
52                 if(!create)
53                         return NULL;
54
55                 // create a new L2 PT.  we actually allocated way more
56                 // space than needed, so also use it for the adjacent
57                 // l2_tables_per_page-1 pages (if they're unmapped)
58
59                 if(kpage_alloc(&new_table))
60                         return NULL;
61                 memset(page2kva(new_table),0,PGSIZE);
62
63                 l2_tables_per_page = PGSIZE/(sizeof(pte_t)*NL2ENTRIES);
64                 l1x_start = L1X(va)/l2_tables_per_page*l2_tables_per_page;
65
66                 for(i = 0; i < l2_tables_per_page; i++)
67                 {
68                         if(l1pt[l1x_start+i] != 0)
69                                 continue;
70
71                         page_incref(new_table);
72                         pa = page2pa(new_table) + i*sizeof(pte_t)*NL2ENTRIES;
73                         l1pt[l1x_start+i] = PTD(pa);
74                 }
75
76                 l1pte = &l1pt[L1X(va)];
77         }
78
79         l2pt = (pte_t*)KADDR(PTD_ADDR(*l1pte));
80         l2pte = &l2pt[L2X(va)];
81         if(*l2pte & PTE_PTE)
82                 return l2pte;
83         if(!(*l2pte & PTE_PTD))
84         {
85                 int i, l2x_start, l3_tables_per_page;
86                 physaddr_t pa;
87
88                 if(!create)
89                         return NULL;
90
91                 if(kpage_alloc(&new_table))
92                         return NULL;
93                 memset(page2kva(new_table),0,PGSIZE);
94
95                 l3_tables_per_page = PGSIZE/(sizeof(pte_t)*NL3ENTRIES);
96                 l2x_start = L2X(va)/l3_tables_per_page*l3_tables_per_page;
97
98                 for(i = 0; i < l3_tables_per_page; i++)
99                 {
100                         if(l2pt[l2x_start+i] != 0)
101                                 continue;
102
103                         page_incref(new_table);
104                         pa = page2pa(new_table) + i*sizeof(pte_t)*NL3ENTRIES;
105                         l2pt[l2x_start+i] = PTD(pa);
106                 }
107
108                 l2pte = &l2pt[L2X(va)];
109         }
110
111         l3pt = (pte_t*)KADDR(PTD_ADDR(*l2pte));
112         l3pte = &l3pt[L3X(va)];
113         return l3pte;
114 }
115
116 /* TODO: this is probably wrong, since it only returns the pte as if it were the
117  * perms. */
118 int get_va_perms(pde_t *pgdir, const void *SNT va)
119 {
120         pte_t* pte = pgdir_walk(pgdir, va, 0);
121         return pte == NULL ? 0 : (*pte & (PTE_ACC | PTE_PTE));
122 }
123
124 void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len)
125 {
126         addr = ROUNDUP(MIN(addr,UMMAP_START),PGSIZE);
127         len = ROUNDUP(len,PGSIZE);
128
129         for(char* a = (char*)addr; a < (char*)USTACKBOT; a += PGSIZE)
130         {
131                 for(char* b = a; b < a+len; b += PGSIZE)
132                 {
133                         pte_t* pte = pgdir_walk(pgdir,b,0);
134                         if(pte && (*pte & PTE_P))
135                         {
136                                 a = b;
137                                 break;
138                         }
139                         if(b+PGSIZE == a+len)
140                                 return a;
141                 }
142         }
143         return NULL;
144 }
145
146 void
147 page_check(void)
148 {
149 }