aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv64/kernel')
-rw-r--r--arch/riscv64/kernel/cpu.c6
-rw-r--r--arch/riscv64/kernel/irq.c30
-rw-r--r--arch/riscv64/kernel/main.c11
-rw-r--r--arch/riscv64/kernel/pmem.c15
-rw-r--r--arch/riscv64/kernel/proc.c15
-rw-r--r--arch/riscv64/kernel/vmem.c182
6 files changed, 259 insertions, 0 deletions
diff --git a/arch/riscv64/kernel/cpu.c b/arch/riscv64/kernel/cpu.c
new file mode 100644
index 0000000..6ae4ee7
--- /dev/null
+++ b/arch/riscv64/kernel/cpu.c
@@ -0,0 +1,6 @@
+#include <apos/cpu.h>
+
+id_t cpu_id()
+{
+ return 0; /* VERY MUCH TEMP */
+}
diff --git a/arch/riscv64/kernel/irq.c b/arch/riscv64/kernel/irq.c
new file mode 100644
index 0000000..f844dd1
--- /dev/null
+++ b/arch/riscv64/kernel/irq.c
@@ -0,0 +1,30 @@
+#include <apos/irq.h>
+#include <apos/attrs.h>
+#include <apos/debug.h>
+#include <csr.h>
+
+void init_irq(void *fdt)
+{
+ UNUSED(fdt);
+ csr_write(CSR_STVEC, &handle_irq);
+
+ long s = 0;
+ csr_read(CSR_SIE, s);
+ info("CSR_SIE: %lx\n", s);
+}
+
+__aligned(4) void handle_irq()
+{
+ while(1);
+}
+
+/* very simple for now */
+void enable_irq()
+{
+ csr_set(CSR_SSTATUS, CSR_SIE);
+}
+
+void disable_irq()
+{
+ csr_clear(CSR_SSTATUS, CSR_SIE);
+}
diff --git a/arch/riscv64/kernel/main.c b/arch/riscv64/kernel/main.c
new file mode 100644
index 0000000..9ce256e
--- /dev/null
+++ b/arch/riscv64/kernel/main.c
@@ -0,0 +1,11 @@
+#include <apos/utils.h>
+#include <csr.h>
+
+void arch_setup(void *fdt)
+{
+ UNUSED(fdt);
+ /* allow supervisor code to touch user pages */
+ csr_set(CSR_SSTATUS, SSTATUS_SUM);
+ /* mark that we want to eventually jump to userspace */
+ csr_clear(CSR_SSTATUS, SSTATUS_SPP);
+}
diff --git a/arch/riscv64/kernel/pmem.c b/arch/riscv64/kernel/pmem.c
new file mode 100644
index 0000000..45b8eeb
--- /dev/null
+++ b/arch/riscv64/kernel/pmem.c
@@ -0,0 +1,15 @@
+#include <apos/pmem.h>
+
+int arch_pmem_conf(void *fdt, size_t *max_order, size_t *base_bits, size_t bits[ORDERS_NUM])
+{
+ UNUSED(fdt);
+
+ /* Sv39 for now */
+ *max_order = 2;
+ *base_bits = 12;
+ /* we can assume bits[] is zeroed out beforehand */
+ for(size_t i = 0; i <= *max_order; ++i)
+ bits[i] = 9;
+
+ return 0;
+}
diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c
new file mode 100644
index 0000000..b696912
--- /dev/null
+++ b/arch/riscv64/kernel/proc.c
@@ -0,0 +1,15 @@
+#include <apos/tcb.h>
+#include <apos/elf.h>
+#include <csr.h>
+
+void jump_to_userspace(struct tcb *t, int argc, char **argv)
+{
+ csr_write(CSR_SEPC, t->entry);
+ __asm__ volatile ("mv sp, %0\n" : "=r" (t->proc_stack) :: "memory");
+ __asm__ volatile ("sret\n" ::: "memory");
+}
+
+void return_to_userspace(struct tcb *t)
+{
+ /* lol */
+}
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
new file mode 100644
index 0000000..bc1a74e
--- /dev/null
+++ b/arch/riscv64/kernel/vmem.c
@@ -0,0 +1,182 @@
+#include <apos/string.h>
+#include <apos/pmem.h>
+#include <apos/vmem.h>
+#include <apos/mem.h>
+#include <apos/debug.h>
+#include <apos/cpu.h>
+#include <pages.h>
+#include <vmem.h>
+#include <csr.h>
+
+#define pte_ppn(pte) (((pm_t)(pte)) >> 10)
+#define pte_flags(pte) (((pm_t)(pte)) & 0xff)
+#define to_pte(p, f) ((pm_to_pnum(p) << 10) | (f))
+#define pte_addr(pte) __va(pnum_to_paddr(pte_ppn(pte)))
+#define pte_paddr(pte) (pnum_to_paddr(pte_ppn(pte)))
+#define vm_to_index(a, o) (pm_to_index(a, o))
+#define is_active(pte) (pte_flags(pte) & VM_V)
+#define is_leaf(pte) (is_active(pte) && (pte_flags(pte) & ~VM_V))
+#define is_branch(pte) (is_active(pte) && !(pte_flags(pte) & ~VM_V))
+
+static pm_t *__find_vmem(struct vm_branch *b, vm_t v, enum mm_order *o)
+{
+ enum mm_order top = __mm_max_order;
+ if(o)
+ *o = MM_O0;
+ do {
+ size_t idx = vm_to_index(v, top);
+ pm_t pte = (pm_t)b->leaf[idx];
+
+ if(!pte)
+ return 0;
+
+ if(is_leaf(pte)){
+ if(o)
+ *o = top;
+
+ return (pm_t *)&b->leaf[idx];
+ }
+
+ b = (struct vm_branch *)pte_addr(pte);
+ } while (top--);
+
+ return 0;
+}
+
+int mod_vmem(struct vm_branch *branch, vm_t vaddr, pm_t paddr, uint8_t flags)
+{
+ pm_t *pte = __find_vmem(branch, vaddr, 0);
+ if(pte){
+ *pte = to_pte((pm_t)__pa(paddr), flags);
+ return 0;
+ }
+
+ return -1;
+}
+
+/* huh, should probably add status flags etc. to all my API functions. Damn, I'm
+ * lazy. */
+int stat_vmem(struct vm_branch *branch, vm_t vaddr, pm_t *paddr,
+ enum mm_order *order, uint8_t *flags)
+{
+ pm_t *pte = __find_vmem(branch, vaddr, order);
+ if(pte){
+ if(paddr)
+ *paddr = (pm_t)pte_addr(*pte);
+
+ if(flags)
+ *flags = pte_flags(*pte);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static struct vm_branch *__create_leaf()
+{
+ pm_t new_leaf = alloc_page(MM_KPAGE, 0);
+ memset((void *)new_leaf, 0, sizeof(struct vm_branch));
+ return (struct vm_branch *)to_pte((pm_t)__pa(new_leaf), VM_V);
+}
+
+static void __destroy_branch(struct vm_branch *b)
+{
+ if(!b)
+ return;
+
+ for(size_t i = 0; i < BASE_PAGE_SIZE / sizeof(pm_t); ++i){
+ if(is_branch(b->leaf[i]))
+ __destroy_branch((struct vm_branch *)pte_addr(b->leaf[i]));
+
+ free_page(MM_KPAGE, (pm_t)pte_addr(b->leaf[i]));
+ }
+}
+
+void map_vmem(struct vm_branch *branch,
+ pm_t paddr, vm_t vaddr, uint8_t flags, enum mm_order order)
+{
+ enum mm_order top = __mm_max_order;
+ while (top != order) {
+ size_t idx = vm_to_index(vaddr, top);
+
+ if (!branch->leaf[idx])
+ branch->leaf[idx] = __create_leaf();
+
+
+ branch = (struct vm_branch *)pte_addr(branch->leaf[idx]);
+ top--;
+ }
+
+ size_t idx = vm_to_index(vaddr, top);
+ if (is_branch(branch->leaf[idx])) /* something has gone terribly wrong */
+ __destroy_branch(branch->leaf[idx]);
+
+ branch->leaf[idx] = (struct vm_branch *)to_pte((pm_t)__pa(paddr), flags);
+}
+
+void unmap_vmem(struct vm_branch *branch, vm_t vaddr)
+{
+
+ pm_t *pte = __find_vmem(branch, vaddr, 0);
+ if(pte)
+ *pte = 0;
+}
+
+void flush_tlb()
+{
+ __asm__ volatile ("sfence.vma %0\n" :: "r" (cpu_id()) : "memory");
+}
+
+void flush_tlb_all()
+{
+ __asm__ volatile ("sfence.vma\n" ::: "memory");
+}
+
+static void start_vmem(struct vm_branch *branch, enum mm_mode m)
+{
+ branch = (struct vm_branch *)__pa(branch);
+
+ if(m == Sv32)
+ csr_write(CSR_SATP, SATP_MODE_Sv32 | pm_to_pnum((pm_t)(branch)));
+ else if (m == Sv39)
+ csr_write(CSR_SATP, SATP_MODE_Sv39 | pm_to_pnum((pm_t)(branch)));
+ else
+ csr_write(CSR_SATP, SATP_MODE_Sv48 | pm_to_pnum((pm_t)(branch)));
+
+ flush_tlb_all();
+ /* Sv57 && Sv64 in the future? */
+}
+
+struct vm_branch *init_vmem(void *fdt)
+{
+ UNUSED(fdt);
+ struct vm_branch *b = (struct vm_branch *)alloc_page(MM_KPAGE, 0);
+ memset(b, 0, MM_KPAGE_SIZE);
+
+ populate_root_branch(b);
+ /* update which memory branch to use */
+ start_vmem(b, Sv39);
+ return b;
+}
+
+void populate_root_branch(struct vm_branch *b)
+{
+ size_t flags = VM_V | VM_R | VM_W | VM_X | VM_G;
+ for(size_t i = KSTART_PAGE; i < IO_PAGE; ++i)
+ b->leaf[i] = (struct vm_branch *)to_pte(RAM_BASE + SZ_1G * (i - KSTART_PAGE), flags);
+
+ /* map kernel IO to zero for now, this will be overridden later
+ * (if at all) */
+ b->leaf[IO_PAGE] = (struct vm_branch *)to_pte(0, flags);
+}
+
+#ifdef DEBUG
+int setup_kernel_io(struct vm_branch *b, vm_t paddr)
+{
+ /* assume Sv39 for now */
+ pm_t gigapage = paddr / MM_GPAGE_SIZE;
+ b->leaf[IO_PAGE] = (struct vm_branch *)to_pte(gigapage, VM_V | VM_R | VM_W);
+ return -SZ_1G + paddr - (gigapage * MM_GPAGE_SIZE);
+}
+#endif