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