Переглянути джерело

Allocate heap at first usage, rather than assuming we can fit it in

below _text.  This should help with the gPXE-on-gPXE-via-PXE case.
tags/v0.9.3
Michael Brown 17 роки тому
джерело
коміт
fbda4837b0
1 змінених файлів з 65 додано та 10 видалено
  1. 65
    10
      src/arch/i386/core/umalloc.c

+ 65
- 10
src/arch/i386/core/umalloc.c Переглянути файл

@@ -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
 }

Завантаження…
Відмінити
Зберегти