diff options
Diffstat (limited to 'riscv/riscv-probe/libfemto/arch')
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/auxval.c | 15 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/csr.c | 284 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/device.c | 53 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/memory.c | 50 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/pmp.c | 191 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/spinlock.c | 142 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/start.c | 21 | ||||
| -rw-r--r-- | riscv/riscv-probe/libfemto/arch/riscv/trap.c | 65 |
8 files changed, 821 insertions, 0 deletions
diff --git a/riscv/riscv-probe/libfemto/arch/riscv/auxval.c b/riscv/riscv-probe/libfemto/arch/riscv/auxval.c new file mode 100644 index 0000000..eff10d3 --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/auxval.c @@ -0,0 +1,15 @@ +// See LICENSE for license details. + +#include "femto.h" + +unsigned long getauxval(unsigned long key) +{ + auxval_t *auxv = __auxv; + while(auxv->key) { + if (auxv->key == key) { + return auxv->val; + } + auxv++; + } + return 0; +} diff --git a/riscv/riscv-probe/libfemto/arch/riscv/csr.c b/riscv/riscv-probe/libfemto/arch/riscv/csr.c new file mode 100644 index 0000000..673e87e --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/csr.c @@ -0,0 +1,284 @@ +// See LICENSE for license details. + +#include "femto.h" +#include "arch/riscv/csr.h" +#include "arch/riscv/encoding.h" +#include "arch/riscv/machine.h" + +static int all_csr_enums[] = { + csr_fflags, + csr_frm, + csr_fcsr, + csr_mcycle, + csr_minstret, + csr_mcycleh, + csr_minstreth, + csr_cycle, + csr_time, + csr_instret, + csr_cycleh, + csr_timeh, + csr_instreth, + csr_mvendorid, + csr_marchid, + csr_mimpid, + csr_mhartid, + csr_mstatus, + csr_misa, + csr_medeleg, + csr_mideleg, + csr_mie, + csr_mtvec, + csr_mcounteren, + csr_mscratch, + csr_mepc, + csr_mcause, + csr_mtval, + csr_mip, + csr_sstatus, + csr_sedeleg, + csr_sideleg, + csr_sie, + csr_stvec, + csr_scounteren, + csr_sscratch, + csr_sepc, + csr_scause, + csr_stval, + csr_sip, + csr_satp, + csr_pmpcfg0, + csr_pmpcfg1, + csr_pmpcfg2, + csr_pmpcfg3, + csr_pmpaddr0, + csr_pmpaddr1, + csr_pmpaddr2, + csr_pmpaddr3, + csr_pmpaddr4, + csr_pmpaddr5, + csr_pmpaddr6, + csr_pmpaddr7, + csr_pmpaddr8, + csr_pmpaddr9, + csr_pmpaddr10, + csr_pmpaddr11, + csr_pmpaddr12, + csr_pmpaddr13, + csr_pmpaddr14, + csr_pmpaddr15, + csr_none, +}; + +static const char* all_csr_names[] = { + "none", + "fflags", + "frm", + "fcsr", + "mcycle", + "minstret", + "mcycleh", + "minstreth", + "cycle", + "time", + "instret", + "cycleh", + "timeh", + "instreth", + "mvendorid", + "marchid", + "mimpid", + "mhartid", + "mstatus", + "misa", + "medeleg", + "mideleg", + "mie", + "mtvec", + "mcounteren", + "mscratch", + "mepc", + "mcause", + "mtval", + "mip", + "sstatus", + "sedeleg", + "sideleg", + "sie", + "stvec", + "scounteren", + "sscratch", + "sepc", + "scause", + "stval", + "sip", + "satp", + "pmpcfg0", + "pmpcfg1", + "pmpcfg2", + "pmpcfg3", + "pmpaddr0", + "pmpaddr1", + "pmpaddr2", + "pmpaddr3", + "pmpaddr4", + "pmpaddr5", + "pmpaddr6", + "pmpaddr7", + "pmpaddr8", + "pmpaddr9", + "pmpaddr10", + "pmpaddr11", + "pmpaddr12", + "pmpaddr13", + "pmpaddr14", + "pmpaddr15" +}; + +int* csr_enum_array() +{ + return all_csr_enums; +} + +const char** csr_name_array() +{ + return all_csr_names; +} + +long read_csr_enum(int csrenum) +{ + long result = -1; + switch (csrenum) { + case csr_fflags: result = read_csr(0x001); break; + case csr_frm: result = read_csr(0x002); break; + case csr_fcsr: result = read_csr(0x003); break; + case csr_mcycle: result = read_csr(0xB00); break; + case csr_minstret: result = read_csr(0xB02); break; + case csr_mcycleh: result = read_csr(0xB80); break; + case csr_minstreth: result = read_csr(0xB82); break; + case csr_cycle: result = read_csr(0xC00); break; + case csr_time: result = read_csr(0xC01); break; + case csr_instret: result = read_csr(0xC02); break; + case csr_cycleh: result = read_csr(0xC80); break; + case csr_timeh: result = read_csr(0xC81); break; + case csr_instreth: result = read_csr(0xC82); break; + case csr_mvendorid: result = read_csr(0xF11); break; + case csr_marchid: result = read_csr(0xF12); break; + case csr_mimpid: result = read_csr(0xF13); break; + case csr_mhartid: result = read_csr(0xF14); break; + case csr_mstatus: result = read_csr(0x300); break; + case csr_misa: result = read_csr(0x301); break; + case csr_medeleg: result = read_csr(0x302); break; + case csr_mideleg: result = read_csr(0x303); break; + case csr_mie: result = read_csr(0x304); break; + case csr_mtvec: result = read_csr(0x305); break; + case csr_mcounteren: result = read_csr(0x306); break; + case csr_mscratch: result = read_csr(0x340); break; + case csr_mepc: result = read_csr(0x341); break; + case csr_mcause: result = read_csr(0x342); break; + case csr_mtval: result = read_csr(0x343); break; + case csr_mip: result = read_csr(0x344); break; + case csr_sstatus: result = read_csr(0x100); break; + case csr_sedeleg: result = read_csr(0x102); break; + case csr_sideleg: result = read_csr(0x103); break; + case csr_sie: result = read_csr(0x104); break; + case csr_stvec: result = read_csr(0x105); break; + case csr_scounteren: result = read_csr(0x106); break; + case csr_sscratch: result = read_csr(0x140); break; + case csr_sepc: result = read_csr(0x141); break; + case csr_scause: result = read_csr(0x142); break; + case csr_stval: result = read_csr(0x143); break; + case csr_sip: result = read_csr(0x144); break; + case csr_satp: result = read_csr(0x180); break; + case csr_pmpcfg0: result = read_csr(0x3A0); break; + case csr_pmpcfg1: result = read_csr(0x3A1); break; + case csr_pmpcfg2: result = read_csr(0x3A2); break; + case csr_pmpcfg3: result = read_csr(0x3A3); break; + case csr_pmpaddr0: result = read_csr(0x3B0); break; + case csr_pmpaddr1: result = read_csr(0x3B1); break; + case csr_pmpaddr2: result = read_csr(0x3B2); break; + case csr_pmpaddr3: result = read_csr(0x3B3); break; + case csr_pmpaddr4: result = read_csr(0x3B4); break; + case csr_pmpaddr5: result = read_csr(0x3B5); break; + case csr_pmpaddr6: result = read_csr(0x3B6); break; + case csr_pmpaddr7: result = read_csr(0x3B7); break; + case csr_pmpaddr8: result = read_csr(0x3B8); break; + case csr_pmpaddr9: result = read_csr(0x3B9); break; + case csr_pmpaddr10: result = read_csr(0x3BA); break; + case csr_pmpaddr11: result = read_csr(0x3BB); break; + case csr_pmpaddr12: result = read_csr(0x3BC); break; + case csr_pmpaddr13: result = read_csr(0x3BD); break; + case csr_pmpaddr14: result = read_csr(0x3BE); break; + case csr_pmpaddr15: result = read_csr(0x3BF); break; + default: break; + } + return result; +} + +void write_csr_enum(int csrenum, long value) +{ + switch (csrenum) { + case csr_fflags: write_csr(0x001, value); break; + case csr_frm: write_csr(0x002, value); break; + case csr_fcsr: write_csr(0x003, value); break; + case csr_mcycle: write_csr(0xB00, value); break; + case csr_minstret: write_csr(0xB02, value); break; + case csr_mcycleh: write_csr(0xB80, value); break; + case csr_minstreth: write_csr(0xB82, value); break; + case csr_cycle: write_csr(0xC00, value); break; + case csr_time: write_csr(0xC01, value); break; + case csr_instret: write_csr(0xC02, value); break; + case csr_cycleh: write_csr(0xC80, value); break; + case csr_timeh: write_csr(0xC81, value); break; + case csr_instreth: write_csr(0xC82, value); break; + case csr_mvendorid: write_csr(0xF11, value); break; + case csr_marchid: write_csr(0xF12, value); break; + case csr_mimpid: write_csr(0xF13, value); break; + case csr_mhartid: write_csr(0xF14, value); break; + case csr_mstatus: write_csr(0x300, value); break; + case csr_misa: write_csr(0x301, value); break; + case csr_medeleg: write_csr(0x302, value); break; + case csr_mideleg: write_csr(0x303, value); break; + case csr_mie: write_csr(0x304, value); break; + case csr_mtvec: write_csr(0x305, value); break; + case csr_mcounteren: write_csr(0x306, value); break; + case csr_mscratch: write_csr(0x340, value); break; + case csr_mepc: write_csr(0x341, value); break; + case csr_mcause: write_csr(0x342, value); break; + case csr_mtval: write_csr(0x343, value); break; + case csr_mip: write_csr(0x344, value); break; + case csr_sstatus: write_csr(0x100, value); break; + case csr_sedeleg: write_csr(0x102, value); break; + case csr_sideleg: write_csr(0x103, value); break; + case csr_sie: write_csr(0x104, value); break; + case csr_stvec: write_csr(0x105, value); break; + case csr_scounteren: write_csr(0x106, value); break; + case csr_sscratch: write_csr(0x140, value); break; + case csr_sepc: write_csr(0x141, value); break; + case csr_scause: write_csr(0x142, value); break; + case csr_stval: write_csr(0x143, value); break; + case csr_sip: write_csr(0x144, value); break; + case csr_satp: write_csr(0x180, value); break; + case csr_pmpcfg0: write_csr(0x3A0, value); break; + case csr_pmpcfg1: write_csr(0x3A1, value); break; + case csr_pmpcfg2: write_csr(0x3A2, value); break; + case csr_pmpcfg3: write_csr(0x3A3, value); break; + case csr_pmpaddr0: write_csr(0x3B0, value); break; + case csr_pmpaddr1: write_csr(0x3B1, value); break; + case csr_pmpaddr2: write_csr(0x3B2, value); break; + case csr_pmpaddr3: write_csr(0x3B3, value); break; + case csr_pmpaddr4: write_csr(0x3B4, value); break; + case csr_pmpaddr5: write_csr(0x3B5, value); break; + case csr_pmpaddr6: write_csr(0x3B6, value); break; + case csr_pmpaddr7: write_csr(0x3B7, value); break; + case csr_pmpaddr8: write_csr(0x3B8, value); break; + case csr_pmpaddr9: write_csr(0x3B9, value); break; + case csr_pmpaddr10: write_csr(0x3BA, value); break; + case csr_pmpaddr11: write_csr(0x3BB, value); break; + case csr_pmpaddr12: write_csr(0x3BC, value); break; + case csr_pmpaddr13: write_csr(0x3BD, value); break; + case csr_pmpaddr14: write_csr(0x3BE, value); break; + case csr_pmpaddr15: write_csr(0x3BF, value); break; + default: break; + } +} diff --git a/riscv/riscv-probe/libfemto/arch/riscv/device.c b/riscv/riscv-probe/libfemto/arch/riscv/device.c new file mode 100644 index 0000000..9c3a6bd --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/device.c @@ -0,0 +1,53 @@ +// See LICENSE for license details. + +#include "femto.h" + +void register_console(console_device_t *dev) +{ + console_dev = dev; + if (dev->init) { + dev->init(); + } +} + +void register_poweroff(poweroff_device_t *dev) +{ + poweroff_dev = dev; + if (dev->init) { + dev->init(); + } +} + +static int default_getchar() +{ + asm volatile("ebreak"); + return 0; +} + +static int default_putchar(int ch) +{ + asm volatile("ebreak"); + return 0; +} + +static void default_poweroff(int status) +{ + asm volatile("ebreak"); + while (1) { + asm volatile("" : : : "memory"); + } +} + +console_device_t console_none = { + NULL, + default_getchar, + default_putchar +}; + +poweroff_device_t poweroff_none = { + NULL, + default_poweroff, +}; + +console_device_t *console_dev = &console_none; +poweroff_device_t *poweroff_dev = &poweroff_none; diff --git a/riscv/riscv-probe/libfemto/arch/riscv/memory.c b/riscv/riscv-probe/libfemto/arch/riscv/memory.c new file mode 100644 index 0000000..440e67c --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/memory.c @@ -0,0 +1,50 @@ +// See LICENSE for license details. + +#include "femto.h" +#include "arch/riscv/trap.h" +#include "arch/riscv/encoding.h" +#include "arch/riscv/machine.h" + +extern char _memory_start; + +static memory_info_t memory_info = { + .start = -1UL, + .end = -1UL +}; + +static volatile int save_cause = -1; + +static void trap_save_cause(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) +{ + save_cause = mcause; + write_csr(mepc, mepc + 4); +} + +uintptr_t memory_probe_range(uintptr_t start, uintptr_t end) +{ + trap_fn save = get_trap_fn(); + set_trap_fn(trap_save_cause); + volatile uintptr_t *p = (volatile uintptr_t *)start; + for (; p < (uintptr_t *)end; p += RISCV_PGSIZE) { + /* trap_save_cause adds 4 to the PC so we + * can't emit compressed instructions */ + asm volatile (".option push"); + asm volatile (".option norvc"); + asm volatile ("" : : "r" (*p)); + asm volatile (".option pop"); + if (save_cause != -1) { + break; + } + } + set_trap_fn(save); + return ((uintptr_t)p)-1; +} + +memory_info_t memory_probe() +{ + if (memory_info.start == -1UL) { + memory_info.start = (uintptr_t)&_memory_start, + memory_info.end = memory_probe_range((uintptr_t)&_memory_start, -1UL); + } + return memory_info; +} diff --git a/riscv/riscv-probe/libfemto/arch/riscv/pmp.c b/riscv/riscv-probe/libfemto/arch/riscv/pmp.c new file mode 100644 index 0000000..a540527 --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/pmp.c @@ -0,0 +1,191 @@ +// See LICENSE for license details. + +#include "femto.h" +#include "arch/riscv/csr.h" +#include "arch/riscv/trap.h" +#include "arch/riscv/encoding.h" +#include "arch/riscv/machine.h" + +static pmp_info_t pmp_info = { + .width = -1, + .count = -1, + .granularity = -1 +}; + +static void trap_save_cause(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) +{ + write_csr(mepc, mepc + 4); +} + +pmp_info_t pmp_probe() +{ + trap_fn save; + + if (pmp_info.count >= 0) { + return pmp_info; + } + + /* loop through PMPs checking we can set any bits */ + save = get_trap_fn(); + set_trap_fn(trap_save_cause); + pmp_info.count = 0; + for (size_t i = 0; i < PMPADDR_COUNT; i++) { + uintptr_t addr, addrsave = read_csr_enum(csr_pmpaddr0 + i); + write_csr_enum(csr_pmpaddr0 + i, -1UL); + addr = read_csr_enum(csr_pmpaddr0 + i); + write_csr_enum(csr_pmpaddr0 + i, addrsave); + if (addr) { + pmp_info.count++; + if (i == 0) { + pmp_info.width = (sizeof(addr) << 3) - clz(addr) + 2; + pmp_info.granularity = ctz(addr) + 2; + } + } else { + if (i == 0) { + pmp_info.width = 0; + pmp_info.granularity = 0; + } + break; + } + } + set_trap_fn(save); + + return pmp_info; +} + +int pmp_entry_width() +{ + if (pmp_info.width < 0) { + pmp_probe(); + } + return pmp_info.width; +} + +int pmp_entry_granularity() +{ + if (pmp_info.granularity < 0) { + pmp_probe(); + } + return pmp_info.granularity; +} + +int pmp_entry_count() +{ + if (pmp_info.count < 0) { + pmp_probe(); + } + return pmp_info.count; +} + +void pmp_clear_all() +{ + trap_fn save = get_trap_fn(); + set_trap_fn(trap_save_cause); + for (size_t i = 0; i < PMPCFG_COUNT; i++) { + write_csr_enum(csr_pmpcfg0 + i, 0); + } + for (size_t i = 0; i < PMPADDR_COUNT; i++) { + write_csr_enum(csr_pmpaddr0 + i, 0); + } + set_trap_fn(save); +} + +void pmp_allow_all() +{ + const uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X; + + if (pmp_entry_count() == 0) { + return; + } + + pmp_clear_all(); + + /* borrowed from bbl */ + asm volatile ("la t0, 1f\n\t" + "csrrw t0, mtvec, t0\n\t" + "csrw pmpaddr0, %1\n\t" + "csrw pmpcfg0, %0\n\t" + ".align 2\n\t" + "1: csrw mtvec, t0" + : : "r" (pmpc), "r" (-1UL) : "t0"); +} + +static int pmp_entry_set_pow2(unsigned n, uint8_t prot, uint64_t addr, uint64_t len) +{ + /* calculate PMP config register and offset */ + int pmpcfg_csr = (__riscv_xlen == 32) ? csr_pmpcfg0 + (n >> 2) : + (__riscv_xlen == 64) ? csr_pmpcfg0 + (n >> 2) & ~1 : -1; + int pmpcfg_shift = (__riscv_xlen == 32) ? (n & 3) << 3 : + (__riscv_xlen == 64) ? (n & 7) << 3 : -1; + if (pmpcfg_csr < 0 || pmpcfg_shift < 0) { + return -1; + } + + /* encode config */ + prot |= (len == 4) ? PMP_NA4 : PMP_NAPOT; + uintptr_t pmpcfg = ((uintptr_t)prot) << pmpcfg_shift; + uintptr_t cfgmask = ~(0xff << pmpcfg_shift); + + /* encode address */ + int pmpaddr_csr = csr_pmpaddr0 + n; + uintptr_t pmpmask = (1UL << (ctz(len) - PMP_SHIFT)) - 1; + uintptr_t pmpaddr = ((addr >> PMP_SHIFT) & ~pmpmask) | (pmpmask >> 1); + + /* write csrs */ + pmpcfg |= (read_csr_enum(pmpcfg_csr) & cfgmask) | pmpcfg; + write_csr_enum(pmpcfg_csr, pmpcfg); + write_csr_enum(pmpaddr_csr, pmpaddr); + + return 0; +} + +static int pmp_entry_set_range(unsigned n, uint8_t prot, uint64_t addr, uint64_t len) +{ + /* calculate PMP config register and offset */ + int pmpcfg_csr0 = (__riscv_xlen == 32) ? csr_pmpcfg0 + (n >> 2) : + (__riscv_xlen == 64) ? csr_pmpcfg0 + (n >> 2) & ~1 : -1; + int pmpcfg_csr1 = (__riscv_xlen == 32) ? csr_pmpcfg0 + ((n+1) >> 2) : + (__riscv_xlen == 64) ? csr_pmpcfg0 + ((n+1) >> 2) & ~1 : -1; + int pmpcfg_shift0 = (__riscv_xlen == 32) ? (n & 3) << 3 : + (__riscv_xlen == 64) ? (n & 7) << 3 : -1; + int pmpcfg_shift1 = (__riscv_xlen == 32) ? ((n+1) & 3) << 3 : + (__riscv_xlen == 64) ? ((n+1) & 7) << 3 : -1; + if (pmpcfg_csr0 < 0 || pmpcfg_csr1 < 0 || pmpcfg_shift0 < 0 || pmpcfg_shift1 < 0) { + return -1; + } + + /* encode config */ + uintptr_t pmpcfg0 = ((uintptr_t)prot) << pmpcfg_shift0; + uintptr_t cfgmask0 = ~(0xff << pmpcfg_shift0); + uintptr_t pmpcfg1 = ((uintptr_t)prot | PMP_TOR) << pmpcfg_shift1; + uintptr_t cfgmask1 = ~(0xff << pmpcfg_shift1); + + /* encode address */ + int pmpaddr_csr0 = csr_pmpaddr0 + n; + int pmpaddr_csr1 = csr_pmpaddr1 + n; + uintptr_t pmpaddr0 = addr >> PMP_SHIFT; + uintptr_t pmpaddr1 = (addr + len) >> PMP_SHIFT; + + /* write csrs */ + pmpcfg0 |= (read_csr_enum(pmpcfg_csr0) & cfgmask0) | pmpcfg0; + write_csr_enum(pmpcfg_csr0, pmpcfg0); + write_csr_enum(pmpaddr_csr0, pmpaddr0); + pmpcfg1 |= (read_csr_enum(pmpcfg_csr1) & cfgmask1) | pmpcfg1; + write_csr_enum(pmpcfg_csr1, pmpcfg1); + write_csr_enum(pmpaddr_csr1, pmpaddr1); + + return 0; +} + +int pmp_entry_set(unsigned n, uint8_t prot, uint64_t addr, uint64_t len) +{ + /* check parameters */ + if (n >= PMPADDR_COUNT || len < 4) { + return -1; + } + if (ispow2(len)) { + return pmp_entry_set_pow2(n, prot, addr, len); + } else { + return pmp_entry_set_range(n, prot, addr, len); + } +} diff --git a/riscv/riscv-probe/libfemto/arch/riscv/spinlock.c b/riscv/riscv-probe/libfemto/arch/riscv/spinlock.c new file mode 100644 index 0000000..b8bbe72 --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/spinlock.c @@ -0,0 +1,142 @@ +// See LICENSE for license details. + +#include <arch/riscv/spinlock.h> + +/** + * spinlock lock + * + * \param lock pointer to lock + * + * lui a2,0x10 + * 1: lr.w.aq a4,(a0) + * addw a5,a2,a4 + * sc.w.rl a3,a5,(a0) + * bnez a4,1b + * srliw a4,a5,0x10 + * fence r,rw + * 2: slliw a5,a5,0x10 + * srliw a5,a5,0x10 + * bne a5,a4,3f + * ret + * 3: lw a5,0(a0) + * fence r,rw + * j 2b + */ + +void spinlock_lock(spinlock_t *lock) +{ + ticketdata_t ld; + ticket_t ticket_num; + + /* increment tail to acquire a ticket number */ + do { + ld = _lr_aq_w(&lock->data) + ((ticketdata_t)1 << TICKET_SHIFT); + } while (_sc_rl_w(&lock->data, ld)); + + /* fetch our ticket number */ + ticket_num = ticketlock_tail(ld); + + /* subsequent modifications are ordered after lock read */ + _barrier_acquire(); + + /* wail until our ticket number is head */ + while (ticketlock_head(ld) != ticket_num) { + ld = _l_aq_w(&lock->data); + } +} + +/** + * spinlock trylock + * + * \param lock pointer to lock + * \return non zero if lock was successfully taken + * + * lui a5,0x10 + * lr.w.aq a4,(a0) + * addw a5,a5,a4 + * slliw a3,a5,0x10 + * srliw a3,a3,0x10 + * srliw a4,a5,0x10 + * beq a3,a4,2f + * 1: li a0,0 + * ret + * 2: sc.w.rl a4,a5,(a0) + * bnez a4,1b + * fence r,rw + * li a0,1 + * ret + */ + +int spinlock_trylock(spinlock_t *lock) +{ + ticketdata_t ld; + ticket_t ticket_num; + int result; + + /* increment tail to the next ticket number */ + ld = _lr_aq_w(&lock->data) + ((ticketdata_t)1 << TICKET_SHIFT); + ticket_num = ticketlock_tail(ld); + + /* return true if our ticket is next and lock update succeeded */ + result = ticketlock_head(ld) == ticket_num && !_sc_rl_w(&lock->data, ld); + + if (result) { + /* subsequent modifications are ordered after lock read */ + _barrier_acquire(); + } + + return result; +} + +/** + * spinlock unlock + * + * \param lock pointer to lock + * + * fence rw,w + * 1: lr.w.aq a4,(a0) + * srliw a5,a4,0x10 + * addiw a4,a4,1 + * slliw a4,a4,0x10 + * srliw a4,a4,0x10 + * slliw a5,a5,0x10 + * or a5,a5,a4 + * sc.w.rl a4,a5,(a0) + * bnez a5,1b + * ret + */ +void spinlock_unlock(spinlock_t *lock) +{ + ticketdata_t ld; + + /* prior modifications are ordered before lock write */ + _barrier_release(); + + /* increment head to release lock to the next ticket holder */ + do { + ld = _lr_aq_w(&lock->data); + ld = ticketlock_data(ticketlock_tail(ld), ticketlock_head(ld) + 1); + } while (_sc_rl_w(&lock->data, ld)); +} + +/** + * spinlock waiters + * + * \param lock pointer to lock + * \return number of waiters + * + * lw a5,0(a0) + * fence r,rw + * srliw a0,a5,0x10 + * slliw a5,a5,0x10 + * srliw a5,a5,0x10 + * subw a0,a0,a5 + * addiw a0,a0,1 + * ret + */ +int spinlock_waiters(spinlock_t *lock) +{ + ticketdata_t ld = _l_aq_w(&lock->data); + + return (int)ticketlock_tail(ld) - (int)ticketlock_head(ld) + 1; +} diff --git a/riscv/riscv-probe/libfemto/arch/riscv/start.c b/riscv/riscv-probe/libfemto/arch/riscv/start.c new file mode 100644 index 0000000..60f48a2 --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/start.c @@ -0,0 +1,21 @@ +// See LICENSE for license details. + +#include "femto.h" +#include "arch/riscv/encoding.h" +#include "arch/riscv/machine.h" + +extern char _bss_start; +extern char _bss_end; +extern char _memory_end; + +int main(int argc, char **argv); + +__attribute__((noreturn)) void libfemto_start_main() +{ + char *argv[] = { "femto", NULL }; + memset(&_bss_start, 0, &_bss_end - &_bss_start); + arch_setup(); + _malloc_addblock(&_bss_end, &_memory_end - &_bss_end); + exit(main(1, argv)); + __builtin_unreachable(); +} diff --git a/riscv/riscv-probe/libfemto/arch/riscv/trap.c b/riscv/riscv-probe/libfemto/arch/riscv/trap.c new file mode 100644 index 0000000..6a7d80c --- /dev/null +++ b/riscv/riscv-probe/libfemto/arch/riscv/trap.c @@ -0,0 +1,65 @@ +// See LICENSE for license details. + +#include "femto.h" +#include "arch/riscv/trap.h" +#include "arch/riscv/encoding.h" +#include "arch/riscv/machine.h" + +static trap_fn tfn = 0; + +const char * riscv_excp_names[16] = { + "misaligned_fetch", + "fault_fetch", + "illegal_instruction", + "breakpoint", + "misaligned_load", + "fault_load", + "misaligned_store", + "fault_store", + "user_ecall", + "supervisor_ecall", + "hypervisor_ecall", + "machine_ecall", + "exec_page_fault", + "load_page_fault", + "reserved", + "store_page_fault" +}; + +const char * riscv_intr_names[16] = { + "u_software", + "s_software", + "h_software", + "m_software", + "u_timer", + "s_timer", + "h_timer", + "m_timer", + "u_external", + "s_external", + "h_external", + "m_external", + "reserved", + "reserved", + "reserved", + "reserved" +}; + +trap_fn get_trap_fn() +{ + return tfn; +} + +void set_trap_fn(trap_fn fn) +{ + tfn = fn; +} + +void trap_handler(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) +{ + if (tfn) { + tfn(regs, mcause, mepc); + } else { + die("machine mode: unhandlable trap %d @ %p", mcause, mepc); + } +} |
