You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

memtop_umalloc.c 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  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.
  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.
  17. */
  18. /**
  19. * @file
  20. *
  21. * External memory allocation
  22. *
  23. */
  24. #include <limits.h>
  25. #include <errno.h>
  26. #include <gpxe/uaccess.h>
  27. #include <gpxe/hidemem.h>
  28. #include <gpxe/memmap.h>
  29. #include <gpxe/umalloc.h>
  30. /** Alignment of external allocated memory */
  31. #define EM_ALIGN ( 4 * 1024 )
  32. /** Equivalent of NOWHERE for user pointers */
  33. #define UNOWHERE ( ~UNULL )
  34. /** An external memory block */
  35. struct external_memory {
  36. /** Size of this memory block (excluding this header) */
  37. size_t size;
  38. /** Block is currently in use */
  39. int used;
  40. };
  41. /** Top of heap */
  42. static userptr_t top = UNULL;
  43. /** Bottom of heap (current lowest allocated block) */
  44. static userptr_t bottom = UNULL;
  45. /**
  46. * Initialise external heap
  47. *
  48. * @ret rc Return status code
  49. */
  50. static int init_eheap ( void ) {
  51. struct memory_map memmap;
  52. unsigned long heap_size = 0;
  53. unsigned int i;
  54. DBG ( "Allocating external heap\n" );
  55. get_memmap ( &memmap );
  56. for ( i = 0 ; i < memmap.count ; i++ ) {
  57. struct memory_region *region = &memmap.regions[i];
  58. unsigned long r_start, r_end;
  59. unsigned long r_size;
  60. DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
  61. /* Truncate block to 4GB */
  62. if ( region->start > UINT_MAX ) {
  63. DBG ( "...starts after 4GB\n" );
  64. continue;
  65. }
  66. r_start = region->start;
  67. if ( region->end > UINT_MAX ) {
  68. DBG ( "...end truncated to 4GB\n" );
  69. r_end = 0; /* =4GB, given the wraparound */
  70. } else {
  71. r_end = region->end;
  72. }
  73. /* Use largest block */
  74. r_size = ( r_end - r_start );
  75. if ( r_size > heap_size ) {
  76. DBG ( "...new best block found\n" );
  77. top = bottom = phys_to_user ( r_end );
  78. heap_size = r_size;
  79. }
  80. }
  81. if ( ! heap_size ) {
  82. DBG ( "No external heap available\n" );
  83. return -ENOMEM;
  84. }
  85. DBG ( "External heap grows downwards from %lx\n",
  86. user_to_phys ( top, 0 ) );
  87. return 0;
  88. }
  89. /**
  90. * Collect free blocks
  91. *
  92. */
  93. static void ecollect_free ( void ) {
  94. struct external_memory extmem;
  95. /* Walk the free list and collect empty blocks */
  96. while ( bottom != top ) {
  97. copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
  98. sizeof ( extmem ) );
  99. if ( extmem.used )
  100. break;
  101. DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
  102. user_to_phys ( bottom, extmem.size ) );
  103. bottom = userptr_add ( bottom,
  104. ( extmem.size + sizeof ( extmem ) ) );
  105. }
  106. }
  107. /**
  108. * Reallocate external memory
  109. *
  110. * @v old_ptr Memory previously allocated by umalloc(), or UNULL
  111. * @v new_size Requested size
  112. * @ret new_ptr Allocated memory, or UNULL
  113. *
  114. * Calling realloc() with a new size of zero is a valid way to free a
  115. * memory block.
  116. */
  117. static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
  118. struct external_memory extmem;
  119. userptr_t new = ptr;
  120. size_t align;
  121. int rc;
  122. /* Initialise external memory allocator if necessary */
  123. if ( bottom == top ) {
  124. if ( ( rc = init_eheap() ) != 0 )
  125. return UNULL;
  126. }
  127. /* Get block properties into extmem */
  128. if ( ptr && ( ptr != UNOWHERE ) ) {
  129. /* Determine old size */
  130. copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
  131. sizeof ( extmem ) );
  132. } else {
  133. /* Create a zero-length block */
  134. ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
  135. DBG ( "EXTMEM allocating [%lx,%lx)\n",
  136. user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
  137. extmem.size = 0;
  138. }
  139. extmem.used = ( new_size > 0 );
  140. /* Expand/shrink block if possible */
  141. if ( ptr == bottom ) {
  142. /* Update block */
  143. new = userptr_add ( ptr, - ( new_size - extmem.size ) );
  144. align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
  145. new_size += align;
  146. new = userptr_add ( new, -align );
  147. DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
  148. user_to_phys ( ptr, 0 ),
  149. user_to_phys ( ptr, extmem.size ),
  150. user_to_phys ( new, 0 ),
  151. user_to_phys ( new, new_size ));
  152. memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
  153. extmem.size : new_size ) );
  154. extmem.size = new_size;
  155. bottom = new;
  156. } else {
  157. /* Cannot expand; can only pretend to shrink */
  158. if ( new_size > extmem.size ) {
  159. /* Refuse to expand */
  160. DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
  161. user_to_phys ( ptr, 0 ),
  162. user_to_phys ( ptr, extmem.size ) );
  163. return UNULL;
  164. }
  165. }
  166. /* Write back block properties */
  167. copy_to_user ( new, -sizeof ( extmem ), &extmem,
  168. sizeof ( extmem ) );
  169. /* Collect any free blocks and update hidden memory region */
  170. ecollect_free();
  171. hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
  172. user_to_phys ( top, 0 ) );
  173. return ( new_size ? new : UNOWHERE );
  174. }
  175. PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );