backported fixes from 256boss
[bootcensus] / src / mem.c
index bfc1b3c..a013607 100644 (file)
--- a/src/mem.c
+++ b/src/mem.c
@@ -17,6 +17,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include <stdio.h>
 #include <string.h>
+#include "config.h"
 #include "panic.h"
 #include "mem.h"
 #include "intr.h"
@@ -37,6 +38,8 @@ struct mem_range {
        uint32_t size;
 };
 
+void move_stack(uint32_t newaddr);     /* defined in startup.s */
+
 static void mark_page(int pg, int used);
 static void add_memory(uint32_t start, size_t size);
 
@@ -49,7 +52,7 @@ extern uint32_t _mem_start;
 
 
 /* A bitmap is used to track which physical memory pages are used, and which
- * are available for allocation by alloc_phys_page.
+ * are available for allocation by alloc_ppage.
  *
  * last_alloc_idx keeps track of the last 32bit element in the bitmap array
  * where a free page was found. It's guaranteed that all the elements before
@@ -63,7 +66,7 @@ static int bmsize, last_alloc_idx;
 
 void init_mem(void)
 {
-       int i, pg, max_pg = 0;
+       int i, pg, max_used_pg, end_pg = 0;
        uint32_t used_end, start, end, sz, total = 0, rem;
        const char *suffix[] = {"bytes", "KB", "MB", "GB"};
 
@@ -107,8 +110,8 @@ void init_mem(void)
                total += sz;
 
                pg = ADDR_TO_PAGE(end);
-               if(max_pg < pg) {
-                       max_pg = pg;
+               if(end_pg < pg) {
+                       end_pg = pg;
                }
        }
 
@@ -120,66 +123,40 @@ void init_mem(void)
        }
        printf("Total usable RAM: %u.%u %s\n", total, 100 * rem / 1024, suffix[i]);
 
-       bmsize = max_pg / 8;    /* size of the useful bitmap in bytes */
+       /* size of the useful part of the bitmap in bytes padded to 4-byte
+        * boundaries to allow 32bit at a time operations.
+        */
+       bmsize = (end_pg / 32) * 4;
 
-       /* mark all pages occupied by the bitmap as usef */
+       /* mark all pages occupied by the bitmap as used */
        used_end = (uint32_t)bitmap + bmsize - 1;
 
-       printf("marking pages up to %x (page: %d) as used\n", used_end, ADDR_TO_PAGE(used_end));
-
-       for(i=0; i<=used_end; i++) {
+       max_used_pg = ADDR_TO_PAGE(used_end);
+       printf("marking pages up to %x (page: %d) as used\n", used_end, max_used_pg);
+       for(i=0; i<=max_used_pg; i++) {
                mark_page(i, USED);
        }
-}
 
-/* alloc_phys_page finds the first available page of physical memory,
- * marks it as used in the bitmap, and returns its number. If there's
- * no unused physical page, -1 is returned.
- */
-int alloc_ppage(void)
-{
-       int i, idx, max, intr_state;
-
-       intr_state = get_intr_flag();
-       disable_intr();
-
-       idx = last_alloc_idx;
-       max = bmsize / 4;
-
-       while(idx <= max) {
-               /* if at least one bit is 0 then we have at least
-                * one free page. find it and allocate it.
-                */
-               if(bitmap[idx] != 0xffffffff) {
-                       for(i=0; i<32; i++) {
-                               int pg = idx * 32 + i;
-
-                               if(IS_FREE(pg)) {
-                                       mark_page(pg, USED);
-
-                                       last_alloc_idx = idx;
-
-                                       /*printf("alloc_phys_page() -> %x (page: %d)\n", PAGE_TO_ADDR(pg), pg);*/
-
-                                       set_intr_flag(intr_state);
-                                       return pg;
-                               }
-                       }
-                       panic("can't happen: alloc_ppage (mem.c)\n");
-               }
-               idx++;
+#ifdef MOVE_STACK_RAMTOP
+       /* allocate space for the stack at the top of RAM and move it there */
+       if((pg = alloc_ppages(STACK_PAGES, MEM_STACK)) != -1) {
+               printf("moving stack-top to: %x (%d pages)\n", PAGE_TO_ADDR(end_pg) - 4, STACK_PAGES);
+               move_stack(PAGE_TO_ADDR(pg + STACK_PAGES) - 4);
        }
+#endif
+}
 
-       set_intr_flag(intr_state);
-       return -1;
+int alloc_ppage(int area)
+{
+       return alloc_ppages(1, area);
 }
 
 /* free_ppage marks the physical page, free in the allocation bitmap.
  *
  * CAUTION: no checks are done that this page should actually be freed or not.
- * If you call free_phys_page with the address of some part of memory that was
+ * If you call free_ppage with the address of some part of memory that was
  * originally reserved due to it being in a memory hole or part of the kernel
- * image or whatever, it will be subsequently allocatable by alloc_phys_page.
+ * image or whatever, it will be subsequently allocatable by alloc_ppage.
  */
 void free_ppage(int pg)
 {
@@ -201,9 +178,69 @@ void free_ppage(int pg)
 }
 
 
+int alloc_ppages(int count, int area)
+{
+       int i, dir, pg, idx, max, intr_state, found_free = 0;
+
+       intr_state = get_intr_flag();
+       disable_intr();
+
+       if(area == MEM_STACK) {
+               idx = (bmsize - 1) / 4;
+               max = -1;
+               dir = -1;
+       } else {
+               idx = last_alloc_idx;
+               max = bmsize / 4;
+               dir = 1;
+       }
+
+       while(idx != max) {
+               /* if at least one bit is 0 then we have at least
+                * one free page. find it and try to allocate a range starting from there
+                */
+               if(bitmap[idx] != 0xffffffff) {
+                       pg = idx * 32;
+                       if(dir < 0) pg += 31;
+
+                       for(i=0; i<32; i++) {
+                               if(IS_FREE(pg)) {
+                                       if(!found_free && dir > 0) {
+                                               last_alloc_idx = idx;
+                                               found_free = 1;
+                                       }
+
+                                       if(alloc_ppage_range(pg, count) != -1) {
+                                               set_intr_flag(intr_state);
+                                               return pg;
+                                       }
+                               }
+                               pg += dir;
+                       }
+               }
+               idx += dir;
+       }
+
+       set_intr_flag(intr_state);
+       return -1;
+}
+
+void free_ppages(int pg0, int count)
+{
+       int i;
+
+       for(i=0; i<count; i++) {
+               free_ppage(pg0++);
+       }
+}
+
 int alloc_ppage_range(int start, int size)
 {
        int i, pg = start;
+       int intr_state;
+
+       intr_state = get_intr_flag();
+       disable_intr();
 
        /* first validate that no page in the requested range is allocated */
        for(i=0; i<size; i++) {
@@ -218,6 +255,8 @@ int alloc_ppage_range(int start, int size)
        for(i=0; i<size; i++) {
                mark_page(pg++, USED);
        }
+
+       set_intr_flag(intr_state);
        return 0;
 }
 
@@ -259,3 +298,17 @@ static void mark_page(int pg, int used)
        }
 }
 
+void print_page_bitmap(void)
+{
+       int i;
+
+       for(i=0; i<bmsize/4; i++) {
+               if((i & 3) == 0) {
+                       uint32_t pg = i * 32;
+                       uint32_t addr = PAGE_TO_ADDR(pg);
+                       printf("\n%5d [%08x]:", (int)pg, (unsigned long)addr);
+               }
+               printf(" %08x", bitmap[i]);
+       }
+       printf("\n");
+}