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