aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv')
-rw-r--r--arch/riscv/include/csr.h6
-rw-r--r--arch/riscv/include/pages.h47
-rw-r--r--arch/riscv/include/sbi.h12
-rw-r--r--arch/riscv/include/vmap.h19
-rw-r--r--arch/riscv/init/head.S10
-rw-r--r--arch/riscv/init/init.c111
-rw-r--r--arch/riscv/main.c13
-rw-r--r--arch/riscv/riscv-link.S20
-rw-r--r--arch/riscv/sbi.c27
-rw-r--r--arch/riscv/source.mk5
10 files changed, 270 insertions, 0 deletions
diff --git a/arch/riscv/include/csr.h b/arch/riscv/include/csr.h
new file mode 100644
index 0000000..13f96cb
--- /dev/null
+++ b/arch/riscv/include/csr.h
@@ -0,0 +1,6 @@
+#ifndef APOS_CSR_H
+#define APOS_CSR_H
+
+#define csr_write(csr, val)
+
+#endif /* APOS_CSR_H */
diff --git a/arch/riscv/include/pages.h b/arch/riscv/include/pages.h
new file mode 100644
index 0000000..4ae2ab9
--- /dev/null
+++ b/arch/riscv/include/pages.h
@@ -0,0 +1,47 @@
+#ifndef APOS_RISCV_PAGES_H
+#define APOS_RISCV_PAGES_H
+
+typedef char pagemask_t;
+typedef char lockbit_t;
+
+struct kilopages {
+ pagemask_t page[64];
+};
+
+struct megapages {
+ lockbit_t lockbit[64];
+ pagemask_t empty[64];
+ pagemask_t full[64];
+ struct kilopages kilo[512];
+};
+
+/* Sv39 */
+struct gigapages {
+ lockbit_t lockbit[64];
+ pagemask_t empty[64];
+ pagemask_t full[64];
+ struct megapages mega[512];
+};
+
+struct terapages {
+ lockbit_t lockbit[64];
+ pagemask_t empty[64];
+ pagemask_t full[64];
+ struct gigapages giga[512];
+};
+
+struct mm_pagearr_info {
+ short tera_num;
+ struct terapages *tera_top;
+
+ short giga_num;
+ struct gigapages *giga_top;
+
+ short mega_num;
+ struct megapages *mega_top;
+
+ short kilo_num;
+ struct kilopages *kilo_top;
+};
+
+#endif /* APOS_RISCV_PAGES_H */
diff --git a/arch/riscv/include/sbi.h b/arch/riscv/include/sbi.h
new file mode 100644
index 0000000..609849d
--- /dev/null
+++ b/arch/riscv/include/sbi.h
@@ -0,0 +1,12 @@
+#ifndef APOS_RISCV_SBI_H
+
+struct sbiret {
+ long error;
+ long value;
+};
+
+struct sbiret sbi_ecall(int ext, int fid,
+ unsigned long arg0, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4, unsigned long arg5);
+
+#endif /* APOS_RISCV_SBI_H */
diff --git a/arch/riscv/include/vmap.h b/arch/riscv/include/vmap.h
new file mode 100644
index 0000000..3dac3a1
--- /dev/null
+++ b/arch/riscv/include/vmap.h
@@ -0,0 +1,19 @@
+#ifndef APOS_RISCV_VMAP_H
+#define APOS_RISCV_VMAP_H
+
+#include <apos/sizes.h>
+
+#define VM_V (1 << 1)
+#define VM_R (1 << 2)
+#define VM_W (1 << 3)
+#define VM_X (1 << 4)
+#define VM_U (1 << 5)
+#define VM_G (1 << 6)
+#define VM_A (1 << 7)
+#define VM_D (1 << 8)
+#define VM_AL 0xff
+
+#define VM_TOP (-1)
+#define VM_KERN (VM_TOP - SZ_1G)
+
+#endif /* APOS_RISCV_VMAP_H */
diff --git a/arch/riscv/init/head.S b/arch/riscv/init/head.S
new file mode 100644
index 0000000..703d265
--- /dev/null
+++ b/arch/riscv/init/head.S
@@ -0,0 +1,10 @@
+.section .init.start
+.global _start
+.type _start, @function
+_start:
+ /* store kernel load address */
+ auipc a4, 0
+ /* stack grows downward */
+ mv sp, a4
+ /* go to proper init */
+ j init
diff --git a/arch/riscv/init/init.c b/arch/riscv/init/init.c
new file mode 100644
index 0000000..cdcfbb7
--- /dev/null
+++ b/arch/riscv/init/init.c
@@ -0,0 +1,111 @@
+#include <stddef.h>
+#include <apos/init.h>
+#include <apos/sizes.h>
+#include <pages.h>
+#include <vmap.h>
+
+struct page_ret {
+ size_t left;
+ size_t num;
+ void *top;
+};
+
+extern void main(struct mm_pagearr_info *pageinfo);
+
+void __init init_zero(void *ptr, size_t bytes)
+{
+ char *byte_ptr = ptr;
+
+ /* Not entirely sure if it would be faster to use a larget type than
+ * char, Linux seems to have memset16/32/64 but I guess I should check
+ * the generated assembly.
+ */
+ while(bytes--)
+ *byte_ptr++ = 0;
+}
+
+struct page_ret __init init_pages(size_t ram_size, void *ram_top,
+ size_t page_size, size_t struct_size)
+{
+ size_t num_pages = ram_size / page_size;
+ size_t size_pages = num_pages * struct_size;
+
+ struct page_ret pageret;
+ pageret.top = ram_top - size_pages;
+ pageret.num = num_pages;
+ pageret.left = ram_size - (size_pages * page_size);
+
+ init_zero(pageret.top, size_pages);
+
+ return pageret;
+};
+
+size_t __init init_align_down(size_t num, size_t a)
+{
+ size_t rem = num % a;
+ return num - rem;
+}
+
+size_t __init init_align_up(size_t num, size_t a)
+{
+ return init_align_down(num, a) + a;
+}
+
+void __init init_enter_vm(unsigned long *root_page)
+{
+ asm volatile ("csrw 0x180, %0\n" "sfence.vma\n"
+ :
+ : "rK" (root_page)
+ : "memory");
+}
+
+void call_main()
+{
+}
+
+void __init init(void *ram_base, void *ram_top, void *initrd, void *fdt, void *boot)
+{
+ size_t ram_size = ram_top - ram_base;
+
+ struct mm_pagearr_info pagearr;
+ struct page_ret pageret;
+
+ /* create crude page status map at the top of physical RAM */
+ pageret = init_pages(ram_size, ram_top,
+ SZ_512G, sizeof(struct terapages));
+ pagearr.tera_num = pageret.num;
+ pagearr.tera_top = pageret.top;
+
+ pageret = init_pages(pageret.left, pageret.top,
+ SZ_1G, sizeof(struct gigapages));
+ pagearr.giga_num = pageret.num;
+ pagearr.giga_top = pageret.top;
+
+ pageret = init_pages(pageret.left, pageret.top,
+ SZ_2M, sizeof(struct megapages));
+ pagearr.mega_num = pageret.num;
+ pagearr.mega_top = pageret.top;
+
+ pageret = init_pages(pageret.left, pageret.top,
+ SZ_4K, sizeof(struct kilopages));
+ pagearr.kilo_num = pageret.num;
+ pagearr.kilo_top = pageret.top;
+
+ unsigned long *root_page = (unsigned long *)
+ (init_align_down((size_t)pagearr.kilo_top, SZ_4K) - SZ_4K);
+
+ /* TODO: should init insert page data into the created arrays? */
+
+ /* map .text.* into top part of RAM */
+ root_page[511] = ((unsigned long)&main & VM_AL) | VM_V | VM_R | VM_W | VM_X;
+
+ /* temporarily map .init.* so that our current physical address matches
+ * the virtual address */
+ root_page[0] = 0 | VM_V | VM_R | VM_W | VM_X;
+
+ /* enter virtual memory */
+ init_enter_vm(root_page);
+
+ /* enter main */
+ call_main();
+}
diff --git a/arch/riscv/main.c b/arch/riscv/main.c
new file mode 100644
index 0000000..382f311
--- /dev/null
+++ b/arch/riscv/main.c
@@ -0,0 +1,13 @@
+#include <pages.h>
+#include <apos/main.h>
+
+void yeet()
+{
+ int a = 23;
+}
+
+void __main main(struct mm_pagearr_info *pageinfo)
+{
+ yeet();
+ while(1){};
+}
diff --git a/arch/riscv/riscv-link.S b/arch/riscv/riscv-link.S
new file mode 100644
index 0000000..ffdf590
--- /dev/null
+++ b/arch/riscv/riscv-link.S
@@ -0,0 +1,20 @@
+#include <vmap.h>
+
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+SECTIONS {
+ . = 0; /* no offset */
+ .init : {
+ *(.init.start);
+ *(.init.text);
+ *(.init.data);
+ . = ALIGN(4K);
+ }
+
+ .text ALIGN(VM_KERN) : AT(ADDR(.init) + SIZEOF(.init)) {
+ *(.init.start);
+ *(.text.start);
+ *(.text);
+ }
+}
diff --git a/arch/riscv/sbi.c b/arch/riscv/sbi.c
new file mode 100644
index 0000000..e255ecf
--- /dev/null
+++ b/arch/riscv/sbi.c
@@ -0,0 +1,27 @@
+#include <sbi.h>
+
+struct sbiret sbi_ecall(int ext, int fid,
+ unsigned long arg0, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4, unsigned long arg5)
+{
+ struct sbiret ret;
+
+ register unsigned long a0 asm("a0") = arg0;
+ register unsigned long a1 asm("a1") = arg1;
+ register unsigned long a2 asm("a2") = arg2;
+ register unsigned long a3 asm("a3") = arg3;
+ register unsigned long a4 asm("a4") = arg4;
+ register unsigned long a5 asm("a5") = arg5;
+ register unsigned long a6 asm("a6") = fid;
+ register unsigned long a7 asm("a7") = ext;
+
+ asm volatile ("ecall"
+ : "+r" (a0), "+r" (a1)
+ : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
+ : "memory");
+
+ ret.error = a0;
+ ret.value = a1;
+
+ return ret;
+}
diff --git a/arch/riscv/source.mk b/arch/riscv/source.mk
new file mode 100644
index 0000000..f52750c
--- /dev/null
+++ b/arch/riscv/source.mk
@@ -0,0 +1,5 @@
+LOCAL_KERNEL_SOURCES := main.c init/head.S init/init.c
+KERNEL_SOURCES += $(addprefix arch/riscv/,$(LOCAL_KERNEL_SOURCES))
+
+INCLUDE_DIRS += arch/riscv/include
+LINKER_SOURCE := arch/riscv/riscv-link.S