libn64/mm: Add memory manager, data structures.
authorTyler J. Stachecki <stachecki.tyler@gmail.com>
Mon, 31 Oct 2016 18:06:30 +0000 (14:06 -0400)
committerTyler J. Stachecki <stachecki.tyler@gmail.com>
Sun, 9 Jul 2017 15:04:41 +0000 (11:04 -0400)
Signed-off-by: Tyler J. Stachecki <stachecki.tyler@gmail.com>
libn64/Makefile
libn64/include/os/mm.h [new file with mode: 0644]
libn64/os/asm/boot.s
libn64/os/main.c
libn64/os/mm.c [new file with mode: 0644]

index a441f1c..07fbb50 100644 (file)
@@ -36,6 +36,7 @@ CFILES = $(call FIXPATH,\
        os/fbtext.c \
        os/kthread.c \
        os/main.c \
+       os/mm.c \
        os/panic.c \
        os/thread.c \
        rcp/vi.c \
diff --git a/libn64/include/os/mm.h b/libn64/include/os/mm.h
new file mode 100644 (file)
index 0000000..2d5005f
--- /dev/null
@@ -0,0 +1,33 @@
+//
+// libn64/include/os/mm.h: OS memory manager definitions.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef LIBN64_INCLUDE_OS_MM_H
+#define LIBN64_INCLUDE_OS_MM_H
+
+#include <stdint.h>
+
+// The RDRAM modules are organized as (up to) 8 banks of 1MB each.
+// The smallest 'block' of memory that libn64 works on is a 4kB page.
+// This makes for about 256 * 4KB pages per bank of RDRAM.
+typedef uint16_t libn64_mm_page_list[8][256];
+
+struct libn64_mm {
+  uint16_t free_page_idxs[8];
+} __attribute__((aligned(16)));
+
+extern libn64_mm_page_list *libn64_mm_pages;
+extern struct libn64_mm libn64_mm;
+
+// Initializes the threading subsystem.
+libn64func
+void libn64_mm_init(uint32_t physmem_bottom, uint32_t physmem_top);
+
+#endif
+
index 0364175..1c00523 100644 (file)
@@ -36,11 +36,11 @@ libn64_ipl:
 # Reserve the necessary amount of space immediately above the stack
 # for thread contexts and queues (0x200 bytes per thread, rounded up
 # to the nearest 4kB page).
-  li $v0, LIBN64_THREADS_MAX
-  addiu $v0, $v0, 0x7
+  li $v0, LIBN64_THREADS_MAX + 0x7
   srl $v0, $v0, 0x3
   sll $v0, $v0, 0xC
   subu $sp, $sp, $v0
+  addu $a0, $sp, $zero
 
 # Set the global pointer reference value.
   la $gp, _gp
index 84d3cfb..df56035 100644 (file)
 
 #include <libn64.h>
 #include <os/kthread.h>
+#include <os/mm.h>
 #include <os/thread.h>
 #include <os/thread_table.h>
 #include <os/syscall.h>
 #include <stddef.h>
 
+extern uint8_t __bss_end;
+
 void main(void *);
 
 libn64func
-__attribute__((noreturn)) void libn64_main(void) {
+__attribute__((noreturn)) void libn64_main(uint32_t kernel_sp) {
+  uint32_t physmem_bottom = (uint32_t) (&__bss_end) + 0x480 + 4095;
+  uint32_t physmem_top = kernel_sp - 4096;
+
+  // Put the given physical memory region under control of the MM.
+  // Both the top and the bottom addresses must be 4k aligned.
+  libn64_mm_init(physmem_bottom, physmem_top);
   libn64_thread_init();
 
   // Hand control over to the application.
diff --git a/libn64/os/mm.c b/libn64/os/mm.c
new file mode 100644 (file)
index 0000000..18d58b2
--- /dev/null
@@ -0,0 +1,54 @@
+//
+// libn64/os/thread.c: OS thread functions.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include <libn64.h>
+#include <os/mm.h>
+#include <stdint.h>
+
+libn64_mm_page_list *libn64_mm_pages;
+struct libn64_mm libn64_mm;
+
+// Initialize the thread table.
+void libn64_mm_init(uint32_t physmem_bottom, uint32_t physmem_top) {
+  unsigned i;
+
+  // Fill the page allocator.
+  physmem_bottom &= 0xFFFFF000;
+  physmem_top &= 0xFFFFF000;
+
+  libn64_mm_pages = (libn64_mm_page_list *) (physmem_top);
+  physmem_top -= 0x1000;
+
+  // TODO: Remove once BSS is cleared out properly.
+  for (i = 0; i < 8; i++)
+    libn64_mm.free_page_idxs[i] = 0;
+
+  for (; physmem_bottom != physmem_top; physmem_bottom += 0x1000) {
+    unsigned bank = (physmem_bottom >> 20) & 0x7;
+    unsigned idx = libn64_mm.free_page_idxs[bank]++;
+
+    (*libn64_mm_pages)[bank][idx] = physmem_bottom >> 12;
+  }
+
+  // Invalidate all the TLB entries.
+  __asm__ __volatile__("mtc0 $zero, $10\n\t" // EntryHi
+                       "mtc0 $zero, $2\n\t"  // EntryLo0
+                       "mtc0 $zero, $3\n\t"  // EntryLo1
+                       "mtc0 $zero, $6\n\t"  // Wired
+  );
+
+  for (i = 0; i < 32; i++) {
+    __asm__ __volatile__("mtc0 %0, $0\n\t"   // Index
+                         "tlbwi\n\t"
+      :: "r" (i)
+    );
+  }
+}
+