aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv64/conf/boot.cmd9
-rw-r--r--arch/riscv64/init/init.c13
-rw-r--r--arch/riscv64/kernel/vmem.c22
-rw-r--r--common/debug.c14
-rw-r--r--common/string.c8
-rw-r--r--include/arch/vmem.h7
6 files changed, 60 insertions, 13 deletions
diff --git a/arch/riscv64/conf/boot.cmd b/arch/riscv64/conf/boot.cmd
index 47f395a..6c06200 100644
--- a/arch/riscv64/conf/boot.cmd
+++ b/arch/riscv64/conf/boot.cmd
@@ -2,3 +2,12 @@ fdt move ${fdt_addr} ${fdt_addr_r}
fdt addr ${fdt_addr_r}
load ${devtype} ${devnum} ${kernel_addr_r} kmi.itb
bootm ${kernel_addr_r} ${kernel_addr_r} ${fdt_addr_r}
+
+# the above works for qemu, visionfive2 looks more like
+#
+# fdt move ${fdt_addr} ${fdt_addr_r}
+# fdt addr ${fdt_addr_r}
+# load virtio 0:1 0x80260000 kmi.bin
+# load virtio 0:1 0x88300000 initrd
+# fdt chosen 0x88300000 0x1000
+# go 0x80260000 ${fdt_addr_r}
diff --git a/arch/riscv64/init/init.c b/arch/riscv64/init/init.c
index 278b9db..38639d7 100644
--- a/arch/riscv64/init/init.c
+++ b/arch/riscv64/init/init.c
@@ -16,6 +16,13 @@
#include "../kernel/csr.h"
+void flush_tlb_full()
+{
+ /** @todo could be nice to have a common set of features with kernel,
+ * but for now this is good enough. */
+ __asm__ volatile ("sfence.vma\n" ::: "memory");
+}
+
/**
* Create page table entry.
* Copy from \ref arch/riscv64/kernel/vmem.c.
@@ -50,7 +57,9 @@ static pm_t __fdt_ram_base(void *fdt)
*/
static void init_bootmem(uintptr_t load_addr, uintptr_t ram_base)
{
- size_t flags = VM_V | VM_X | VM_R | VM_W;
+ /* set all flags on, especially A and D since MMUs are allowed to raise
+ * exceptions that we're not ready to handle if they're unset. */
+ size_t flags = VM_V | VM_X | VM_R | VM_W | VM_D | VM_A;
extern char *__kernel;
extern char *__kernel_size;
@@ -83,6 +92,8 @@ static void init_bootmem(uintptr_t load_addr, uintptr_t ram_base)
case Sv48: mode = SATP_MODE_Sv48; break;
default: break;
};
+
+ flush_tlb_full();
csr_write(CSR_SATP, mode | ((uintptr_t)root_branch >> 12));
}
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index 235884b..f29c325 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -203,6 +203,8 @@ stat_t clear_vpage_flags(struct vmem *branch, vm_t vaddr, vmflags_t flags)
stat_t mod_vpage(struct vmem *branch, vm_t vaddr, pm_t paddr, vmflags_t flags)
{
+ flags |= VM_A | VM_D;
+
enum mm_order order;
pm_t *pte = __find_vmem(branch, vaddr, &order);
if (pte) {
@@ -296,6 +298,10 @@ stat_t map_vpage(struct vmem *branch, pm_t paddr, vm_t vaddr, vmflags_t flags,
struct vmem *root = branch;
enum mm_order top = __mm_max_order;
+ /* eventually we may want to keep track of page accesses,
+ * but for now they're mainly a nuisance. */
+ flags |= VM_A | VM_D;
+
while (top != order) {
size_t idx = vm_to_index(vaddr, top);
@@ -356,13 +362,19 @@ stat_t unmap_vpage(struct vmem *branch, vm_t vaddr)
return ERR_NF;
}
-void flush_tlb()
+void flush_tlb(uintptr_t addr)
+{
+ __asm__ volatile ("sfence.vma %0, x0\n" : : "r" (addr) : "memory");
+}
+
+void flush_tlb_full()
{
- __asm__ volatile ("sfence.vma %0\n" : : "r" (0) : "memory");
+ __asm__ volatile ("sfence.vma %0\n" :: "r" (0) : "memory");
}
void flush_tlb_all()
{
+ /** @todo this only works on a single core atm. */
__asm__ volatile ("sfence.vma\n" ::: "memory");
}
@@ -386,8 +398,8 @@ static void __use_vmem(struct vmem *branch, enum mm_mode m)
else if (m == Sv48)
mode = SATP_MODE_Sv48;
+ flush_tlb_full();
csr_write(CSR_SATP, mode | pn);
- flush_tlb();
/* Sv57 && Sv64 in the future? */
/** @todo ASID table for maybe faster context switches? */
}
@@ -424,7 +436,7 @@ stat_t destroy_vmem(struct vmem *b)
stat_t populate_kvmem(struct vmem *b)
{
- size_t flags = VM_V | VM_R | VM_W | VM_X | VM_G;
+ size_t flags = VM_V | VM_R | VM_W | VM_X | VM_G | VM_D | VM_A;
for (size_t i = KSTART_PAGE; i < IO_PAGE; ++i)
b->leaf[i] = (struct vmem *)to_pte(
get_ram_base() + TOP_PAGE_SIZE * (i - KSTART_PAGE),
@@ -440,7 +452,7 @@ vm_t setup_kernel_io(struct vmem *b, vm_t paddr)
{
pm_t top_page = paddr / TOP_PAGE_SIZE;
b->leaf[IO_PAGE] = (struct vmem *)to_pte(top_page * TOP_PAGE_SIZE,
- VM_V | VM_R | VM_W);
+ VM_V | VM_R | VM_W | VM_A | VM_D);
return -TOP_PAGE_SIZE + paddr - (top_page * TOP_PAGE_SIZE);
}
#endif
diff --git a/common/debug.c b/common/debug.c
index 2cd4570..346934a 100644
--- a/common/debug.c
+++ b/common/debug.c
@@ -123,6 +123,12 @@ static struct uart_8250 *port = 0;
*/
static int __serial_tx_empty()
{
+ /**
+ * @todo visionfive2 loops on lsr indefinitely, why?
+ * answer: because apparently visionfive2 uart has reg-shift = 2,
+ * meaning the registers are spaced apart more in memory than my naive
+ * struct.
+ * */
return port->lsr & LSR_THRE;
}
@@ -177,7 +183,13 @@ static struct dbg_info __dbg_from_fdt(const void *fdt)
const char *stdout =
fdt_getprop(fdt, chosen_offset, "stdout-path", NULL);
- int stdout_offset = fdt_path_offset(fdt, stdout);
+ /* discard options */
+ size_t baselen = strlen(stdout);
+ const char *options = strchr(stdout, ':');
+ if (options)
+ baselen = options - stdout;
+
+ int stdout_offset = fdt_path_offset_namelen(fdt, stdout, baselen);
/* get serial device type */
const char *dev_name = (const char *)fdt_getprop(fdt, stdout_offset,
diff --git a/common/string.c b/common/string.c
index a76c875..359a938 100644
--- a/common/string.c
+++ b/common/string.c
@@ -105,13 +105,13 @@ __weak char *strchr(const char *str, int chr)
const char *s1 = str;
ssize_t num = strlen(s1);
- while (num-- && *(s1--) != chr)
+ while (num-- && *(s1++) != chr)
;
if (num < 0)
return 0;
- return (char *)(s1 + 1);
+ return (char *)(s1 - 1);
}
#undef strtok
@@ -339,10 +339,10 @@ static int __hexval(char c)
return c - '0';
if (c >= 'a' && c <= 'f')
- return c - 'a';
+ return 10 + c - 'a';
if (c >= 'A' && c <= 'F')
- return c - 'A';
+ return 10 + c - 'A';
return -1;
}
diff --git a/include/arch/vmem.h b/include/arch/vmem.h
index 3f73a8f..d2f031d 100644
--- a/include/arch/vmem.h
+++ b/include/arch/vmem.h
@@ -98,8 +98,11 @@ stat_t mod_vpage(struct vmem *branch, vm_t vaddr, pm_t paddr, vmflags_t flags);
stat_t stat_vpage(struct vmem *branch, vm_t vaddr, pm_t *paddr,
enum mm_order *order, vmflags_t *flags);
-/** Flush tlb of current processor. */
-void flush_tlb();
+/** Flush tlb entry where associated with address \p addr. */
+void flush_tlb(uintptr_t addr);
+
+/** Flush full tlb of current address space. */
+void flush_tlb_full();
/** Flush tlbs of all processors. */
void flush_tlb_all();