28
|
1 /* Memory manager functions,
|
|
2 *
|
|
3 * Uses a bitmap to keep track of 4k pages that are in use.
|
|
4 *
|
|
5 * */
|
26
|
6
|
|
7 #include "kernel.h"
|
|
8
|
29
|
9 static uint64_t *frames = 0;
|
|
10 static uint64_t nframes = 0;
|
26
|
11
|
29
|
12 memmap_t* kernel_map = 0; // kernel memory mapping
|
|
13 memmap_t* current_map = 0; // The currently active memory mapping
|
|
14
|
|
15 static void set_frame(uint64_t frame)
|
26
|
16 {
|
|
17 uint64_t idx = frame / 64;
|
|
18 uint64_t off = frame % 64;
|
|
19 frames[idx] |= (0x1 << off);
|
|
20 }
|
|
21
|
29
|
22 static void clear_frame(uint64_t frame)
|
26
|
23 {
|
|
24 uint64_t idx = frame / 64;
|
|
25 uint64_t off = frame % 64;
|
|
26 frames[idx] &= ~(0x1 << off);
|
|
27 }
|
|
28
|
|
29 uint64_t test_frame(uint64_t frame)
|
|
30 {
|
|
31 uint64_t idx = frame / 64;
|
|
32 uint64_t off = frame % 64;
|
|
33 return (frames[idx] & (0x1 << off));
|
|
34 }
|
|
35
|
29
|
36 static uint64_t first_frame()
|
26
|
37 {
|
|
38 uint64_t i, j;
|
28
|
39 for (i = 0; i < nframes / 64; i++)
|
26
|
40 {
|
|
41 if (frames[i] != 0xFFFFFFFFFFFFFFFF)
|
|
42 {
|
|
43 for (j = 0; j < 64; j++)
|
|
44 {
|
|
45 uint64_t dut = 0x1 << j;
|
|
46 if ((frames[i] & dut) != dut)
|
|
47 {
|
|
48 return i*64+j;
|
|
49 }
|
|
50 }
|
|
51 }
|
|
52 }
|
29
|
53
|
|
54 // No frame found:
|
|
55 return (uint64_t) -1;
|
26
|
56 }
|
|
57
|
|
58 // Memory manager functions:
|
28
|
59 void init_memory(uint64_t total_mem_size)
|
|
60 {
|
30
|
61 printf("Size of PT_t = %d\n", sizeof(PD_t));
|
|
62 printf("Size of page_t = %d\n", sizeof(page_t));
|
29
|
63 // Allocate and clear bits to remember which 4kb-frames are in use:
|
|
64 nframes = (total_mem_size / 0x1000);
|
|
65 frames = (uint64_t*)kmalloc_int( (nframes / 64) * sizeof(uint64_t) );
|
|
66 memset(frames, 0, (nframes / 64) * sizeof(uint64_t));
|
|
67
|
|
68 // Create kernel map:
|
|
69 kernel_map = (memmap_t*)kmalloc_aligned_int(sizeof(memmap_t));
|
|
70 memset(kernel_map, 0, sizeof(memmap_t));
|
|
71
|
|
72 // Identity map lower memory and mark as used by the kernel.
|
|
73 // Mark as used by the kernel:
|
|
74 uint64_t i;
|
|
75 i = 0;
|
|
76 while ( i <= placement_address)
|
|
77 {
|
|
78 page_t *page;
|
|
79
|
|
80 page = get_page(i, kernel_map); // Get page for address
|
|
81 page->address = i >> 12; // Set the address of this page.
|
|
82 page->present = 1;
|
|
83 page->rw = 1;
|
|
84 page->us = 1; // Make all things accessable for users for now.
|
30
|
85 //page->pwt = 1; // Is this bit required?
|
29
|
86
|
|
87 set_frame(i / 0x1000);
|
|
88
|
|
89 i += 0x1000; // Increase a 4 k frame
|
|
90 }
|
|
91
|
|
92 // Set the created mapping as active:
|
30
|
93 switch_mapping(kernel_map);
|
|
94
|
29
|
95 // TODO: set the use of placement malloc to invalid after here.
|
28
|
96 }
|
|
97
|
29
|
98 void alloc_frame(page_t *page)
|
26
|
99 {
|
29
|
100 if (page->address != 0)
|
|
101 {
|
|
102 return;
|
|
103 }
|
26
|
104 uint64_t idx = first_frame();
|
|
105 if (idx == (uint64_t) -1)
|
|
106 {
|
|
107 panic("No more memory!");
|
|
108 }
|
|
109 set_frame(idx);
|
29
|
110
|
|
111 page->present = 1;
|
|
112 page->rw = 1;
|
|
113 page->us = 0;
|
|
114 page->address = idx; // set address in frame number, the byte address is 0x1000 times this value.
|
26
|
115 }
|
|
116
|
28
|
117 void free_frame(page_t *page)
|
|
118 {
|
29
|
119 clear_frame(page->address / 0x1000);
|
|
120 page->address = 0;
|
|
121 page->present = 0;
|
|
122 }
|
|
123
|
|
124 void switch_mapping(memmap_t* mapping)
|
|
125 {
|
|
126 current_map = mapping;
|
|
127 printf("Switching to use of other at %x\n", &mapping->table);
|
|
128
|
|
129 asm volatile("mov %0, %%cr3" :: "r"(&mapping->table));
|
|
130
|
|
131 // Enable paging (and flush cache):
|
|
132 uint64_t cr0;
|
|
133 asm volatile("mov %%cr0, %0": "=r"(cr0));
|
|
134 cr0 |= 0x80000000;
|
|
135 asm volatile("mov %0, %%cr0":: "r"(cr0));
|
28
|
136 }
|
26
|
137
|
29
|
138 /* Get a page for a virtual address, and create other tables if required */
|
|
139 page_t* get_page(uint64_t address, memmap_t *mapping)
|
|
140 {
|
|
141 // Retrieve the correct PDP (page dir pointer table):
|
|
142 uint64_t pml4index = (address >> 39) & 0x1FF;
|
|
143 PDPT_t *pdpt = 0;
|
|
144 if (mapping->table[pml4index].present == 1)
|
|
145 {
|
|
146 pdpt = (PDPT_t*)((uint64_t)mapping->table[pml4index].address << 12);
|
|
147 }
|
|
148 else
|
|
149 {
|
|
150 // Create new table:
|
|
151 pdpt = (PDPT_t*)kmalloc_aligned_int(sizeof(PDPT_t));
|
|
152 memset(pdpt, 0, sizeof(PDPT_t));
|
|
153
|
|
154 // TODO: get function like virt2phys or something here
|
|
155 uint64_t address = (uint64_t)pdpt; // get the physical address
|
|
156 mapping->table[pml4index].address = address >> 12; // shift right
|
|
157 mapping->table[pml4index].rw = 1;
|
|
158 mapping->table[pml4index].us = 1;
|
|
159 mapping->table[pml4index].present = 1;
|
|
160 }
|
|
161
|
|
162 uint64_t pdptindex = (address >> 30) & 0x1FF;
|
|
163 // Retrieve the correct page directory:
|
|
164 PD_t *pd = 0;
|
|
165 if (pdpt->table[pdptindex].present == 1)
|
|
166 {
|
|
167 pd = (PD_t*)((uint64_t)pdpt->table[pdptindex].address << 12);
|
|
168 }
|
|
169 else
|
|
170 {
|
|
171 // Create a new table:
|
|
172 pd = (PD_t*)kmalloc_aligned_int(sizeof(PD_t));
|
|
173 memset(pd, 0, sizeof(PD_t));
|
|
174
|
|
175 // Enter table into PDPT:
|
|
176 // TODO: make virt2phys function:
|
|
177 uint64_t address = (uint64_t)pd;
|
|
178 pdpt->table[pdptindex].address = address >> 12;
|
|
179 pdpt->table[pdptindex].rw = 1;
|
|
180 pdpt->table[pdptindex].us = 1;
|
|
181 pdpt->table[pdptindex].present = 1;
|
|
182 }
|
|
183
|
|
184 // Retrieve the correct page table:
|
|
185 uint64_t pdindex = (address >> 21) & 0x1FF;
|
|
186 PT_t *pt = 0;
|
|
187 if (pd->table[pdindex].present == 1)
|
|
188 {
|
|
189 pt = (PT_t*)((uint64_t)pd->table[pdindex].address << 12);
|
|
190 }
|
|
191 else
|
|
192 {
|
|
193 // Create table:
|
|
194 pt = (PT_t*)kmalloc_aligned_int(sizeof(PD_t));
|
|
195 memset(pt, 0, sizeof(PT_t));
|
|
196
|
|
197 // Enter PT into PD:
|
|
198 uint64_t address = (uint64_t)pt;
|
|
199 pd->table[pdindex].address = address >> 12;
|
|
200 pd->table[pdindex].rw = 1;
|
|
201 pd->table[pdindex].us = 1;
|
|
202 pd->table[pdindex].present = 1;
|
|
203 }
|
|
204
|
|
205 // Finally get the page from the directory:
|
|
206 // TODO: convert from physical address to virtual address:
|
|
207 uint64_t ptindex = (address >> 12) & 0x1FF;
|
|
208 return &pt->table[ptindex];
|
|
209 }
|
|
210
|