Procházet zdrojové kódy

Rewritten in a much saner way, now that we don't have to worry about

continually reallocating the real-mode stack.
tags/v0.9.3
Michael Brown před 19 roky
rodič
revize
48feb91a40
1 změnil soubory, kde provedl 78 přidání a 196 odebrání
  1. 78
    196
      src/arch/i386/firmware/pcbios/basemem.c

+ 78
- 196
src/arch/i386/firmware/pcbios/basemem.c Zobrazit soubor

1
-#ifdef PCBIOS
2
-
1
+#include "stdint.h"
2
+#include "stddef.h"
3
+#include "memsizes.h"
3
 #include "etherboot.h"
4
 #include "etherboot.h"
4
-#include "realmode.h" /* for real_mode_stack */
5
+#include "basemem.h"
5
 
6
 
6
 /* Routines to allocate base memory in a BIOS-compatible way, by
7
 /* Routines to allocate base memory in a BIOS-compatible way, by
7
  * updating the Free Base Memory Size counter at 40:13h.
8
  * updating the Free Base Memory Size counter at 40:13h.
8
  *
9
  *
9
  * Michael Brown <mbrown@fensystems.co.uk> (mcb30)
10
  * Michael Brown <mbrown@fensystems.co.uk> (mcb30)
10
- * $Id$
11
+ *
12
+ * We no longer have anything to do with the real-mode stack.  The
13
+ * only code that can end up creating a huge bubble of wasted base
14
+ * memory is the UNDI driver, so we make it the responsibility of the
15
+ * UNDI driver to reallocate the real-mode stack if required.
11
  */
16
  */
12
 
17
 
13
-#define fbms ( ( uint16_t * ) phys_to_virt ( 0x413 ) )
14
-#define BASE_MEMORY_MAX ( 640 )
15
-#define FREE_BLOCK_MAGIC ( ('!'<<0) + ('F'<<8) + ('R'<<16) + ('E'<<24) )
16
-#define FREE_BASE_MEMORY ( (uint32_t) ( *fbms << 10 ) )
17
-
18
-/* Prototypes */
19
-void * _allot_base_memory ( size_t size );
20
-void _forget_base_memory ( void *ptr, size_t size );
21
-
22
-typedef struct free_base_memory_block {
23
-	uint32_t	magic;
24
-	uint16_t	size_kb;
25
-} free_base_memory_block_t;
26
-
27
-/* Return amount of free base memory in bytes
18
+/* "fbms" is an alias to the BIOS FBMS counter at 40:13, and acts just
19
+ * like any other uint16_t.  We can't be used under -DKEEP_IT_REAL
20
+ * anyway, so we may as well be efficient.
28
  */
21
  */
22
+#define fbms ( * ( ( uint16_t * ) phys_to_virt ( 0x413 ) ) )
23
+#define FBMS_MAX ( 640 )
29
 
24
 
30
-uint32_t get_free_base_memory ( void ) {
31
-	return FREE_BASE_MEMORY;
32
-}
33
-
34
-/* Start of our image in base memory.
25
+/* Structure that we use to represent a free block of base memory
35
  */
26
  */
36
-#define __text16_nocompress __attribute__ ((section (".text16.nocompress")))
37
-uint32_t image_basemem __text16_nocompress = 0;
38
-uint32_t image_basemem_size __text16_nocompress = 0;
27
+#define FREE_BLOCK_MAGIC ( ('!'<<0) + ('F'<<8) + ('R'<<16) + ('E'<<24) )
28
+union free_base_memory_block {
29
+	struct {
30
+		uint32_t	magic;
31
+		uint16_t	size_kb;
32
+	};
33
+	char bytes[1024];
34
+};
35
+
36
+/* Local prototypes */
37
+static void free_unused_base_memory ( void );
38
+
39
+#undef DBG
40
+#ifdef DEBUG_BASEMEM
41
+#define DBG(...) printf ( __VA_ARGS__ )
42
+#else
43
+#define DBG(...)
44
+#endif
39
 
45
 
40
-/* Allot/free the real-mode stack
46
+/*
47
+ * Return amount of free base memory in bytes
48
+ *
41
  */
49
  */
42
-
43
-void allot_real_mode_stack ( void )
44
-{
45
-	void *new_real_mode_stack;
46
-
47
-	if ( lock_real_mode_stack ) 
48
-		return;
49
-
50
-	/* This is evil hack. 
51
-	 * Until we have a real_mode stack use 0x7c00.
52
-	 * Except for 0 - 0x600 membory below 0x7c00 is hardly every used.
53
-	 * This stack should never be used unless the stack allocation fails,
54
-	 * or if someone has placed a print statement in a dangerous location.
55
-	 */
56
-	if (!real_mode_stack) {
57
-		real_mode_stack = 0x7c00;
58
-	}
59
-	new_real_mode_stack = _allot_base_memory ( real_mode_stack_size );
60
-	if ( ! new_real_mode_stack ) {
61
-		printf ( "FATAL: No real-mode stack\n" );
62
-		while ( 1 ) {};
63
-	}
64
-	real_mode_stack = virt_to_phys ( new_real_mode_stack );
65
-	get_memsizes();
66
-}
67
-
68
-void forget_real_mode_stack ( void )
69
-{
70
-	if ( lock_real_mode_stack ) 
71
-		return;
72
-
73
-	if ( real_mode_stack) {
74
-		_forget_base_memory ( phys_to_virt(real_mode_stack),
75
-				      real_mode_stack_size );
76
-		/* get_memsizes() uses the real_mode stack we just freed
77
-		 * for it's BIOS calls.
78
-		 */
79
-		get_memsizes();
80
-		real_mode_stack = 0;
81
-	}
50
+uint32_t get_free_base_memory ( void ) {
51
+	return fbms << 10;
82
 }
52
 }
83
 
53
 
84
 /* Allocate N bytes of base memory.  Amount allocated will be rounded
54
 /* Allocate N bytes of base memory.  Amount allocated will be rounded
85
  * up to the nearest kB, since that's the granularity of the BIOS FBMS
55
  * up to the nearest kB, since that's the granularity of the BIOS FBMS
86
  * counter.  Returns NULL if memory cannot be allocated.
56
  * counter.  Returns NULL if memory cannot be allocated.
57
+ *
87
  */
58
  */
88
-
89
-static void * _allot_base_memory ( size_t size ) 
90
-{
59
+void * alloc_base_memory ( size_t size ) {
91
 	uint16_t size_kb = ( size + 1023 ) >> 10;
60
 	uint16_t size_kb = ( size + 1023 ) >> 10;
92
-	void *ptr = NULL;
61
+	void *ptr;
93
 
62
 
94
-#ifdef DEBUG_BASEMEM
95
-	printf ( "Trying to allocate %d kB of base memory from %d kB free\n",
96
-		 size_kb, *fbms );
97
-#endif
63
+	DBG ( "Trying to allocate %d bytes of base memory from %d kB free\n",
64
+	      size, fbms );
98
 
65
 
99
 	/* Free up any unused memory before we start */
66
 	/* Free up any unused memory before we start */
100
 	free_unused_base_memory();
67
 	free_unused_base_memory();
101
 
68
 
102
 	/* Check available base memory */
69
 	/* Check available base memory */
103
-	if ( size_kb > *fbms ) { return NULL; }
70
+	if ( size_kb > fbms ) {
71
+		DBG ( "Could not allocate %d kB of base memory: "
72
+		      "only %d kB free\n", size_kb, fbms );
73
+		return NULL;
74
+	}
104
 
75
 
105
 	/* Reduce available base memory */
76
 	/* Reduce available base memory */
106
-	*fbms -= size_kb;
77
+	fbms -= size_kb;
107
 
78
 
108
 	/* Calculate address of memory allocated */
79
 	/* Calculate address of memory allocated */
109
-	ptr = phys_to_virt ( FREE_BASE_MEMORY );
80
+	ptr = phys_to_virt ( fbms << 10 );
110
 
81
 
111
 	/* Zero out memory.  We do this so that allocation of
82
 	/* Zero out memory.  We do this so that allocation of
112
 	 * already-used space will show up in the form of a crash as
83
 	 * already-used space will show up in the form of a crash as
119
 	 */
90
 	 */
120
 	memset ( ptr, 0, size_kb << 10 );
91
 	memset ( ptr, 0, size_kb << 10 );
121
 
92
 
122
-#ifdef DEBUG_BASEMEM
123
-	printf ( "Allocated %d kB at [%x,%x)\n", size_kb,
124
-		 virt_to_phys ( ptr ),
125
-		 virt_to_phys ( ptr ) + size_kb * 1024 );
126
-#endif
127
-
128
-	return ptr;
129
-}
93
+	DBG ( "Allocated %d kB of base memory at [%hx:0000,%hx:0000)\n",
94
+	      size_kb, ( fbms << 6 ), ( ( fbms + size_kb ) << 6 ) );
130
 
95
 
131
-void * allot_base_memory ( size_t size )
132
-{
133
-	void *ptr;
134
-
135
-	/* Free real-mode stack, allocate memory, reallocate real-mode
136
-	 * stack.
137
-	 */
138
-	forget_real_mode_stack();
139
-	ptr = _allot_base_memory ( size );
96
+	/* Update our memory map */
140
 	get_memsizes();
97
 	get_memsizes();
98
+
141
 	return ptr;
99
 	return ptr;
142
 }
100
 }
143
 
101
 
144
-/* Free base memory allocated by allot_base_memory.  The BIOS provides
102
+/* Free base memory allocated by alloc_base_memory.  The BIOS provides
145
  * nothing better than a LIFO mechanism for freeing memory (i.e. it
103
  * nothing better than a LIFO mechanism for freeing memory (i.e. it
146
  * just has the single "total free memory" counter), but we improve
104
  * just has the single "total free memory" counter), but we improve
147
- * upon this slightly; as long as you free all the allotted blocks, it
105
+ * upon this slightly; as long as you free all the allocated blocks, it
148
  * doesn't matter what order you free them in.  (This will only work
106
  * doesn't matter what order you free them in.  (This will only work
149
- * for blocks that are freed via forget_base_memory()).
107
+ * for blocks that are freed via free_base_memory()).
150
  *
108
  *
151
  * Yes, it's annoying that you have to remember the size of the blocks
109
  * Yes, it's annoying that you have to remember the size of the blocks
152
- * you've allotted.  However, since our granularity of allocation is
110
+ * you've allocated.  However, since our granularity of allocation is
153
  * 1K, the alternative is to risk wasting the occasional kB of base
111
  * 1K, the alternative is to risk wasting the occasional kB of base
154
  * memory, which is a Bad Thing.  Really, you should be using as
112
  * memory, which is a Bad Thing.  Really, you should be using as
155
  * little base memory as possible, so consider the awkwardness of the
113
  * little base memory as possible, so consider the awkwardness of the
156
  * API to be a feature! :-)
114
  * API to be a feature! :-)
115
+ *
157
  */
116
  */
158
-
159
-static void _forget_base_memory ( void *ptr, size_t size ) 
160
-{
161
-	uint16_t remainder = virt_to_phys(ptr) & 1023;
117
+void free_base_memory ( void *ptr, size_t size ) {
118
+	uint16_t remainder = virt_to_phys ( ptr ) & 1023;
162
 	uint16_t size_kb = ( size + remainder + 1023 ) >> 10;
119
 	uint16_t size_kb = ( size + remainder + 1023 ) >> 10;
163
-	free_base_memory_block_t *free_block =
164
-		( free_base_memory_block_t * ) ( ptr - remainder );
120
+	union free_base_memory_block *free_block = 
121
+		( ( void * ) ( ptr - remainder ) );
165
 	
122
 	
166
 	if ( ( ptr == NULL ) || ( size == 0 ) ) { 
123
 	if ( ( ptr == NULL ) || ( size == 0 ) ) { 
167
 		return; 
124
 		return; 
168
 	}
125
 	}
169
 
126
 
170
-#ifdef DEBUG_BASEMEM
171
-	printf ( "Trying to free %d bytes base memory at 0x%x\n",
172
-		 size, virt_to_phys ( ptr ) );
173
-	if ( remainder > 0 ) {
174
-		printf ( "WARNING: destructively expanding free block "
175
-			 "downwards to 0x%x\n",
176
-			 virt_to_phys ( ptr - remainder ) );
177
-	}
178
-#endif
127
+	DBG ( "Trying to free %d bytes base memory at %hx:%hx\n", size,
128
+	      ( virt_to_phys ( ptr - remainder ) >> 4 ),
129
+	      ( virt_to_phys ( ptr - remainder ) & 0xf ) + remainder );
179
 
130
 
180
 	/* Mark every kilobyte within this block as free.  This is
131
 	/* Mark every kilobyte within this block as free.  This is
181
 	 * overkill for normal purposes, but helps when something has
132
 	 * overkill for normal purposes, but helps when something has
191
 	 * keep this in so that debug messages are friendlier.  It
142
 	 * keep this in so that debug messages are friendlier.  It
192
 	 * probably adds around 8 bytes to the overall code size.
143
 	 * probably adds around 8 bytes to the overall code size.
193
 	 */
144
 	 */
194
-	while ( size_kb > 0 ) {
145
+	for ( ; size_kb > 0 ; free_block++, size_kb-- ) {
195
 		/* Mark this block as unused */
146
 		/* Mark this block as unused */
196
 		free_block->magic = FREE_BLOCK_MAGIC;
147
 		free_block->magic = FREE_BLOCK_MAGIC;
197
 		free_block->size_kb = size_kb;
148
 		free_block->size_kb = size_kb;
198
-		/* Move up by 1 kB */
199
-		free_block = (void *)(((char *)free_block) + (1 << 10));
200
-		size_kb--;
201
 	}
149
 	}
202
 
150
 
203
 	/* Free up unused base memory */
151
 	/* Free up unused base memory */
204
 	free_unused_base_memory();
152
 	free_unused_base_memory();
205
-}
206
 
153
 
207
-void forget_base_memory ( void *ptr, size_t size )
208
-{
209
-	/* Free memory, free real-mode stack, re-allocate real-mode
210
-	 * stack.  Do this so that we don't end up wasting a huge
211
-	 * block of memory trapped behind the real-mode stack.
212
-	 */
213
-	_forget_base_memory ( ptr, size );
214
-	forget_real_mode_stack();
154
+	/* Update our memory map */
215
 	get_memsizes();
155
 	get_memsizes();
156
+
157
+	DBG ( "%d kB of base memory now free\n", fbms );
216
 }
158
 }
217
 
159
 
218
 /* Do the actual freeing of memory.  This is split out from
160
 /* Do the actual freeing of memory.  This is split out from
219
- * forget_base_memory() so that it may be called separately.  It
161
+ * free_base_memory() so that it may be called separately.  It
220
  * should be called whenever base memory is deallocated by an external
162
  * should be called whenever base memory is deallocated by an external
221
  * entity (if we can detect that it has done so) so that we get the
163
  * entity (if we can detect that it has done so) so that we get the
222
  * chance to free up our own blocks.
164
  * chance to free up our own blocks.
223
  */
165
  */
224
 static void free_unused_base_memory ( void ) {
166
 static void free_unused_base_memory ( void ) {
225
-	free_base_memory_block_t *free_block = NULL;
167
+	union free_base_memory_block *free_block;
226
 
168
 
227
 	/* Try to release memory back to the BIOS.  Free all
169
 	/* Try to release memory back to the BIOS.  Free all
228
 	 * consecutive blocks marked as free.
170
 	 * consecutive blocks marked as free.
229
 	 */
171
 	 */
230
 	while ( 1 ) {
172
 	while ( 1 ) {
231
 		/* Calculate address of next potential free block */
173
 		/* Calculate address of next potential free block */
232
-		free_block = ( free_base_memory_block_t * )
233
-			phys_to_virt ( FREE_BASE_MEMORY );
174
+		free_block = phys_to_virt ( fbms << 10 );
234
 		
175
 		
235
 		/* Stop processing if we're all the way up to 640K or
176
 		/* Stop processing if we're all the way up to 640K or
236
 		 * if this is not a free block
177
 		 * if this is not a free block
237
 		 */
178
 		 */
238
-		if ( ( *fbms == BASE_MEMORY_MAX ) ||
179
+		if ( ( fbms == FBMS_MAX ) ||
239
 		     ( free_block->magic != FREE_BLOCK_MAGIC ) ) {
180
 		     ( free_block->magic != FREE_BLOCK_MAGIC ) ) {
240
 			break;
181
 			break;
241
 		}
182
 		}
242
 
183
 
243
 		/* Return memory to BIOS */
184
 		/* Return memory to BIOS */
244
-		*fbms += free_block->size_kb;
185
+		fbms += free_block->size_kb;
245
 
186
 
246
-#ifdef DEBUG_BASEMEM
247
-		printf ( "Freed %d kB base memory, %d kB now free\n",
248
-			 free_block->size_kb, *fbms );
249
-#endif
187
+		DBG ( "Freed %d kB of base memory at [%hx:0000,%hx:0000)\n",
188
+		      free_block->size_kb, ( fbms << 6 ),
189
+		      ( fbms + free_block->size_kb ) << 6 );
250
 		
190
 		
251
 		/* Zero out freed block.  We do this in case
191
 		/* Zero out freed block.  We do this in case
252
 		 * the block contained any structures that
192
 		 * the block contained any structures that
254
 		 * memory.
194
 		 * memory.
255
 		 */
195
 		 */
256
 		memset ( free_block, 0, free_block->size_kb << 10 );
196
 		memset ( free_block, 0, free_block->size_kb << 10 );
257
-	}
258
-}
259
 
197
 
260
-/* Free base memory used by the prefix.  Called once at start of
261
- * Etherboot by arch_main().
262
- */
263
-void forget_prefix_base_memory ( void )
264
-{
265
-	/* runtime_start_kb is _text rounded down to a physical kB boundary */
266
-	uint32_t runtime_start_kb = virt_to_phys(_text) & ~0x3ff;
267
-	/* prefix_size_kb is the prefix size excluding any portion
268
-	 * that overlaps into the first kB used by the runtime image
269
-	 */
270
-	uint32_t prefix_size_kb = runtime_start_kb - image_basemem;
271
-
272
-#ifdef DEBUG_BASEMEM
273
-	printf ( "Attempting to free base memory used by prefix\n" );
274
-#endif
275
-
276
-	/* If the decompressor is in allocated base memory
277
-	 * *and* the Etherboot text is in base
278
-	 * memory, then free the decompressor.
279
-	 */
280
-	if ( ( image_basemem >= FREE_BASE_MEMORY ) &&
281
-	     ( runtime_start_kb >= FREE_BASE_MEMORY ) &&
282
-	     ( runtime_start_kb <= ( BASE_MEMORY_MAX << 10 ) ) ) 
283
-	{
284
-		forget_base_memory ( phys_to_virt ( image_basemem ),
285
-				     prefix_size_kb );
286
-		/* Update image_basemem and image_basemem_size to
287
-		 * indicate that our allocation now starts with _text
288
-		 */
289
-		image_basemem = runtime_start_kb;
290
-		image_basemem_size -= prefix_size_kb;
291
 	}
198
 	}
292
 }
199
 }
293
-
294
-/* Free base memory used by the runtime image.  Called after
295
- * relocation by arch_relocated_from().
296
- */
297
-void forget_runtime_base_memory ( unsigned long old_addr )
298
-{
299
-	/* text_start_kb is old _text rounded down to a physical KB boundary */
300
-	uint32_t old_text_start_kb = old_addr & ~0x3ff;
301
-
302
-#ifdef DEBUG_BASEMEM
303
-	printf ( "Attempting to free base memory used by runtime image\n" );
304
-#endif
305
-
306
-	if ( ( image_basemem >= FREE_BASE_MEMORY ) &&
307
-	     ( image_basemem == old_text_start_kb ) ) 
308
-	{
309
-		forget_base_memory ( phys_to_virt ( image_basemem ),
310
-				     image_basemem_size );
311
-		/* Update image_basemem to show no longer in use */
312
-		image_basemem = 0;
313
-		image_basemem_size = 0;
314
-	}
315
-}
316
-
317
-#endif /* PCBIOS */

Načítá se…
Zrušit
Uložit