kern

view src/mem.c @ 80:4db99a52863e

fixed the "endianess" of the text messages in the ATA identify info block. this is the first time I've seen wrong byteorder in ascii text, the ATA committee should be commended.
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 06 Dec 2011 13:35:39 +0200
parents 9939a6d7a45a
children
line source
1 #include <stdio.h>
2 #include <string.h>
3 #include "mem.h"
4 #include "panic.h"
5 #include "vm.h"
6 #include "intr.h"
8 #define FREE 0
9 #define USED 1
11 #define BM_IDX(pg) ((pg) / 32)
12 #define BM_BIT(pg) ((pg) & 0x1f)
14 #define IS_FREE(pg) ((bitmap[BM_IDX(pg)] & (1 << BM_BIT(pg))) == 0)
16 static void mark_page(int pg, int free);
17 static void add_memory(uint32_t start, size_t size);
19 /* end of kernel image */
20 extern int _end;
22 /* A bitmap is used to track which physical memory pages are used or available
23 * for allocation by alloc_phys_page.
24 *
25 * last_alloc_idx keeps track of the last 32bit element in the bitmap array
26 * where a free page was found. It's guaranteed that all the elements before
27 * this have no free pages, but it doesn't imply that there will be another
28 * free page there. So it's used as a starting point for the search.
29 */
30 static uint32_t *bitmap;
31 static int bmsize, last_alloc_idx;
34 void init_mem(struct mboot_info *mb)
35 {
36 int i, num_pages, max_pg = 0;
37 uint32_t used_end;
39 num_pages = 0;
40 last_alloc_idx = 0;
42 /* the allocation bitmap starts right at the end of the ELF image */
43 bitmap = (uint32_t*)&_end;
45 /* start by marking all posible pages (2**20) as used. We do not "reserve"
46 * all this space. Pages beyond the end of the useful bitmap area
47 * ((char*)bitmap + bmsize), which will be determined after we traverse the
48 * memory map, are going to be marked as available for allocation.
49 */
50 memset(bitmap, 0xff, 1024 * 1024 / 8);
52 /* if the bootloader gave us an available memory map, traverse it and mark
53 * all the corresponding pages as free.
54 */
55 if(mb->flags & MB_MMAP) {
56 struct mboot_mmap *mem, *mmap_end;
58 mem = mb->mmap;
59 mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len);
61 printf("memory map:\n");
62 while(mem < mmap_end) {
63 /* ignore memory ranges that start beyond the 4gb mark */
64 if(mem->base_high == 0 && mem->base_low != 0xffffffff) {
65 char *type;
66 unsigned int end, rest = 0xffffffff - mem->base_low;
68 /* make sure the length does not extend beyond 4gb */
69 if(mem->length_high || mem->length_low > rest) {
70 mem->length_low = rest;
71 }
72 end = mem->base_low + mem->length_low;
74 if(mem->type == MB_MEM_VALID) {
75 type = "free:";
76 add_memory(mem->base_low, mem->length_low);
78 num_pages = ADDR_TO_PAGE(mem->base_low + mem->length_low);
79 if(max_pg < num_pages) {
80 max_pg = num_pages;
81 }
82 } else {
83 type = "hole:";
84 }
86 printf(" %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low);
87 }
88 mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip);
89 }
90 } else if(mb->flags & MB_MEM) {
91 /* if we don't have a detailed memory map, just use the lower and upper
92 * memory block sizes to determine which pages should be available.
93 */
94 add_memory(0, mb->mem_lower);
95 add_memory(0x100000, mb->mem_upper * 1024);
96 max_pg = mb->mem_upper / 4;
98 printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper);
99 } else {
100 /* I don't think this should ever happen with a multiboot-compliant boot loader */
101 panic("didn't get any memory info from the boot loader, I give up\n");
102 }
104 bmsize = max_pg / 8; /* size of the useful bitmap in bytes */
106 /* mark all the used pages as ... well ... used */
107 used_end = ((uint32_t)bitmap + bmsize - 1);
109 printf("marking pages up to %x ", used_end);
110 used_end = ADDR_TO_PAGE(used_end);
111 printf("(page: %d) inclusive as used\n", used_end);
113 for(i=0; i<=used_end; i++) {
114 mark_page(i, USED);
115 }
116 }
118 /* alloc_phys_page finds the first available page of physical memory,
119 * marks it as used in the bitmap, and returns its address. If there's
120 * no unused physical page, 0 is returned.
121 */
122 uint32_t alloc_phys_page(void)
123 {
124 int i, idx, max, intr_state;
126 intr_state = get_intr_state();
127 disable_intr();
129 idx = last_alloc_idx;
130 max = bmsize / 4;
132 while(idx <= max) {
133 /* if at least one bit is 0 then we have at least
134 * one free page. find it and allocate it.
135 */
136 if(bitmap[idx] != 0xffffffff) {
137 for(i=0; i<32; i++) {
138 int pg = idx * 32 + i;
140 if(IS_FREE(pg)) {
141 mark_page(pg, USED);
143 last_alloc_idx = idx;
145 /*printf("alloc_phys_page() -> %x (page: %d)\n", PAGE_TO_ADDR(pg), pg);*/
147 set_intr_state(intr_state);
148 return PAGE_TO_ADDR(pg);
149 }
150 }
151 panic("can't happen: alloc_phys_page (mem.c)\n");
152 }
153 idx++;
154 }
156 set_intr_state(intr_state);
157 return 0;
158 }
160 /* free_phys_page marks the physical page which corresponds to the specified
161 * address as free in the allocation bitmap.
162 *
163 * CAUTION: no checks are done that this page should actually be freed or not.
164 * If you call free_phys_page with the address of some part of memory that was
165 * originally reserved due to it being in a memory hole or part of the kernel
166 * image or whatever, it will be subsequently allocatable by alloc_phys_page.
167 */
168 void free_phys_page(uint32_t addr)
169 {
170 int pg = ADDR_TO_PAGE(addr);
171 int bmidx = BM_IDX(pg);
173 int intr_state = get_intr_state();
174 disable_intr();
176 if(IS_FREE(pg)) {
177 panic("free_phys_page(%d): I thought that was already free!\n", pg);
178 }
180 mark_page(pg, FREE);
181 if(bmidx < last_alloc_idx) {
182 last_alloc_idx = bmidx;
183 }
185 set_intr_state(intr_state);
186 }
188 /* this is only ever used by the VM init code to find out what the extends of
189 * the kernel image are, in order to map them 1-1 before enabling paging.
190 */
191 void get_kernel_mem_range(uint32_t *start, uint32_t *end)
192 {
193 if(start) {
194 *start = 0x100000;
195 }
196 if(end) {
197 uint32_t e = (uint32_t)bitmap + bmsize;
199 if(e & PGOFFS_MASK) {
200 *end = (e + 4096) & ~PGOFFS_MASK;
201 } else {
202 *end = e;
203 }
204 }
205 }
207 /* adds a range of physical memory to the available pool. used during init_mem
208 * when traversing the memory map.
209 */
210 static void add_memory(uint32_t start, size_t sz)
211 {
212 int i, szpg, pg;
214 szpg = ADDR_TO_PAGE(sz);
215 pg = ADDR_TO_PAGE(start);
217 for(i=0; i<szpg; i++) {
218 mark_page(pg++, FREE);
219 }
220 }
222 /* maps a page as used or free in the allocation bitmap */
223 static void mark_page(int pg, int used)
224 {
225 int idx = BM_IDX(pg);
226 int bit = BM_BIT(pg);
228 if(used) {
229 bitmap[idx] |= 1 << bit;
230 } else {
231 bitmap[idx] &= ~(1 << bit);
232 }
233 }