|
@@ -8,88 +8,75 @@ struct heap_block {
|
8
|
8
|
char data[0];
|
9
|
9
|
};
|
10
|
10
|
|
11
|
|
-size_t heap_ptr, heap_top, heap_bot;
|
|
11
|
+/* Linker symbols */
|
|
12
|
+extern char _text[];
|
|
13
|
+extern char _end[];
|
12
|
14
|
|
13
|
|
-#define _virt_start 0
|
|
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;
|
14
|
26
|
|
15
|
|
-static void init_heap(void)
|
16
|
|
-{
|
17
|
|
- size_t size;
|
18
|
|
- size_t start, end;
|
19
|
|
- unsigned i;
|
20
|
|
- /* Find the largest contiguous area of memory that
|
21
|
|
- * I can use for the heap, which is organized as
|
22
|
|
- * a stack that grows backwards through memory.
|
23
|
|
- */
|
24
|
|
-
|
25
|
|
- /* If I have virtual address that do not equal physical addresses
|
26
|
|
- * there is a change I will try to use memory from both sides of
|
27
|
|
- * the virtual address space simultaneously, which can cause all kinds
|
28
|
|
- * of interesting problems.
|
29
|
|
- * Avoid it by logically extending etherboot. Once I know that relocation
|
30
|
|
- * works I can just start the virtual address space at 0, and this problem goes
|
31
|
|
- * away so that is probably a better solution.
|
32
|
|
- */
|
33
|
|
-#if 0
|
34
|
|
- start = virt_to_phys(_text);
|
35
|
|
-#else
|
36
|
|
- /* segment wrap around is nasty don't chance it. */
|
37
|
|
- start = virt_to_phys(_virt_start);
|
38
|
|
-#endif
|
39
|
|
- end = virt_to_phys(_end);
|
40
|
27
|
size = 0;
|
41
|
|
- for(i = 0; i < meminfo.map_count; i++) {
|
42
|
|
- unsigned long r_start, r_end;
|
43
|
|
- if (meminfo.map[i].type != E820_RAM)
|
44
|
|
- continue;
|
45
|
|
- if (meminfo.map[i].addr > ULONG_MAX)
|
|
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 )
|
46
|
39
|
continue;
|
47
|
|
- if (meminfo.map[i].size > ULONG_MAX)
|
|
40
|
+ if ( meminfo.map[i].addr > ULONG_MAX )
|
48
|
41
|
continue;
|
49
|
|
-
|
50
|
42
|
r_start = meminfo.map[i].addr;
|
51
|
|
- r_end = r_start + meminfo.map[i].size;
|
52
|
|
- if (r_end < r_start) {
|
|
43
|
+ if ( r_start + meminfo.map[i].size > ULONG_MAX ) {
|
53
|
44
|
r_end = ULONG_MAX;
|
|
45
|
+ } else {
|
|
46
|
+ r_end = r_start + meminfo.map[i].size;
|
54
|
47
|
}
|
55
|
|
- /* Handle areas that overlap etherboot */
|
56
|
|
- if ((end > r_start) && (start < r_end)) {
|
57
|
|
- /* Etherboot completely covers the region */
|
58
|
|
- if ((start <= r_start) && (end >= r_end))
|
59
|
|
- continue;
|
60
|
|
- /* Etherboot is completely contained in the region */
|
61
|
|
- if ((start > r_start) && (end < r_end)) {
|
62
|
|
- /* keep the larger piece */
|
63
|
|
- if ((r_end - end) >= (r_start - start)) {
|
64
|
|
- r_start = end;
|
65
|
|
- }
|
66
|
|
- else {
|
67
|
|
- r_end = start;
|
68
|
|
- }
|
69
|
|
- }
|
70
|
|
- /* Etherboot covers one end of the region.
|
71
|
|
- * Shrink the region.
|
72
|
|
- */
|
73
|
|
- else if (end >= r_end) {
|
74
|
|
- r_end = start;
|
75
|
|
- }
|
76
|
|
- else if (start <= r_start) {
|
77
|
|
- r_start = end;
|
|
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;
|
78
|
62
|
}
|
79
|
63
|
}
|
80
|
|
- /* If two areas are the size prefer the greater address */
|
81
|
|
- if (((r_end - r_start) > size) ||
|
82
|
|
- (((r_end - r_start) == size) && (r_start > heap_top))) {
|
83
|
|
- size = r_end - r_start;
|
84
|
|
- heap_top = r_start;
|
85
|
|
- heap_bot = r_end;
|
|
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;
|
86
|
75
|
}
|
87
|
76
|
}
|
88
|
|
- if (size == 0) {
|
89
|
|
- printf("init_heap: No heap found.\n");
|
90
|
|
- exit(1);
|
91
|
|
- }
|
92
|
|
- heap_ptr = heap_bot;
|
|
77
|
+
|
|
78
|
+ ASSERT ( size != 0 );
|
|
79
|
+ heap_ptr = heap_end;
|
93
|
80
|
}
|
94
|
81
|
|
95
|
82
|
/*
|
|
@@ -104,7 +91,7 @@ void * emalloc ( size_t size, unsigned int align ) {
|
104
|
91
|
|
105
|
92
|
addr = ( ( ( heap_ptr - size ) & ~( align - 1 ) )
|
106
|
93
|
- sizeof ( struct heap_block ) );
|
107
|
|
- if ( addr < heap_top ) {
|
|
94
|
+ if ( addr < heap_start ) {
|
108
|
95
|
return NULL;
|
109
|
96
|
}
|
110
|
97
|
|
|
@@ -119,7 +106,7 @@ void * emalloc ( size_t size, unsigned int align ) {
|
119
|
106
|
*
|
120
|
107
|
*/
|
121
|
108
|
void * emalloc_all ( size_t *size ) {
|
122
|
|
- *size = heap_ptr - heap_top - sizeof ( struct heap_block );
|
|
109
|
+ *size = heap_ptr - heap_start - sizeof ( struct heap_block );
|
123
|
110
|
return emalloc ( *size, sizeof ( void * ) );
|
124
|
111
|
}
|
125
|
112
|
|
|
@@ -136,7 +123,7 @@ void efree ( void *ptr ) {
|
136
|
123
|
( ptr - offsetof ( struct heap_block, data ) );
|
137
|
124
|
heap_ptr += block->size;
|
138
|
125
|
|
139
|
|
- ASSERT ( heap_ptr <= heap_bot );
|
|
126
|
+ ASSERT ( heap_ptr <= heap_end );
|
140
|
127
|
}
|
141
|
128
|
|
142
|
129
|
/*
|
|
@@ -144,7 +131,7 @@ void efree ( void *ptr ) {
|
144
|
131
|
*
|
145
|
132
|
*/
|
146
|
133
|
void efree_all ( void ) {
|
147
|
|
- heap_ptr = heap_bot;
|
|
134
|
+ heap_ptr = heap_end;
|
148
|
135
|
}
|
149
|
136
|
|
150
|
137
|
INIT_FN ( INIT_HEAP, init_heap, efree_all, NULL );
|