cynix

x86 UNIX-like OS
git clone git://git.2f30.org/cynix
Log | Files | Refs | README | LICENSE

heap.c (3256B)


      1 /*
      2  *  core/heap.c
      3  *
      4  *  Copyright (C) 2009 stateless
      5  */
      6 
      7 #include <heap.h>
      8 #include <mm.h>
      9 #include <common.h>
     10 #include <x86.h>
     11 #include <errno.h>
     12 #include <list.h>
     13 #include <tty.h>
     14 
     15 /* for debugging purposes */
     16 #define DUMP_CHUNK(chunk) \
     17 	({ \
     18 		printf("\tbase_addr = 0x%lx, end_addr = 0x%lx, size = 0x%x\n", \
     19 		       chunk->base_addr, \
     20 		       chunk->end_addr, chunk->size); \
     21 		serial_dump("\tbase_addr = 0x%lx, end_addr = 0x%lx, size = 0x%x\n", \
     22 			    chunk->base_addr, \
     23 			    chunk->end_addr, chunk->size); \
     24 	})
     25 
     26 struct chunk_t {
     27 	uint32_t base_addr;
     28 	uint32_t end_addr;
     29 	size_t size;
     30 	struct list_head list;
     31 };
     32 
     33 static int is_init = 0;
     34 static struct list_head freelist;
     35 static struct list_head allolist;
     36 
     37 void
     38 walk_heap_lists(void)
     39 {
     40 	uint32_t state;
     41 	struct list_head *iter;
     42 	struct chunk_t *tmp;
     43 
     44 	save_flags(&state);
     45 	cli();
     46 	printf("Summary of free chunks\n");
     47 	serial_dump("Summary of free chunks\n");
     48 	list_for_each(iter, &freelist) {
     49 		tmp = list_entry(iter, struct chunk_t, list);
     50 		DUMP_CHUNK(tmp);
     51 	}
     52 	printf("Summary of allocated chunks\n");
     53 	serial_dump("Summary of allocated chunks\n");
     54 	list_for_each(iter, &allolist) {
     55 		tmp = list_entry(iter, struct chunk_t, list);
     56 		DUMP_CHUNK(tmp);
     57 	}
     58 	load_flags(state);
     59 }
     60 
     61 void
     62 kfree(void *ptr)
     63 {
     64 	struct chunk_t *tmp;
     65 	struct list_head *iter, *q;
     66 	uint32_t state;
     67 
     68 	if (!ptr) return; /* free-ing NULL pointers is good */
     69 	if (!is_init)
     70 		panic("allocator is not initialized!");
     71 	save_flags(&state);
     72 	cli();
     73 	list_for_each_safe(iter, q, &allolist) {
     74 		tmp = list_entry(iter, struct chunk_t, list);
     75 		if (tmp->base_addr == (uint32_t)ptr) {
     76 			list_del(&tmp->list);
     77 			list_add_tail(&tmp->list, &freelist);
     78 			goto out;
     79 		}
     80 	}
     81 	panic("trying to free non-existent chunk at 0x%08lx!", ptr);
     82 out:
     83 	load_flags(state);
     84 }
     85 
     86 void *
     87 kmalloc_ext(size_t size, enum heap_cntl flag)
     88 {
     89 	struct list_head *iter, *q;
     90 	struct chunk_t *tmp, *new;
     91 	uint32_t addr, state;
     92 	int ret;
     93 
     94 	if (!is_init)
     95 		panic("allocator is not initialized!");
     96 
     97 	if (flag != DEFAULT)
     98 		return ERR_PTR(-ENOTSUP);
     99 
    100 	if (!size)
    101 		return ERR_PTR(-EINVAL);
    102 	save_flags(&state);
    103 	cli();
    104 	size += sizeof(struct chunk_t);
    105 	do {
    106 		list_for_each_safe(iter, q, &freelist) {
    107 			tmp = list_entry(iter, struct chunk_t, list);
    108 			if (size > tmp->size)
    109 				continue;
    110 			new = (struct chunk_t *)(tmp->end_addr - size);
    111 			new->base_addr = tmp->end_addr - size + sizeof(*tmp);
    112 			new->size = size - sizeof(*tmp);
    113 			new->end_addr = tmp->end_addr;
    114 			tmp->size -= size;
    115 			tmp->end_addr -= size;
    116 			list_add_tail(&new->list, &allolist);
    117 			load_flags(state);
    118 			return (void *)new->base_addr;
    119 		}
    120 		addr = (uint32_t)sbrk(size);
    121 		if (IS_ERR((void *)addr)) {
    122 			ret = PTR_ERR((void *)addr);
    123 			break;
    124 		}
    125 		tmp = (struct chunk_t *)addr;
    126 		tmp->base_addr = addr + sizeof(*tmp);
    127 		tmp->size = size;
    128 		tmp->size = roundup_pagesize(tmp->size);
    129 		tmp->size -= sizeof(*tmp);
    130 		tmp->end_addr = tmp->base_addr + tmp->size;
    131 		list_add_tail(&tmp->list, &freelist);
    132 	} while (1);
    133 	load_flags(state);
    134 	return ERR_PTR(ret);
    135 }
    136 
    137 void *
    138 kmalloc(size_t size)
    139 {
    140 	return kmalloc_ext(size, DEFAULT);
    141 }
    142 
    143 void
    144 init_heap(void)
    145 {
    146 	uint32_t state;
    147 
    148 	save_flags(&state);
    149 	cli();
    150 	INIT_LIST_HEAD(&freelist);
    151 	INIT_LIST_HEAD(&allolist);
    152 	is_init = 1;
    153 	load_flags(state);
    154 }
    155