Browse Source

Provide {get,set}_fbms() in basemem.h.

set_fbms() will also update the E820 hidden region.
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
0b0e34e667

+ 30
- 171
src/arch/i386/firmware/pcbios/basemem.c View File

@@ -1,185 +1,44 @@
1
-#include "stdint.h"
2
-#include "stddef.h"
3
-#include "memsizes.h"
4
-#include "etherboot.h"
5
-#include "basemem.h"
6
-
7
-/* Routines to allocate base memory in a BIOS-compatible way, by
8
- * updating the Free Base Memory Size counter at 40:13h.
9
- *
10
- * Michael Brown <mbrown@fensystems.co.uk> (mcb30)
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.
16
- */
17
-
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.
21
- */
22
-#define fbms ( * ( ( uint16_t * ) phys_to_virt ( 0x413 ) ) )
23
-#define FBMS_MAX ( 640 )
24
-
25
-/* Local prototypes */
26
-static void free_unused_base_memory ( void );
27
-
28 1
 /*
29
- * Return amount of free base memory in bytes
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
30 3
  *
31
- */
32
-unsigned int get_free_base_memory ( void ) {
33
-	return fbms << 10;
34
-}
35
-
36
-/* Allocate N bytes of base memory.  Amount allocated will be rounded
37
- * up to the nearest kB, since that's the granularity of the BIOS FBMS
38
- * counter.  Returns NULL if memory cannot be allocated.
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
39 8
  *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40 17
  */
41
-void * alloc_base_memory ( size_t size ) {
42
-	unsigned int size_kb = ( size + 1023 ) >> 10;
43
-	void *ptr;
44
-
45
-	DBG ( "Trying to allocate %d bytes of base memory from %d kB free\n",
46
-	      size, fbms );
47
-
48
-	/* Free up any unused memory before we start */
49
-	free_unused_base_memory();
50 18
 
51
-	/* Check available base memory */
52
-	if ( size_kb > fbms ) {
53
-		DBG ( "Could not allocate %d kB of base memory: "
54
-		      "only %d kB free\n", size_kb, fbms );
55
-		return NULL;
56
-	}
19
+#include <stdint.h>
20
+#include <realmode.h>
21
+#include <bios.h>
22
+#include <basemem.h>
23
+#include <gpxe/hidemem.h>
57 24
 
58
-	/* Reduce available base memory */
59
-	fbms -= size_kb;
60
-
61
-	/* Calculate address of memory allocated */
62
-	ptr = phys_to_virt ( fbms << 10 );
63
-
64
-	/* Zero out memory.  We do this so that allocation of
65
-	 * already-used space will show up in the form of a crash as
66
-	 * soon as possible.
67
-	 *
68
-	 * Update: there's another reason for doing this.  If we don't
69
-	 * zero the contents, then they could still retain our "free
70
-	 * block" markers and be liable to being freed whenever a
71
-	 * base-memory allocation routine is next called.
72
-	 */
73
-	memset ( ptr, 0, size_kb << 10 );
74
-
75
-	DBG ( "Allocated %d kB of base memory at [%4.4lx:0000,%4.4lx:0000), "
76
-	      "%d kB now free\n", size_kb,
77
-	      ( virt_to_phys ( ptr ) >> 4 ),
78
-	      ( ( virt_to_phys ( ptr ) + ( size_kb << 10 ) ) >> 4 ), fbms );
79
-
80
-	/* Update our memory map */
81
-	get_memsizes();
82
-
83
-	return ptr;
84
-}
85
-
86
-/* Free base memory allocated by alloc_base_memory.  The BIOS provides
87
- * nothing better than a LIFO mechanism for freeing memory (i.e. it
88
- * just has the single "total free memory" counter), but we improve
89
- * upon this slightly; as long as you free all the allocated blocks, it
90
- * doesn't matter what order you free them in.  (This will only work
91
- * for blocks that are freed via free_base_memory()).
25
+/** @file
92 26
  *
93
- * Yes, it's annoying that you have to remember the size of the blocks
94
- * you've allocated.  However, since our granularity of allocation is
95
- * 1K, the alternative is to risk wasting the occasional kB of base
96
- * memory, which is a Bad Thing.  Really, you should be using as
97
- * little base memory as possible, so consider the awkwardness of the
98
- * API to be a feature! :-)
27
+ * Base memory allocation
99 28
  *
100 29
  */
101
-void free_base_memory ( void *ptr, size_t size ) {
102
-	unsigned int remainder = virt_to_phys ( ptr ) & 1023;
103
-	unsigned int size_kb = ( size + remainder + 1023 ) >> 10;
104
-	union free_base_memory_block *free_block = 
105
-		( ( void * ) ( ptr - remainder ) );
106
-	
107
-	if ( ( ptr == NULL ) || ( size == 0 ) ) { 
108
-		return; 
109
-	}
110 30
 
111
-	DBG ( "Trying to free %d bytes base memory at %4.4lx:%4.4lx "
112
-	      "from %d kB free\n", size,
113
-	      ( virt_to_phys ( ptr - remainder ) >> 4 ),
114
-	      ( virt_to_phys ( ptr - remainder ) & 0xf ) + remainder,
115
-	      fbms );
116
-
117
-	/* Mark every kilobyte within this block as free.  This is
118
-	 * overkill for normal purposes, but helps when something has
119
-	 * allocated base memory with a granularity finer than the
120
-	 * BIOS granularity of 1kB.  PXE ROMs tend to do this when
121
-	 * they allocate their own memory.  This method allows us to
122
-	 * free their blocks (admittedly in a rather dangerous,
123
-	 * tread-on-anything-either-side sort of way, but there's no
124
-	 * other way to do it).
125
-	 *
126
-	 * Since we're marking every kB as free, there's actually no
127
-	 * need for recording the size of the blocks.  However, we
128
-	 * keep this in so that debug messages are friendlier.  It
129
-	 * probably adds around 8 bytes to the overall code size.
130
-	 */
131
-	for ( ; size_kb > 0 ; free_block++, size_kb-- ) {
132
-		/* Mark this block as unused */
133
-		free_block->header.magic = FREE_BLOCK_MAGIC;
134
-		free_block->header.size_kb = size_kb;
135
-	}
136
-
137
-	/* Free up unused base memory */
138
-	free_unused_base_memory();
139
-
140
-	/* Update our memory map */
141
-	get_memsizes();
142
-}
143
-
144
-/* Do the actual freeing of memory.  This is split out from
145
- * free_base_memory() so that it may be called separately.  It
146
- * should be called whenever base memory is deallocated by an external
147
- * entity (if we can detect that it has done so) so that we get the
148
- * chance to free up our own blocks.
31
+/**
32
+ * Set the BIOS free base memory counter
33
+ *
34
+ * @v new_fbms		New free base memory counter (in kB)
149 35
  */
150
-static void free_unused_base_memory ( void ) {
151
-	union free_base_memory_block *free_block;
152
-
153
-	/* Try to release memory back to the BIOS.  Free all
154
-	 * consecutive blocks marked as free.
155
-	 */
156
-	while ( 1 ) {
157
-		/* Calculate address of next potential free block */
158
-		free_block = phys_to_virt ( fbms << 10 );
159
-		
160
-		/* Stop processing if we're all the way up to 640K or
161
-		 * if this is not a free block
162
-		 */
163
-		if ( ( fbms == FBMS_MAX ) ||
164
-		     ( free_block->header.magic != FREE_BLOCK_MAGIC ) ) {
165
-			break;
166
-		}
36
+void set_fbms ( unsigned int new_fbms ) {
37
+	uint16_t fbms = new_fbms;
167 38
 
168
-		/* Return memory to BIOS */
169
-		fbms += free_block->header.size_kb;
39
+	/* Update the BIOS memory counter */
40
+	put_real ( fbms, BDA_SEG, BDA_FBMS );
170 41
 
171
-		DBG ( "Freed %ld kB of base memory at [%4.4lx:0000,%4.4lx:0000), "
172
-		      "%d kB now free\n",
173
-		      free_block->header.size_kb,
174
-		      ( virt_to_phys ( free_block ) >> 4 ),
175
-		      ( ( virt_to_phys ( free_block ) + 
176
-			  ( free_block->header.size_kb << 10 ) ) >> 4 ),
177
-		      fbms );
178
-		
179
-		/* Do not zero out the freed block, because it might
180
-		 * be the one containing librm, in which case we're
181
-		 * going to have severe problems the next time we use
182
-		 * DBG() or, failing that, call get_memsizes().
183
-		 */
184
-	}
42
+	/* Update our hidden memory region map */
43
+	hide_basemem();
185 44
 }

+ 7
- 8
src/arch/i386/firmware/pcbios/hidemem.c View File

@@ -16,8 +16,8 @@
16 16
  */
17 17
 
18 18
 #include <realmode.h>
19
-#include <bios.h>
20 19
 #include <biosint.h>
20
+#include <basemem.h>
21 21
 #include <gpxe/hidemem.h>
22 22
 
23 23
 /** Alignment for hidden memory regions */
@@ -71,10 +71,12 @@ void hide_region ( unsigned int region_id, physaddr_t start, physaddr_t end ) {
71 71
 	/* Some operating systems get a nasty shock if a region of the
72 72
 	 * E820 map seems to start on a non-page boundary.  Make life
73 73
 	 * safer by rounding out our edited region.
74
-	 */	
74
+	 */
75 75
 	region->start = ( start & ~( ALIGN_HIDDEN - 1 ) );
76 76
 	region->end = ( ( end + ALIGN_HIDDEN - 1 ) & ~( ALIGN_HIDDEN - 1 ) );
77
-	DBG ( "Hiding [%lx,%lx)\n", region->start, region->end );
77
+
78
+	DBG ( "Hiding region %d [%lx,%lx)\n",
79
+	      region_id, region->start, region->end );
78 80
 }
79 81
 
80 82
 /**
@@ -94,15 +96,12 @@ static void hide_text ( void ) {
94 96
  * Hide used base memory
95 97
  *
96 98
  */
97
-static void hide_basemem ( void ) {
98
-	uint16_t fbms;
99
-
99
+void hide_basemem ( void ) {
100 100
 	/* Hide from the top of free base memory to 640kB.  Don't use
101 101
 	 * hide_region(), because we don't want this rounded to the
102 102
 	 * nearest page boundary.
103 103
 	 */
104
-	get_real ( fbms, BDA_SEG, BDA_FBMS );
105
-	hidden_regions[BASEMEM].start = ( fbms * 1024 );
104
+	hidden_regions[BASEMEM].start = ( get_fbms() * 1024 );
106 105
 }
107 106
 
108 107
 /**

+ 33
- 33
src/arch/i386/include/basemem.h View File

@@ -1,33 +1,33 @@
1
-#ifndef BASEMEM_H
2
-#define BASEMEM_H
3
-
4
-#ifdef ASSEMBLY
5
-
6
-/* Must match sizeof(struct free_base_memory_header) */
7
-#define FREE_BASEMEM_HEADER_SIZE 8
8
-
9
-#else /* ASSEMBLY */
10
-
11
-#include "stdint.h"
12
-
13
-/* Structures that we use to represent a free block of base memory */
14
-
15
-#define FREE_BLOCK_MAGIC ( ('!'<<0) + ('F'<<8) + ('R'<<16) + ('E'<<24) )
16
-struct free_base_memory_header {
17
-	uint32_t	magic;
18
-	uint32_t	size_kb;
19
-};
20
-
21
-union free_base_memory_block {
22
-	struct free_base_memory_header header;
23
-	char bytes[1024];
24
-};
25
-
26
-/* Function prototypes */
27
-extern unsigned int get_free_base_memory ( void );
28
-extern void * alloc_base_memory ( size_t size );
29
-extern void free_base_memory ( void *ptr, size_t size );
30
-
31
-#endif /* ASSEMBLY */
32
-
33
-#endif /* BASEMEM_H */
1
+#ifndef _BASEMEM_H
2
+#define _BASEMEM_H
3
+
4
+/** @file
5
+ *
6
+ * Base memory allocation
7
+ *
8
+ */
9
+
10
+#include <stdint.h>
11
+#include <realmode.h>
12
+#include <bios.h>
13
+
14
+/**
15
+ * Read the BIOS free base memory counter
16
+ *
17
+ * @ret fbms		Free base memory counter (in kB)
18
+ */
19
+static inline unsigned int get_fbms ( void ) {
20
+	uint16_t fbms;
21
+
22
+	get_real ( fbms, BDA_SEG, BDA_FBMS );
23
+	return fbms;
24
+}
25
+
26
+extern void set_fbms ( unsigned int new_fbms );
27
+
28
+/* Actually in hidemem.c, but putting it here avoids polluting the
29
+ * architecture-independent include/hidemem.h.
30
+ */
31
+extern void hide_basemem ( void );
32
+
33
+#endif /* _BASEMEM_H */

Loading…
Cancel
Save