Mercurial > lcfOS
annotate cos/kernel/mm.c @ 287:1c7c1e619be8
File movage
author | Windel Bouwman |
---|---|
date | Thu, 21 Nov 2013 11:57:27 +0100 |
parents | 35cc54e078dd |
children |
rev | line source |
---|---|
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 | |
40 | 9 #define HEAP_START 0xC000000000000000 |
10 #define HEAP_INITIAL_SIZE 0x100000 | |
11 | |
37 | 12 // Bitmap that keeps track of all the 4 kB memory pages in the system: |
29 | 13 static uint64_t *frames = 0; |
14 static uint64_t nframes = 0; | |
26 | 15 |
29 | 16 memmap_t* kernel_map = 0; // kernel memory mapping |
40 | 17 // TODO: determine if this is required. |
29 | 18 memmap_t* current_map = 0; // The currently active memory mapping |
19 | |
40 | 20 heap_t* kernel_heap = 0; |
21 | |
29 | 22 static void set_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 | 29 static void clear_frame(uint64_t frame) |
26 | 30 { |
31 uint64_t idx = frame / 64; | |
32 uint64_t off = frame % 64; | |
33 frames[idx] &= ~(0x1 << off); | |
34 } | |
35 | |
36 uint64_t test_frame(uint64_t frame) | |
37 { | |
38 uint64_t idx = frame / 64; | |
39 uint64_t off = frame % 64; | |
40 return (frames[idx] & (0x1 << off)); | |
41 } | |
42 | |
29 | 43 static uint64_t first_frame() |
26 | 44 { |
45 uint64_t i, j; | |
28 | 46 for (i = 0; i < nframes / 64; i++) |
26 | 47 { |
48 if (frames[i] != 0xFFFFFFFFFFFFFFFF) | |
49 { | |
50 for (j = 0; j < 64; j++) | |
51 { | |
52 uint64_t dut = 0x1 << j; | |
53 if ((frames[i] & dut) != dut) | |
54 { | |
55 return i*64+j; | |
56 } | |
57 } | |
58 } | |
59 } | |
29 | 60 |
61 // No frame found: | |
62 return (uint64_t) -1; | |
26 | 63 } |
64 | |
40 | 65 void memory_status(void) |
66 { | |
67 // Determine amount of used memory. | |
68 uint64_t i, j; | |
69 uint64_t inuse = 0; | |
70 for (i = 0; i < nframes / 64; i++) | |
71 { | |
72 for (j = 0; j < 64; j++) | |
73 { | |
74 if ((frames[i] & (1UL<<j)) == (1UL<<j)) | |
75 { | |
76 inuse++; | |
77 } | |
78 } | |
79 } | |
80 printf("Memory: %d, in use: %d\n", nframes/0x100, inuse/0x100); | |
81 } | |
82 | |
37 | 83 /* |
84 * Initializes the memory manager, allocating a bitmap once. | |
85 */ | |
28 | 86 void init_memory(uint64_t total_mem_size) |
87 { | |
37 | 88 printf("Running with %d MB ram\n", total_mem_size / 1000000); |
89 | |
40 | 90 // Memory size is from address 0x100000 |
91 total_mem_size += 0x100000; | |
92 | |
32
3a6a9b929db0
Added initial ramdisk and some virtual file system functions
windel
parents:
30
diff
changeset
|
93 // Only here placement malloc is used! |
3a6a9b929db0
Added initial ramdisk and some virtual file system functions
windel
parents:
30
diff
changeset
|
94 // |
37 | 95 // Allocate and clear bits to remember which 4KiB-frames are in use: |
40 | 96 // Calculate number of frames. memory size is indicated from address 0x100000 |
97 nframes = (total_mem_size) / 0x1000; // Calculate number of frames | |
98 int numbytes = ((nframes / 64) + 1) * sizeof(uint64_t); | |
99 frames = (uint64_t*)kmalloc(numbytes); | |
100 memset(frames, 0, numbytes); | |
29 | 101 |
102 // Create kernel map: | |
40 | 103 kernel_map = (memmap_t*)kmalloc_a(sizeof(memmap_t)); |
29 | 104 memset(kernel_map, 0, sizeof(memmap_t)); |
105 | |
106 // Identity map lower memory and mark as used by the kernel. | |
107 // Mark as used by the kernel: | |
108 uint64_t i; | |
109 i = 0; | |
40 | 110 while ( i <= placement_address + 0x100000) |
29 | 111 { |
112 page_t *page; | |
113 | |
114 page = get_page(i, kernel_map); // Get page for address | |
115 page->address = i >> 12; // Set the address of this page. | |
116 page->present = 1; | |
117 page->rw = 1; | |
118 page->us = 1; // Make all things accessable for users for now. | |
30 | 119 //page->pwt = 1; // Is this bit required? |
29 | 120 |
121 set_frame(i / 0x1000); | |
122 | |
123 i += 0x1000; // Increase a 4 k frame | |
124 } | |
125 | |
126 // Set the created mapping as active: | |
41 | 127 switch_mapping(kernel_map); // Loads cr3 |
30 | 128 |
29 | 129 // TODO: set the use of placement malloc to invalid after here. |
40 | 130 // kernel_heap = create_heap(HEAP_START, HEAP_INITIAL_SIZE); |
28 | 131 } |
132 | |
29 | 133 void alloc_frame(page_t *page) |
26 | 134 { |
29 | 135 if (page->address != 0) |
136 { | |
137 return; | |
138 } | |
26 | 139 uint64_t idx = first_frame(); |
140 if (idx == (uint64_t) -1) | |
141 { | |
142 panic("No more memory!"); | |
143 } | |
144 set_frame(idx); | |
29 | 145 |
146 page->present = 1; | |
147 page->rw = 1; | |
148 page->us = 0; | |
149 page->address = idx; // set address in frame number, the byte address is 0x1000 times this value. | |
26 | 150 } |
151 | |
28 | 152 void free_frame(page_t *page) |
153 { | |
29 | 154 clear_frame(page->address / 0x1000); |
155 page->address = 0; | |
156 page->present = 0; | |
157 } | |
158 | |
159 void switch_mapping(memmap_t* mapping) | |
160 { | |
161 current_map = mapping; | |
162 | |
40 | 163 // Load table address: |
29 | 164 asm volatile("mov %0, %%cr3" :: "r"(&mapping->table)); |
165 | |
166 // Enable paging (and flush cache): | |
167 uint64_t cr0; | |
168 asm volatile("mov %%cr0, %0": "=r"(cr0)); | |
169 cr0 |= 0x80000000; | |
170 asm volatile("mov %0, %%cr0":: "r"(cr0)); | |
28 | 171 } |
26 | 172 |
29 | 173 /* Get a page for a virtual address, and create other tables if required */ |
174 page_t* get_page(uint64_t address, memmap_t *mapping) | |
175 { | |
176 // Retrieve the correct PDP (page dir pointer table): | |
177 uint64_t pml4index = (address >> 39) & 0x1FF; | |
178 PDPT_t *pdpt = 0; | |
179 if (mapping->table[pml4index].present == 1) | |
180 { | |
181 pdpt = (PDPT_t*)((uint64_t)mapping->table[pml4index].address << 12); | |
182 } | |
183 else | |
184 { | |
185 // Create new table: | |
40 | 186 printf("Get page for address %x\n", address); |
187 // TODO: make sure that this function calls kmalloc instead of placement malloc. | |
188 pdpt = (PDPT_t*)kmalloc_a(sizeof(PDPT_t)); | |
29 | 189 memset(pdpt, 0, sizeof(PDPT_t)); |
190 | |
191 // TODO: get function like virt2phys or something here | |
192 uint64_t address = (uint64_t)pdpt; // get the physical address | |
193 mapping->table[pml4index].address = address >> 12; // shift right | |
194 mapping->table[pml4index].rw = 1; | |
195 mapping->table[pml4index].us = 1; | |
196 mapping->table[pml4index].present = 1; | |
197 } | |
198 | |
199 uint64_t pdptindex = (address >> 30) & 0x1FF; | |
200 // Retrieve the correct page directory: | |
201 PD_t *pd = 0; | |
202 if (pdpt->table[pdptindex].present == 1) | |
203 { | |
204 pd = (PD_t*)((uint64_t)pdpt->table[pdptindex].address << 12); | |
205 } | |
206 else | |
207 { | |
208 // Create a new table: | |
40 | 209 pd = (PD_t*)kmalloc_a(sizeof(PD_t)); |
29 | 210 memset(pd, 0, sizeof(PD_t)); |
211 | |
212 // Enter table into PDPT: | |
213 // TODO: make virt2phys function: | |
214 uint64_t address = (uint64_t)pd; | |
215 pdpt->table[pdptindex].address = address >> 12; | |
216 pdpt->table[pdptindex].rw = 1; | |
217 pdpt->table[pdptindex].us = 1; | |
218 pdpt->table[pdptindex].present = 1; | |
219 } | |
220 | |
221 // Retrieve the correct page table: | |
222 uint64_t pdindex = (address >> 21) & 0x1FF; | |
223 PT_t *pt = 0; | |
224 if (pd->table[pdindex].present == 1) | |
225 { | |
226 pt = (PT_t*)((uint64_t)pd->table[pdindex].address << 12); | |
227 } | |
228 else | |
229 { | |
230 // Create table: | |
40 | 231 pt = (PT_t*)kmalloc_a(sizeof(PD_t)); |
29 | 232 memset(pt, 0, sizeof(PT_t)); |
233 | |
234 // Enter PT into PD: | |
235 uint64_t address = (uint64_t)pt; | |
236 pd->table[pdindex].address = address >> 12; | |
237 pd->table[pdindex].rw = 1; | |
238 pd->table[pdindex].us = 1; | |
239 pd->table[pdindex].present = 1; | |
240 } | |
241 | |
242 // Finally get the page from the directory: | |
243 // TODO: convert from physical address to virtual address: | |
244 uint64_t ptindex = (address >> 12) & 0x1FF; | |
245 return &pt->table[ptindex]; | |
246 } | |
247 |