123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- #include "etherboot.h"
- #include "init.h"
- #include "memsizes.h"
-
- size_t heap_ptr, heap_top, heap_bot;
-
- #define _virt_start 0
-
- static void init_heap(void)
- {
- size_t size;
- size_t start, end;
- unsigned i;
- /* Find the largest contiguous area of memory that
- * I can use for the heap, which is organized as
- * a stack that grows backwards through memory.
- */
-
- /* If I have virtual address that do not equal physical addresses
- * there is a change I will try to use memory from both sides of
- * the virtual address space simultaneously, which can cause all kinds
- * of interesting problems.
- * Avoid it by logically extending etherboot. Once I know that relocation
- * works I can just start the virtual address space at 0, and this problem goes
- * away so that is probably a better solution.
- */
- #if 0
- start = virt_to_phys(_text);
- #else
- /* segment wrap around is nasty don't chance it. */
- start = virt_to_phys(_virt_start);
- #endif
- end = virt_to_phys(_end);
- size = 0;
- for(i = 0; i < meminfo.map_count; i++) {
- unsigned long r_start, r_end;
- if (meminfo.map[i].type != E820_RAM)
- continue;
- if (meminfo.map[i].addr > ULONG_MAX)
- continue;
- if (meminfo.map[i].size > ULONG_MAX)
- continue;
-
- r_start = meminfo.map[i].addr;
- r_end = r_start + meminfo.map[i].size;
- if (r_end < r_start) {
- r_end = ULONG_MAX;
- }
- /* Handle areas that overlap etherboot */
- if ((end > r_start) && (start < r_end)) {
- /* Etherboot completely covers the region */
- if ((start <= r_start) && (end >= r_end))
- continue;
- /* Etherboot is completely contained in the region */
- if ((start > r_start) && (end < r_end)) {
- /* keep the larger piece */
- if ((r_end - end) >= (r_start - start)) {
- r_start = end;
- }
- else {
- r_end = start;
- }
- }
- /* Etherboot covers one end of the region.
- * Shrink the region.
- */
- else if (end >= r_end) {
- r_end = start;
- }
- else if (start <= r_start) {
- r_start = end;
- }
- }
- /* If two areas are the size prefer the greater address */
- if (((r_end - r_start) > size) ||
- (((r_end - r_start) == size) && (r_start > heap_top))) {
- size = r_end - r_start;
- heap_top = r_start;
- heap_bot = r_end;
- }
- }
- if (size == 0) {
- printf("init_heap: No heap found.\n");
- exit(1);
- }
- heap_ptr = heap_bot;
- }
-
- static void reset_heap(void)
- {
- heap_ptr = heap_bot;
- }
-
- void *allot(size_t size)
- {
- void *ptr;
- size_t *mark, addr;
- /* Get an 16 byte aligned chunk of memory off of the heap
- * An extra sizeof(size_t) bytes is allocated to track
- * the size of the object allocated on the heap.
- */
- addr = (heap_ptr - (size + sizeof(size_t))) & ~15;
- if (addr < heap_top) {
- ptr = 0;
- } else {
- mark = phys_to_virt(addr);
- *mark = size;
- heap_ptr = addr;
- ptr = phys_to_virt(addr + sizeof(size_t));
- }
- return ptr;
- }
-
- //if mask = 0xf, it will be 16 byte aligned
- //if mask = 0xff, it will be 256 byte aligned
- //For DMA memory allocation, because it has more reqiurement on alignment
- void *allot2(size_t size, uint32_t mask)
- {
- void *ptr;
- size_t *mark, addr;
- uint32_t *mark1;
-
- addr = ((heap_ptr - size ) & ~mask) - sizeof(size_t) - sizeof(uint32_t);
- if (addr < heap_top) {
- ptr = 0;
- } else {
- mark = phys_to_virt(addr);
- *mark = size;
- mark1 = phys_to_virt(addr+sizeof(size_t));
- *mark1 = mask;
- heap_ptr = addr;
- ptr = phys_to_virt(addr + sizeof(size_t) + sizeof(uint32_t));
- }
- return ptr;
- }
-
- void forget(void *ptr)
- {
- size_t *mark, addr;
- size_t size;
-
- if (!ptr) {
- return;
- }
- addr = virt_to_phys(ptr);
- mark = phys_to_virt(addr - sizeof(size_t));
- size = *mark;
- addr += (size + 15) & ~15;
-
- if (addr > heap_bot) {
- addr = heap_bot;
- }
- heap_ptr = addr;
- }
-
- void forget2(void *ptr)
- {
- size_t *mark, addr;
- size_t size;
- uint32_t mask;
- uint32_t *mark1;
-
- if (!ptr) {
- return;
- }
- addr = virt_to_phys(ptr);
- mark = phys_to_virt(addr - sizeof(size_t) - sizeof(uint32_t));
- size = *mark;
- mark1 = phys_to_virt(addr - sizeof(uint32_t));
- mask = *mark1;
- addr += (size + mask) & ~mask;
-
- if (addr > heap_bot) {
- addr = heap_bot;
- }
- heap_ptr = addr;
- }
-
- INIT_FN ( INIT_HEAP, init_heap, reset_heap, NULL );
|