heap.c 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include "etherboot.h"
  2. #include "init.h"
  3. #include "memsizes.h"
  4. #include "heap.h"
  5. struct heap_block {
  6. size_t size;
  7. char data[0];
  8. };
  9. /* Linker symbols */
  10. extern char _text[];
  11. extern char _end[];
  12. static unsigned long heap_start, heap_end, heap_ptr;
  13. /*
  14. * Find the largest contiguous area of memory that I can use for the
  15. * heap.
  16. *
  17. */
  18. static void init_heap ( void ) {
  19. unsigned int i;
  20. unsigned long eb_start, eb_end;
  21. unsigned long size;
  22. size = 0;
  23. /* Region occupied by Etherboot */
  24. eb_start = virt_to_phys ( _text );
  25. eb_end = virt_to_phys ( _end );
  26. for ( i = 0 ; i < meminfo.map_count ; i++ ) {
  27. unsigned long r_start, r_end, r_size;
  28. unsigned long pre_eb, post_eb;
  29. /* Get start and end addresses of the region */
  30. if ( meminfo.map[i].type != E820_RAM )
  31. continue;
  32. if ( meminfo.map[i].addr > ULONG_MAX )
  33. continue;
  34. r_start = meminfo.map[i].addr;
  35. if ( r_start + meminfo.map[i].size > ULONG_MAX ) {
  36. r_end = ULONG_MAX;
  37. } else {
  38. r_end = r_start + meminfo.map[i].size;
  39. }
  40. /* Avoid overlap with Etherboot. When Etherboot is
  41. * completely contained within the region, choose the
  42. * larger of the two remaining portions.
  43. */
  44. if ( ( eb_start < r_end ) && ( eb_end > r_start ) ) {
  45. pre_eb = ( eb_start > r_start ) ?
  46. ( eb_start - r_start ) : 0;
  47. post_eb = ( r_end > eb_end ) ?
  48. ( r_end - eb_end ) : 0;
  49. if ( pre_eb > post_eb ) {
  50. r_end = eb_start;
  51. } else {
  52. r_start = eb_end;
  53. }
  54. }
  55. /* Use the biggest region. Where two regions are the
  56. * same size, use the later region. (Provided that
  57. * the memory map is laid out in a sensible order,
  58. * this should give us the higher region.)
  59. */
  60. r_size = r_end - r_start;
  61. if ( r_size >= size ) {
  62. heap_start = r_start;
  63. heap_end = r_end;
  64. size = r_size;
  65. }
  66. }
  67. ASSERT ( size != 0 );
  68. DBG ( "HEAP using region [%x,%x)\n", heap_start, heap_end );
  69. heap_ptr = heap_end;
  70. }
  71. /*
  72. * Allocate a block from the heap.
  73. *
  74. */
  75. void * emalloc ( size_t size, unsigned int align ) {
  76. physaddr_t addr;
  77. struct heap_block *block;
  78. ASSERT ( ( align & ( align - 1 ) ) == 0 );
  79. addr = ( ( ( heap_ptr - size ) & ~( align - 1 ) )
  80. - sizeof ( struct heap_block ) );
  81. if ( addr < heap_start ) {
  82. DBG ( "HEAP no space for %x bytes (alignment %d) in [%x,%x)\n",
  83. size, align, heap_start, heap_ptr );
  84. return NULL;
  85. }
  86. block = phys_to_virt ( addr );
  87. block->size = ( heap_ptr - addr );
  88. DBG ( "HEAP allocated %x bytes (alignment %d) at %x [%x,%x)\n",
  89. size, align, virt_to_phys ( block->data ), addr, heap_ptr );
  90. heap_ptr = addr;
  91. return block->data;
  92. }
  93. /*
  94. * Allocate all remaining space on the heap
  95. *
  96. */
  97. void * emalloc_all ( size_t *size ) {
  98. *size = heap_ptr - heap_start - sizeof ( struct heap_block );
  99. return emalloc ( *size, sizeof ( void * ) );
  100. }
  101. /*
  102. * Free a heap block
  103. *
  104. */
  105. void efree ( void *ptr ) {
  106. struct heap_block *block;
  107. ASSERT ( ptr == phys_to_virt ( heap_ptr + sizeof ( size_t ) ) );
  108. block = ( struct heap_block * )
  109. ( ptr - offsetof ( struct heap_block, data ) );
  110. heap_ptr += block->size;
  111. DBG ( "HEAP freed %x [%x,%x)\n", virt_to_phys ( ptr ),
  112. virt_to_phys ( block ), heap_ptr );
  113. ASSERT ( heap_ptr <= heap_end );
  114. }
  115. /*
  116. * Free all allocated heap blocks
  117. *
  118. */
  119. void efree_all ( void ) {
  120. DBG ( "HEAP discarding allocated blocks in [%x,%x)\n",
  121. heap_ptr, heap_end );
  122. heap_ptr = heap_end;
  123. }
  124. INIT_FN ( INIT_HEAP, init_heap, efree_all, NULL );