diff --git a/riscv-sbi/Makefile b/riscv-sbi/Makefile new file mode 100644 index 00000000..7f4eeecd --- /dev/null +++ b/riscv-sbi/Makefile @@ -0,0 +1,91 @@ + +# Makefile for Phoenix SBI +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +SIL ?= @ +MAKEFLAGS += --no-print-directory + +KERNEL=1 + +include ../../phoenix-rtos-build/Makefile.common + +# check necessary variables +ifeq ($(filter clean,$(MAKECMDGOALS)),) + ifeq ($(PAYLOAD_PATH),) + $(error PAYLOAD_PATH is not set) + endif + ifeq ($(PAYLOAD_ADDR),) + $(error PAYLOAD_ADDR is not set) + endif +endif + +LDGEN ?= $(CC) + +CFLAGS += -I. -Iinclude +CPPFLAGS += -DPAYLOAD_PATH=\"$(PAYLOAD_PATH)\" + +ifneq ($(FDT_PATH),) + CPPFLAGS += -DFDT_PATH=\"$(FDT_PATH)\" +endif + +LDSFLAGS += -DPAYLOAD_ADDR=$(PAYLOAD_ADDR) + +OBJS := + +include core/Makefile +include devices/Makefile + +OBJS += $(addprefix $(PREFIX_O), entry.o) + +.PHONY: all clean + +.PRECIOUS: $(BUILD_DIR)%/. + + +all: $(PREFIX_PROG_STRIPPED)sbi-$(TARGET_SUBFAMILY).elf $(PREFIX_PROG_STRIPPED)sbi-$(TARGET_SUBFAMILY).img + + +$(PREFIX_PROG)sbi-$(TARGET_SUBFAMILY).elf: $(PREFIX_O)/sbi-$(TARGET_SUBFAMILY).ld $(OBJS) | $(PREFIX_PROG)/. + @echo "LD $(@F)" + $(SIL)$(LD) $(CFLAGS) $(LDFLAGS) -Wl,-Map=$<.map -o $@ -Wl,-T,$^ -nostdlib -lgcc + + +$(PREFIX_PROG_STRIPPED)%.hex: $(PREFIX_PROG_STRIPPED)%.elf + @echo "HEX $(@F)" + $(SIL)$(OBJCOPY) -O ihex $< $@ + + +$(PREFIX_PROG_STRIPPED)%.img: $(PREFIX_PROG_STRIPPED)%.elf + @echo "BIN $(@F)" + $(SIL)$(OBJCOPY) -O binary $< $@ + + +-include $(PREFIX_O)/sbi-$(TARGET_SUBFAMILY)*ld.d +$(PREFIX_O)/sbi-$(TARGET_SUBFAMILY).ld: | $(PREFIX_O)/. + @echo "GEN $(@F)" + $(SIL)$(LDGEN) $(LDSFLAGS) -MP -MF $@.d -MMD -D__LINKER__ -undef -xc -E -P ld/$(TARGET_SUBFAMILY).ldt > $@ + $(SIL)$(SED) -i.tmp -e 's`.*\.o[ \t]*:`$@:`' $@.d && rm $@.d.tmp + + +$(PREFIX_O)/sbi-$(TARGET_SUBFAMILY)-%.ld: | $(PREFIX_O)/. + @echo "GEN $(@F)" + $(SIL)$(LDGEN) $(LDSFLAGS) -MP -MF $@.d -MMD -D__LINKER__ -D$* -undef -xc -E -P ld/$(TARGET_SUBFAMILY).ldt > $@ + $(SIL)$(SED) -i.tmp -e 's`.*\.o[ \t]*:`$@:`' $@.d && rm $@.d.tmp + + +%/.: + @echo "MKDIR $(@D)" + $(SIL)mkdir -p "$(@D)" + + +clean: + @echo "rm -rf $(BUILD_DIR)" + + +ifneq ($(filter clean,$(MAKECMDGOALS)),) + $(shell rm -rf $(BUILD_DIR)) +endif diff --git a/riscv-sbi/core/Makefile b/riscv-sbi/core/Makefile new file mode 100644 index 00000000..3a7b39f1 --- /dev/null +++ b/riscv-sbi/core/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for Phoenix SBI +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +include platform/$(TARGET_SUBFAMILY)/Makefile +include core/extensions/Makefile +include core/fdt/Makefile + +OBJS += $(addprefix $(PREFIX_O)core/, _interrupts.o _start.o _string.o csr.o exceptions.o hart.o interrupts.o sbi.o string.o) diff --git a/riscv-sbi/core/_interrupts.S b/riscv-sbi/core/_interrupts.S new file mode 100644 index 00000000..b9bbf6cd --- /dev/null +++ b/riscv-sbi/core/_interrupts.S @@ -0,0 +1,178 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Interrupt stubs + * + * Copyright 2023, 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#define __ASSEMBLY__ + + +#include "csr.h" + +.text + +.align 2 + +.global _interrupts_dispatch +.type _interrupts_dispatch, @function +_interrupts_dispatch: + csrrw a1, CSR_MSCRATCH, a1 /* a1 = &perHartData[hartid] */ + sd a0, 8(a1) /* Save a0 */ + + csrr a0, CSR_MSTATUS + + /* Determine in which mode we were executing before interrupt + * MPP = 3 -> machine mode + */ + srli a0, a0, 11 + xori a0, a0, 3 + bnez a0, 1f + + /* Machine mode */ + sd sp, -272(sp) + + addi sp, sp, -280 + j 2f + +1: + /* U/S mode + * Load machine stack pointer from hart data + */ + ld a0, (a1) + + /* Save task's stack pointer */ + sd sp, -272(a0) + + /* Swap to machine stack */ + addi sp, a0, -280 + +2: + /* restore a0, a1 */ + ld a0, 8(a1) + csrrw a1, CSR_MSCRATCH, a1 + + /* Save context */ + sd ra, (sp) + sd gp, 16(sp) + sd tp, 24(sp) + sd t0, 32(sp) + sd t1, 40(sp) + sd t2, 48(sp) + sd s0, 56(sp) + sd s1, 64(sp) + sd a0, 72(sp) + sd a1, 80(sp) + sd a2, 88(sp) + sd a3, 96(sp) + sd a4, 104(sp) + sd a5, 112(sp) + sd a6, 120(sp) + sd a7, 128(sp) + sd s2, 136(sp) + sd s3, 144(sp) + sd s4, 152(sp) + sd s5, 160(sp) + sd s6, 168(sp) + sd s7, 176(sp) + sd s8, 184(sp) + sd s9, 192(sp) + sd s10, 200(sp) + sd s11, 208(sp) + sd t3, 216(sp) + sd t4, 224(sp) + sd t5, 232(sp) + sd t6, 240(sp) + + csrr s0, CSR_MSTATUS + csrr s1, CSR_MEPC + csrr s2, CSR_MCAUSE + + sd s0, 248(sp) /* mstatus */ + sd s1, 256(sp) /* mepc */ + sd s2, 264(sp) /* mcause */ + + /* Check interrupt source */ + li t0, MCAUSE_INTR + and t1, s2, t0 + andi s0, s2, MCAUSE_IRQ_MSK /* Exception code */ + beqz t1, _interrupts_notIrq + +_interrupts_dispatchIntr: + mv a0, s0 + call interrupts_dispatch + tail _interrupts_restoreAll + +_interrupts_notIrq: + li s2, MCAUSE_S_ECALL + bne s0, s2, _interrupts_dispatchExc + + /* s1 = mepc, move past ecall instruction */ + addi s1, s1, 4 + sd s1, 256(sp) + + /* a0-a7 are preserved */ + call sbi_dispatchEcall + tail _interrupts_restoreAfterEcall + +_interrupts_dispatchExc: + csrr s1, CSR_MTVAL + sd s1, 272(sp) /* mtval */ + + mv a0, s0 + mv a1, sp + call exceptions_dispatch + +_interrupts_restoreAll: + ld a0, 72(sp) + ld a1, 80(sp) + +_interrupts_restoreAfterEcall: + ld s0, 248(sp) + csrw CSR_MSTATUS, s0 + + ld s0, 256(sp) + csrw CSR_MEPC, s0 + + ld ra, (sp) + ld gp, 16(sp) + ld tp, 24(sp) + ld t0, 32(sp) + ld t1, 40(sp) + ld t2, 48(sp) + ld s0, 56(sp) + ld s1, 64(sp) + ld a2, 88(sp) + ld a3, 96(sp) + ld a4, 104(sp) + ld a5, 112(sp) + ld a6, 120(sp) + ld a7, 128(sp) + ld s2, 136(sp) + ld s3, 144(sp) + ld s4, 152(sp) + ld s5, 160(sp) + ld s6, 168(sp) + ld s7, 176(sp) + ld s8, 184(sp) + ld s9, 192(sp) + ld s10, 200(sp) + ld s11, 208(sp) + ld t3, 216(sp) + ld t4, 224(sp) + ld t5, 232(sp) + ld t6, 240(sp) + + /* Restore task's stack pointer */ + ld sp, 8(sp) + + mret +.size _interrupts_dispatch, .-_interrupts_dispatch diff --git a/riscv-sbi/core/_start.S b/riscv-sbi/core/_start.S new file mode 100644 index 00000000..975e4b69 --- /dev/null +++ b/riscv-sbi/core/_start.S @@ -0,0 +1,168 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Low level initialization + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#define __ASSEMBLY__ + + +#include "csr.h" +#include "sbi.h" + +.extern __bss_start +.extern __bss_end + +.section ".init", "ax" + +.align 2 + +.globl _start +.type _start, @function +_start: + /* Disable interrupts */ + csrw CSR_MIE, zero + csrw CSR_MIP, zero + + /* Clear/set registers */ + mv ra, zero + mv sp, zero + mv gp, zero + mv tp, zero + mv t0, zero + mv t1, zero + mv t2, zero + mv s0, zero + mv s1, zero + mv a0, zero +#ifdef FDT_PATH + la a1, __fdt_start +#endif /* else assume a1 contains the fdt address */ + + mv a2, zero + mv a3, zero + mv a4, zero + mv a5, zero + mv a6, zero + mv a7, zero + mv s2, zero + mv s3, zero + mv s4, zero + mv s5, zero + mv s6, zero + mv s7, zero + mv s8, zero + mv s9, zero + mv s10, zero + mv s11, zero + mv t3, zero + mv t4, zero + mv t5, zero + mv t6, zero + csrw CSR_MSCRATCH, zero + +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + csrr a0, CSR_MHARTID + + mv s1, a1 /* save fdt address */ + + /* Set the stack pointer */ + la sp, _stack + slli a1, a0, 12 /* 4KB stack */ + add sp, sp, a1 + + la a1, hartLock + li a2, 1 + amoadd.w.aq a3, a2, (a1) + bnez a3, _wait_boot_hart + + /* Clear the .bss section */ + la a0, __bss_start + li a1, 0 + la a2, __bss_end + sub a2, a2, a0 + + call sbi_memset + + csrr s0, CSR_MHARTID + la a1, bootHartId + sw s0, (a1) + + fence w, rw + + la a1, bootReady + li a2, 1 + amoadd.w.aqrl zero, a2, (a1) + +_boot_continue: + /* Mark ourselves in the hart mask */ + la a1, hartMask + sll a3, a2, s0 + amoor.w.aq zero, a3, (a1) + + mv a0, s0 + mv a1, s1 + mv a2, sp + call sbi_scratchInit + + /* Set interrupt vector */ + la a0, _interrupts_dispatch + csrw CSR_MTVEC, a0 + + /* Quickly initialize some basic cpu features (e.g. cache) */ + call platform_cpuEarlyInit + + mv a0, s0 + mv a1, s1 + j entry + +_wait_boot_hart: + /* Wait for the boot hart to finish clearing the .bss section */ + la a1, bootReady + lw a2, (a1) + beqz a2, _wait_boot_hart + + csrr a0, CSR_MHARTID + li a2, 1 + j _boot_continue +.size _start, . - _start + + +.align 2 +hartLock: + .word 0 + +.align 2 +bootReady: + .word 0 + + +#ifdef FDT_PATH + +.section .rodata +.align 4 +.globl __fdt_start +__fdt_start: + .incbin FDT_PATH + +#endif + + +.section ".payload", "ax", %progbits +.align 4 +.globl __payload_start +__payload_start: + .incbin PAYLOAD_PATH diff --git a/riscv-sbi/core/_string.S b/riscv-sbi/core/_string.S new file mode 100644 index 00000000..63c9eade --- /dev/null +++ b/riscv-sbi/core/_string.S @@ -0,0 +1,220 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * String functions + * + * Copyright 2018 Phoenix Systems + * Author: Pawel Pisarczyk + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#define __ASSEMBLY__ + +.text + +.globl sbi_memcpy +.type sbi_memcpy, @function +sbi_memcpy: + /* Preserve return value */ + move t6, a0 + sltiu a3, a2, 128 + bnez a3, 4f + + /* Use word-oriented copy only if low-order bits match */ \ + andi a3, t6, 7 + andi a4, a1, 7 + bne a3, a4, 4f + + /* Skip if already aligned */ + beqz a3, 2f + + /* Round to nearest double word-aligned address */ + andi a3, a1, ~7 + addi a3, a3, 8 + + /* Handle initial misalignment */ + sub a4, a3, a1 +1: + lb a5, 0(a1); + addi a1, a1, 1 + sb a5, 0(t6) + addi t6, t6, 1 + bltu a1, a3, 1b + + /* Update count */ + sub a2, a2, a4 +2: + andi a4, a2, ~((16 * 8) - 1) + beqz a4, 4f + add a3, a1, a4 +3: + /* Copy 128-byte blocks of data using registers */ \ + ld a4, 0(a1) + ld a5, 8(a1) + ld a6, 16(a1) + ld a7, 24(a1) + ld t0, 32(a1) + ld t1, 40(a1) + ld t2, 48(a1) + ld t3, 56(a1) + ld t4, 64(a1) + ld t5, 72(a1) + sd a4, 0(t6) + sd a5, 8(t6) + sd a6, 16(t6) + sd a7, 24(t6) + sd t0, 32(t6) + sd t1, 40(t6) + sd t2, 48(t6) + sd t3, 56(t6) + sd t4, 64(t6) + sd t5, 72(t6) + ld a4, 80(a1) + ld a5, 88(a1) + ld a6, 96(a1) + ld a7, 104(a1) + ld t0, 112(a1) + ld t1, 120(a1) + addi a1, a1, 128; + sd a4, 80(t6); + sd a5, 88(t6) + sd a6, 96(t6) + sd a7, 104(t6) + sd t0, 112(t6) + sd t1, 120(t6) + addi t6, t6, 128 + bltu a1, a3, 3b + + /* Update count */ + andi a2, a2, 127 +4: + /* Handle trailing misalignment */ + beqz a2, 6f + add a3, a1, a2 + + /* Use word-oriented copy if co-aligned to word boundary */ \ + or a5, a1, t6 + or a5, a5, a3 + andi a5, a5, 3 + bnez a5, 5f +7: + lw a4, 0(a1) + addi a1, a1, 4 + sw a4, 0(t6) + addi t6, t6, 4 + bltu a1, a3, 7b + ret +5: + lb a4, 0(a1) + addi a1, a1, 1 + sb a4, 0(t6) + addi t6, t6, 1 + bltu a1, a3, 5b +6: + ret + +.size sbi_memcpy, .-sbi_memcpy + + +.globl sbi_memset +.type sbi_memset, @function +sbi_memset: + move t0, a0 + + /* Defer to byte-oriented fill for small sizes */ + sltiu a3, a2, 16 + bnez a3, 4f + + /* Round to nearest aligned address */ + addi a3, t0, 7 + andi a3, a3, ~7 + beq a3, t0, 2f + + /* Handle initial misalignment */ + sub a4, a3, t0 +1: + sb a1, 0(t0) + addi t0, t0, 1 + bltu t0, a3, 1b + sub a2, a2, a4 +2: + /* Broadcast value into all bytes */ + andi a1, a1, 0xff + slli a3, a1, 8 + or a1, a3, a1 + slli a3, a1, 16 + or a1, a3, a1 + slli a3, a1, 32 + or a1, a3, a1 + + /* Calculate end address */ + andi a4, a2, ~7 + add a3, t0, a4 + + andi a4, a4, 31 * 8 /* Calculate remainder */ + beqz a4, 3f /* Shortcut if no remainder */ + neg a4, a4 + addi a4, a4, 32 * 8 /* Calculate initial offset */ + + /* Adjust start address with offset */ + sub t0, t0, a4 + + /* Jump into loop body - assumes 32-bit instruction lengths */ + la a5, 3f + srli a4, a4, 1 + add a5, a5, a4 + jr a5 +3: + sd a1, 0(t0) + sd a1, 8(t0) + sd a1, 16(t0) + sd a1, 24(t0) + sd a1, 32(t0) + sd a1, 40(t0) + sd a1, 48(t0) + sd a1, 56(t0) + sd a1, 64(t0) + sd a1, 72(t0) + sd a1, 80(t0) + sd a1, 88(t0) + sd a1, 96(t0) + sd a1, 104(t0) + sd a1, 112(t0) + sd a1, 120(t0) + sd a1, 128(t0) + sd a1, 136(t0) + sd a1, 144(t0) + sd a1, 152(t0) + sd a1, 160(t0) + sd a1, 168(t0) + sd a1, 176(t0) + sd a1, 184(t0) + sd a1, 192(t0) + sd a1, 200(t0) + sd a1, 208(t0) + sd a1, 216(t0) + sd a1, 224(t0) + sd a1, 232(t0) + sd a1, 240(t0) + sd a1, 248(t0) + addi t0, t0, 256 + bltu t0, a3, 3b + + /* Update count */ + andi a2, a2, 7 +4: + /* Handle trailing misalignment */ + beqz a2, 6f + add a3, t0, a2 +5: + sb a1, 0(t0) + addi t0, t0, 1 + bltu t0, a3, 5b +6: + ret +.size sbi_memset, .-sbi_memset diff --git a/riscv-sbi/core/csr.c b/riscv-sbi/core/csr.c new file mode 100644 index 00000000..52a7235d --- /dev/null +++ b/riscv-sbi/core/csr.c @@ -0,0 +1,57 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * CSR functions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include "csr.h" +#include "types.h" + +#include "devices/clint.h" + + +int csr_emulateRead(u32 csr, u64 *val) +{ + int ret = 0; + + switch (csr) { + case CSR_TIME: + *val = clint_getTime(); + break; + + case CSR_INSTRET: + *val = csr_read(CSR_MINSTRET); + break; + + case CSR_CYCLE: + *val = csr_read(CSR_MCYCLE); + break; + + default: + ret = -1; + break; + } + + return ret; +} + + +int csr_emulateWrite(u32 csr, u64 val) +{ + (void)csr; + (void)val; + + /* Applicable only for H-mode */ + + return -1; +} \ No newline at end of file diff --git a/riscv-sbi/core/exceptions.c b/riscv-sbi/core/exceptions.c new file mode 100644 index 00000000..fe70cfdc --- /dev/null +++ b/riscv-sbi/core/exceptions.c @@ -0,0 +1,315 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * Exception handling + * + * Copyright 2023 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "csr.h" +#include "hart.h" +#include "string.h" +#include "types.h" + +#include "devices/console.h" + + +typedef struct _exc_context_t { + u64 ra; /* x1 */ + u64 sp; /* x2 */ + u64 gp; /* x3 */ + u64 tp; /* x4 */ + + u64 t0; /* x5 */ + u64 t1; /* x6 */ + u64 t2; /* x7 */ + + u64 s0; /* x8 */ + u64 s1; /* x9 */ + + u64 a0; /* x10 */ + u64 a1; /* x11 */ + u64 a2; /* x12 */ + u64 a3; /* x13 */ + u64 a4; /* x14 */ + u64 a5; /* x15 */ + u64 a6; /* x16 */ + u64 a7; /* x17 */ + + u64 s2; /* x18 */ + u64 s3; /* x19 */ + u64 s4; /* x20 */ + u64 s5; /* x21 */ + u64 s6; /* x22 */ + u64 s7; /* x23 */ + u64 s8; /* x24 */ + u64 s9; /* x25 */ + u64 s10; /* x26 */ + u64 s11; /* x27 */ + + u64 t3; /* x28 */ + u64 t4; /* x29 */ + u64 t5; /* x30 */ + u64 t6; /* x31 */ + + u64 mstatus; + u64 mepc; + u64 mcause; + u64 mtval; +} __attribute__((packed, aligned(8))) exc_context_t; + + +static void exceptions_DumpContext(char *buff, exc_context_t *ctx, int n) +{ + unsigned int i = 0; + + static const char *mnemonics[] = { + "0 Instruction address missaligned", "1 Instruction access fault", "2 Illegal instruction", "3 Breakpoint", + "4 Reserved", "5 Load access fault", "6 AMO address misaligned", "7 Store/AMO access fault", + "8 Environment call", "9 Reserved", "10 Reserved", "11 Reserved", + "12 Instruction page fault", "13 Load page fault", "14 Reserved", "15 Store/AMO page fault" + }; + + n &= 0xf; + + sbi_strcpy(buff, "\nException: "); + sbi_strcpy(buff += sbi_strlen(buff), mnemonics[n]); + sbi_strcpy(buff += sbi_strlen(buff), "\n"); + buff += sbi_strlen(buff); + + i += sbi_i2s("zero: ", &buff[i], 0, 16, 1); + i += sbi_i2s(" ra : ", &buff[i], (u64)ctx->ra, 16, 1); + i += sbi_i2s(" sp : ", &buff[i], (u64)ctx->sp, 16, 1); + i += sbi_i2s(" gp : ", &buff[i], (u64)ctx->gp, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" tp : ", &buff[i], (u64)ctx->tp, 16, 1); + i += sbi_i2s(" t0 : ", &buff[i], (u64)ctx->t0, 16, 1); + i += sbi_i2s(" t1 : ", &buff[i], (u64)ctx->t1, 16, 1); + i += sbi_i2s(" t2 : ", &buff[i], (u64)ctx->t2, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" s0 : ", &buff[i], (u64)ctx->s0, 16, 1); + i += sbi_i2s(" s1 : ", &buff[i], (u64)ctx->s1, 16, 1); + i += sbi_i2s(" a0 : ", &buff[i], (u64)ctx->a0, 16, 1); + i += sbi_i2s(" a1 : ", &buff[i], (u64)ctx->a1, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" a2 : ", &buff[i], (u64)ctx->a2, 16, 1); + i += sbi_i2s(" a3 : ", &buff[i], (u64)ctx->a3, 16, 1); + i += sbi_i2s(" a4 : ", &buff[i], (u64)ctx->a4, 16, 1); + i += sbi_i2s(" a5 : ", &buff[i], (u64)ctx->a5, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" a6 : ", &buff[i], (u64)ctx->a6, 16, 1); + i += sbi_i2s(" a7 : ", &buff[i], (u64)ctx->a7, 16, 1); + i += sbi_i2s(" s2 : ", &buff[i], (u64)ctx->s2, 16, 1); + i += sbi_i2s(" s3 : ", &buff[i], (u64)ctx->s3, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" s4 : ", &buff[i], (u64)ctx->s4, 16, 1); + i += sbi_i2s(" s5 : ", &buff[i], (u64)ctx->s5, 16, 1); + i += sbi_i2s(" s6 : ", &buff[i], (u64)ctx->s6, 16, 1); + i += sbi_i2s(" s7 : ", &buff[i], (u64)ctx->s7, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" s8 : ", &buff[i], (u64)ctx->s8, 16, 1); + i += sbi_i2s(" s9 : ", &buff[i], (u64)ctx->s9, 16, 1); + i += sbi_i2s(" s10 : ", &buff[i], (u64)ctx->s10, 16, 1); + i += sbi_i2s(" s11 : ", &buff[i], (u64)ctx->s11, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" t3 : ", &buff[i], (u64)ctx->t3, 16, 1); + i += sbi_i2s(" t4 : ", &buff[i], (u64)ctx->t4, 16, 1); + i += sbi_i2s(" t5 : ", &buff[i], (u64)ctx->t5, 16, 1); + i += sbi_i2s(" t6 : ", &buff[i], (u64)ctx->t6, 16, 1); + buff[i++] = '\n'; + + i += sbi_i2s(" mstatus : ", &buff[i], (u64)ctx->mstatus, 16, 1); + i += sbi_i2s(" mepc : ", &buff[i], (u64)ctx->mepc, 16, 1); + i += sbi_i2s(" mcause : ", &buff[i], (u64)ctx->mcause, 16, 1); + + buff[i++] = '\n'; + + buff[i] = 0; +} + + +static void __attribute__((noreturn)) exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) +{ + char buff[512]; + + exceptions_DumpContext(buff, ctx, n); + console_print(buff); + + hart_halt(); +} + + +static void exceptions_redirect(unsigned int n, u64 insn, exc_context_t *ctx) +{ + u64 prevMode = (ctx->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT; + u64 mstatus = ctx->mstatus; + + /* Update S-mode CSRs */ + csr_write(CSR_SEPC, ctx->mepc); + csr_write(CSR_SCAUSE, ctx->mcause); + csr_write(CSR_STVAL, insn); + + /* Update exception context */ + ctx->mepc = csr_read(CSR_STVEC); + + mstatus &= ~(MSTATUS_MPP | MSTATUS_SPP | MSTATUS_SPIE); + /* Set MPP to S-mode */ + mstatus |= (PRV_S << MSTATUS_MPP_SHIFT); + + /* Set SPP accordingly */ + if (prevMode == PRV_S) { + mstatus |= MSTATUS_SPP; + } + + /* Update SPIE */ + if ((ctx->mstatus & MSTATUS_SIE) != 0) { + mstatus |= MSTATUS_SPIE; + } + + /* Clear SIE */ + mstatus &= ~MSTATUS_SIE; + + ctx->mstatus = mstatus; +} + + +static u64 exceptions_getRegval(unsigned int regNum, exc_context_t *ctx) +{ + if (regNum == 0) { + return 0; + } + + return *((u64 *)((addr_t)ctx + (regNum - 1) * sizeof(u64))); +} + + +static void exceptions_setRegval(unsigned int regNum, u64 regVal, exc_context_t *ctx) +{ + if (regNum != 0) { + *((u64 *)((addr_t)ctx + (regNum - 1) * sizeof(u64))) = regVal; + } +} + + +static void exceptions_illSystem(unsigned int n, exc_context_t *ctx) +{ + /* Assuming we trapped on CSR instruction (not checked) */ + u64 insn = ctx->mtval; + u32 csr = (insn >> 20) & 0xfffu; + u64 csrVal, newCsrVal; + u64 prevMode = (ctx->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT; + u32 rs1 = (insn >> 15) & 0x1fu; + u64 rs1Val = exceptions_getRegval(rs1, ctx); + u32 write = rs1; + u32 rd = (insn >> 7) & 0x1fu; + + if (prevMode == PRV_M) { + /* Trapped on CSR access from M-mode, halt */ + exceptions_defaultHandler(n, ctx); + } + + if (csr_emulateRead(csr, &csrVal) < 0) { + exceptions_defaultHandler(n, ctx); + } + + /* Check funct3 */ + switch ((insn >> 12) & 0x7) { + case 1: + /* CSRRW */ + newCsrVal = rs1Val; + write = 1; + break; + + case 2: + /* CSRRS */ + newCsrVal = csrVal | rs1Val; + break; + + case 3: + /* CSRRC */ + newCsrVal = csrVal & ~rs1Val; + break; + + case 5: + /* CSRRWI */ + newCsrVal = rs1; + write = 1; + break; + + case 6: + /* CSRRSI */ + newCsrVal = csrVal | rs1; + break; + + case 7: + /* CSRRCI */ + newCsrVal = csrVal & ~rs1; + break; + + default: + exceptions_defaultHandler(n, ctx); + break; + } + + if ((write != 0) && (csr_emulateWrite(csr, newCsrVal) < 0)) { + exceptions_defaultHandler(n, ctx); + } + + exceptions_setRegval(rd, csrVal, ctx); + + /* Skip instruction */ + ctx->mepc += 4; +} + + +static void exceptions_illegalHandler(unsigned int n, exc_context_t *ctx) +{ + u64 insn = ctx->mtval; + u64 prevMode = (ctx->mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT; + + /* Check failing instruction */ + if (((insn & 3) == 3) && (((insn & 0x7c) >> 2) == 0x1c)) { + /* Non-compressed, SYSTEM opcode */ + exceptions_illSystem(n, ctx); + } + else if (insn == 0) { + /* RV implementation didn't write mtval. + * TODO: get failing instruction through unprivileged access + */ + exceptions_defaultHandler(n, ctx); + } + else { + if (prevMode == PRV_M) { + /* Trapped on illegal instruction in M-mode */ + exceptions_defaultHandler(n, ctx); + } + else { + exceptions_redirect(n, insn, ctx); + } + } +} + + +void exceptions_dispatch(unsigned int n, exc_context_t *ctx) +{ + if (n == MCAUSE_ILLEGAL) { + exceptions_illegalHandler(n, ctx); + } + else { + exceptions_defaultHandler(n, ctx); + } +} diff --git a/riscv-sbi/core/extensions/Makefile b/riscv-sbi/core/extensions/Makefile new file mode 100644 index 00000000..4095db7b --- /dev/null +++ b/riscv-sbi/core/extensions/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for Phoenix SBI - extensions +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)core/extensions/, ecall_base.o ecall_hsm.o ecall_ipi.o ecall_rfence.o \ + ecall_time.o hsm.o ipi.o) diff --git a/riscv-sbi/core/extensions/ecall_base.c b/riscv-sbi/core/extensions/ecall_base.c new file mode 100644 index 00000000..fcb76ca0 --- /dev/null +++ b/riscv-sbi/core/extensions/ecall_base.c @@ -0,0 +1,113 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI BASE handler + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include "sbi.h" +#include "csr.h" + + +#define SBI_VERSION_MAJOR 2 +#define SBI_VERSION_MINOR 0 + +#define SBI_VERSION(major, minor) (((((major)) & 0x7f) << 24) | (minor & 0xffffff)) + + +#define PHOENIX_SBI_ID 10 +#define PHOENIX_SBI_VERSION 1 + + +/* Anchors for section which contains extension entries */ +extern const sbi_ext_t __ext_start[]; +extern const sbi_ext_t __ext_end[]; + + +enum { + BASE_GET_SPEC_VERSION = 0, + BASE_GET_IMPL_ID, + BASE_GET_IMPL_VERSION, + BASE_PROBE_EXT, + BASE_GET_MVENDORID, + BASE_GET_MARCHID, + BASE_GET_MIMPID, +}; + + +static long base_probeExt(unsigned long extid) +{ + const sbi_ext_t *ext; + for (ext = __ext_start; ext < __ext_end; ext++) { + if (ext->eid == extid) { + return SBI_SUCCESS; + } + } + + return SBI_ERR_NOT_SUPPORTED; +} + + +static sbiret_t sbi_ext_baseHandler(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid) +{ + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + + sbiret_t ret = { + .error = SBI_SUCCESS, + }; + + switch (fid) { + case BASE_GET_SPEC_VERSION: + ret.value = SBI_VERSION(SBI_VERSION_MAJOR, SBI_VERSION_MINOR); + break; + + case BASE_GET_IMPL_ID: + ret.value = PHOENIX_SBI_ID; + break; + + case BASE_GET_IMPL_VERSION: + ret.value = PHOENIX_SBI_VERSION; + break; + + case BASE_PROBE_EXT: + ret.value = base_probeExt(a0); + break; + + case BASE_GET_MVENDORID: + ret.value = csr_read(CSR_MVENDORID); + break; + + case BASE_GET_MARCHID: + ret.value = csr_read(CSR_MARCHID); + break; + + case BASE_GET_MIMPID: + ret.value = csr_read(CSR_MIMPID); + break; + + default: + ret.error = SBI_ERR_NOT_SUPPORTED; + ret.value = 0; + break; + } + + return ret; +} + +static const sbi_ext_t sbi_ext_base __attribute__((section("extensions"), used)) = { + .eid = SBI_EXT_BASE, + .handler = sbi_ext_baseHandler, +}; diff --git a/riscv-sbi/core/extensions/ecall_hsm.c b/riscv-sbi/core/extensions/ecall_hsm.c new file mode 100644 index 00000000..00a95d9e --- /dev/null +++ b/riscv-sbi/core/extensions/ecall_hsm.c @@ -0,0 +1,65 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI HSM handler + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "sbi.h" + +#include "extensions/hsm.h" + + +enum { + HSM_HART_START = 0, + HSM_HART_STOP, + HSM_HART_GET_STATUS, + HSM_HART_SUSPEND, +}; + + +static sbiret_t sbi_ext_hsmHandler(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid) +{ + sbiret_t ret = { + .error = SBI_SUCCESS, + }; + + switch (fid) { + case HSM_HART_START: + ret.error = hsm_hartStart(a0, a1, a2); + break; + + case HSM_HART_STOP: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + case HSM_HART_GET_STATUS: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + case HSM_HART_SUSPEND: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + default: + ret.error = SBI_ERR_NOT_SUPPORTED; + ret.value = 0; + break; + } + + return ret; +} + + +static const sbi_ext_t sbi_ext_hsm __attribute__((section("extensions"), used)) = { + .eid = SBI_EXT_HSM, + .handler = sbi_ext_hsmHandler, +}; diff --git a/riscv-sbi/core/extensions/ecall_ipi.c b/riscv-sbi/core/extensions/ecall_ipi.c new file mode 100644 index 00000000..93dad634 --- /dev/null +++ b/riscv-sbi/core/extensions/ecall_ipi.c @@ -0,0 +1,49 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI IPI handler + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "sbi.h" + + +enum { + IPI_SEND_IPI = 0, +}; + + +static sbiret_t sbi_ext_ipiHandler(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid) +{ + /* TODO */ + sbiret_t ret = { + .error = SBI_SUCCESS, + }; + + switch (fid) { + case IPI_SEND_IPI: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + default: + ret.error = SBI_ERR_NOT_SUPPORTED; + ret.value = 0; + break; + } + + return ret; +} + + +static const sbi_ext_t sbi_ext_ipi __attribute__((section("extensions"), used)) = { + .eid = SBI_EXT_IPI, + .handler = sbi_ext_ipiHandler, +}; \ No newline at end of file diff --git a/riscv-sbi/core/extensions/ecall_rfence.c b/riscv-sbi/core/extensions/ecall_rfence.c new file mode 100644 index 00000000..df419749 --- /dev/null +++ b/riscv-sbi/core/extensions/ecall_rfence.c @@ -0,0 +1,68 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI RFENCE handler + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "sbi.h" + + +enum { + RFENCE_FENCE_I = 0, + RFENCE_SFENCE_VMA, + RFENCE_SFENCE_VMA_ASID, + RFENCE_HFENCE_GVMA_VMID, + RFENCE_HFENCE_GVMA, + RFENCE_HFENCE_VVMA_ASID, + RFENCE_HFENCE_VVMA +}; + + +static sbiret_t sbi_ext_rfenceHandler(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid) +{ + sbiret_t ret = { + .error = SBI_SUCCESS, + }; + + + /* TODO */ + switch (fid) { + case RFENCE_FENCE_I: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + case RFENCE_SFENCE_VMA: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + case RFENCE_SFENCE_VMA_ASID: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + + case RFENCE_HFENCE_GVMA_VMID: + case RFENCE_HFENCE_GVMA: + case RFENCE_HFENCE_VVMA_ASID: + case RFENCE_HFENCE_VVMA: + default: + ret.error = SBI_ERR_NOT_SUPPORTED; + ret.value = 0; + break; + } + + return ret; +} + + +static const sbi_ext_t sbi_ext_rfence __attribute__((section("extensions"), used)) = { + .eid = SBI_EXT_RFENCE, + .handler = sbi_ext_rfenceHandler, +}; \ No newline at end of file diff --git a/riscv-sbi/core/extensions/ecall_time.c b/riscv-sbi/core/extensions/ecall_time.c new file mode 100644 index 00000000..8a0584d5 --- /dev/null +++ b/riscv-sbi/core/extensions/ecall_time.c @@ -0,0 +1,50 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI TIMER handler + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "sbi.h" + +#include "devices/clint.h" + + +enum { + TIME_SET_TIMER = 0, +}; + + +static sbiret_t sbi_ext_timeHandler(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid) +{ + sbiret_t ret = { + .error = SBI_SUCCESS, + .value = 0, + }; + + switch (fid) { + case TIME_SET_TIMER: + clint_setTimecmp(a0); + break; + + default: + ret.error = SBI_ERR_NOT_SUPPORTED; + break; + } + + return ret; +} + + +static const sbi_ext_t sbi_ext_time __attribute__((section("extensions"), used)) = { + .eid = SBI_EXT_TIME, + .handler = sbi_ext_timeHandler, +}; diff --git a/riscv-sbi/core/extensions/hsm.c b/riscv-sbi/core/extensions/hsm.c new file mode 100644 index 00000000..29071ed7 --- /dev/null +++ b/riscv-sbi/core/extensions/hsm.c @@ -0,0 +1,92 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI HSM extension + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "atomic.h" +#include "hart.h" +#include "csr.h" + +#include "extensions/hsm.h" + + +extern u32 bootHartId; + + +long hsm_hartStart(sbi_param hartid, sbi_param startAddr, sbi_param opaque) +{ + sbi_perHartData_t *data; + int state; + + if (hartid >= sbi_getHartCount()) { + return SBI_ERR_INVALID_PARAM; + } + + data = sbi_getPerHartData(hartid); + + state = atomic_cas64(&data->state, SBI_HSM_STOPPED, SBI_HSM_START_PENDING); + if (state == SBI_HSM_STARTED) { + return SBI_ERR_ALREADY_AVAILABLE; + } + + if (state != SBI_HSM_STOPPED) { + return SBI_ERR_INVALID_PARAM; + } + + ATOMIC_WRITE(&data->nextAddr, startAddr); + ATOMIC_WRITE(&data->nextArg1, opaque); + + return SBI_SUCCESS; +} + + +void __attribute__((noreturn)) hsm_hartStartJump(u32 hartid) +{ + sbi_perHartData_t *data = sbi_getPerHartData(hartid); + + if (atomic_cas64(&data->state, SBI_HSM_START_PENDING, SBI_HSM_STARTED) != SBI_HSM_START_PENDING) { + /* This should never happen */ + hart_halt(); + } + + hart_changeMode(hartid, ATOMIC_READ(&data->nextArg1), ATOMIC_READ(&data->nextAddr), PRV_S); +} + + +static void hsm_hartWait(u32 hartid) +{ + sbi_perHartData_t *data = sbi_getPerHartData(hartid); + unsigned long mie = csr_read(CSR_MIE); + + csr_clear(CSR_MIE, MIP_MSIP | MIP_MEIP); + + while (ATOMIC_READ(&data->state) != SBI_HSM_START_PENDING) { + __WFI(); + } + + csr_write(CSR_MIE, mie); +} + + +void hsm_init(u32 hartid) +{ + sbi_perHartData_t *data; + + if (hartid == bootHartId) { + data = sbi_getPerHartData(hartid); + ATOMIC_WRITE(&data->state, SBI_HSM_START_PENDING); + } + else { + hsm_hartWait(hartid); + } +} diff --git a/riscv-sbi/core/extensions/ipi.c b/riscv-sbi/core/extensions/ipi.c new file mode 100644 index 00000000..79c784a1 --- /dev/null +++ b/riscv-sbi/core/extensions/ipi.c @@ -0,0 +1,24 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * IPI handling + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "sbi.h" + + +/* TODO */ + + +void sbi_ipiInit(void) +{ +} diff --git a/riscv-sbi/core/fdt/Makefile b/riscv-sbi/core/fdt/Makefile new file mode 100644 index 00000000..fc7184a2 --- /dev/null +++ b/riscv-sbi/core/fdt/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Phoenix SBI - FDT +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)core/fdt/, fdt.o fdt-helper.o) diff --git a/riscv-sbi/core/fdt/fdt-helper.c b/riscv-sbi/core/fdt/fdt-helper.c new file mode 100644 index 00000000..a8822b45 --- /dev/null +++ b/riscv-sbi/core/fdt/fdt-helper.c @@ -0,0 +1,239 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * FDT parsing + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "fdt.h" +#include "fdt-internal.h" +#include "string.h" + + +static ssize_t fdt_findNodeByName(ssize_t offset, int *depth, const char *targetName, size_t targetNameLen, int targetDepth) +{ + const char *name; + + for (;;) { + offset = fdt_nextNode(offset, depth); + if (offset < 0) { + return offset; + } + + name = fdt_getNodeName(offset); + if ((*depth == targetDepth) && (sbi_strncmp(targetName, name, targetNameLen) == 0)) { + return offset; + } + } +} + + +static ssize_t fdt_findInCurrentNode(ssize_t offset, int *depth, const char *targetName, size_t targetNameLen, int targetDepth) +{ + const char *name; + + do { + offset = fdt_nextNode(offset, depth); + if (offset < 0) { + return offset; + } + + name = fdt_getNodeName(offset); + if ((*depth == targetDepth) && (sbi_strncmp(targetName, name, targetNameLen) == 0)) { + return offset; + } + } while (*depth >= targetDepth); + + return FDT_ENOTFOUND; +} + + +int fdt_parseCpus(void) +{ + int cpus = 0; + int depth = -1; + + ssize_t offset = fdt_findNodeByName(0, &depth, "cpus", 4, 1); + if (offset < 0) { + return offset; + } + + for (;;) { + offset = fdt_findInCurrentNode(offset, &depth, "cpu@", 4, 2); + if (offset >= 0) { + cpus++; + } + else if (offset == FDT_ENOTFOUND) { + break; + } + else { + return offset; + } + } + + return cpus; +} + + +/* Get #address-cells and #size-cells from node */ +static ssize_t fdt_getPeripheralAddressCells(ssize_t offset, int *depth, fdt_cellInfo_t *info, const char *node) +{ + static const fdt_cellInfo_t defaultCells = { .addressCells = 2, .sizeCells = 1 }; + fdt_cellInfo_t cells; + int err; + + /* Get soc node info */ + offset = fdt_findNodeByName(offset, depth, node, 4, 1); + if (offset < 0) { + return offset; + } + + err = fdt_getCellInfo(offset, &cells); + if ((err != FDT_EOK) && (err != FDT_ENOTFOUND)) { + return err; + } + + /* Make sth out of what we have */ + if (err == FDT_ENOTFOUND) { + /* No info, use default */ + sbi_memcpy(info, &defaultCells, sizeof(fdt_cellInfo_t)); + } + else { + sbi_memcpy(info, &cells, sizeof(fdt_cellInfo_t)); + } + + return offset; +} + + +static void fdt_getReg(sbi_reg_t *reg, fdt_prop_t *prop, fdt_cellInfo_t *cells) +{ + addr_t base; + size_t size; + if (cells->addressCells == 2) { + base = fdt32_to_cpu(prop->data[0]); + base <<= 32; + base |= fdt32_to_cpu(prop->data[1]); + } + else { + base = fdt32_to_cpu(prop->data[0]); + } + + if (cells->sizeCells == 2) { + size = fdt32_to_cpu(prop->data[cells->addressCells]); + size <<= 32; + size |= fdt32_to_cpu(prop->data[cells->addressCells + 1]); + } + else { + size = fdt32_to_cpu(prop->data[cells->addressCells]); + } + + reg->base = base; + reg->size = size; +} + + +static ssize_t fdt_getPeripheralReg(ssize_t offset, int *depth, sbi_reg_t *reg, const char *compatible) +{ + fdt_cellInfo_t cells; + fdt_prop_t *prop; + + offset = fdt_getPeripheralAddressCells(offset, depth, &cells, "soc"); + if (offset < 0) { + return offset; + } + + offset = fdt_findNodeByCompatible(offset, depth, compatible); + if (offset < 0) { + return offset; + } + + prop = fdt_getProperty(offset, "reg"); + if (prop == NULL) { + return FDT_EBADSTRUCT; + } + + fdt_getReg(reg, prop, &cells); + + return offset; +} + + +int fdt_getUartInfo(uart_info_t *uart, const char *compatible) +{ + ssize_t offset = 0, clockOffset = 0; + int depth = -1, clockDepth = -1; + u32 phandle; + fdt_prop_t *prop; + + offset = fdt_getPeripheralReg(offset, &depth, &uart->reg, compatible); + if (offset < 0) { + return offset; + } + + prop = fdt_getProperty(offset, "clock-frequency"); + if (prop == NULL) { + prop = fdt_getProperty(offset, "clocks"); + if (prop == NULL) { + return FDT_EBADSTRUCT; + } + + phandle = fdt32_to_cpu(*prop->data); + clockOffset = fdt_findNodeByPhandle(0, &clockDepth, phandle); + if (clockOffset < 0) { + return clockOffset; + } + + prop = fdt_getProperty(clockOffset, "clock-frequency"); + if (prop == NULL) { + return FDT_EBADSTRUCT; + } + } + uart->freq = fdt32_to_cpu(*prop->data); + + prop = fdt_getProperty(offset, "current-speed"); + if (prop != NULL) { + uart->baud = fdt32_to_cpu(*prop->data); + } + else { + uart->baud = 115200; + } + + return FDT_EOK; +} + + +int fdt_getClintInfo(clint_info_t *clint) +{ + ssize_t offset = 0; + int depth = -1; + + offset = fdt_getPeripheralReg(offset, &depth, &clint->reg, "riscv,clint0"); + if (offset < 0) { + return offset; + } + + return FDT_EOK; +} + + +const char *fdt_getModel(void) +{ + ssize_t offset = 0; + int depth = -1; + + offset = fdt_nextNode(offset, &depth); + if (offset < 0) { + return NULL; + } + + return (const char *)fdt_getProperty(offset, "model")->data; +} diff --git a/riscv-sbi/core/fdt/fdt-internal.h b/riscv-sbi/core/fdt/fdt-internal.h new file mode 100644 index 00000000..54aa8135 --- /dev/null +++ b/riscv-sbi/core/fdt/fdt-internal.h @@ -0,0 +1,75 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * FDT internal definitions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _FDT_INTERNAL_H_ +#define _FDT_INTERNAL_H_ + + +#include "types.h" + + +#define FDT_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 1 +#define FDT_END_NODE 2 +#define FDT_PROP 3 +#define FDT_NOP 4 +#define FDT_END 9 + + +#define FDT_EOK 0 +#define FDT_EBADOFFS -1 +#define FDT_EBADSTRUCT -2 +#define FDT_EEND -3 +#define FDT_ENODEEND -4 +#define FDT_ENOTFOUND -5 + + +#define fdt32_to_cpu(x) (__builtin_bswap32(x)) +#define fdt64_to_cpu(x) (__builtin_bswap64(x)) + + +typedef struct { + u32 token; + u32 len; + u32 nameoff; + u32 data[]; +} __attribute__((packed, aligned(4))) fdt_prop_t; + + +typedef struct { + u32 addressCells; + u32 sizeCells; +} __attribute__((packed, aligned(4))) fdt_cellInfo_t; + + +ssize_t fdt_nextNode(ssize_t offset, int *depth); + + +const char *fdt_getNodeName(ssize_t offset); + + +fdt_prop_t *fdt_getProperty(ssize_t offset, const char *name); + + +ssize_t fdt_findNodeByCompatible(ssize_t offset, int *depth, const char *compatible); + + +ssize_t fdt_findNodeByPhandle(ssize_t offset, int *depth, u32 phandle); + + +int fdt_getCellInfo(ssize_t offset, fdt_cellInfo_t *info); + + +#endif diff --git a/riscv-sbi/core/fdt/fdt.c b/riscv-sbi/core/fdt/fdt.c new file mode 100644 index 00000000..8cc5e011 --- /dev/null +++ b/riscv-sbi/core/fdt/fdt.c @@ -0,0 +1,293 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * FDT parsing + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "fdt-internal.h" +#include "string.h" + + +#define CEIL(x, y) (((x) + (y) - 1) & ~((y) - 1)) + + +typedef struct { + u32 magic; + u32 totalsize; + u32 off_dt_struct; + u32 off_dt_strings; + u32 off_mem_rsvmap; + u32 version; + u32 last_comp_version; + u32 boot_cpuid_phys; + u32 size_dt_strings; + u32 size_dt_struct; +} __attribute__((packed, aligned(4))) fdt_header_t; + + +static struct { + const void *fdt; + const void *dt_struct; + const void *dt_strings; +} fdt_common; + + +static const void *fdt_get_off_dt_struct(const void *fdt) +{ + fdt_header_t *header = (fdt_header_t *)fdt; + + return (u8 *)fdt + fdt32_to_cpu(header->off_dt_struct); +} + + +static const void *fdt_get_off_dt_strings(const void *fdt) +{ + fdt_header_t *header = (fdt_header_t *)fdt; + + return (u8 *)fdt + fdt32_to_cpu(header->off_dt_strings); +} + + +static u32 fdt_consumeProp(const u32 *pos) +{ + const fdt_prop_t *p = (const fdt_prop_t *)pos; + + return sizeof(*p) + CEIL(fdt32_to_cpu(p->len), sizeof(u32)); +} + + +static const u32 *fdt_tryConsumeNode(const u32 *pos, ssize_t offset, int *depth) +{ + u8 *p; + + if (fdt32_to_cpu(*pos) == FDT_BEGIN_NODE) { + if ((depth != NULL) && (offset == 0)) { + (*depth)++; + } + pos++; + p = (u8 *)pos; + /* Consume node name */ + while (*p++ != '\0') { } + pos = (void *)CEIL((addr_t)p, sizeof(u32)); + } + + return pos; +} + + +/* Returns the offset of the next node in the device tree */ +ssize_t fdt_nextNode(ssize_t offset, int *depth) +{ + const u32 *nextPos = (u32 *)((u8 *)fdt_common.dt_struct + offset); + const u32 *pos; + u32 token; + + if ((size_t)offset >= (fdt32_to_cpu(((fdt_header_t *)fdt_common.fdt)->size_dt_struct)) || ((offset % sizeof(u32)) != 0)) { + return FDT_EBADOFFS; + } + + if ((offset != 0) && (fdt32_to_cpu(*nextPos) != FDT_BEGIN_NODE)) { + return FDT_EBADOFFS; + } + + nextPos = fdt_tryConsumeNode(nextPos, offset, depth); + + do { + pos = nextPos; + token = fdt32_to_cpu(*nextPos++); + switch (token) { + case FDT_BEGIN_NODE: + (*depth)++; + break; + + case FDT_END_NODE: + if (*depth < 0) { + return FDT_EBADSTRUCT; + } + (*depth)--; + break; + + case FDT_END: + return FDT_EEND; + + case FDT_PROP: + nextPos = (u32 *)((addr_t)pos + fdt_consumeProp(pos)); + break; + + case FDT_NOP: + default: + break; + } + } while (token != FDT_BEGIN_NODE); + + return (ssize_t)((addr_t)pos - (addr_t)fdt_common.dt_struct); +} + + +const char *fdt_getNodeName(ssize_t offset) +{ + const u32 *pos = (u32 *)((u8 *)fdt_common.dt_struct + offset); + if (fdt32_to_cpu(*pos) != FDT_BEGIN_NODE) { + return NULL; + } + + return (const char *)(pos + 1); +} + + +/* Returns offset of the property with given name in current node */ +static ssize_t fdt_getPropertyByName(ssize_t offset, const char *name) +{ + const u32 *nextPos = (u32 *)((u8 *)fdt_common.dt_struct + offset); + const u32 *pos; + fdt_prop_t *prop; + const char *propName; + u32 token; + + nextPos = fdt_tryConsumeNode(nextPos, offset, NULL); + + for (;;) { + pos = nextPos; + token = fdt32_to_cpu(*nextPos++); + switch (token) { + case FDT_PROP: + prop = (fdt_prop_t *)pos; + propName = fdt_common.dt_strings + fdt32_to_cpu(prop->nameoff); + if (sbi_strcmp(propName, name) == 0) { + return (ssize_t)((addr_t)pos - (addr_t)fdt_common.dt_struct); + } + nextPos = (u32 *)((addr_t)pos + fdt_consumeProp(pos)); + break; + + case FDT_BEGIN_NODE: + case FDT_END_NODE: + case FDT_END: + return FDT_ENOTFOUND; + + case FDT_NOP: + default: + break; + } + } +} + + +fdt_prop_t *fdt_getProperty(ssize_t offset, const char *name) +{ + ssize_t propOffset = fdt_getPropertyByName(offset, name); + if (propOffset < 0) { + return NULL; + } + + return (fdt_prop_t *)((u8 *)fdt_common.dt_struct + propOffset); +} + + +ssize_t fdt_findNodeByCompatible(ssize_t offset, int *depth, const char *compatible) +{ + fdt_prop_t *prop; + ssize_t propOffset; + size_t propLen; + const char *propData, *currStr; + + offset = fdt_nextNode(offset, depth); + if (offset < 0) { + return offset; + } + + while (offset >= 0) { + propOffset = fdt_getPropertyByName(offset, "compatible"); + if (propOffset >= 0) { + prop = (fdt_prop_t *)((u8 *)fdt_common.dt_struct + propOffset); + propData = (const char *)prop->data; + propLen = fdt32_to_cpu(prop->len); + + currStr = propData; + while (currStr < propData + propLen) { + if (sbi_strcmp(currStr, compatible) == 0) { + return offset; + } + currStr += sbi_strlen(currStr) + 1; + } + } + offset = fdt_nextNode(offset, depth); + } + + return FDT_ENOTFOUND; +} + + +ssize_t fdt_findNodeByPhandle(ssize_t offset, int *depth, u32 phandle) +{ + fdt_prop_t *prop; + ssize_t propOffset; + const u32 *propData; + u32 propLen; + + offset = fdt_nextNode(offset, depth); + if (offset < 0) { + return offset; + } + + while (offset >= 0) { + propOffset = fdt_getPropertyByName(offset, "phandle"); + if (propOffset >= 0) { + prop = (fdt_prop_t *)((u8 *)fdt_common.dt_struct + propOffset); + propData = prop->data; + propLen = fdt32_to_cpu(prop->len); + + if (propLen == sizeof(u32) && fdt32_to_cpu(*propData) == phandle) { + return offset; + } + } + offset = fdt_nextNode(offset, depth); + } + + return FDT_ENOTFOUND; +} + + +int fdt_getCellInfo(ssize_t offset, fdt_cellInfo_t *info) +{ + ssize_t propOffset; + fdt_prop_t *prop; + const u32 *pos = (u32 *)((u8 *)fdt_common.dt_struct + offset); + + if (fdt32_to_cpu(*pos) != FDT_BEGIN_NODE) { + return FDT_EBADOFFS; + } + + propOffset = fdt_getPropertyByName(offset, "#address-cells"); + if (propOffset < 0) { + return propOffset; + } + prop = (fdt_prop_t *)((u8 *)fdt_common.dt_struct + propOffset); + info->addressCells = fdt32_to_cpu(*prop->data); + + propOffset = fdt_getPropertyByName(offset, "#size-cells"); + if (propOffset < 0) { + return propOffset; + } + + prop = (fdt_prop_t *)((u8 *)fdt_common.dt_struct + propOffset); + info->sizeCells = fdt32_to_cpu(*prop->data); + + return FDT_EOK; +} + + +void fdt_init(const void *fdt) +{ + fdt_common.fdt = fdt; + fdt_common.dt_struct = fdt_get_off_dt_struct(fdt); + fdt_common.dt_strings = fdt_get_off_dt_strings(fdt); +} diff --git a/riscv-sbi/core/hart.c b/riscv-sbi/core/hart.c new file mode 100644 index 00000000..0f0d71a3 --- /dev/null +++ b/riscv-sbi/core/hart.c @@ -0,0 +1,72 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * HART features + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "csr.h" +#include "hart.h" + + +void __attribute__((noreturn)) hart_halt(void) +{ + while (1) { + __WFI(); + } + __builtin_unreachable(); +} + + +void __attribute__((noreturn)) hart_changeMode(sbi_param arg0, sbi_param arg1, addr_t nextAddr, sbi_param nextMode) +{ + unsigned long v = csr_read(CSR_MSTATUS); + + v = (v & ~(MSTATUS_MPP | MSTATUS_MIE)) | (nextMode << 11); + + csr_write(CSR_MSTATUS, v); + csr_write(CSR_MEPC, nextAddr); + csr_write(CSR_STVEC, nextAddr); + csr_write(CSR_SSCRATCH, 0); + csr_write(CSR_SIE, 0); + csr_write(CSR_SATP, 0); + + /* clang-format off */ + __asm__ volatile( + "mv a0, %0\n\t" + "mv a1, %1\n\t" + "mret" + : + : "r"(arg0), "r"(arg1) + : "a0", "a1" + ); + /* clang-format on */ + + __builtin_unreachable(); +} + + +void hart_init(void) +{ + /* Enable counters for supervisor */ + csr_write(CSR_MCOUNTEREN, -1); + + /* Enable IR, TM, CY counters for user */ + csr_write(CSR_SCOUNTEREN, 0x7); + + /* Delegate supervisor software, timer and external interrupts to S-Mode */ + csr_write(CSR_MIDELEG, 0x222); + + /* Delegate most exceptions to S-Mode + * Change this if we want to emulate some functionality in M-Mode + */ + csr_write(CSR_MEDELEG, 0xb1fb); +} diff --git a/riscv-sbi/core/interrupts.c b/riscv-sbi/core/interrupts.c new file mode 100644 index 00000000..9b777cf6 --- /dev/null +++ b/riscv-sbi/core/interrupts.c @@ -0,0 +1,41 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Interrupt handling + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "csr.h" +#include "devices/clint.h" + + +void interrupts_dispatch(unsigned int irq) +{ + switch (irq) { + case IRQ_M_SOFT: + /* TODO: handle IPI */ + break; + + case IRQ_M_TIMER: + clint_timerIrqHandler(); + break; + } +} + + +void interrupts_initHart(void) +{ +} + + +void interrupts_init(void) +{ +} diff --git a/riscv-sbi/core/sbi.c b/riscv-sbi/core/sbi.c new file mode 100644 index 00000000..97ee975d --- /dev/null +++ b/riscv-sbi/core/sbi.c @@ -0,0 +1,115 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI functions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include "hart.h" +#include "csr.h" +#include "fdt.h" +#include "sbi.h" + +#include "devices/clint.h" +#include "devices/console.h" + +#include "extensions/hsm.h" + +#include "ld/noelv.ldt" + + +extern const void *__payload_start; + +/* Anchors for section which contains extension entries */ +extern const sbi_ext_t __ext_start[]; +extern const sbi_ext_t __ext_end[]; + + +volatile u32 hartMask; + + +static struct { + volatile u32 hartCount; + sbi_perHartData_t perHartData[MAX_HART_COUNT] __attribute__((aligned(8))); +} sbi_common; + + +sbiret_t sbi_dispatchEcall(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid, int eid) +{ + const sbi_ext_t *ext; + + sbiret_t ret = { + .error = SBI_ERR_NOT_SUPPORTED, + .value = 0 + }; + + for (ext = __ext_start; ext < __ext_end; ext++) { + if (ext->eid == eid) { + ret = ext->handler(a0, a1, a2, a3, a4, a5, fid); + break; + } + } + + return ret; +} + + +sbi_perHartData_t *sbi_getPerHartData(u32 hartid) +{ + return &sbi_common.perHartData[hartid]; +} + + +u32 sbi_getHartCount(void) +{ + return sbi_common.hartCount; +} + + +void sbi_scratchInit(u32 hartid, const void *fdt, addr_t sp) +{ + sbi_perHartData_t *data = &sbi_common.perHartData[hartid]; + data->mstack = sp; + data->state = SBI_HSM_STOPPED; + data->nextAddr = (addr_t)&__payload_start; + data->nextArg1 = (addr_t)fdt; + RISCV_FENCE(w, rw); + csr_write(CSR_MSCRATCH, data); +} + + +void __attribute__((noreturn)) sbi_initCold(u32 hartid, const void *fdt) +{ + fdt_init(fdt); + + sbi_common.hartCount = fdt_parseCpus(); + + hsm_init(hartid); + + hart_init(); + console_init(); + clint_init(); + + console_print("Phoenix SBI\n"); + + hsm_hartStartJump(hartid); +} + + +void __attribute__((noreturn)) sbi_initWarm(u32 hartid) +{ + hsm_init(hartid); + + hart_init(); + + hsm_hartStartJump(hartid); +} diff --git a/riscv-sbi/core/string.c b/riscv-sbi/core/string.c new file mode 100644 index 00000000..107d7504 --- /dev/null +++ b/riscv-sbi/core/string.c @@ -0,0 +1,156 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * String functions + * + * Copyright 2012, 2024 Phoenix Systems + * Copyright 2001, 2005-2006 Pawel Pisarczyk + * Author: Pawel Pisarczyk, Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "string.h" + + +int sbi_memcmp(const void *ptr1, const void *ptr2, size_t num) +{ + int i; + + for (i = 0; i < num; ++i) { + if (((const u8 *)ptr1)[i] < ((const u8 *)ptr2)[i]) { + return -1; + } + else if (((const u8 *)ptr1)[i] > ((const u8 *)ptr2)[i]) { + return 1; + } + } + + return 0; +} + + +size_t sbi_strlen(const char *s) +{ + size_t k; + + for (k = 0; *s != '\0'; s++, k++) { + } + + return k; +} + + +int sbi_strcmp(const char *s1, const char *s2) +{ + const unsigned char *us1 = (const unsigned char *)s1; + const unsigned char *us2 = (const unsigned char *)s2; + const unsigned char *p; + unsigned int k; + + for (p = us1, k = 0; *p != '\0'; p++, k++) { + + if (*p < *(us2 + k)) { + return -1; + } + else if (*p > *(us2 + k)) { + return 1; + } + } + + if (*p != *(us2 + k)) { + return -1; + } + + return 0; +} + + +int sbi_strncmp(const char *s1, const char *s2, size_t count) +{ + const unsigned char *us1 = (const unsigned char *)s1; + const unsigned char *us2 = (const unsigned char *)s2; + size_t k; + + for (k = 0; (k < count) && (*us1 != '\0') && (*us2 != '\0') && (*us1 == *us2); ++k, ++us1, ++us2) { + } + + if ((k == count) || ((*us1 == '\0') && (*us2 == '\0'))) { + return 0; + } + + return (*us1 < *us2) ? (-k - 1) : (k + 1); +} + + +char *sbi_strcpy(char *dest, const char *src) +{ + int i = 0; + + do { + dest[i] = src[i]; + } while (src[i++] != '\0'); + + return dest; +} + + +char *sbi_strncpy(char *dest, const char *src, size_t n) +{ + int i = 0; + + if (n == 0) { + return dest; + } + + do { + dest[i] = src[i]; + i++; + } while ((i < n) && (src[i - 1] != '\0')); + + return dest; +} + + +char *sbi_strchr(const char *s, int c) +{ + do { + if (*s == c) { + return (char *)s; + } + } while (*s++ != '\0'); + + return NULL; +} + + +int sbi_i2s(char *prefix, char *s, unsigned long i, unsigned char b, char zero) +{ + static const char digits[] = "0123456789abcdef"; + char c; + unsigned long l, k, m; + + m = sbi_strlen(prefix); + sbi_memcpy(s, prefix, m); + + for (k = m, l = (unsigned long)-1; l != 0; i /= b, l /= b) { + if (!zero && !i) { + break; + } + s[k++] = digits[i % b]; + } + + l = k--; + + while (k > m) { + c = s[m]; + s[m++] = s[k]; + s[k--] = c; + } + + return l; +} diff --git a/riscv-sbi/devices/Makefile b/riscv-sbi/devices/Makefile new file mode 100644 index 00000000..e5dd308c --- /dev/null +++ b/riscv-sbi/devices/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Phoenix SBI - FDT +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)devices/, clint.o console.o uart-16550.o uart-grlib.o) diff --git a/riscv-sbi/devices/clint.c b/riscv-sbi/devices/clint.c new file mode 100644 index 00000000..f8b28d5d --- /dev/null +++ b/riscv-sbi/devices/clint.c @@ -0,0 +1,70 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * CLINT driver + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include "csr.h" +#include "fdt.h" +#include "types.h" + +#include "devices/clint.h" + + +#define CLINT_MSIP(hartid) (0x0 + 4 * (hartid)) +#define CLINT_MTIMECMP(hartid) (0x4000 + 8 * (hartid)) +#define CLINT_MTIMER 0xbff8 + + +static struct { + addr_t base; +} clint_common; + + +void clint_timerIrqHandler(void) +{ + /* Disable MTIMER interrupt */ + csr_clear(CSR_MIE, MIP_MTIP); + + /* Set STIMER interrupt pending */ + csr_set(CSR_MIP, MIP_STIP); +} + + +void clint_setTimecmp(u64 time) +{ + u32 hartid = csr_read(CSR_MHARTID); + + *((vu64 *)(clint_common.base + CLINT_MTIMECMP(hartid))) = time; + + csr_clear(CSR_MIP, MIP_STIP); + + csr_set(CSR_MIE, MIP_MTIP); +} + + +u64 clint_getTime(void) +{ + return *((vu64 *)(clint_common.base + CLINT_MTIMER)); +} + + +void clint_init(void) +{ + clint_info_t info; + + if (fdt_getClintInfo(&info) < 0) { + return; + } + clint_common.base = info.reg.base; +} diff --git a/riscv-sbi/devices/console.c b/riscv-sbi/devices/console.c new file mode 100644 index 00000000..2dd15e9d --- /dev/null +++ b/riscv-sbi/devices/console.c @@ -0,0 +1,54 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Console driver + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include "devices/console.h" + + +extern const uart_driver_t __uart_start[], __uart_end[]; + + +static struct { + const uart_driver_t *drv; +} console_common; + + +void console_putc(char c) +{ + if (console_common.drv != NULL) { + console_common.drv->putc(c); + } +} + + +void console_print(const char *s) +{ + while (*s != '\0') { + console_putc(*s++); + } +} + + +void console_init(void) +{ + const uart_driver_t *drv; + + for (drv = __uart_start; drv < __uart_end; drv++) { + if (drv->init(drv->compatible) == 0) { + console_common.drv = drv; + break; + } + } +} diff --git a/riscv-sbi/devices/uart-16550.c b/riscv-sbi/devices/uart-16550.c new file mode 100644 index 00000000..13239f49 --- /dev/null +++ b/riscv-sbi/devices/uart-16550.c @@ -0,0 +1,112 @@ +// implement uart-16550 driver, only for writing and no interrupts + +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates. + * + * Authors: + * Anup Patel + */ + +#include "fdt.h" +#include "hart.h" +#include "types.h" + +#include "devices/console.h" + + +typedef struct { + unsigned int speed; + unsigned int divisor; + unsigned char mode; +} baud_t; + + +/* UART 16550 registers */ +enum { + rbr = 0, /* Receiver Buffer Register */ + thr = 0, /* Transmitter Holding Register */ + dll = 0, /* Divisor Latch LSB */ + ier = 1, /* Interrupt Enable Register */ + dlm = 1, /* Divisor Latch MSB */ + iir = 2, /* Interrupt Identification Register */ + fcr = 2, /* FIFO Control Register */ + lcr = 3, /* Line Control Register */ + mcr = 4, /* Modem Control Register */ + lsr = 5, /* Line Status Register */ + msr = 6, /* Modem Status Register */ + spr = 7, /* Scratch Pad Register */ +}; + + +static struct { + volatile u8 *base; +} uart16550_common; + + +static void setReg(u8 reg, u8 val) +{ + *(uart16550_common.base + reg) = val; + RISCV_FENCE(w, o); +} + + +static u8 readReg(u8 reg) +{ + u8 val = *(uart16550_common.base + reg); + RISCV_FENCE(i, r); + return val; +} + + +static void uart16550_putc(char c) +{ + /* Wait until THR is empty */ + while ((readReg(lsr) & 0x40) == 0) { } + setReg(thr, c); +} + + +static int uart16550_init(const char *compatible) +{ + u16 bdiv; + uart_info_t info; + if (fdt_getUartInfo(&info, compatible) < 0) { + return -1; + } + uart16550_common.base = (vu8 *)info.reg.base; + bdiv = (info.freq + 8 * info.baud) / (16 * info.baud); + + /* Disable all interrupts */ + setReg(ier, 0x00); + + /* Set speed */ + setReg(lcr, 0x80); + setReg(dll, bdiv & 0xff); + setReg(dlm, (bdiv >> 8) & 0xff); + + /* 8 bits, no parity, one stop bit */ + setReg(lcr, 0x03); + + /* Enable FIFO */ + setReg(fcr, 0xa7); + + /* No modem control DTR RTS */ + setReg(mcr, 0x00); + + /* Clear line status */ + readReg(lsr); + /* Read receive buffer */ + readReg(rbr); + /* Set scratchpad */ + setReg(spr, 0x00); + + return 0; +} + + +static const uart_driver_t uart_16550[] __attribute__((section("uart_drivers"), used)) = { + { .compatible = "ns16550a", .init = uart16550_init, .putc = uart16550_putc }, + { .compatible = "ns16550", .init = uart16550_init, .putc = uart16550_putc }, +}; diff --git a/riscv-sbi/devices/uart-grlib.c b/riscv-sbi/devices/uart-grlib.c new file mode 100644 index 00000000..5873b79d --- /dev/null +++ b/riscv-sbi/devices/uart-grlib.c @@ -0,0 +1,75 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * GRLIB UART driver + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "hart.h" +#include "fdt.h" +#include "types.h" + +#include "devices/console.h" + + +/* UART control bits */ +#define TX_EN (1 << 1) +#define TX_FIFO_FULL (1 << 9) + +enum { + uart_data, /* Data register : 0x00 */ + uart_status, /* Status register : 0x04 */ + uart_ctrl, /* Control register : 0x08 */ + uart_scaler, /* Scaler reload register : 0x0C */ + uart_dbg /* FIFO debug register : 0x10 */ +}; + + +static struct { + volatile u32 *base; +} uart_grlib_common; + + +static void uart_grlib_putc(char c) +{ + while ((*(uart_grlib_common.base + uart_status) & TX_FIFO_FULL) != 0) { } + *(uart_grlib_common.base + uart_data) = c; +} + + +static u32 uart_grlib_calcScaler(u32 freq, u32 baud) +{ + return (freq / (baud * 8 + 7)); +} + + +static int uart_grlib_init(const char *compatible) +{ + uart_info_t info; + if (fdt_getUartInfo(&info, compatible) < 0) { + return -1; + } + uart_grlib_common.base = (vu32 *)info.reg.base; + *(uart_grlib_common.base + uart_ctrl) = 0; + RISCV_FENCE(w, o); + *(uart_grlib_common.base + uart_scaler) = uart_grlib_calcScaler(info.freq, info.baud); + RISCV_FENCE(w, o); + *(uart_grlib_common.base + uart_ctrl) = TX_EN; + + return 0; +} + + +static const uart_driver_t uart_grlib __attribute__((section("uart_drivers"), used)) = { + .compatible = "gaisler,apbuart", + .init = uart_grlib_init, + .putc = uart_grlib_putc +}; diff --git a/riscv-sbi/entry.c b/riscv-sbi/entry.c new file mode 100644 index 00000000..257ffd1a --- /dev/null +++ b/riscv-sbi/entry.c @@ -0,0 +1,32 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Main + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "csr.h" +#include "sbi.h" +#include "types.h" + + +volatile u32 bootHartId; + + +void __attribute__((noreturn)) entry(u32 hartid, const void *fdt) +{ + if (hartid == bootHartId) { + sbi_initCold(hartid, fdt); + } + else { + sbi_initWarm(hartid); + } +} diff --git a/riscv-sbi/include/atomic.h b/riscv-sbi/include/atomic.h new file mode 100644 index 00000000..76853952 --- /dev/null +++ b/riscv-sbi/include/atomic.h @@ -0,0 +1,85 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Atomic operations + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_ATOMIC_H_ +#define _SBI_ATOMIC_H_ + + +#include "hart.h" +#include "types.h" + + +static inline u64 atomic_cas64(vu64 *ptr, u64 old, u64 new) +{ + u64 prev; + + /* clang-format off */ + __asm__ volatile ( + "1:\n\t" + "lr.d.aqrl %0, (%2)\n\t" + "bne %0, %3, 2f\n\t" + "sc.d.rl %1, %4, (%2)\n\t" + "bnez %1, 1b\n\t" + "2:\n\t" + : "=&r" (prev), "=&r" (old), "+r" (ptr) + : "r" (old), "r" (new) + : "memory" + ); + /* clang-format on */ + + return prev; +} + + +static inline void atomic_add32(vu32 *ptr, u32 val) +{ + /* clang-format off */ + __asm__ volatile ( + "amoadd.w.aq zero, %1, (%0)" + : "+r" (ptr) + : "r" (val) + : "memory" + ); + /* clang-format on */ +} + + +static inline void atomic_add64(vu64 *ptr, u64 val) +{ + /* clang-format off */ + __asm__ volatile ( + "amoadd.d.aq zero, %1, (%0)" + : "+r" (ptr) + : "r" (val) + : "memory" + ); + /* clang-format on */ +} + + +#define ATOMIC_READ(ptr) ({ \ + typeof(*ptr) ret = *ptr; \ + RISCV_FENCE(ir, ir); \ + ret; \ +}) + + +#define ATOMIC_WRITE(ptr, val) ({ \ + *ptr = val; \ + RISCV_FENCE(ow, ow); \ +}) + + +#endif diff --git a/riscv-sbi/include/csr.h b/riscv-sbi/include/csr.h new file mode 100644 index 00000000..7197277e --- /dev/null +++ b/riscv-sbi/include/csr.h @@ -0,0 +1,176 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * CSR definitions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_CSR_H_ +#define _SBI_CSR_H_ + + +#ifndef __ASSEMBLY__ + + +#include "types.h" + + +/* clang-format off */ + +#define csr_set(csr, val) \ + ({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ volatile ( \ + "csrs %0, %1" \ + :: "i"(csr), "rK"(__v) \ + : "memory"); \ + __v; \ + }) + + +#define csr_write(csr, val) \ + ({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ volatile ( \ + "csrw %0, %1" \ + :: "i"(csr), "rK"(__v) \ + : "memory"); \ + }) + + +#define csr_clear(csr, val) \ + ({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ volatile ( \ + "csrc %0, %1" \ + ::"i"(csr), "rK"(__v) \ + : "memory"); \ + }) + + +#define csr_read(csr) \ + ({ \ + register unsigned long __v; \ + __asm__ volatile ( \ + "csrr %0, %1" \ + : "=r"(__v) \ + : "i"(csr) \ + :"memory"); \ + __v; \ + }) + +/* clang-format on */ + + +int csr_emulateRead(u32 csr, u64 *val); + + +int csr_emulateWrite(u32 csr, u64 val); + + +#endif /* __ASSEMBLY__ */ + + +/* Interrupt numbers */ + +#define IRQ_S_SOFT 1 +#define IRQ_M_SOFT 3 +#define IRQ_S_TIMER 5 +#define IRQ_M_TIMER 7 +#define IRQ_S_EXT 9 +#define IRQ_M_EXT 11 +#define IRQ_PMU_OVF 13 + +/* Unprivileged CSRs */ + +#define CSR_CYCLE 0xc00u +#define CSR_TIME 0xc01u +#define CSR_INSTRET 0xc02u + +/* Supervisor CSRs */ + +#define CSR_SSTATUS 0x100u +#define CSR_SIE 0x104u +#define CSR_STVEC 0x105u +#define CSR_SCOUNTEREN 0x106u +#define CSR_SSCRATCH 0x140u +#define CSR_SATP 0x180u + +#define CSR_SEPC 0x141u +#define CSR_SCAUSE 0x142u +#define CSR_STVAL 0x143u +#define CSR_SIP 0x144u + +/* Machine CSRs */ + +#define CSR_MSTATUS 0x300u +#define CSR_MISA 0x301u +#define CSR_MEDELEG 0x302u +#define CSR_MIDELEG 0x303u +#define CSR_MIE 0x304u +#define CSR_MTVEC 0x305u +#define CSR_MCOUNTEREN 0x306u +#define CSR_MENVCFG 0x30au + +#define CSR_MSCRATCH 0x340u +#define CSR_MEPC 0x341u +#define CSR_MCAUSE 0x342u +#define CSR_MTVAL 0x343u +#define CSR_MIP 0x344u +#define CSR_MTINST 0x34au + +#define CSR_MCYCLE 0xb00u +#define CSR_MINSTRET 0xb02u + +#define CSR_MVENDORID 0xf11u +#define CSR_MARCHID 0xf12u +#define CSR_MIMPID 0xf13u +#define CSR_MHARTID 0xf14u + +/* Machine memory protection */ + +#define CSR_PMPCFG0 0x3a0u +#define CSR_PMPADDR0 0x3b0u + +/* CSR bits */ + +#define MSTATUS_MPP_SHIFT 11 + +#define MSTATUS_SIE (1UL << 1) +#define MSTATUS_MIE (1UL << 3) +#define MSTATUS_SPIE (1UL << 5) +#define MSTATUS_MPIE (1UL << 7) +#define MSTATUS_SPP (1UL << 8) +#define MSTATUS_MPP (3UL << MSTATUS_MPP_SHIFT) + +#define MIE_MSIE (1UL << 3) + +#define MIP_SSIP (1UL << IRQ_S_SOFT) +#define MIP_MSIP (1UL << IRQ_M_SOFT) +#define MIP_STIP (1UL << IRQ_S_TIMER) +#define MIP_MTIP (1UL << IRQ_M_TIMER) +#define MIP_SEIP (1UL << IRQ_S_EXT) +#define MIP_MEIP (1UL << IRQ_M_EXT) + +#define MCAUSE_IRQ_MSK 0xffUL + +#define MCAUSE_ILLEGAL 0x2UL +#define MCAUSE_S_ECALL 0x9UL +#define MCAUSE_INTR (1UL << 63) + +/* Privilege levels */ + +#define PRV_U 0UL +#define PRV_S 1UL +#define PRV_M 3UL + + +#endif diff --git a/riscv-sbi/include/devices/clint.h b/riscv-sbi/include/devices/clint.h new file mode 100644 index 00000000..3a072aee --- /dev/null +++ b/riscv-sbi/include/devices/clint.h @@ -0,0 +1,40 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * CLINT driver + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_DEVICES_CLINT_H_ +#define _SBI_DEVICES_CLINT_H_ + + +#include "peripherals.h" + + +typedef struct { + sbi_reg_t reg; +} clint_info_t; + + +void clint_timerIrqHandler(void); + + +void clint_setTimecmp(u64 time); + + +u64 clint_getTime(void); + + +void clint_init(void); + + +#endif \ No newline at end of file diff --git a/riscv-sbi/include/devices/console.h b/riscv-sbi/include/devices/console.h new file mode 100644 index 00000000..abd75dd6 --- /dev/null +++ b/riscv-sbi/include/devices/console.h @@ -0,0 +1,46 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Console driver + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_DEVICES_CONSOLE_H_ +#define _SBI_DEVICES_CONSOLE_H_ + + +#include "peripherals.h" + + +typedef struct { + const char *compatible; + int (*init)(const char *compatible); + void (*putc)(char c); +} uart_driver_t; + + +typedef struct { + sbi_reg_t reg; + u32 freq; + u32 baud; +} uart_info_t; + + +void console_putc(char c); + + +void console_print(const char *s); + + +void console_init(void); + + +#endif \ No newline at end of file diff --git a/riscv-sbi/include/extensions/hsm.h b/riscv-sbi/include/extensions/hsm.h new file mode 100644 index 00000000..bbc55d8f --- /dev/null +++ b/riscv-sbi/include/extensions/hsm.h @@ -0,0 +1,33 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI HSM extension + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_EXT_HSM_H_ +#define _SBI_EXT_HSM_H_ + + +#include "sbi.h" +#include "types.h" + + +long hsm_hartStart(sbi_param hartid, sbi_param startAddr, sbi_param opaque); + + +void __attribute__((noreturn)) hsm_hartStartJump(u32 hartid); + + +void hsm_init(u32 hartid); + + +#endif diff --git a/riscv-sbi/include/extensions/ipi.h b/riscv-sbi/include/extensions/ipi.h new file mode 100644 index 00000000..8d2f064f --- /dev/null +++ b/riscv-sbi/include/extensions/ipi.h @@ -0,0 +1,24 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * IPI definitions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _SBI_IPI_H_ +#define _SBI_IPI_H_ + + +/* TODO */ + + +#endif diff --git a/riscv-sbi/include/fdt.h b/riscv-sbi/include/fdt.h new file mode 100644 index 00000000..637c823e --- /dev/null +++ b/riscv-sbi/include/fdt.h @@ -0,0 +1,39 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * FDT parsing + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_FDT_H_ +#define _SBI_FDT_H_ + + +#include "devices/clint.h" +#include "devices/console.h" + + +int fdt_parseCpus(void); + + +int fdt_getUartInfo(uart_info_t *uart, const char *compatible); + + +int fdt_getClintInfo(clint_info_t *clint); + + +const char *fdt_getModel(void); + + +void fdt_init(const void *fdt); + + +#endif diff --git a/riscv-sbi/include/hart.h b/riscv-sbi/include/hart.h new file mode 100644 index 00000000..8d8b68b0 --- /dev/null +++ b/riscv-sbi/include/hart.h @@ -0,0 +1,47 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * CPU related definitions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _SBI_HART_H_ +#define _SBI_HART_H_ + + +#include "sbi.h" + + +/* clang-format off */ +#define RISCV_FENCE(p, s) \ + ({ \ + __asm__ volatile ("fence " #p ", " #s ::: "memory"); \ + }) + + +#define __WFI() \ + do { \ + __asm__ volatile ("wfi" ::: "memory"); \ + } while (0) +/* clang-format on */ + + +void __attribute__((noreturn)) hart_halt(void); + + +void __attribute__((noreturn)) hart_changeMode(sbi_param ar0, sbi_param arg1, addr_t nextAddr, sbi_param nextMode); + + +void hart_init(void); + + +#endif diff --git a/riscv-sbi/include/peripherals.h b/riscv-sbi/include/peripherals.h new file mode 100644 index 00000000..be268caa --- /dev/null +++ b/riscv-sbi/include/peripherals.h @@ -0,0 +1,29 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Peripherals + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_PERIPHERALS_H_ +#define _SBI_PERIPHERALS_H_ + + +#include "types.h" + + +typedef struct { + addr_t base; + size_t size; +} sbi_reg_t; + + +#endif diff --git a/riscv-sbi/include/platform.h b/riscv-sbi/include/platform.h new file mode 100644 index 00000000..88e998d5 --- /dev/null +++ b/riscv-sbi/include/platform.h @@ -0,0 +1,31 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Platform layer + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_PLATFORM_H_ +#define _SBI_PLATFORM_H_ + + +void platform_cpuInit(void); + + +void platform_init(void); + + +/* Called very early in the boot sequence, must not depend on any other subsystems. + * May be used to initialize early CPU features, such as caches. */ +void platform_earlyInit(void); + + +#endif diff --git a/riscv-sbi/include/sbi.h b/riscv-sbi/include/sbi.h new file mode 100644 index 00000000..f9b18664 --- /dev/null +++ b/riscv-sbi/include/sbi.h @@ -0,0 +1,98 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * SBI functions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_H_ +#define _SBI_H_ + + +#define SBI_SUCCESS 0 +#define SBI_ERR_FAILED -1 +#define SBI_ERR_NOT_SUPPORTED -2 +#define SBI_ERR_INVALID_PARAM -3 +#define SBI_ERR_DENIED -4 +#define SBI_ERR_INVALID_ADDRESS -5 +#define SBI_ERR_ALREADY_AVAILABLE -6 +#define SBI_ERR_ALREADY_STARTED -7 +#define SBI_ERR_ALREADY_STOPPED -8 +#define SBI_ERR_NO_SHMEM -9 + +/* Supported SBI extensions */ + +#define SBI_EXT_BASE 0x10 +#define SBI_EXT_TIME 0x54494D45 +#define SBI_EXT_IPI 0x735049 +#define SBI_EXT_RFENCE 0x52464E43 +#define SBI_EXT_HSM 0x48534D + + +/* HSM extension: Hart states */ +#define SBI_HSM_STARTED 0 +#define SBI_HSM_STOPPED 1 +#define SBI_HSM_START_PENDING 2 +#define SBI_HSM_STOP_PENDING 3 +#define SBI_HSM_SUSPENDED 4 +#define SBI_HSM_SUSPEND_PENDING 5 +#define SBI_HSM_RESUME_PENDING 6 + + +#ifndef __ASSEMBLY__ + + +#include "types.h" + + +typedef unsigned long sbi_param; + + +typedef struct { + long error; + long value; +} sbiret_t; + + +typedef struct { + int eid; + sbiret_t (*handler)(sbi_param a0, sbi_param a1, sbi_param a2, sbi_param a3, sbi_param a4, sbi_param a5, int fid); +} sbi_ext_t; + + +typedef struct { + addr_t mstack; /* M-mode sp */ + addr_t scratch; /* temporary storage */ + volatile addr_t state; /* current hart state */ + volatile addr_t nextArg1; /* 'a1' register for next boot stage */ + volatile addr_t nextAddr; /* address of next boot stage */ +} __attribute__((packed, aligned(8))) sbi_perHartData_t; + + +sbi_perHartData_t *sbi_getPerHartData(u32 hartid); + + +u32 sbi_getHartCount(void); + + +void __attribute__((noreturn)) sbi_initCold(u32 hartid, const void *fdt); + + +void __attribute__((noreturn)) sbi_initWarm(u32 hartid); + + +#endif + + +#define SIZEOF_SBI_PERHARTDATA 48 + + +#endif diff --git a/riscv-sbi/include/string.h b/riscv-sbi/include/string.h new file mode 100644 index 00000000..f565dd77 --- /dev/null +++ b/riscv-sbi/include/string.h @@ -0,0 +1,53 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * String functions + * + * Copyright 2017, 2018, 2021, 2024 Phoenix Systems + * Author: Pawel Pisarczyk, Aleksander Kaminski, Hubert Buczynski, Lukasz Kosinski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_STRING_H_ +#define _SBI_STRING_H_ + + +#include "types.h" + + +void *sbi_memcpy(void *dst, const void *src, size_t l); + + +int sbi_memcmp(const void *ptr1, const void *ptr2, size_t num); + + +void sbi_memset(void *dst, int v, size_t l); + + +size_t sbi_strlen(const char *s); + + +int sbi_strcmp(const char *s1, const char *s2); + + +int sbi_strncmp(const char *s1, const char *s2, size_t count); + + +char *sbi_strcpy(char *dest, const char *src); + + +char *sbi_strncpy(char *dest, const char *src, size_t n); + + +char *sbi_strchr(const char *str, int z); + + +int sbi_i2s(char *prefix, char *s, unsigned long i, unsigned char b, char zero); + + +#endif diff --git a/riscv-sbi/include/types.h b/riscv-sbi/include/types.h new file mode 100644 index 00000000..1ff83eb6 --- /dev/null +++ b/riscv-sbi/include/types.h @@ -0,0 +1,47 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Types + * + * Copyright 2023, 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_TYPES_H_ +#define _SBI_TYPES_H_ + +#define NULL 0 + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; +typedef volatile unsigned long long vu64; + +typedef vu8 *reg8; +typedef vu16 *reg16; +typedef vu32 *reg32; +typedef vu64 *reg64; + +typedef u64 addr_t; +typedef u64 size_t; +typedef s64 ssize_t; +typedef unsigned long long time_t; + + +#endif diff --git a/riscv-sbi/ld/generic.ldt b/riscv-sbi/ld/generic.ldt new file mode 100644 index 00000000..cc55f66f --- /dev/null +++ b/riscv-sbi/ld/generic.ldt @@ -0,0 +1,47 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Linker Template and Platform Config for RISC-V 64 NOEL-V + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef RISCV64_GENERIC_LDT +#define RISCV64_GENERIC_LDT + +/* Platform specific definitions */ +#define MAX_HART_COUNT 8 +#define SIZE_PAGE 0x1000 +#define SIZE_STACK (MAX_HART_COUNT * SIZE_PAGE) + +#define ADDR_DDR 0x80000000 +#define SIZE_SBI 0x20000 + +#if defined(__LINKER__) + +/* Memory map setup */ +MEMORY +{ + m_ram (rwx) : ORIGIN = ADDR_DDR, LENGTH = 0x20000 + m_payload (rx) : ORIGIN = PAYLOAD_ADDR, LENGTH = 0x100000 +} + +REGION_ALIAS("SBI_IMAGE", m_ram); +REGION_ALIAS("DATA", m_ram); +REGION_ALIAS("BSS", m_ram); +REGION_ALIAS("STACK", m_ram); +REGION_ALIAS("PAYLOAD", m_payload); + +#include "riscv-common.lds" + +#endif + + +#endif diff --git a/riscv-sbi/ld/noelv.ldt b/riscv-sbi/ld/noelv.ldt new file mode 100644 index 00000000..1d827230 --- /dev/null +++ b/riscv-sbi/ld/noelv.ldt @@ -0,0 +1,47 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Linker Template and Platform Config for RISC-V 64 NOEL-V + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef RISCV64_NOELV_LDT +#define RISCV64_NOELV_LDT + +/* Platform specific definitions */ +#define MAX_HART_COUNT 8 +#define SIZE_PAGE 0x1000 +#define SIZE_STACK (MAX_HART_COUNT * SIZE_PAGE) + +#define ADDR_DDR 0x00000 +#define SIZE_SBI 0x20000 + +#if defined(__LINKER__) + +/* Memory map setup */ +MEMORY +{ + m_ram (rwx) : ORIGIN = ADDR_DDR, LENGTH = 0x20000 + m_payload (rx) : ORIGIN = PAYLOAD_ADDR, LENGTH = 0x100000 +} + +REGION_ALIAS("SBI_IMAGE", m_ram); +REGION_ALIAS("DATA", m_ram); +REGION_ALIAS("BSS", m_ram); +REGION_ALIAS("STACK", m_ram); +REGION_ALIAS("PAYLOAD", m_payload); + +#include "riscv-common.lds" + +#endif + + +#endif diff --git a/riscv-sbi/ld/riscv-common.lds b/riscv-sbi/ld/riscv-common.lds new file mode 100644 index 00000000..bd538181 --- /dev/null +++ b/riscv-sbi/ld/riscv-common.lds @@ -0,0 +1,147 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * Common Linker Script for RV64 targets + * + * Copyright 2023 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +OUTPUT_FORMAT("elf64-littleriscv", "elf64-big", "elf64-littleriscv") + +OUTPUT_ARCH(riscv) + +/* Entry point */ +ENTRY(_start) + +SECTIONS +{ + . = ORIGIN(SBI_IMAGE); + + .init : + { + __init_start = .; + KEEP (*(.init)) + __init_end = .; + } > SBI_IMAGE + + .text : + { + __text_start = .; + . = ALIGN(8); + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.eh_frame) + . = ALIGN(8); + PROVIDE_HIDDEN(__text_end = .); + } > SBI_IMAGE + + .fini : { KEEP (*(SORT_NONE(.fini))) } > SBI_IMAGE + + /* define a global symbol at end of code */ + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.srodata .srodata.*) + } > SBI_IMAGE + + /* Section dedicated for SBI extensions */ + .extensions : ALIGN(8) + { + __ext_start = .; + KEEP (*(SORT_BY_NAME(extensions))) + __ext_end = .; + } > SBI_IMAGE + + /* Section dedicated for UART drivers info */ + .uart_drivers : ALIGN(8) + { + __uart_start = .; + KEEP (*(SORT_BY_NAME(uart_drivers))) + __uart_end = .; + } > SBI_IMAGE + + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } > SBI_IMAGE + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } > SBI_IMAGE + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } > SBI_IMAGE + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } > SBI_IMAGE + + .data : ALIGN(8) + { + . = ALIGN(8); + __data_load = LOADADDR(.data); + __data_start = .; + *(.data) + *(.data*) + *(.sdata .sdata*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + __data_end = .; + _edata = .; + PROVIDE (edata = .); + } > DATA AT > SBI_IMAGE + + .bss (NOLOAD) : + { + . = ALIGN(8); + __bss_start = .; + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(.sbss .sbss.*) + *(COMMON) + . = ALIGN(8); + __bss_end = .; + } > BSS + + _end = .; + PROVIDE (end = .); + + .stack (NOLOAD) : ALIGN(8) + { + __stack_limit = .; + . += SIZE_STACK; + . = ALIGN(8); + __stack_top = .; + } > STACK + + PROVIDE(_stacksz = __stack_top - __stack_limit); + PROVIDE(_stack = __stack_top); + + _sbi_size = LOADADDR(.data) + SIZEOF(.data) - ORIGIN(SBI_IMAGE); + _sbi_load_addr = ORIGIN(SBI_IMAGE); + + .payload : ALIGN(0x1000) + { + PROVIDE(_payload_start = .); + *(.payload) + . = ALIGN(8); + PROVIDE(_payload_end = .); + } > PAYLOAD + + + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/riscv-sbi/platform/generic/Makefile b/riscv-sbi/platform/generic/Makefile new file mode 100644 index 00000000..bdeca879 --- /dev/null +++ b/riscv-sbi/platform/generic/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Phoenix SBI - platform +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)platform/$(TARGET_SUBFAMILY)/, platform.o) diff --git a/riscv-sbi/platform/generic/platform.c b/riscv-sbi/platform/generic/platform.c new file mode 100644 index 00000000..1b47de6f --- /dev/null +++ b/riscv-sbi/platform/generic/platform.c @@ -0,0 +1,29 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * NOEL-V CPU specific functions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "csr.h" + + +void platform_cpuInit(void) +{ +} + + +void platform_cpuEarlyInit(void) +{ + /* Quick and dirty PMP configuration: full memory range RWX for S/U */ + csr_write(CSR_PMPADDR0, -1); + csr_write(CSR_PMPCFG0, 0x0f); +} diff --git a/riscv-sbi/platform/noelv/Makefile b/riscv-sbi/platform/noelv/Makefile new file mode 100644 index 00000000..bdeca879 --- /dev/null +++ b/riscv-sbi/platform/noelv/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Phoenix SBI - platform +# +# Copyright 2024 Phoenix Systems +# +# %LICENSE% +# + +OBJS += $(addprefix $(PREFIX_O)platform/$(TARGET_SUBFAMILY)/, platform.o) diff --git a/riscv-sbi/platform/noelv/custom-csr.h b/riscv-sbi/platform/noelv/custom-csr.h new file mode 100644 index 00000000..bd2b4f3d --- /dev/null +++ b/riscv-sbi/platform/noelv/custom-csr.h @@ -0,0 +1,24 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * NOEL-V custom CSR definitions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SBI_NOELV_CUSTOM_CSR_H_ +#define _SBI_NOELV_CUSTOM_CSR_H_ + + +#define CSR_FEATURES 0x7c0 +#define CSR_CCTRL 0x7c1 + + +#endif diff --git a/riscv-sbi/platform/noelv/platform.c b/riscv-sbi/platform/noelv/platform.c new file mode 100644 index 00000000..202eb681 --- /dev/null +++ b/riscv-sbi/platform/noelv/platform.c @@ -0,0 +1,32 @@ +/* + * Phoenix-RTOS + * + * Phoenix SBI + * + * NOEL-V CPU specific functions + * + * Copyright 2024 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "csr.h" +#include "custom-csr.h" + + +void platform_cpuInit(void) +{ + /* Enable execution of cache management instructions */ + csr_write(CSR_MENVCFG, 0xffu); +} + + +void platform_cpuEarlyInit(void) +{ + csr_write(CSR_MENVCFG, 0xffu); + /* Enable I & D-cache and snooping */ + csr_write(CSR_CCTRL, (1 << 8) | 0xf); +}