Added debugging
[people/lynusvaz/gpxe.git] / src / core / heap.c
1 #include "etherboot.h"
2 #include "init.h"
3 #include "memsizes.h"
4 #include "heap.h"
5
6 struct heap_block {
7         size_t size;
8         char data[0];
9 };
10
11 /* Linker symbols */
12 extern char _text[];
13 extern char _end[];
14
15 static unsigned long heap_start, heap_end, heap_ptr;
16
17 /*
18  * Find the largest contiguous area of memory that I can use for the
19  * heap.
20  *
21  */
22 static void init_heap ( void ) {
23         unsigned int i;
24         unsigned long eb_start, eb_end;
25         unsigned long size;
26
27         size = 0;
28         
29         /* Region occupied by Etherboot */
30         eb_start = virt_to_phys ( _text );
31         eb_end = virt_to_phys ( _end );
32
33         for ( i = 0 ; i < meminfo.map_count ; i++ ) {
34                 unsigned long r_start, r_end, r_size;
35                 unsigned long pre_eb, post_eb;
36
37                 /* Get start and end addresses of the region */
38                 if ( meminfo.map[i].type != E820_RAM )
39                         continue;
40                 if ( meminfo.map[i].addr > ULONG_MAX )
41                         continue;
42                 r_start = meminfo.map[i].addr;
43                 if ( r_start + meminfo.map[i].size > ULONG_MAX ) {
44                         r_end = ULONG_MAX;
45                 } else {
46                         r_end = r_start + meminfo.map[i].size;
47                 }
48                 
49                 /* Avoid overlap with Etherboot.  When Etherboot is
50                  * completely contained within the region, choose the
51                  * larger of the two remaining portions.
52                  */
53                 if ( ( eb_start < r_end ) && ( eb_end > r_start ) ) {
54                         pre_eb = ( eb_start > r_start ) ?
55                                 ( eb_start - r_start ) : 0;
56                         post_eb = ( r_end > eb_end ) ?
57                                 ( r_end - eb_end ) : 0;
58                         if ( pre_eb > post_eb ) {
59                                 r_end = eb_start;
60                         } else {
61                                 r_start = eb_end;
62                         }
63                 }
64
65                 /* Use the biggest region.  Where two regions are the
66                  * same size, use the later region.  (Provided that
67                  * the memory map is laid out in a sensible order,
68                  * this should give us the higher region.)
69                  */
70                 r_size = r_end - r_start;
71                 if ( r_size >= size ) {
72                         heap_start = r_start;
73                         heap_end = r_end;
74                         size = r_size;
75                 }
76         }
77
78         ASSERT ( size != 0 );
79         DBG ( "HEAP using region [%x,%x)\n", heap_start, heap_end );
80         heap_ptr = heap_end;
81 }
82
83 /*
84  * Allocate a block from the heap.
85  *
86  */
87 void * emalloc ( size_t size, unsigned int align ) {
88         physaddr_t addr;
89         struct heap_block *block;
90         
91         ASSERT ( ( align & ( align - 1 ) ) == 0 );
92         
93         addr = ( ( ( heap_ptr - size ) & ~( align - 1 ) )
94                  - sizeof ( struct heap_block ) );
95         if ( addr < heap_start ) {
96                 DBG ( "HEAP no space for %x bytes (alignment %d) in [%x,%x)\n",
97                       size, align, heap_start, heap_ptr );
98                 return NULL;
99         }
100
101         block = phys_to_virt ( addr );
102         block->size = ( heap_ptr - addr );
103         DBG ( "HEAP allocated %x bytes (alignment %d) at %x [%x,%x)\n",
104               size, align, virt_to_phys ( block->data ), addr, heap_ptr );
105         heap_ptr = addr;
106         return block->data;
107 }
108
109 /*
110  * Allocate all remaining space on the heap
111  *
112  */
113 void * emalloc_all ( size_t *size ) {
114         *size = heap_ptr - heap_start - sizeof ( struct heap_block );
115         return emalloc ( *size, sizeof ( void * ) );
116 }
117
118 /*
119  * Free a heap block
120  *
121  */
122 void efree ( void *ptr ) {
123         struct heap_block *block;
124
125         ASSERT ( ptr == phys_to_virt ( heap_ptr + sizeof ( size_t ) ) );
126         
127         block = ( struct heap_block * )
128                 ( ptr - offsetof ( struct heap_block, data ) );
129         heap_ptr += block->size;
130
131         DBG ( "HEAP freed %x [%x,%x)\n", virt_to_phys ( ptr ),
132               virt_to_phys ( block ), heap_ptr );
133
134         ASSERT ( heap_ptr <= heap_end );
135 }
136
137 /*
138  * Free all allocated heap blocks
139  *
140  */
141 void efree_all ( void ) {
142         DBG ( "HEAP discarding allocated blocks in [%x,%x)\n",
143               heap_ptr, heap_end );
144
145         heap_ptr = heap_end;
146 }
147
148 INIT_FN ( INIT_HEAP, init_heap, efree_all, NULL );