|
@@ -23,8 +23,11 @@
|
23
|
23
|
*
|
24
|
24
|
*/
|
25
|
25
|
|
|
26
|
+#include <limits.h>
|
|
27
|
+#include <errno.h>
|
26
|
28
|
#include <gpxe/uaccess.h>
|
27
|
29
|
#include <gpxe/hidemem.h>
|
|
30
|
+#include <gpxe/memmap.h>
|
28
|
31
|
#include <gpxe/umalloc.h>
|
29
|
32
|
|
30
|
33
|
/** Alignment of external allocated memory */
|
|
@@ -36,9 +39,6 @@
|
36
|
39
|
/** Start of Etherboot text, as defined by the linker */
|
37
|
40
|
extern char _text[];
|
38
|
41
|
|
39
|
|
-/** Top of allocatable memory */
|
40
|
|
-#define TOP ( virt_to_user ( _text ) )
|
41
|
|
-
|
42
|
42
|
/** An external memory block */
|
43
|
43
|
struct external_memory {
|
44
|
44
|
/** Size of this memory block (excluding this header) */
|
|
@@ -47,11 +47,63 @@ struct external_memory {
|
47
|
47
|
int used;
|
48
|
48
|
};
|
49
|
49
|
|
50
|
|
-/** Current lowest allocated block
|
|
50
|
+/** Top of heap */
|
|
51
|
+static userptr_t top = UNULL;
|
|
52
|
+
|
|
53
|
+/** Bottom of heap (current lowest allocated block) */
|
|
54
|
+static userptr_t bottom = UNULL;
|
|
55
|
+
|
|
56
|
+/**
|
|
57
|
+ * Initialise external heap
|
51
|
58
|
*
|
52
|
|
- * A value of UNULL indicates that no blocks are currently allocated.
|
|
59
|
+ * @ret rc Return status code
|
53
|
60
|
*/
|
54
|
|
-userptr_t bottom = UNULL;
|
|
61
|
+static int init_eheap ( void ) {
|
|
62
|
+ struct memory_map memmap;
|
|
63
|
+ unsigned long heap_size = 0;
|
|
64
|
+ unsigned int i;
|
|
65
|
+
|
|
66
|
+ DBG ( "Allocating external heap\n" );
|
|
67
|
+
|
|
68
|
+ get_memmap ( &memmap );
|
|
69
|
+ for ( i = 0 ; i < memmap.count ; i++ ) {
|
|
70
|
+ struct memory_region *region = &memmap.regions[i];
|
|
71
|
+ unsigned long r_start, r_end;
|
|
72
|
+ unsigned long r_size;
|
|
73
|
+
|
|
74
|
+ DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
|
|
75
|
+
|
|
76
|
+ /* Truncate block to 4GB */
|
|
77
|
+ if ( region->start > UINT_MAX ) {
|
|
78
|
+ DBG ( "...starts after 4GB\n" );
|
|
79
|
+ continue;
|
|
80
|
+ }
|
|
81
|
+ r_start = region->start;
|
|
82
|
+ if ( region->end > UINT_MAX ) {
|
|
83
|
+ DBG ( "...end truncated to 4GB\n" );
|
|
84
|
+ r_end = 0; /* =4GB, given the wraparound */
|
|
85
|
+ } else {
|
|
86
|
+ r_end = region->end;
|
|
87
|
+ }
|
|
88
|
+
|
|
89
|
+ /* Use largest block */
|
|
90
|
+ r_size = ( r_end - r_start );
|
|
91
|
+ if ( r_size > heap_size ) {
|
|
92
|
+ DBG ( "...new best block found\n" );
|
|
93
|
+ top = bottom = phys_to_user ( r_end );
|
|
94
|
+ heap_size = r_size;
|
|
95
|
+ }
|
|
96
|
+ }
|
|
97
|
+
|
|
98
|
+ if ( ! top ) {
|
|
99
|
+ DBG ( "No external heap available\n" );
|
|
100
|
+ return -ENOMEM;
|
|
101
|
+ }
|
|
102
|
+
|
|
103
|
+ DBG ( "External heap grows downwards from %lx\n",
|
|
104
|
+ user_to_phys ( top, 0 ) );
|
|
105
|
+ return 0;
|
|
106
|
+}
|
55
|
107
|
|
56
|
108
|
/**
|
57
|
109
|
* Collect free blocks
|
|
@@ -61,7 +113,7 @@ static void ecollect_free ( void ) {
|
61
|
113
|
struct external_memory extmem;
|
62
|
114
|
|
63
|
115
|
/* Walk the free list and collect empty blocks */
|
64
|
|
- while ( bottom != TOP ) {
|
|
116
|
+ while ( bottom != top ) {
|
65
|
117
|
copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
|
66
|
118
|
sizeof ( extmem ) );
|
67
|
119
|
if ( extmem.used )
|
|
@@ -87,10 +139,13 @@ userptr_t urealloc ( userptr_t ptr, size_t new_size ) {
|
87
|
139
|
struct external_memory extmem;
|
88
|
140
|
userptr_t new = ptr;
|
89
|
141
|
size_t align;
|
|
142
|
+ int rc;
|
90
|
143
|
|
91
|
144
|
/* Initialise external memory allocator if necessary */
|
92
|
|
- if ( ! bottom )
|
93
|
|
- bottom = TOP;
|
|
145
|
+ if ( ! top ) {
|
|
146
|
+ if ( ( rc = init_eheap() ) != 0 )
|
|
147
|
+ return rc;
|
|
148
|
+ }
|
94
|
149
|
|
95
|
150
|
/* Get block properties into extmem */
|
96
|
151
|
if ( ptr && ( ptr != UNOWHERE ) ) {
|
|
@@ -140,7 +195,7 @@ userptr_t urealloc ( userptr_t ptr, size_t new_size ) {
|
140
|
195
|
/* Collect any free blocks and update hidden memory region */
|
141
|
196
|
ecollect_free();
|
142
|
197
|
hide_region ( EXTMEM, user_to_phys ( bottom, -sizeof ( extmem ) ),
|
143
|
|
- user_to_phys ( TOP, 0 ) );
|
|
198
|
+ user_to_phys ( top, 0 ) );
|
144
|
199
|
|
145
|
200
|
return ( new_size ? new : UNOWHERE );
|
146
|
201
|
}
|