nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
page_allocator.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <stddef.h>
4 #include <stdint.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8 
9 #include <page_allocator.h>
10 #include <debug.h>
11 
22  unsigned long base;
23  unsigned long nr_of_pages;
25  unsigned long max_order;
26  unsigned long bitmap_sz;
27 
28  unsigned int page_size_bits;
29 
30  char bitmap[];
31 };
32 
33 static inline int page_allocator_handle_size(unsigned int nr_of_pages)
34 {
35  return sizeof(struct page_allocator) + (nr_of_pages << 1);
36 }
37 
38 #define BYTE_IDX(j) ((j) >> 3)
39 #define BIT_IDX(j) ((j) & 0x07)
40 #define BIT_MASK(j) (0x01 << BIT_IDX(j))
41 
45 static inline void initialize_header(struct page_allocator *handle, unsigned int base, unsigned int size)
46 {
47  unsigned int i;
48  unsigned int bit_count;
49 
50  /* base & nr_of_pages will be updated after initiate the bitmap */
51  handle->base = (unsigned int)base;
52  handle->nr_of_pages = (size >> handle->page_size_bits);
53 
54  for (bit_count = 0, i = 1; i < handle->nr_of_pages; i <<= 1, bit_count++);
55 
85  handle->bitmap_sz = i >> 2;
86 
91  handle->max_order = bit_count;
92  return;
93 }
94 
95 static inline void initialize_bitmap(struct page_allocator *handle)
96 {
97  unsigned int nr_of_pages;
98  unsigned int order;
99  unsigned int idx;
100  unsigned int tmp;
101  unsigned int start_idx;
102 
103  memset(handle->bitmap, 0, handle->bitmap_sz << 1);
104 
105  nr_of_pages = handle->nr_of_pages;
106  order = handle->max_order;
107 
116  start_idx = 0;
117  do {
118  tmp = 0x01 << order;
119  idx = (0x01 << (handle->max_order - order));
120  idx--;
121 
122  while (tmp <= nr_of_pages) {
123  handle->bitmap[BYTE_IDX(idx + start_idx)] |= BIT_MASK(idx + start_idx);
124  nr_of_pages -= tmp;
125  start_idx++;
126  }
127 
128  order--;
129  start_idx <<= 0x01;
130  } while (nr_of_pages > 0);
131 }
132 
133 #if defined(_DEBUG)
134 static inline void debug_dump_bitmap(struct page_allocator *handle)
135 {
136  unsigned int i;
137  int bit_idx;
138  unsigned int cnt;
139  unsigned int line;
140  unsigned int order;
141 
142  dbg_printf("Available bitmap\n");
143  cnt = 0;
144  line = 0x01;
145  order = handle->max_order;
146  dbg_printf("%d: ", order);
147  for (i = 0; i < handle->bitmap_sz; i++) {
148  for (bit_idx = 0; bit_idx < 8; bit_idx++) {
149  dbg_printf("%d", !!(handle->bitmap[i] & (0x01 << bit_idx)));
150  if (cnt++ == (line - 1)) {
151  order--;
152  dbg_printf("\n%d: ", order);
153  line = line << 0x01;
154  cnt = 0;
155  }
156  }
157  }
158  dbg_printf("\n");
159 
160  dbg_printf("Allocated bitmap\n");
161  cnt = 0;
162  line = 0x01;
163  order = handle->max_order;
164  dbg_printf("%d: ", order);
165  for (i = 0; i < handle->bitmap_sz; i++) {
166  for (bit_idx = 0; bit_idx < 8; bit_idx++) {
167  dbg_printf("%d", !!(handle->bitmap[handle->bitmap_sz + i] & (0x01 << bit_idx)));
168  if (cnt++ == (line - 1)) {
169  order--;
170  dbg_printf("\n%d: ", order);
171  line = line << 0x01;
172  cnt = 0;
173  }
174  }
175  }
176  dbg_printf("\n");
177 }
178 #endif
179 
180 struct page_allocator *page_allocator_init(void *info, void *addr, unsigned int size)
181 {
182  struct page_allocator *handle;
183 
184  handle = (struct page_allocator *)info;
185  for (handle->page_size_bits = 0; (0x01 << handle->page_size_bits) < sysconf(_SC_PAGESIZE); handle->page_size_bits++);
186 
187  if (size & (handle->page_size_bits - 1)) {
188  return NULL;
189  }
190 
191  if ((unsigned int)addr & (handle->page_size_bits - 1)) {
192  return NULL;
193  }
194 
195  /* Initiate bitmap */
196  initialize_header(handle, (unsigned int)addr, size);
197  initialize_bitmap(handle);
198 
199  return handle;
200 }
201 
203 {
204  if (!handle) {
205  return -EINVAL;
206  }
207 
208  return 0;
209 }
210 
211 static inline int validate_power_of_two(unsigned int nr_of_pages, unsigned int *order)
212 {
213  unsigned int i;
214  unsigned int _order;
215  int ret;
216 
217  for (_order = 0, i = 1; i < nr_of_pages; i <<= 1, _order++) {
218  /* Do nothing */
219  }
220 
221  ret = (i == nr_of_pages);
222 
223  if (ret) {
224  if (order) {
225  *order = _order;
226  }
227  }
228 
229  return ret;
230 }
231 
232 void *page_allocator_alloc(struct page_allocator *handle, unsigned int nr_of_pages)
233 {
234  unsigned int order;
235  unsigned int idx;
236  unsigned int i;
237  unsigned int j;
238  unsigned int total;
239 
240  if (!handle) {
241  dbg_printf("Invalid handle\n");
242  return (void *)-1;
243  }
244 
245  if (!validate_power_of_two(nr_of_pages, &order)) {
246  dbg_printf("Invalid nr_of_pages\n");
247  return (void *)-1;
248  }
249 
250  idx = 0x01 << (handle->max_order - order);
251  total = idx << 1;
252  idx--;
253  total--;
254 
255  for (i = idx; i < total; i++) {
256  if (handle->bitmap[BYTE_IDX(i)] & BIT_MASK(i)) {
257  handle->bitmap[BYTE_IDX(i)] &= ~BIT_MASK(i);
258  handle->bitmap[handle->bitmap_sz + BYTE_IDX(i)] |= BIT_MASK(i);
259  i = (i - idx) << order;
260 
261  if (BYTE_IDX(i) >= handle->bitmap_sz) {
262  dbg_printf("Out of buffer\n");
263  return (void *)-1;
264  }
265  return (void *)(handle->base + (i << handle->page_size_bits));
266  }
267  }
268 
269  /* Try to split more bigger bit-group */
270  j = order;
271  while (j < handle->max_order) {
276  j++;
277 
278  idx = 0x01 << (handle->max_order - j);
279  total = idx << 1;
280  idx--;
281  total--;
282 
283  for (i = idx; i < total; i++) {
284  if (handle->bitmap[BYTE_IDX(i)] & BIT_MASK(i)) {
285  handle->bitmap[BYTE_IDX(i)] &= ~BIT_MASK(i);
286  break;
287  }
288  }
289 
290  if (i == total) {
291  continue;
292  }
293 
298  do {
299  i -= idx; /* Get the pure index. */
300  j--; /* Go to the lower order */
301 
306  idx = (0x01 << (handle->max_order - j)) - 1;
307  i = idx + (i << 1);
308  handle->bitmap[BYTE_IDX(i + 1)] |= BIT_MASK(i + 1);
309  } while (j != order);
310  handle->bitmap[handle->bitmap_sz + BYTE_IDX(i)] |= BIT_MASK(i);
311  i = (i - idx) << order;
312 
313  if (BYTE_IDX(i) >= handle->bitmap_sz) {
314  dbg_printf("Out of buffer\n");
315  return (void *)-1;
316  }
317  return (void *)(handle->base + (i << handle->page_size_bits));
318  }
319 
320  dbg_printf("Failed to allocate\n");
321  return (void *)-1;
322 }
323 
324 int page_allocator_free(struct page_allocator *handle, void *addr)
325 {
326  unsigned int order;
327  unsigned int idx;
328  unsigned int i;
329  int ret = -ENOENT;
330 
331  if (!handle) {
332  return -EINVAL;
333  }
334 
335  for (order = 0; order <= handle->max_order; order++) {
336  i = ((unsigned int)addr - handle->base) >> (handle->page_size_bits + order);
337  idx = (0x01 << (handle->max_order - order)) - 1;
338 
339  if (handle->bitmap[handle->bitmap_sz + BYTE_IDX(idx + i)] & BIT_MASK(idx + i)) {
340  unsigned int buddy;
341 
342  handle->bitmap[handle->bitmap_sz + BYTE_IDX(idx + i)] &= ~BIT_MASK(idx + i);
343 
344  do {
345  buddy = idx + i + (((idx + i) & 0x01) ? 1 : -1);
346  if (buddy != (unsigned int)-1 && handle->bitmap[BYTE_IDX(buddy)] & BIT_MASK(buddy)) {
347  handle->bitmap[BYTE_IDX(buddy)] &= ~BIT_MASK(buddy);
348  } else {
349  handle->bitmap[BYTE_IDX(idx + i)] |= BIT_MASK(idx + i);
350  ret = 0;
351  break;
352  }
353 
354  order++;
355  i = ((unsigned int)addr - handle->base) >> (handle->page_size_bits + order);
356  idx = (0x01 << (handle->max_order - order)) - 1;
357  } while (order < handle->max_order);
358 
359  if (order == handle->max_order) {
360  handle->bitmap[BYTE_IDX(idx + i)] |= BIT_MASK(idx + i);
361  ret = 0;
362  }
363 
364  break;
365  }
366  }
367 
368  /*
369  if (ret != 0 && order == handle->max_order) {
370  if (handle->bitmap[handle->bitmap_sz + BYTE_IDX(0)] & BIT_MASK(0)) {
371  handle->bitmap[handle->bitmap_sz + BYTE_IDX(0)] &= ~BIT_MASK(0);
372  handle->bitmap[BYTE_IDX(0)] |= BIT_MASK(0);
373  ret = 0;
374  }
375  }
376  */
377 
378  return ret;
379 }
380 
382 {
383  dbg_printf("base: %x\n", handle->base);
384  dbg_printf("The number of pages: %u\n", handle->nr_of_pages);
385  dbg_printf("Max order: %u\n", handle->max_order);
386  dbg_printf("Size of bitmap block: %u\n", handle->bitmap_sz);
387 #if defined(_DEBUG)
388  debug_dump_bitmap(handle);
389 #endif
390 }
391 
392 unsigned int page_allocator_info_size(unsigned int size)
393 {
394  unsigned int nr_of_pages;
395  unsigned int i;
396  unsigned int page_size_bits;
397 
398  for (page_size_bits = 0; (0x01 << page_size_bits) < sysconf(_SC_PAGESIZE); page_size_bits++);
399 
400  if (size & (page_size_bits - 1)) {
401  return 0;
402  }
403 
404  nr_of_pages = size >> page_size_bits;
405  for (i = 1; i < nr_of_pages; i <<= 1) {
406  }
407 
413  return (i >> 1) + sizeof(struct page_allocator);
414 }
415 
416 int page_allocator_get_region(struct page_allocator *handle, unsigned int *start, unsigned int *end)
417 {
418  if (!handle) {
419  return -EINVAL;
420  }
421 
422  *start = handle->base;
423  *end = handle->base + handle->nr_of_pages * sysconf(_SC_PAGESIZE);
424  return 0;
425 }
426 
427 /* End of a file */