2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
29 * External memory allocation
35 #include <ipxe/uaccess.h>
36 #include <ipxe/hidemem.h>
38 #include <ipxe/memblock.h>
39 #include <ipxe/umalloc.h>
41 /** Alignment of external allocated memory */
42 #define EM_ALIGN ( 4 * 1024 )
44 /** Equivalent of NOWHERE for user pointers */
45 #define UNOWHERE ( ~UNULL )
47 /** An external memory block */
48 struct external_memory {
49 /** Size of this memory block (excluding this header) */
51 /** Block is currently in use */
56 static userptr_t top = UNULL;
58 /** Bottom of heap (current lowest allocated block) */
59 static userptr_t bottom = UNULL;
61 /** Remaining space on heap */
62 static size_t heap_size;
65 * Initialise external heap
68 static void init_eheap ( void ) {
71 heap_size = largest_memblock ( &base );
72 bottom = top = userptr_add ( base, heap_size );
73 DBG ( "External heap grows downwards from %lx (size %zx)\n",
74 user_to_phys ( top, 0 ), heap_size );
81 static void ecollect_free ( void ) {
82 struct external_memory extmem;
85 /* Walk the free list and collect empty blocks */
86 while ( bottom != top ) {
87 copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
91 DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
92 user_to_phys ( bottom, extmem.size ) );
93 len = ( extmem.size + sizeof ( extmem ) );
94 bottom = userptr_add ( bottom, len );
100 * Reallocate external memory
102 * @v old_ptr Memory previously allocated by umalloc(), or UNULL
103 * @v new_size Requested size
104 * @ret new_ptr Allocated memory, or UNULL
106 * Calling realloc() with a new size of zero is a valid way to free a
109 static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
110 struct external_memory extmem;
114 /* (Re)initialise external memory allocator if necessary */
118 /* Get block properties into extmem */
119 if ( ptr && ( ptr != UNOWHERE ) ) {
120 /* Determine old size */
121 copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
124 /* Create a zero-length block */
125 if ( heap_size < sizeof ( extmem ) ) {
126 DBG ( "EXTMEM out of space\n" );
129 ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
130 heap_size -= sizeof ( extmem );
131 DBG ( "EXTMEM allocating [%lx,%lx)\n",
132 user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
135 extmem.used = ( new_size > 0 );
137 /* Expand/shrink block if possible */
138 if ( ptr == bottom ) {
140 if ( new_size > ( heap_size - extmem.size ) ) {
141 DBG ( "EXTMEM out of space\n" );
144 new = userptr_add ( ptr, - ( new_size - extmem.size ) );
145 align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
147 new = userptr_add ( new, -align );
148 DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
149 user_to_phys ( ptr, 0 ),
150 user_to_phys ( ptr, extmem.size ),
151 user_to_phys ( new, 0 ),
152 user_to_phys ( new, new_size ));
153 memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
154 extmem.size : new_size ) );
156 heap_size -= ( new_size - extmem.size );
157 extmem.size = new_size;
159 /* Cannot expand; can only pretend to shrink */
160 if ( new_size > extmem.size ) {
161 /* Refuse to expand */
162 DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
163 user_to_phys ( ptr, 0 ),
164 user_to_phys ( ptr, extmem.size ) );
169 /* Write back block properties */
170 copy_to_user ( new, -sizeof ( extmem ), &extmem,
173 /* Collect any free blocks and update hidden memory region */
175 hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
176 0 : -sizeof ( extmem ) ) ),
177 user_to_phys ( top, 0 ) );
179 return ( new_size ? new : UNOWHERE );
182 PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );