rev |
line source |
nuclear@17
|
1 #include <stdio.h>
|
nuclear@17
|
2 #include <string.h>
|
nuclear@17
|
3 #include <inttypes.h>
|
nuclear@17
|
4 #include "vm.h"
|
nuclear@17
|
5 #include <stdio.h>
|
nuclear@17
|
6 #include "intr.h"
|
nuclear@17
|
7 #include "mem.h"
|
nuclear@17
|
8 #include "panic.h"
|
nuclear@17
|
9
|
nuclear@17
|
10
|
nuclear@17
|
11 /* defined in vm-asm.S */
|
nuclear@17
|
12 void enable_paging(void);
|
nuclear@17
|
13 void set_pgdir_addr(uint32_t addr);
|
nuclear@17
|
14 uint32_t get_fault_addr(void);
|
nuclear@17
|
15
|
nuclear@17
|
16 static void pgfault(int inum, uint32_t err);
|
nuclear@17
|
17
|
nuclear@17
|
18 /* page directory */
|
nuclear@18
|
19 static uint32_t *pgdir;
|
nuclear@17
|
20
|
nuclear@17
|
21 #define KMEM_START 0xc0000000
|
nuclear@17
|
22 #define IDMAP_START 0xa0000
|
nuclear@17
|
23
|
nuclear@17
|
24 #define ATTR_PGDIR_MASK 0x3f
|
nuclear@17
|
25 #define ATTR_PGTBL_MASK 0x1ff
|
nuclear@17
|
26 #define ADDR_PGENT_MASK 0xfffff000
|
nuclear@17
|
27
|
nuclear@17
|
28 #define PAGEFAULT 14
|
nuclear@17
|
29
|
nuclear@17
|
30 void init_vm(struct mboot_info *mb)
|
nuclear@17
|
31 {
|
nuclear@17
|
32 init_mem(mb);
|
nuclear@17
|
33
|
nuclear@18
|
34 pgdir = (uint32_t*)alloc_phys_page();
|
nuclear@17
|
35 memset(pgdir, 0, sizeof pgdir);
|
nuclear@17
|
36
|
nuclear@17
|
37 /* map the video memory and kernel code 1-1 */
|
nuclear@17
|
38 map_mem_range(IDMAP_START, MAX_BRK - IDMAP_START, IDMAP_START, 0);
|
nuclear@17
|
39
|
nuclear@17
|
40 interrupt(PAGEFAULT, pgfault);
|
nuclear@17
|
41
|
nuclear@17
|
42 set_pgdir_addr((int32_t)pgdir);
|
nuclear@17
|
43 enable_paging();
|
nuclear@17
|
44 }
|
nuclear@17
|
45
|
nuclear@17
|
46 void map_page(int vpage, int ppage, unsigned int attr)
|
nuclear@17
|
47 {
|
nuclear@17
|
48 uint32_t *pgtbl;
|
nuclear@17
|
49 int diridx = PAGE_TO_PGTBL(vpage);
|
nuclear@17
|
50 int pgidx = PAGE_TO_PGTBL_PG(vpage);
|
nuclear@17
|
51
|
nuclear@17
|
52 if(!(pgdir[diridx] & PG_PRESENT)) {
|
nuclear@17
|
53 uint32_t addr = alloc_phys_page();
|
nuclear@17
|
54 pgtbl = (uint32_t*)addr;
|
nuclear@18
|
55 memset(pgtbl, 0, PGSIZE);
|
nuclear@18
|
56
|
nuclear@17
|
57 pgdir[diridx] = addr | (attr & ATTR_PGDIR_MASK) | PG_PRESENT;
|
nuclear@17
|
58 } else {
|
nuclear@17
|
59 pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK);
|
nuclear@17
|
60 }
|
nuclear@17
|
61
|
nuclear@17
|
62 pgtbl[pgidx] = PAGE_TO_ADDR(ppage) | (attr & ATTR_PGTBL_MASK) | PG_PRESENT;
|
nuclear@17
|
63 }
|
nuclear@17
|
64
|
nuclear@17
|
65 void unmap_page(int vpage)
|
nuclear@17
|
66 {
|
nuclear@17
|
67 uint32_t *pgtbl;
|
nuclear@17
|
68 int diridx = PAGE_TO_PGTBL(vpage);
|
nuclear@17
|
69 int pgidx = PAGE_TO_PGTBL_PG(vpage);
|
nuclear@17
|
70
|
nuclear@17
|
71 if(!(pgdir[diridx] & PG_PRESENT)) {
|
nuclear@17
|
72 goto err;
|
nuclear@17
|
73 }
|
nuclear@17
|
74 pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK);
|
nuclear@17
|
75
|
nuclear@17
|
76 if(!(pgtbl[pgidx] & PG_PRESENT)) {
|
nuclear@17
|
77 goto err;
|
nuclear@17
|
78 }
|
nuclear@17
|
79 pgtbl[pgidx] = 0;
|
nuclear@17
|
80
|
nuclear@17
|
81 return;
|
nuclear@17
|
82 err:
|
nuclear@17
|
83 printf("unmap_page(%d): page already not mapped\n", vpage);
|
nuclear@17
|
84 }
|
nuclear@17
|
85
|
nuclear@17
|
86 void map_page_range(int vpg_start, int pgcount, int ppg_start, unsigned int attr)
|
nuclear@17
|
87 {
|
nuclear@17
|
88 int i;
|
nuclear@17
|
89
|
nuclear@17
|
90 for(i=0; i<pgcount; i++) {
|
nuclear@17
|
91 map_page(vpg_start + i, ppg_start + i, attr);
|
nuclear@17
|
92 }
|
nuclear@17
|
93 }
|
nuclear@17
|
94
|
nuclear@17
|
95 void map_mem_range(uint32_t vaddr, size_t sz, uint32_t paddr, unsigned int attr)
|
nuclear@17
|
96 {
|
nuclear@17
|
97 int vpg_start, ppg_start, num_pages;
|
nuclear@17
|
98
|
nuclear@17
|
99 if(!sz) return;
|
nuclear@17
|
100
|
nuclear@17
|
101 if(ADDR_TO_PGOFFS(paddr)) {
|
nuclear@17
|
102 panic("map_mem_range called with unaligned physical address: %x\n", paddr);
|
nuclear@17
|
103 }
|
nuclear@17
|
104
|
nuclear@17
|
105 vpg_start = ADDR_TO_PAGE(vaddr);
|
nuclear@17
|
106 ppg_start = ADDR_TO_PAGE(paddr);
|
nuclear@17
|
107 num_pages = ADDR_TO_PAGE(sz) + 1;
|
nuclear@17
|
108
|
nuclear@17
|
109 map_page_range(vpg_start, num_pages, ppg_start, attr);
|
nuclear@17
|
110 }
|
nuclear@17
|
111
|
nuclear@17
|
112
|
nuclear@17
|
113 /* if(mb->flags & MB_MMAP) {
|
nuclear@17
|
114 struct mboot_mmap *mem, *mmap_end;
|
nuclear@17
|
115
|
nuclear@17
|
116 mem = mb->mmap;
|
nuclear@17
|
117 mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len);
|
nuclear@17
|
118
|
nuclear@17
|
119 printf("memory map:\n");
|
nuclear@17
|
120 while(mem < mmap_end) {
|
nuclear@17
|
121 unsigned int end = mem->base_low + mem->length_low;
|
nuclear@17
|
122 char *type = mem->type == MB_MEM_VALID ? "free:" : "hole:";
|
nuclear@17
|
123
|
nuclear@17
|
124 printf(" %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low);
|
nuclear@17
|
125 mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip);
|
nuclear@17
|
126 }
|
nuclear@17
|
127 }
|
nuclear@17
|
128
|
nuclear@17
|
129 if(mb->flags & MB_MEM) {
|
nuclear@17
|
130 printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper);
|
nuclear@17
|
131 }
|
nuclear@17
|
132 */
|
nuclear@17
|
133
|
nuclear@18
|
134 uint32_t virt_to_phys(uint32_t vaddr)
|
nuclear@18
|
135 {
|
nuclear@18
|
136 uint32_t pgaddr, *pgtbl;
|
nuclear@18
|
137 int diridx = ADDR_TO_PGTBL(vaddr);
|
nuclear@18
|
138 int pgidx = ADDR_TO_PGTBL_PG(vaddr);
|
nuclear@18
|
139
|
nuclear@18
|
140 if(!(pgdir[diridx] & PG_PRESENT)) {
|
nuclear@18
|
141 panic("virt_to_phys(%x): page table %d not present\n", vaddr, diridx);
|
nuclear@18
|
142 }
|
nuclear@18
|
143 pgtbl = (uint32_t*)(pgdir[diridx] & PGENT_ADDR_MASK);
|
nuclear@18
|
144
|
nuclear@18
|
145 if(!(pgtbl[pgidx] & PG_PRESENT)) {
|
nuclear@18
|
146 panic("virt_to_phys(%x): page %d not present\n", vaddr, ADDR_TO_PAGE(vaddr));
|
nuclear@18
|
147 }
|
nuclear@18
|
148 pgaddr = pgtbl[pgidx] & PGENT_ADDR_MASK;
|
nuclear@18
|
149
|
nuclear@18
|
150 return pgaddr | ADDR_TO_PGOFFS(vaddr);
|
nuclear@18
|
151 }
|
nuclear@18
|
152
|
nuclear@17
|
153 static void pgfault(int inum, uint32_t err)
|
nuclear@17
|
154 {
|
nuclear@17
|
155 printf("~~~~ PAGE FAULT ~~~~\n");
|
nuclear@17
|
156
|
nuclear@17
|
157 printf("fault address: %x\n", get_fault_addr());
|
nuclear@17
|
158
|
nuclear@17
|
159 if(err & PG_PRESENT) {
|
nuclear@17
|
160 if(err & 8) {
|
nuclear@17
|
161 printf("reserved bit set in some paging structure\n");
|
nuclear@17
|
162 } else {
|
nuclear@17
|
163 printf("%s protection violation ", (err & PG_WRITABLE) ? "write" : "read");
|
nuclear@17
|
164 printf("in %s mode\n", err & PG_USER ? "user" : "kernel");
|
nuclear@17
|
165 }
|
nuclear@17
|
166 } else {
|
nuclear@17
|
167 printf("page not present\n");
|
nuclear@17
|
168 }
|
nuclear@17
|
169 }
|