fix DBG macro unknown variable
[people/xl0/gpxe.git] / src / arch / i386 / firmware / pcbios / basemem.c
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 /*
29  * Return amount of free base memory in bytes
30  *
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.
39  *
40  */
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
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         }
57
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 [%hx:0000,%hx: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()).
92  *
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! :-)
99  *
100  */
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
111         DBG ( "Trying to free %d bytes base memory at %hx:%hx "
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.
149  */
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                 }
167
168                 /* Return memory to BIOS */
169                 fbms += free_block->header.size_kb;
170
171                 DBG ( "Freed %d kB of base memory at [%hx:0000,%hx: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         }
185 }