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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "etherboot.h"
  2. #include "init.h"
  3. #include "memsizes.h"
  4. size_t heap_ptr, heap_top, heap_bot;
  5. #define _virt_start 0
  6. static void init_heap(void)
  7. {
  8. size_t size;
  9. size_t start, end;
  10. unsigned i;
  11. /* Find the largest contiguous area of memory that
  12. * I can use for the heap, which is organized as
  13. * a stack that grows backwards through memory.
  14. */
  15. /* If I have virtual address that do not equal physical addresses
  16. * there is a change I will try to use memory from both sides of
  17. * the virtual address space simultaneously, which can cause all kinds
  18. * of interesting problems.
  19. * Avoid it by logically extending etherboot. Once I know that relocation
  20. * works I can just start the virtual address space at 0, and this problem goes
  21. * away so that is probably a better solution.
  22. */
  23. #if 0
  24. start = virt_to_phys(_text);
  25. #else
  26. /* segment wrap around is nasty don't chance it. */
  27. start = virt_to_phys(_virt_start);
  28. #endif
  29. end = virt_to_phys(_end);
  30. size = 0;
  31. for(i = 0; i < meminfo.map_count; i++) {
  32. unsigned long r_start, r_end;
  33. if (meminfo.map[i].type != E820_RAM)
  34. continue;
  35. if (meminfo.map[i].addr > ULONG_MAX)
  36. continue;
  37. if (meminfo.map[i].size > ULONG_MAX)
  38. continue;
  39. r_start = meminfo.map[i].addr;
  40. r_end = r_start + meminfo.map[i].size;
  41. if (r_end < r_start) {
  42. r_end = ULONG_MAX;
  43. }
  44. /* Handle areas that overlap etherboot */
  45. if ((end > r_start) && (start < r_end)) {
  46. /* Etherboot completely covers the region */
  47. if ((start <= r_start) && (end >= r_end))
  48. continue;
  49. /* Etherboot is completely contained in the region */
  50. if ((start > r_start) && (end < r_end)) {
  51. /* keep the larger piece */
  52. if ((r_end - end) >= (r_start - start)) {
  53. r_start = end;
  54. }
  55. else {
  56. r_end = start;
  57. }
  58. }
  59. /* Etherboot covers one end of the region.
  60. * Shrink the region.
  61. */
  62. else if (end >= r_end) {
  63. r_end = start;
  64. }
  65. else if (start <= r_start) {
  66. r_start = end;
  67. }
  68. }
  69. /* If two areas are the size prefer the greater address */
  70. if (((r_end - r_start) > size) ||
  71. (((r_end - r_start) == size) && (r_start > heap_top))) {
  72. size = r_end - r_start;
  73. heap_top = r_start;
  74. heap_bot = r_end;
  75. }
  76. }
  77. if (size == 0) {
  78. printf("init_heap: No heap found.\n");
  79. exit(1);
  80. }
  81. heap_ptr = heap_bot;
  82. }
  83. static void reset_heap(void)
  84. {
  85. heap_ptr = heap_bot;
  86. }
  87. void *allot(size_t size)
  88. {
  89. void *ptr;
  90. size_t *mark, addr;
  91. /* Get an 16 byte aligned chunk of memory off of the heap
  92. * An extra sizeof(size_t) bytes is allocated to track
  93. * the size of the object allocated on the heap.
  94. */
  95. addr = (heap_ptr - (size + sizeof(size_t))) & ~15;
  96. if (addr < heap_top) {
  97. ptr = 0;
  98. } else {
  99. mark = phys_to_virt(addr);
  100. *mark = size;
  101. heap_ptr = addr;
  102. ptr = phys_to_virt(addr + sizeof(size_t));
  103. }
  104. return ptr;
  105. }
  106. //if mask = 0xf, it will be 16 byte aligned
  107. //if mask = 0xff, it will be 256 byte aligned
  108. //For DMA memory allocation, because it has more reqiurement on alignment
  109. void *allot2(size_t size, uint32_t mask)
  110. {
  111. void *ptr;
  112. size_t *mark, addr;
  113. uint32_t *mark1;
  114. addr = ((heap_ptr - size ) & ~mask) - sizeof(size_t) - sizeof(uint32_t);
  115. if (addr < heap_top) {
  116. ptr = 0;
  117. } else {
  118. mark = phys_to_virt(addr);
  119. *mark = size;
  120. mark1 = phys_to_virt(addr+sizeof(size_t));
  121. *mark1 = mask;
  122. heap_ptr = addr;
  123. ptr = phys_to_virt(addr + sizeof(size_t) + sizeof(uint32_t));
  124. }
  125. return ptr;
  126. }
  127. void forget(void *ptr)
  128. {
  129. size_t *mark, addr;
  130. size_t size;
  131. if (!ptr) {
  132. return;
  133. }
  134. addr = virt_to_phys(ptr);
  135. mark = phys_to_virt(addr - sizeof(size_t));
  136. size = *mark;
  137. addr += (size + 15) & ~15;
  138. if (addr > heap_bot) {
  139. addr = heap_bot;
  140. }
  141. heap_ptr = addr;
  142. }
  143. void forget2(void *ptr)
  144. {
  145. size_t *mark, addr;
  146. size_t size;
  147. uint32_t mask;
  148. uint32_t *mark1;
  149. if (!ptr) {
  150. return;
  151. }
  152. addr = virt_to_phys(ptr);
  153. mark = phys_to_virt(addr - sizeof(size_t) - sizeof(uint32_t));
  154. size = *mark;
  155. mark1 = phys_to_virt(addr - sizeof(uint32_t));
  156. mask = *mark1;
  157. addr += (size + mask) & ~mask;
  158. if (addr > heap_bot) {
  159. addr = heap_bot;
  160. }
  161. heap_ptr = addr;
  162. }
  163. INIT_FN ( INIT_HEAP, init_heap, reset_heap, NULL );