summaryrefslogtreecommitdiff
path: root/riscv/riscv-probe/libfemto/include
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/riscv-probe/libfemto/include')
-rw-r--r--riscv/riscv-probe/libfemto/include/alloca.h3
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/csr.h81
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/encoding.h197
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/machine.h183
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/pte.h121
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/spinlock.h192
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/stdatomic.h592
-rw-r--r--riscv/riscv-probe/libfemto/include/arch/riscv/trap.h51
-rw-r--r--riscv/riscv-probe/libfemto/include/auxval.h34
-rw-r--r--riscv/riscv-probe/libfemto/include/device.h39
-rw-r--r--riscv/riscv-probe/libfemto/include/elf.h545
-rw-r--r--riscv/riscv-probe/libfemto/include/endian.h95
-rw-r--r--riscv/riscv-probe/libfemto/include/femto.h14
-rw-r--r--riscv/riscv-probe/libfemto/include/list.h495
-rw-r--r--riscv/riscv-probe/libfemto/include/spinlock.h6
-rw-r--r--riscv/riscv-probe/libfemto/include/stdarg.h8
-rw-r--r--riscv/riscv-probe/libfemto/include/stdatomic.h61
-rw-r--r--riscv/riscv-probe/libfemto/include/stdbits.h63
-rw-r--r--riscv/riscv-probe/libfemto/include/stddef.h8
-rw-r--r--riscv/riscv-probe/libfemto/include/stdint.h52
-rw-r--r--riscv/riscv-probe/libfemto/include/stdio.h20
-rw-r--r--riscv/riscv-probe/libfemto/include/stdlib.h17
-rw-r--r--riscv/riscv-probe/libfemto/include/string.h21
23 files changed, 2898 insertions, 0 deletions
diff --git a/riscv/riscv-probe/libfemto/include/alloca.h b/riscv/riscv-probe/libfemto/include/alloca.h
new file mode 100644
index 0000000..2ae6a3e
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/alloca.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#define alloca(size) __builtin_alloca (size)
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/csr.h b/riscv/riscv-probe/libfemto/include/arch/riscv/csr.h
new file mode 100644
index 0000000..8bbc5f4
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/csr.h
@@ -0,0 +1,81 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int* csr_enum_array();
+const char** csr_name_array();
+long read_csr_enum(int csrenum);
+void write_csr_enum(int csrenum, long value);
+
+enum {
+ csr_none,
+ 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
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/encoding.h b/riscv/riscv-probe/libfemto/include/arch/riscv/encoding.h
new file mode 100644
index 0000000..d592bbc
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/encoding.h
@@ -0,0 +1,197 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_SUM 0x00040000
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_TVM 0x00100000
+#define MSTATUS_TW 0x00200000
+#define MSTATUS_TSR 0x00400000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_SUM 0x00040000
+#define SSTATUS_MXR 0x00080000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define DCSR_XDEBUGVER (3U<<30)
+#define DCSR_NDRESET (1<<29)
+#define DCSR_FULLRESET (1<<28)
+#define DCSR_EBREAKM (1<<15)
+#define DCSR_EBREAKH (1<<14)
+#define DCSR_EBREAKS (1<<13)
+#define DCSR_EBREAKU (1<<12)
+#define DCSR_STOPCYCLE (1<<10)
+#define DCSR_STOPTIME (1<<9)
+#define DCSR_CAUSE (7<<6)
+#define DCSR_DEBUGINT (1<<5)
+#define DCSR_HALT (1<<3)
+#define DCSR_STEP (1<<2)
+#define DCSR_PRV (3<<0)
+
+#define DCSR_CAUSE_NONE 0
+#define DCSR_CAUSE_SWBP 1
+#define DCSR_CAUSE_HWBP 2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_HALT 5
+
+#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT (1<<19)
+#define MCONTROL_TIMING (1<<18)
+#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_CHAIN (1<<11)
+#define MCONTROL_MATCH (0xf<<7)
+#define MCONTROL_M (1<<6)
+#define MCONTROL_H (1<<5)
+#define MCONTROL_S (1<<4)
+#define MCONTROL_U (1<<3)
+#define MCONTROL_EXECUTE (1<<2)
+#define MCONTROL_STORE (1<<1)
+#define MCONTROL_LOAD (1<<0)
+
+#define MCONTROL_TYPE_NONE 0
+#define MCONTROL_TYPE_MATCH 2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
+#define MCONTROL_ACTION_DEBUG_MODE 1
+#define MCONTROL_ACTION_TRACE_START 2
+#define MCONTROL_ACTION_TRACE_STOP 3
+#define MCONTROL_ACTION_TRACE_EMIT 4
+
+#define MCONTROL_MATCH_EQUAL 0
+#define MCONTROL_MATCH_NAPOT 1
+#define MCONTROL_MATCH_GE 2
+#define MCONTROL_MATCH_LT 3
+#define MCONTROL_MATCH_MASK_LOW 4
+#define MCONTROL_MATCH_MASK_HIGH 5
+
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_HSIP (1 << IRQ_H_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_HTIP (1 << IRQ_H_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_HEIP (1 << IRQ_H_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define SPTBR32_MODE 0x80000000
+#define SPTBR32_ASID 0x7FC00000
+#define SPTBR32_PPN 0x003FFFFF
+#define SPTBR64_MODE 0xF000000000000000
+#define SPTBR64_ASID 0x0FFFF00000000000
+#define SPTBR64_PPN 0x00000FFFFFFFFFFF
+
+#define SPTBR_MODE_OFF 0
+#define SPTBR_MODE_SV32 1
+#define SPTBR_MODE_SV39 8
+#define SPTBR_MODE_SV48 9
+#define SPTBR_MODE_SV57 10
+#define SPTBR_MODE_SV64 11
+
+#define PMP_R 0x01
+#define PMP_W 0x02
+#define PMP_X 0x04
+#define PMP_A 0x18
+#define PMP_L 0x80
+#define PMP_SHIFT 2
+#define PMPCFG_COUNT 4
+#define PMPADDR_COUNT 16
+
+#define PMP_OFF 0x00
+#define PMP_TOR 0x08
+#define PMP_NA4 0x10
+#define PMP_NAPOT 0x18
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define DEFAULT_RSTVEC 0x00001000
+#define CLINT_BASE 0x02000000
+#define CLINT_SIZE 0x000c0000
+#define EXT_IO_BASE 0x40000000
+#define DRAM_BASE 0x80000000
+
+// page table entry (PTE) fields
+#define PTE_V 0x001 // Valid
+#define PTE_R 0x002 // Read
+#define PTE_W 0x004 // Write
+#define PTE_X 0x008 // Execute
+#define PTE_U 0x010 // User
+#define PTE_G 0x020 // Global
+#define PTE_A 0x040 // Accessed
+#define PTE_D 0x080 // Dirty
+#define PTE_SOFT 0x300 // Reserved for Software
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#ifdef __riscv
+
+#if __riscv_xlen == 64
+# define MSTATUS_SD MSTATUS64_SD
+# define SSTATUS_SD SSTATUS64_SD
+# define RISCV_PGLEVEL_BITS 9
+# define SPTBR_MODE SPTBR64_MODE
+#else
+# define MSTATUS_SD MSTATUS32_SD
+# define SSTATUS_SD SSTATUS32_SD
+# define RISCV_PGLEVEL_BITS 10
+# define SPTBR_MODE SPTBR32_MODE
+#endif
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/machine.h b/riscv/riscv-probe/libfemto/include/arch/riscv/machine.h
new file mode 100644
index 0000000..077a6c1
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/machine.h
@@ -0,0 +1,183 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+
+void arch_setup();
+void exit(int status) __attribute__((noreturn));
+
+#define die(str, ...) ({ \
+ printf("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(-1); })
+
+#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); })
+
+#define read_const_csr(reg) ({ unsigned long __tmp; \
+ asm ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
+
+#define read_csr(reg) ({ unsigned long __tmp; \
+ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
+
+#define write_csr(reg, val) ({ \
+ asm volatile ("csrw " #reg ", %0" :: "rK"(val)); })
+
+#define swap_csr(reg, val) ({ unsigned long __tmp; \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); __tmp; })
+
+#define set_csr(reg, bit) ({ unsigned long __tmp; \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; })
+
+#define clear_csr(reg, bit) ({ unsigned long __tmp; \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); __tmp; })
+
+static inline uintptr_t get_field(uintptr_t reg, uintptr_t mask)
+{
+ return ((reg & mask) / (mask & ~(mask << 1)));
+}
+
+static inline uintptr_t set_field(uintptr_t reg, uintptr_t mask, uintptr_t val)
+{
+ return ((reg & ~mask) | ((val * (mask & ~(mask << 1))) & mask));
+}
+
+static inline unsigned long rdtime() { return read_csr(time); }
+static inline unsigned long rdcycle() { return read_csr(cycle); }
+static inline unsigned long rdinstret() { return read_csr(instret); }
+static inline int64_t misa() { return read_const_csr(misa); }
+static inline int has_ext(char ext) { return misa() & (1 << (ext - 'a')); }
+static inline int xlen() { return misa() < 0 ? 64 : 32; }
+static inline void wfi() { asm volatile ("wfi" ::: "memory"); }
+
+__attribute__((noreturn)) static inline void mret()
+{
+ asm volatile ("mret");
+ __builtin_unreachable();
+}
+
+
+/*
+ * Memory
+ *
+ * TODO - improve this API to return a list of memory segments
+ */
+
+typedef struct memory_info
+{
+ uintptr_t start;
+ uintptr_t end;
+} memory_info_t;
+
+
+/*
+ * memory_probe - return memory_info
+ */
+memory_info_t memory_probe();
+
+/*
+ * memory_probe_range - probe a memory address range
+ */
+uintptr_t memory_probe_range(uintptr_t start, uintptr_t end);
+
+
+/*
+ * Physical Memory Protection
+ *
+ * PMP is optional but if implememented, enforcement must be enabled by
+ * default, if no PMP entries are set. This means loads, stores or fetches
+ * from any mode besides M mode, will fail unless explicitly allowed.
+ * PMP must be configured irregardless of whether it is implemented.
+ */
+
+typedef struct pmp_info
+{
+ int width;
+ int granularity;
+ int count;
+} pmp_info_t;
+
+/*
+ * pmp_probe - return pmp_info
+ */
+pmp_info_t pmp_probe();
+
+/*
+ * pmp_entry_granularity - return PMP entry width (physical memory width)
+ */
+int pmp_entry_width();
+
+/*
+ * pmp_entry_granularity - return PMP entry granularity (smallest entry size)
+ */
+int pmp_entry_granularity();
+
+/*
+ * pmp_entry_count - return number of PMP entries
+ */
+int pmp_entry_count();
+
+/*
+ * pmp_clear_all - set PMP to disallow mode != PRV_M physical memory accesses
+ */
+void pmp_clear_all();
+
+/*
+ * pmp_allow_all - set PMP to allow mode != PRV_M physical memory accesses
+ */
+void pmp_allow_all();
+
+/*
+ * pmp_entry_set - set one PMP entry
+ *
+ * - n : pmp entry number
+ * - prot : protection (PMP_R | PMP_W | PMP_X)
+ * - addr : start address
+ * - len : power of two length
+ */
+int pmp_entry_set(unsigned n, uint8_t prot, uint64_t addr, uint64_t len);
+
+
+/*
+ * Privileged modes
+ */
+
+/*
+ * mode_set_and_jump
+ *
+ * Set mstatus.mpp, sets mepc to passed function pointer and then issues mret
+ * Note: the hart will continue running on the same stack
+ */
+static inline void mode_set_and_jump(unsigned mode, void (*fn)(void))
+{
+ assert(mode <= PRV_U);
+ write_csr(mstatus, set_field(read_csr(mstatus), MSTATUS_MPP, mode));
+ write_csr(mepc, fn);
+ mret();
+}
+
+/*
+ * mode_set_and_continue
+ *
+ * Set mstatus.mpp, sets mepc to instruction after mret and then issues mret
+ * Note: the hart will continue running on the same stack
+ */
+static inline void mode_set_and_continue(unsigned mode)
+{
+ assert(mode <= PRV_U);
+ write_csr(mstatus, set_field(read_csr(mstatus), MSTATUS_MPP, mode));
+ asm volatile (
+ "lla t0, 1f\n"
+ "csrw mepc, t0\n"
+ "mret\n"
+ "1:"
+ ::: "t0"
+ );
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/pte.h b/riscv/riscv-probe/libfemto/include/arch/riscv/pte.h
new file mode 100644
index 0000000..38d7b8d
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/pte.h
@@ -0,0 +1,121 @@
+#pragma once
+
+enum {
+ PTE_SHIFT_V = 0,
+ PTE_SHIFT_R = 1,
+ PTE_SHIFT_W = 2,
+ PTE_SHIFT_X = 3,
+ PTE_SHIFT_U = 4,
+ PTE_SHIFT_G = 5,
+ PTE_SHIFT_A = 6,
+ PTE_SHIFT_D = 7,
+ PTE_SHIFT_SW1 = 8,
+ PTE_SHIFT_SW2 = 9,
+ PTE_V = 1 << PTE_SHIFT_V,
+ PTE_R = 1 << PTE_SHIFT_R,
+ PTE_W = 1 << PTE_SHIFT_W,
+ PTE_X = 1 << PTE_SHIFT_X,
+ PTE_U = 1 << PTE_SHIFT_U,
+ PTE_G = 1 << PTE_SHIFT_G,
+ PTE_A = 1 << PTE_SHIFT_A,
+ PTE_D = 1 << PTE_SHIFT_D,
+ PTE_SW1 = 1 << PTE_SHIFT_SW1,
+ PTE_SW2 = 1 << PTE_SHIFT_SW2
+};
+
+enum {
+ SV32_LEVELS = 2,
+ SV32_LEVEL_BITS = 10,
+ SV32_PTE_SIZE = 4
+};
+
+union sv32_va {
+ uint32_t val;
+ struct {
+ uint32_t pg_off : 12;
+ uint32_t vpn : 20;
+ } va;
+};
+
+union sv32_pa {
+ uint64_t val;
+ struct {
+ uint64_t pg_off : 12;
+ uint64_t ppn : 22;
+ uint64_t rsrv : 30;
+ } pa;
+};
+
+union sv32_pte {
+ uint32_t val;
+ struct {
+ uint32_t flags : 10;
+ uint32_t ppn : 22;
+ } pte;
+};
+
+enum {
+ SV39_LEVELS = 3,
+ SV39_LEVEL_BITS = 9,
+ SV39_PTE_SIZE = 8
+};
+
+union sv39_va {
+ uint64_t val;
+ struct {
+ uint64_t pg_off : 12;
+ uint64_t vpn : 27;
+ uint64_t rsrv : 25;
+ } va;
+};
+
+union sv39_pa {
+ uint64_t val;
+ struct {
+ uint64_t pg_off : 12;
+ uint64_t ppn : 44;
+ uint64_t rsrv : 8;
+ } pa;
+};
+
+union sv39_pte {
+ uint64_t val;
+ struct {
+ uint64_t flags : 10;
+ uint64_t ppn : 44;
+ uint64_t rsrv : 10;
+ } pte;
+};
+
+enum {
+ SV48_LEVELS = 4,
+ SV48_LEVEL_BITS = 9,
+ SV48_PTE_SIZE = 8
+};
+
+union sv48_va {
+ uint64_t val;
+ struct {
+ uint64_t pg_off : 12;
+ uint64_t vpn : 36;
+ uint64_t rsrv : 16;
+ } va;
+};
+
+union sv48_pa {
+ uint64_t val;
+ struct {
+ uint64_t pg_off : 12;
+ uint64_t ppn : 44;
+ uint64_t rsrv : 8;
+ } pa;
+};
+
+union sv48_pte {
+ uint64_t val;
+ struct {
+ uint64_t flags : 10;
+ uint64_t ppn : 44;
+ uint64_t rsrv : 10;
+ } pte;
+};
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/spinlock.h b/riscv/riscv-probe/libfemto/include/arch/riscv/spinlock.h
new file mode 100644
index 0000000..d747cef
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/spinlock.h
@@ -0,0 +1,192 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Ticket Lock
+ *
+ * Author: Michael Clark <[email protected]>
+ *
+ * Ticket locks are fair spinlocks that order acccess on a first-in,
+ * first-out basis. The lock is composed of a head counter and a tail
+ * counter. The head counter indicates the ticket number of the current
+ * lock owner. The tail counter indicates the last issued ticket number.
+ * To acquire the lock, the acquiring thread atomically increments the
+ * tail counter to assign itself a ticket number. It then waits until
+ * its assigned ticket number is seen in the head counter. If the lock
+ * is not contended, then head will equal the ticket number just assigned.
+ * To release the lock, the lock owner atomically increments head counter
+ * thereby allowing access to the thread holding the next ticket number.
+ *
+ * Initialializtion - the lock is initialized unlocked, so that the
+ * next tail increment returns a ticket that will acquire the lock.
+ *
+ * tail | head
+ * -------|-------
+ * 0x0000 | 0x0001
+ *
+ * Lock - the tail is incremented, and the thread waits unti the tail
+ * is equal to the head before returning control, which is the typical
+ * case if the lock is uncontended.
+ *
+ * tail | head
+ * -------|-------
+ * 0x0001 | 0x0001
+ *
+ * Unlock - the head is incremented, so that it will now equal the value
+ * of the ticket of the next waiter, if any.
+ *
+ * tail | head
+ * -------|-------
+ * 0x0001 | 0x0002
+ *
+ * Waiters - the number of waiters can be calculated by subtracting
+ * head (current ticket) from the tail plus one (next ticket)
+ *
+ * num_waiters = tail + 1 - head
+ */
+
+/**
+ * Ticket lock types
+ */
+
+typedef unsigned short ticket_t;
+typedef unsigned int ticketdata_t;
+
+typedef struct {
+ volatile ticketdata_t data;
+} spinlock_t;
+
+#define TICKET_SHIFT ((sizeof(ticketdata_t) / sizeof(ticket_t)) * 8)
+
+/**
+ * Ticket lock encode
+ */
+static inline ticketdata_t ticketlock_data(ticket_t tail, ticket_t head)
+{
+ return (((ticketdata_t)tail) << TICKET_SHIFT) | (ticketdata_t)head;
+}
+
+/**
+ * Ticket lock tail
+ */
+static inline ticket_t ticketlock_tail(ticketdata_t data) { return data >> 16; }
+
+/**
+ * Ticket lock head
+ */
+static inline ticket_t ticketlock_head(ticketdata_t data) { return data; }
+
+/**
+ * Ticket lock initializer
+ */
+#define SPINLOCK_INIT (spinlock_t){1};
+
+/**
+ * load reserved acquire
+ *
+ * \param pvalue pointer to word to load from
+ * \return loaded value
+ */
+static inline unsigned int _lr_aq_w(volatile unsigned int *pvalue)
+{
+ unsigned int value;
+ asm volatile (
+ "lr.w.aq %0, %1"
+ : "=&r"(value), "+A"(*pvalue));
+ return value;
+}
+
+/**
+ * store conditional release
+ *
+ * \param pvalue pointer to word to store to
+ * \param value word to write
+ * \return true for failure
+ */
+static inline int _sc_rl_w(volatile unsigned int *pvalue, unsigned int value)
+{
+ int result;
+ asm volatile (
+ "sc.w.rl %0, %2, %1"
+ : "=&r"(result), "+A"(*pvalue)
+ : "r"(value)
+ : "memory"
+ );
+ return result;
+}
+
+/**
+ * load acquire
+ *
+ * \param pvalue pointer to word to load from
+ * \return loaded value
+ */
+static inline unsigned int _l_aq_w(volatile unsigned int *pvalue)
+{
+ unsigned int result;
+ asm volatile (
+ "lw %0, %1\n"
+ "fence r,rw"
+ : "=&r"(result), "+A"(*pvalue)
+ );
+ return result;
+}
+
+/**
+ * barrier acquire
+ *
+ * order subsequent modifications after prior lock reads
+ *
+ * <read lock>
+ * _barrier_acquire();
+ */
+static inline void _barrier_acquire() { asm volatile ("fence r,rw"); }
+
+/**
+ * barrier release
+ *
+ * order prior modifications before subsequent lock write
+ *
+ * _barrier_release();
+ * <write lock>
+ */
+static inline void _barrier_release() { asm volatile ("fence rw,w"); }
+
+/**
+ * spinlock lock
+ *
+ * \param lock pointer to lock
+ */
+void spinlock_lock(spinlock_t *lock);
+
+/**
+ * spinlock trylock
+ *
+ * \param lock pointer to lock
+ * \return non zero if lock was successfully taken
+ */
+int spinlock_trylock(spinlock_t *lock);
+
+/**
+ * spinlock unlock
+ *
+ * \param lock pointer to lock
+ */
+void spinlock_unlock(spinlock_t *lock);
+
+/**
+ * spinlock waiters
+ *
+ * \param lock pointer to lock
+ * \return number of waiters
+ */
+int spinlock_waiters(spinlock_t *lock);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/stdatomic.h b/riscv/riscv-probe/libfemto/include/arch/riscv/stdatomic.h
new file mode 100644
index 0000000..8672636
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/stdatomic.h
@@ -0,0 +1,592 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * We use the GCC implementation of __atomic_is_lock_free
+ */
+
+#define atomic_is_lock_free(obj) \
+ __atomic_is_lock_free(sizeof(obj), obj)
+
+/*
+ * GCC Built-in Atomics (not enabled by default, because they are buggy)
+ */
+
+#if defined(LIBFEMTO_USE_GCC_BUILTINS)
+
+#define atomic_flag_test_and_set(obj) \
+ __atomic_test_and_set(obj, __ATOMIC_SEQ_CST)
+#define atomic_flag_test_and_set_explicit(obj, order) \
+ __atomic_test_and_set(obj, order)
+
+#define atomic_flag_clear(obj) \
+ __atomic_test_and_set(obj, __ATOMIC_SEQ_CST)
+#define atomic_flag_clear_explicit(obj, order) \
+ __atomic_test_and_set(obj, order)
+
+#define atomic_thread_fence(order) \
+ __atomic_thread_fence(order)
+
+#define atomic_signal_fence(order) \
+ __atomic_signal_fence(order)
+
+#define atomic_store(obj, desired) \
+ __atomic_store_n(obj, desired, __ATOMIC_SEQ_CST)
+#define atomic_store_explicit(obj, desired, order) \
+ __atomic_store_n(obj, desired, order)
+
+#define atomic_load(obj) \
+ __atomic_load_n(obj, __ATOMIC_SEQ_CST)
+#define atomic_load_explicit(obj,order) \
+ __atomic_load_n(obj,order)
+
+#define atomic_exchange(obj, desired) \
+ __atomic_exchange_n(obj, desired, __ATOMIC_SEQ_CST)
+#define atomic_exchange_explicit(obj, desired, order) \
+ __atomic_exchange_n(obj, desired, order)
+
+#define atomic_compare_exchange_strong(obj, expected, desired) \
+ __atomic_compare_exchange_n(obj, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong_explicit(obj, expected, desired, succ, fail) \
+ __atomic_compare_exchange_n(obj, expected, desired, 0, succ, fail)
+
+#define atomic_compare_exchange_weak(obj, expected, desired) \
+ __atomic_compare_exchange_n(obj, expected, desired, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_weak_explicit(obj, expected, desired, succ, fail) \
+ __atomic_compare_exchange_n(obj, expected, desired, 1, succ, fail)
+
+#define atomic_fetch_add(obj, arg) \
+ __atomic_fetch_add(obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ __atomic_fetch_add(obj, arg, order)
+
+#define atomic_fetch_sub(obj, arg) \
+ __atomic_fetch_sub(obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ __atomic_fetch_sub(obj, arg, order)
+
+#define atomic_fetch_or(obj, arg) \
+ __atomic_fetch_or(obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_or_explicit(obj, arg, order) \
+ __atomic_fetch_or(obj, arg, order)
+
+#define atomic_fetch_xor(obj, arg) \
+ __atomic_fetch_xor(obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_xor_explicit(obj, arg, order) \
+ __atomic_fetch_xor(obj, arg, order)
+
+#define atomic_fetch_and(obj, arg) \
+ __atomic_fetch_and(obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_and_explicit(obj, arg, order) \
+ __atomic_fetch_and(obj, arg, order)
+#endif
+
+#elif defined(__riscv)
+
+/*
+ * atomic_load
+ */
+
+#define __atomic_load_asm(obj, ASM_BARRIER, ASM_ACQUIRE) \
+__extension__ ({ \
+ __typeof__(obj) __obj = (obj); \
+ __typeof__(*(obj)) __result; \
+ switch (sizeof(__typeof__(*obj))) { \
+ case 1: \
+ __asm__ volatile ( \
+ ASM_BARRIER "\n" "lb %0, %1\n" ASM_ACQUIRE \
+ : "=&r"(__result), "+A"(*__obj) \
+ ); \
+ break; \
+ case 2: \
+ __asm__ volatile ( \
+ ASM_BARRIER "\n" "lh %0, %1\n" ASM_ACQUIRE \
+ : "=&r"(__result), "+A"(*__obj) \
+ ); \
+ break; \
+ case 4: \
+ __asm__ volatile ( \
+ ASM_BARRIER "\n" "lw %0, %1\n" ASM_ACQUIRE \
+ : "=&r"(__result), "+A"(*__obj) \
+ ); \
+ break; \
+ case 8: \
+ if (__riscv_xlen < 64) __builtin_unreachable(); \
+ __asm__ volatile ( \
+ ASM_BARRIER "\n" "ld %0, %1\n" ASM_ACQUIRE \
+ : "=&r"(__result), "+A"(*__obj) \
+ ); \
+ break; \
+ } \
+ __result; \
+})
+
+#define __atomic_load_relaxed(obj) \
+ __atomic_load_asm(obj, "", "")
+
+#define __atomic_load_acquire(obj) \
+ __atomic_load_asm(obj, "", "fence r,rw")
+
+#define __atomic_load_seq_cst(obj) \
+ __atomic_load_asm(obj, "fence rw,rw", "fence r,rw")
+
+#define atomic_load_explicit(obj, order) \
+__extension__ ({ \
+ __typeof__(*(obj)) __result; \
+ switch (order) { \
+ case __ATOMIC_ACQUIRE: \
+ __result = __atomic_load_acquire(obj) ; break; \
+ case __ATOMIC_SEQ_CST: \
+ __result = __atomic_load_seq_cst(obj) ; break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __result = __atomic_load_relaxed(obj) ; break; \
+ } \
+ __result; \
+})
+
+#define atomic_load(obj) \
+ atomic_load_explicit(obj, __ATOMIC_SEQ_CST)
+
+/*
+ * atomic_store
+ */
+
+#define __atomic_store_asm(obj, value, ASM_RELEASE) \
+__extension__ ({ \
+ __typeof__(obj) __obj = (obj); \
+ __typeof__(*(obj)) __value = (value); \
+ switch (sizeof(__typeof__(*obj))) { \
+ case 1: \
+ __asm__ volatile ( \
+ ASM_RELEASE "\n" "sb %1, %0\n" \
+ : "+A"(*__obj) : "r"(__value) : "memory" \
+ ); \
+ break; \
+ case 2: \
+ __asm__ volatile ( \
+ ASM_RELEASE "\n" "sh %1, %0\n" \
+ : "+A"(*__obj) : "r"(__value) : "memory" \
+ ); \
+ break; \
+ case 4: \
+ __asm__ volatile ( \
+ ASM_RELEASE "\n" "sw %1, %0\n" \
+ : "+A"(*__obj) : "r"(__value) : "memory" \
+ ); \
+ break; \
+ case 8: \
+ if (__riscv_xlen < 64) __builtin_unreachable(); \
+ __asm__ volatile ( \
+ ASM_RELEASE "\n" "sd %1, %0\n" \
+ : "+A"(*__obj) : "r"(__value) : "memory" \
+ ); \
+ break; \
+ } \
+})
+
+#define __atomic_store_relaxed(obj, value) \
+ __atomic_store_asm(obj, value, "")
+
+#define __atomic_store_release(obj, value) \
+ __atomic_store_asm(obj, value, "fence rw,w")
+
+#define __atomic_store_seq_cst(obj, value) \
+ __atomic_store_asm(obj, value, "fence rw,w")
+
+
+#define atomic_store_explicit(obj, value, order) \
+__extension__ ({ \
+ switch (order) { \
+ case __ATOMIC_RELEASE: \
+ __atomic_store_release(obj, value) ; break; \
+ case __ATOMIC_SEQ_CST: \
+ __atomic_store_seq_cst(obj, value) ; break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __atomic_store_relaxed(obj, value) ; break; \
+ } \
+})
+
+#define atomic_store(obj, value) \
+ atomic_store_explicit(obj, value, __ATOMIC_SEQ_CST)
+
+/*
+ * atomic_compare_exchange
+ */
+
+#define __atomic_cmpxchg_asm(obj, exp, val, ASM_AQ, ASM_RL) \
+__extension__ ({ \
+ __typeof__(obj) __obj = (obj); \
+ __typeof__(*(obj)) __exp = (exp); \
+ __typeof__(*(obj)) __val = (val); \
+ __typeof__(*(obj)) __result; \
+ register unsigned int __ret; \
+ switch (sizeof(__typeof__(*obj))) { \
+ case 1: \
+ case 2: \
+ __builtin_unreachable(); \
+ break; \
+ case 4: \
+ __asm__ volatile ( \
+ "0: lr.w" ASM_AQ " %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w" ASM_RL " %1, %z4, %2\n" \
+ " bnez %1, 0b \n" /* always strong */ \
+ "1:\n" \
+ : "=&r"(__result), "=&r" (__ret), "+A"(*__obj) \
+ : "r"(__exp), "r"(__val) \
+ : "memory" \
+ ); \
+ break; \
+ case 8: \
+ if (__riscv_xlen < 64) __builtin_unreachable(); \
+ __asm__ volatile ( \
+ "0: lr.d" ASM_AQ " %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d" ASM_RL " %1, %z4, %2\n" \
+ " bnez %1, 0b \n" /* always strong */ \
+ "1:\n" \
+ : "=&r"(__result), "=&r" (__ret), "+A"(*__obj) \
+ : "r"(__exp), "r"(__val) \
+ : "memory" \
+ ); \
+ break; \
+ } \
+ __result; \
+})
+
+#define __atomic_cmpxchg_relaxed(obj, exp, val) \
+ __atomic_cmpxchg_asm(obj, exp, val, "", "")
+
+#define __atomic_cmpxchg_acquire(obj, exp, val) \
+ __atomic_cmpxchg_asm(obj, exp, val, ".aq", "")
+
+#define __atomic_cmpxchg_release(obj, exp, val) \
+ __atomic_cmpxchg_asm(obj, exp, val, "", ".rl")
+
+#define __atomic_cmpxchg_acq_rel(obj, exp, val) \
+ __atomic_cmpxchg_asm(obj, exp, val, ".aq", ".rl")
+
+#define __atomic_cmpxchg_seq_cst(obj, exp, val) \
+ __atomic_cmpxchg_asm(obj, exp, val, ".aqrl", ".rl")
+
+#define __atomic_cmpxchg_strong(obj, exp, val, succ, fail) \
+__extension__ ({ \
+ __typeof__(*(obj)) __result; \
+ switch (succ) { \
+ case __ATOMIC_ACQUIRE: \
+ case __ATOMIC_CONSUME: /* promote to acquire for now */ \
+ __result = __atomic_cmpxchg_acquire(obj, exp, val); break; \
+ case __ATOMIC_RELEASE: \
+ __result = __atomic_cmpxchg_release(obj, exp, val); break; \
+ case __ATOMIC_ACQ_REL: \
+ __result = __atomic_cmpxchg_acq_rel(obj, exp, val); break; \
+ case __ATOMIC_SEQ_CST: \
+ __result = __atomic_cmpxchg_seq_cst(obj, exp, val); break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __result = __atomic_cmpxchg_relaxed(obj, exp, val); break; \
+ } \
+ __result; \
+})
+
+#define atomic_compare_exchange_strong(obj, exp, val) \
+ __atomic_cmpxchg_strong(obj, exp, val, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong_explicit(obj, exp, val, succ, fail) \
+ __atomic_cmpxchg_strong(obj, exp, val, succ, fail)
+
+#define atomic_compare_exchange_weak(obj, exp, val) \
+ __atomic_cmpxchg_strong(obj, exp, val, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_weak_explicit(obj, exp, val, succ, fail) \
+ __atomic_cmpxchg_strong(obj, exp, val, succ, fail)
+
+/*
+ * atomic_op template
+ */
+
+#define __atomic_op_asm(AMO_OP, obj, arg, ASM_AQRL) \
+__extension__ ({ \
+ __typeof__(obj) __obj = (obj); \
+ __typeof__(*(obj)) __arg = (arg); \
+ __typeof__(*(obj)) __result; \
+ switch (sizeof(__typeof__(*obj))) { \
+ case 1: \
+ case 2: \
+ __builtin_unreachable(); \
+ break; \
+ case 4: \
+ __asm__ volatile ( \
+ AMO_OP ".w" ASM_AQRL " %0, %2, %1\n" \
+ : "=&r"(__result), "+A"(*__obj) \
+ : "r"(__arg) \
+ : "memory" \
+ ); \
+ break; \
+ case 8: \
+ if (__riscv_xlen < 64) __builtin_unreachable(); \
+ __asm__ volatile ( \
+ AMO_OP ".d" ASM_AQRL " %0, %2, %1\n" \
+ : "=&r"(__result), "+A"(*__obj) \
+ : "r"(__arg) \
+ : "memory" \
+ ); \
+ break; \
+ } \
+ __result; \
+})
+
+#define __atomic_op_relaxed(op, obj, arg) \
+ __atomic_op_asm(op, obj, arg, "")
+
+#define __atomic_op_acquire(op, obj, arg) \
+ __atomic_op_asm(op, obj, arg, ".aq")
+
+#define __atomic_op_release(op, obj, arg) \
+ __atomic_op_asm(op, obj, arg, ".rl")
+
+#define __atomic_op_acq_rel(op, obj, arg) \
+ __atomic_op_asm(op, obj, arg, ".aqrl")
+
+#define __atomic_op_seq_cst(op, obj, arg) \
+ __atomic_op_asm(op, obj, arg, ".aqrl")
+
+#define __atomic_op(op, obj, arg, order) \
+__extension__ ({ \
+ __typeof__(*(obj)) __result; \
+ switch (order) { \
+ case __ATOMIC_ACQUIRE: \
+ case __ATOMIC_CONSUME: /* promote to acquire for now */ \
+ __result = __atomic_op_acquire(op, obj, arg); break; \
+ case __ATOMIC_RELEASE: \
+ __result = __atomic_op_release(op, obj, arg); break; \
+ case __ATOMIC_ACQ_REL: \
+ __result = __atomic_op_acq_rel(op, obj, arg); break; \
+ case __ATOMIC_SEQ_CST: \
+ __result = __atomic_op_seq_cst(op, obj, arg); break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __result = __atomic_op_relaxed(op, obj, arg); break; \
+ } \
+ __result; \
+})
+
+/*
+ * atomic_exchange
+ */
+
+#define atomic_exchange(obj, arg) \
+ __atomic_op("amoswap", obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_exchange_explicit(obj, arg, order) \
+ __atomic_op("amoswap", obj, arg, order)
+
+/*
+ * atomic_fetch_add
+ */
+
+#define atomic_fetch_add(obj, arg) \
+ __atomic_op("amoadd", obj, arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_add_explicit(obj, arg, order) \
+ __atomic_op("amoadd", obj, arg, order)
+
+/*
+ * atomic_fetch_sub
+ */
+
+#define atomic_fetch_sub(obj, arg) \
+ __atomic_op("amoadd", obj, -arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_sub_explicit(obj, arg, order) \
+ __atomic_op("amoadd", obj, -arg, order)
+
+/*
+ * atomic_fetch_or
+ */
+
+#define atomic_fetch_or(obj, arg) \
+ __atomic_op("amoor", obj, -arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_or_explicit(obj, arg, order) \
+ __atomic_op("amoor", obj, -arg, order)
+
+/*
+ * atomic_fetch_xor
+ */
+
+#define atomic_fetch_xor(obj, arg) \
+ __atomic_op("amoxor", obj, -arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_xor_explicit(obj, arg, order) \
+ __atomic_op("amoxor", obj, -arg, order)
+
+/*
+ * atomic_fetch_and
+ */
+
+#define atomic_fetch_and(obj, arg) \
+ __atomic_op("amoand", obj, -arg, __ATOMIC_SEQ_CST)
+#define atomic_fetch_and_explicit(obj, arg, order) \
+ __atomic_op("amoand", obj, -arg, order)
+
+
+/*
+ * atomic_flag_test_and_set
+ */
+
+#define __atomic_flag_test_and_set_asm(obj, ASM_AQRL) \
+__extension__ ({ \
+ struct atomic_flag* __obj = (obj); \
+ size_t __shift = (((unsigned long)__obj) & 3) << 3; \
+ uint32_t *__word = (uint32_t *)(((unsigned long)__obj) & ~3); \
+ uint32_t __mask = 1 << __shift; \
+ uint32_t __result; \
+ __asm__ volatile ( \
+ "amoor.w" ASM_AQRL " %0, %2, %1\n" \
+ : "=&r"(__result), "+A"(*__word) \
+ : "r"(__mask) \
+ : "memory" \
+ ); \
+ ((__result >> __shift) & 0xff); \
+})
+
+#define __atomic_flag_test_and_set_relaxed(obj) \
+ __atomic_flag_test_and_set_asm(obj, "")
+
+#define __atomic_flag_test_and_set_acquire(obj) \
+ __atomic_flag_test_and_set_asm(obj, ".aq")
+
+#define __atomic_flag_test_and_set_release(obj) \
+ __atomic_flag_test_and_set_asm(obj, ".rl")
+
+#define __atomic_flag_test_and_set_acq_rel(obj) \
+ __atomic_flag_test_and_set_asm(obj, ".aqrl")
+
+#define __atomic_flag_test_and_set_seq_cst(obj) \
+ __atomic_flag_test_and_set_asm(obj, ".aqrl")
+
+
+#define __atomic_flag_test_and_set(obj, order) \
+__extension__ ({ \
+ _Bool __result; \
+ switch (order) { \
+ case __ATOMIC_ACQUIRE: \
+ case __ATOMIC_CONSUME: /* promote to acquire for now */ \
+ __result = __atomic_flag_test_and_set_acquire(obj); break; \
+ case __ATOMIC_RELEASE: \
+ __result = __atomic_flag_test_and_set_release(obj); break; \
+ case __ATOMIC_ACQ_REL: \
+ __result = __atomic_flag_test_and_set_acq_rel(obj); break; \
+ case __ATOMIC_SEQ_CST: \
+ __result = __atomic_flag_test_and_set_seq_cst(obj); break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __result = __atomic_flag_test_and_set_relaxed(obj); break; \
+ } \
+ __result; \
+})
+
+#define atomic_flag_test_and_set_explicit(obj, order) \
+ __atomic_flag_test_and_set(obj, order)
+#define atomic_flag_test_and_set(obj, order) \
+ __atomic_flag_test_and_set(obj, __ATOMIC_SEQ_CST)
+
+/*
+ * atomic_flag_clear
+ */
+
+#define __atomic_flag_clear_asm(obj, ASM_AQRL) \
+__extension__ ({ \
+ struct atomic_flag* __obj = (obj); \
+ size_t __shift = (((unsigned long)__obj) & 3) << 3; \
+ uint32_t *__word = (uint32_t *)(((unsigned long)__obj) & ~3); \
+ uint32_t __mask = ~(0xff << __shift); \
+ uint32_t __result; \
+ __asm__ volatile ( \
+ "amoand.w" ASM_AQRL " %0, %2, %1\n" \
+ : "=&r"(__result), "+A"(*__word) \
+ : "r"(__mask) \
+ : "memory" \
+ ); \
+ ((__result >> __shift) & 0xff); \
+})
+
+#define __atomic_flag_clear_relaxed(obj) \
+ __atomic_flag_clear_asm(obj, "")
+
+#define __atomic_flag_clear_acquire(obj) \
+ __atomic_flag_clear_asm(obj, ".aq")
+
+#define __atomic_flag_clear_release(obj) \
+ __atomic_flag_clear_asm(obj, ".rl")
+
+#define __atomic_flag_clear_acq_rel(obj) \
+ __atomic_flag_clear_asm(obj, ".aqrl")
+
+#define __atomic_flag_clear_seq_cst(obj) \
+ __atomic_flag_clear_asm(obj, ".aqrl")
+
+
+#define __atomic_flag_clear(obj, order) \
+__extension__ ({ \
+ _Bool __result; \
+ switch (order) { \
+ case __ATOMIC_ACQUIRE: \
+ case __ATOMIC_CONSUME: /* promote to acquire for now */ \
+ __result = __atomic_flag_clear_acquire(obj); break; \
+ case __ATOMIC_RELEASE: \
+ __result = __atomic_flag_clear_release(obj); break; \
+ case __ATOMIC_ACQ_REL: \
+ __result = __atomic_flag_clear_acq_rel(obj); break; \
+ case __ATOMIC_SEQ_CST: \
+ __result = __atomic_flag_clear_seq_cst(obj); break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __result = __atomic_flag_clear_relaxed(obj); break; \
+ } \
+ __result; \
+})
+
+#define atomic_flag_clear_explicit(obj, order) \
+ __atomic_flag_clear(obj, order)
+#define atomic_flag_clear(obj, order) \
+ __atomic_flag_clear(obj, __ATOMIC_SEQ_CST)
+
+/*
+ * atomic_thread_fence
+ */
+
+#define __atomic_thread_fence_asm(order) \
+__extension__ ({ \
+ switch (order) { \
+ case __ATOMIC_ACQUIRE: \
+ case __ATOMIC_CONSUME: /* promote to acquire for now */ \
+ __asm__ volatile ("fence r,rw" ::: "memory"); break; \
+ case __ATOMIC_RELEASE: \
+ __asm__ volatile ("fence rw,w" ::: "memory"); break; \
+ case __ATOMIC_ACQ_REL: /* should be fence.tso */ \
+ __asm__ volatile ("fence rw,rw" ::: "memory"); break; \
+ case __ATOMIC_SEQ_CST: \
+ __asm__ volatile ("fence rw,rw" ::: "memory"); break; \
+ case __ATOMIC_RELAXED: \
+ default: \
+ __asm__ volatile ("" ::: "memory"); break; \
+ } \
+})
+
+#define atomic_thread_fence(order) \
+ __atomic_thread_fence_asm(order)
+
+/*
+ * atomic_signal_fence
+ */
+
+#define atomic_signal_fence(order) \
+ __asm__ volatile ("" ::: "memory")
+
+#endif /* __riscv */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/arch/riscv/trap.h b/riscv/riscv-probe/libfemto/include/arch/riscv/trap.h
new file mode 100644
index 0000000..0b33ec5
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/arch/riscv/trap.h
@@ -0,0 +1,51 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*trap_fn)(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
+trap_fn get_trap_fn();
+void set_trap_fn(trap_fn fn);
+
+const char * riscv_excp_names[16];
+const char * riscv_intr_names[16];
+
+enum {
+ cause_misaligned_fetch = 0,
+ cause_fault_fetch = 1,
+ cause_illegal_instruction = 2,
+ cause_breakpoint = 3,
+ cause_misaligned_load = 4,
+ cause_fault_load = 5,
+ cause_misaligned_store = 6,
+ cause_fault_store = 7,
+ cause_user_ecall = 8,
+ cause_supervisor_ecall = 9,
+ cause_hypervisor_ecall = 10,
+ cause_machine_ecall = 11,
+ cause_exec_page_fault = 12,
+ cause_load_page_fault = 13,
+ cause_store_page_fault = 15
+};
+
+enum {
+ intr_u_software = 0,
+ intr_s_software = 1,
+ intr_h_software = 2,
+ intr_m_software = 3,
+ intr_u_timer = 4,
+ intr_s_timer = 5,
+ intr_h_timer = 6,
+ intr_m_timer = 7,
+ intr_u_external = 8,
+ intr_s_external = 9,
+ intr_h_external = 10,
+ intr_m_external = 11,
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/auxval.h b/riscv/riscv-probe/libfemto/include/auxval.h
new file mode 100644
index 0000000..de10824
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/auxval.h
@@ -0,0 +1,34 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ HART0_CLOCK_FREQ = 0x00010000,
+ UART0_CLOCK_FREQ = 0x00011000,
+ UART0_BAUD_RATE = 0x00011100,
+ NS16550A_UART0_CTRL_ADDR = 0x00030000,
+ RISCV_HTIF_BASE_ADDR = 0x00050000,
+ SIFIVE_CLINT_CTRL_ADDR = 0x55550000,
+ SIFIVE_CLIC_CRTL_ADDR = 0x55550001,
+ SIFIVE_TEST_CTRL_ADDR = 0x55550002,
+ SIFIVE_UART0_CTRL_ADDR = 0x55550010,
+ SIFIVE_GPIO0_CTRL_ADDR = 0x55550020,
+ SIFIVE_SPI0_CTRL_ADDR = 0x55550030,
+};
+
+typedef struct auxval {
+ unsigned long key;
+ unsigned long val;
+} auxval_t;
+
+extern auxval_t __auxv[];
+
+unsigned long getauxval(unsigned long key);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/device.h b/riscv/riscv-probe/libfemto/include/device.h
new file mode 100644
index 0000000..822ab8c
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/device.h
@@ -0,0 +1,39 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct console_device {
+ void (*init)();
+ int (*getchar)();
+ int (*putchar)(int);
+} console_device_t;
+
+typedef struct poweroff_device {
+ void (*init)();
+ void (*poweroff)(int);
+} poweroff_device_t;
+
+void register_console(console_device_t *dev);
+void register_poweroff(poweroff_device_t *dev);
+
+extern console_device_t *console_dev;
+extern poweroff_device_t *poweroff_dev;
+
+extern console_device_t console_none;
+extern console_device_t console_htif;
+extern console_device_t console_ns16550a;
+extern console_device_t console_sifive_uart;
+extern console_device_t console_semihost;
+
+extern poweroff_device_t poweroff_none;
+extern poweroff_device_t poweroff_htif;
+extern poweroff_device_t poweroff_sifive_test;
+extern poweroff_device_t poweroff_semihost;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/elf.h b/riscv/riscv-probe/libfemto/include/elf.h
new file mode 100644
index 0000000..abfb892
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/elf.h
@@ -0,0 +1,545 @@
+#pragma once
+
+#include <stdint.h>
+
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Word;
+typedef uint8_t Elf32_Byte;
+
+typedef uint64_t Elf64_Addr;
+typedef uint16_t Elf64_Half;
+typedef uint64_t Elf64_Off;
+typedef int32_t Elf64_Sword;
+typedef uint32_t Elf64_Word;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+typedef uint8_t Elf64_Byte;
+
+enum {
+ AT_NULL = 0,
+ AT_PHDR = 3,
+ AT_PHENT = 4,
+ AT_PHNUM = 5,
+ AT_PAGESZ = 6,
+ AT_BASE = 7,
+ AT_FLAGS = 8,
+ AT_ENTRY = 9,
+ AT_UID = 11,
+ AT_EUID = 12,
+ AT_GID = 13,
+ AT_EGID = 14,
+ AT_CLKTCK = 17,
+ AT_SECURE = 23,
+ AT_RANDOM = 25
+};
+
+typedef struct {
+ Elf32_Word a_type;
+ Elf32_Word a_val;
+} Elf32_auxv;
+
+typedef struct {
+ Elf64_Word a_type;
+ Elf64_Word a_val;
+} Elf64_auxv;
+
+enum {
+ ET_NONE = 0,
+ ET_REL = 1,
+ ET_EXEC = 2,
+ ET_DYN = 3,
+ ET_CORE = 4,
+ ET_LOPROC = 0xff00,
+ ET_HIPROC = 0xffff
+};
+
+enum {
+ EM_NONE = 0,
+ EM_X86_64 = 62,
+ EM_RISCV = 243
+};
+
+enum {
+ EV_NONE = 0,
+ EV_CURRENT = 1
+};
+
+enum {
+ EI_MAG0 = 0,
+ EI_MAG1 = 1,
+ EI_MAG2 = 2,
+ EI_MAG3 = 3,
+ EI_CLASS = 4,
+ EI_DATA = 5,
+ EI_VERSION = 6,
+ EI_OSABI = 7,
+ EI_ABIVERSION = 8,
+ EI_PAD = 9,
+ EI_NIDENT = 16
+};
+
+enum {
+ ELFMAG0 = 0x7f,
+ ELFMAG1 = 'E',
+ ELFMAG2 = 'L',
+ ELFMAG3 = 'F'
+};
+
+enum {
+ ELFCLASSNONE = 0,
+ ELFCLASS32 = 1,
+ ELFCLASS64 = 2,
+ ELFCLASS128 = 3
+};
+
+enum {
+ ELFDATANONE = 0,
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2
+};
+
+enum {
+ ELFOSABI_SYSV = 0,
+ ELFOSABI_LINUX = 3,
+ ELFOSABI_SOLARIS = 6,
+ ELFOSABI_FREEBSD = 9
+};
+
+enum {
+ ELFABIVERSION_NONE = 0
+};
+
+typedef struct {
+ Elf32_Byte e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+ Elf64_Byte e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry;
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+enum {
+ PT_NULL = 0,
+ PT_LOAD = 1,
+ PT_DYNAMIC = 2,
+ PT_INTERP = 3,
+ PT_NOTE = 4,
+ PT_SHLIB = 5,
+ PT_PHDR = 6,
+ PT_TLS = 7,
+ PT_LOOS = 0x60000000,
+ PT_GNU_EH_FRAME = 0x6474e550,
+ PT_GNU_STACK = 0x6474e551,
+ PT_GNU_RELRO = 0x6474e552,
+ PT_HIOS = 0x6fffffff,
+ PT_LOPROC = 0x70000000,
+ PT_HIPROC = 0x7fffffff
+};
+
+enum {
+ PF_X = 0x1,
+ PF_W = 0x2,
+ PF_R = 0x4,
+ PF_MASKOS = 0x00FF0000,
+ PF_MASKPROC = 0xFF000000,
+};
+
+typedef struct {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct {
+ Elf64_Word p_type;
+ Elf64_Word p_flags;
+ Elf64_Off p_offset;
+ Elf64_Addr p_vaddr;
+ Elf64_Addr p_paddr;
+ Elf64_Xword p_filesz;
+ Elf64_Xword p_memsz;
+ Elf64_Xword p_align;
+} Elf64_Phdr;
+
+enum {
+ SHN_UNDEF = 0,
+ SHN_LOPROC = 0xff00,
+ SHN_HIPROC = 0xff1f,
+ SHN_LOOS = 0xff20,
+ SHN_HIOS = 0xff3f,
+ SHN_ABS = 0xfff1,
+ SHN_COMMON = 0xfff2,
+ SHN_XINDEX = 0xffff,
+ SHN_HIRESERVE = 0xffff,
+};
+
+enum {
+ SHT_NULL = 0,
+ SHT_PROGBITS = 1,
+ SHT_SYMTAB = 2,
+ SHT_STRTAB = 3,
+ SHT_RELA = 4,
+ SHT_HASH = 5,
+ SHT_DYNAMIC = 6,
+ SHT_NOTE = 7,
+ SHT_NOBITS = 8,
+ SHT_REL = 9,
+ SHT_SHLIB = 10,
+ SHT_DYNSYM = 11,
+ SHT_INIT_ARRAY = 14,
+ SHT_FINI_ARRAY = 15,
+ SHT_PREINIT_ARRAY = 16,
+ SHT_GROUP = 17,
+ SHT_SYMTAB_SHNDX = 18,
+ SHT_LOOS = 0x60000000,
+ SHT_GNU_VERDEF = 0x6ffffffd,
+ SHT_GNU_VERNEED = 0x6ffffffe,
+ SHT_GNU_VERSYM = 0x6fffffff,
+ SHT_HIOS = 0x6fffffff,
+ SHT_LOPROC = 0x70000000,
+ SHT_HIPROC = 0x7fffffff,
+ SHT_LOUSER = 0x80000000,
+ SHT_HIUSER = 0xffffffff
+};
+
+enum {
+ SHF_WRITE = 0x1,
+ SHF_ALLOC = 0x2,
+ SHF_EXECINSTR = 0x4,
+ SHF_MERGE = 0x10,
+ SHF_STRINGS = 0x20,
+ SHF_INFO_LINK = 0x40,
+ SHF_LINK_ORDER = 0x80,
+ SHF_GROUP = 0x200,
+ SHF_TLS = 0x400,
+ SHF_MASKOS = 0x0F000000,
+ SHF_MASKPROC = 0xf0000000
+};
+
+enum {
+ GRP_COMDAT = 0x1,
+ GRP_MASKOS = 0x0ff00000,
+ GRP_MASKPROC = 0xf0000000
+};
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Xword sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Xword sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Xword sh_addralign;
+ Elf64_Xword sh_entsize;
+} Elf64_Shdr;
+
+
+typedef struct {
+ Elf32_Word n_namesz;
+ Elf32_Word n_descsz;
+ Elf32_Word n_type;
+} Elf32_Nhdr;
+
+typedef struct {
+ Elf64_Word n_namesz;
+ Elf64_Word n_descsz;
+ Elf64_Word n_type;
+} Elf64_Nhdr;
+
+static inline const Elf32_Byte ELF32_ST_BIND(Elf32_Word i) { return i >> 4; }
+static inline const Elf32_Byte ELF32_ST_TYPE(Elf32_Word i) { return i & 0xf; }
+static inline const Elf32_Byte ELF32_ST_INFO(Elf32_Word b, Elf32_Word t) { return (b << 4) | (t & 0xf); }
+
+static inline const Elf32_Byte ELF64_ST_BIND(Elf32_Word i) { return i >> 4; }
+static inline const Elf32_Byte ELF64_ST_TYPE(Elf32_Word i) { return i & 0xf; }
+static inline const Elf32_Byte ELF64_ST_INFO(Elf32_Word b, Elf32_Word t) { return (b << 4) | (t & 0xf); }
+
+enum {
+ STB_LOCAL = 0,
+ STB_GLOBAL = 1,
+ STB_WEAK = 2,
+ STB_LOOS = 10,
+ STB_HIOS = 12,
+ STB_LOPROC = 13,
+ STB_HIPROC = 15
+};
+
+enum {
+ STT_NOTYPE = 0,
+ STT_OBJECT = 1,
+ STT_FUNC = 2,
+ STT_SECTION = 3,
+ STT_FILE = 4,
+ STT_LOOS = 10,
+ STT_HIOS = 12,
+ STT_LOPROC = 13,
+ STT_HIPROC = 15
+};
+
+enum {
+ STV_DEFAULT = 0,
+ STV_INTERNAL = 1,
+ STV_HIDDEN = 2,
+ STV_PROTECTED = 3
+};
+
+typedef struct {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ Elf32_Byte st_info;
+ Elf32_Byte st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+typedef struct {
+ Elf64_Word st_name;
+ Elf64_Byte st_info;
+ Elf64_Byte st_other;
+ Elf64_Half st_shndx;
+ Elf64_Addr st_value;
+ Elf64_Xword st_size;
+} Elf64_Sym;
+
+static inline const Elf32_Word ELF32_R_SYM(Elf32_Word i) { return i >> 8; }
+static inline const Elf32_Word ELF32_R_TYPE(Elf32_Word i) { return i & 0xff; }
+static inline const Elf32_Word ELF32_R_INFO(Elf32_Word s, Elf32_Word t) { return (s << 8) | (t & 0xff); }
+
+static inline const Elf64_Xword ELF64_R_SYM(Elf64_Xword i) { return i >> 32; }
+static inline const Elf64_Xword ELF64_R_TYPE(Elf64_Xword i) { return i & 0xffffffffUL; }
+static inline const Elf64_Xword ELF64_R_INFO(Elf64_Xword s, Elf64_Xword t) { return (s << 32) | (t & 0xffffffffUL); }
+
+typedef struct {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+typedef struct
+{
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+} Elf64_Rel;
+
+typedef struct
+{
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+ Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+enum {
+ R_X86_64_NONE = 0,
+ R_X86_64_64 = 1,
+ R_X86_64_PC32 = 2,
+ R_X86_64_GOT32 = 3,
+ R_X86_64_PLT32 = 4,
+ R_X86_64_COPY = 5,
+ R_X86_64_GLOB_DAT = 6,
+ R_X86_64_JUMP_SLOT = 7,
+ R_X86_64_RELATIVE = 8,
+ R_X86_64_GOTPCREL = 9,
+ R_X86_64_32 = 10,
+ R_X86_64_32S = 11,
+ R_X86_64_16 = 12,
+ R_X86_64_PC16 = 13,
+ R_X86_64_8 = 14,
+ R_X86_64_PC8 = 15,
+ R_X86_64_DTPMOD64 = 16,
+ R_X86_64_DTPOFF64 = 17,
+ R_X86_64_TPOFF64 = 18,
+ R_X86_64_TLSGD = 19,
+ R_X86_64_TLSLD = 20,
+ R_X86_64_DTPOFF32 = 21,
+ R_X86_64_GOTTPOFF = 22,
+ R_X86_64_TPOFF32 = 23,
+ R_X86_64_PC64 = 24,
+ R_X86_64_GOTOFF64 = 25,
+ R_X86_64_GOTPC32 = 26,
+ R_X86_64_SIZE32 = 32,
+ R_X86_64_SIZE64 = 33,
+ R_X86_64_GOTPC32_TLSDESC = 34,
+ R_X86_64_TLSDESC_CALL = 35,
+ R_X86_64_TLSDESC = 36,
+ R_X86_64_IRELATIVE = 37,
+ R_X86_64_RELATIVE64 = 38
+};
+
+enum {
+ R_RISCV_NONE = 0,
+ R_RISCV_32 = 1,
+ R_RISCV_64 = 2,
+ R_RISCV_RELATIVE = 3,
+ R_RISCV_COPY = 4,
+ R_RISCV_JUMP_SLOT = 5,
+ R_RISCV_TLS_DTPMOD32 = 6,
+ R_RISCV_TLS_DTPMOD64 = 7,
+ R_RISCV_TLS_DTPREL32 = 8,
+ R_RISCV_TLS_DTPREL64 = 9,
+ R_RISCV_TLS_TPREL32 = 10,
+ R_RISCV_TLS_TPREL64 = 11,
+ R_RISCV_BRANCH = 16,
+ R_RISCV_JAL = 17,
+ R_RISCV_CALL = 18,
+ R_RISCV_CALL_PLT = 19,
+ R_RISCV_GOT_HI20 = 20,
+ R_RISCV_TLS_GOT_HI20 = 21,
+ R_RISCV_TLS_GD_HI20 = 22,
+ R_RISCV_PCREL_HI20 = 23,
+ R_RISCV_PCREL_LO12_I = 24,
+ R_RISCV_PCREL_LO12_S = 25,
+ R_RISCV_HI20 = 26,
+ R_RISCV_LO12_I = 27,
+ R_RISCV_LO12_S = 28,
+ R_RISCV_TPREL_HI20 = 29,
+ R_RISCV_TPREL_LO12_I = 30,
+ R_RISCV_TPREL_LO12_S = 31,
+ R_RISCV_TPREL_ADD = 32,
+ R_RISCV_ADD8 = 33,
+ R_RISCV_ADD16 = 34,
+ R_RISCV_ADD32 = 35,
+ R_RISCV_ADD64 = 36,
+ R_RISCV_SUB8 = 37,
+ R_RISCV_SUB16 = 38,
+ R_RISCV_SUB32 = 39,
+ R_RISCV_SUB64 = 40,
+ R_RISCV_GNU_VTINHERIT = 41,
+ R_RISCV_GNU_VTENTRY = 42,
+ R_RISCV_ALIGN = 43,
+ R_RISCV_RVC_BRANCH = 44,
+ R_RISCV_RVC_JUMP = 45,
+ R_RISCV_RVC_LUI = 46,
+ R_RISCV_GPREL_I = 47,
+ R_RISCV_GPREL_S = 48,
+ R_RISCV_TPREL_I = 49,
+ R_RISCV_TPREL_S = 50,
+ R_RISCV_RELAX = 51,
+ R_RISCV_SUB6 = 52,
+ R_RISCV_SET6 = 53,
+ R_RISCV_SET8 = 54,
+ R_RISCV_SET16 = 55,
+ R_RISCV_SET32 = 56,
+};
+
+enum {
+ EF_RISCV_RVC = 0x1,
+ EF_RISCV_FLOAT_ABI_SINGLE = 0x2,
+ EF_RISCV_FLOAT_ABI_DOUBLE = 0x4,
+ EF_RISCV_FLOAT_ABI_QUAD = 0x6,
+ EF_RISCV_RVE = 0x8
+};
+
+enum {
+ DF_ORIGIN = 1,
+ DF_SYMBOLIC = 2,
+ DF_TEXTREL = 4,
+ DF_BIND_NOW = 8,
+ DF_STATIC_TLS = 16
+};
+
+enum {
+ DT_NULL = 0,
+ DT_NEEDED = 1,
+ DT_PLTRELSZ = 2,
+ DT_PLTGOT = 3,
+ DT_HASH = 4,
+ DT_STRTAB = 5,
+ DT_SYMTAB = 6,
+ DT_RELA = 7,
+ DT_RELASZ = 8,
+ DT_RELAENT = 9,
+ DT_STRSZ = 10,
+ DT_SYMENT = 11,
+ DT_INIT = 12,
+ DT_FINI = 13,
+ DT_SONAME = 14,
+ DT_RPATH = 15,
+ DT_SYMBOLIC = 16,
+ DT_REL = 17,
+ DT_RELSZ = 18,
+ DT_RELENT = 19,
+ DT_PLTREL = 20,
+ DT_DEBUG = 21,
+ DT_TEXTREL = 22,
+ DT_JMPREL = 23,
+ DT_BIND_NOW = 24,
+ DT_INIT_ARRAY = 25,
+ DT_FINI_ARRAY = 26,
+ DT_INIT_ARRAYSZ = 27,
+ DT_FINI_ARRAYSZ = 28,
+ DT_RUNPATH = 29,
+ DT_FLAGS = 30,
+ DT_LOOS = 0x60000000,
+ DT_HIOS = 0x6fffffff,
+ DT_LOPROC = 0x70000000,
+ DT_HIPROC = 0x7fffffff
+};
+
+typedef struct {
+ Elf32_Sword d_tag;
+ union {
+ Elf32_Word d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+ Elf64_Sxword d_tag;
+ union {
+ Elf64_Xword d_val;
+ Elf64_Addr d_ptr;
+ } d_un;
+} Elf64_Dyn;
diff --git a/riscv/riscv-probe/libfemto/include/endian.h b/riscv/riscv-probe/libfemto/include/endian.h
new file mode 100644
index 0000000..8510f29
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/endian.h
@@ -0,0 +1,95 @@
+#pragma once
+
+#define bswap16(x) __builtin_bswap16(x)
+#define bswap32(x) __builtin_bswap32(x)
+#define bswap64(x) __builtin_bswap64(x)
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline uint16_t htobe16(uint16_t x) { return bswap16(x); }
+static inline uint16_t htole16(uint16_t x) { return x; }
+static inline uint16_t be16toh(uint16_t x) { return bswap16(x); }
+static inline uint16_t le16toh(uint16_t x) { return x; }
+
+static inline uint32_t htobe32(uint32_t x) { return bswap32(x); }
+static inline uint32_t htole32(uint32_t x) { return x; }
+static inline uint32_t be32toh(uint32_t x) { return bswap32(x); }
+static inline uint32_t le32toh(uint32_t x) { return x; }
+
+static inline uint64_t htobe64(uint64_t x) { return bswap64(x); }
+static inline uint64_t htole64(uint64_t x) { return x; }
+static inline uint64_t be64toh(uint64_t x) { return bswap64(x); }
+static inline uint64_t le64toh(uint64_t x) { return x; }
+#elif __BYTE_ORDER == __BIG_ENDIAN
+static inline uint16_t htobe16(uint16_t x) { return x; }
+static inline uint16_t htole16(uint16_t x) { return bswap16(x); }
+static inline uint16_t be16toh(uint16_t x) { return x; }
+static inline uint16_t le16toh(uint16_t x) { return bswap16(x); }
+
+static inline uint32_t htobe32(uint32_t x) { return x; }
+static inline uint32_t htole32(uint32_t x) { return bswap32(x); }
+static inline uint32_t be32toh(uint32_t x) { return x; }
+static inline uint32_t le32toh(uint16_t x) { return bswap64(x); }
+
+static inline uint64_t htobe64(uint64_t x) { return x; }
+static inline uint64_t htole64(uint64_t x) { return bswap64(x); }
+static inline uint64_t be64toh(uint64_t x) { return x; }
+static inline uint64_t le64toh(uint64_t x) { return bswap64(x); }
+#endif
+
+#if __SIZE_WIDTH__ == 32
+#define _htobel htobe32
+#define _beltoh be32toh
+#define _htolel htole32
+#define _leltoh le32toh
+#endif
+
+#if __SIZE_WIDTH__ == 64
+#define _htobel htobe64
+#define _beltoh be64toh
+#define _htolel htole64
+#define _leltoh le64toh
+#endif
+
+#define htobe(X) _Generic((X), \
+ short: htobe16, \
+ unsigned short: htobe16, \
+ int: htobe32, \
+ unsigned int: htobe32, \
+ long: _htobel, \
+ unsigned long: _htobel, \
+ long long: htobe64, \
+ unsigned long long: htobe64 \
+ )(X)
+
+#define betoh(X) _Generic((X), \
+ short: be16toh, \
+ unsigned short: be16toh, \
+ int: be32toh, \
+ unsigned int: be32toh, \
+ long: _beltoh, \
+ unsigned long: _beltoh, \
+ long long: be64toh, \
+ unsigned long long: be64toh \
+ )(X)
+
+#define htole(X) _Generic((X), \
+ short: htole16, \
+ unsigned short: htole16, \
+ int: htole32, \
+ unsigned int: htole32, \
+ long: _htolel, \
+ unsigned long: _htolel, \
+ long long: htole64, \
+ unsigned long long: htole64 \
+ )(X)
+
+#define letoh(X) _Generic((X), \
+ short: le16toh, \
+ unsigned short: le16toh, \
+ int: le32toh, \
+ unsigned int: le32toh, \
+ long: _leltoh, \
+ unsigned long: _leltoh, \
+ long long: le64toh, \
+ unsigned long long: le64toh \
+ )(X)
diff --git a/riscv/riscv-probe/libfemto/include/femto.h b/riscv/riscv-probe/libfemto/include/femto.h
new file mode 100644
index 0000000..aa8b4cf
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/femto.h
@@ -0,0 +1,14 @@
+// See LICENSE for license details.
+
+#pragma once
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdbits.h>
+#include <string.h>
+
+#include "auxval.h"
+#include "device.h"
diff --git a/riscv/riscv-probe/libfemto/include/list.h b/riscv/riscv-probe/libfemto/include/list.h
new file mode 100644
index 0000000..5f4cc72
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/list.h
@@ -0,0 +1,495 @@
+/*
+ * Minimal Linux-like double-linked list helper functions
+ *
+ * Copyright (c) 2012-2016, Sven Eckelmann <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+/**
+ * container_of() - Calculate address of object that contains address ptr
+ * @ptr: pointer to member variable
+ * @type: type of the structure containing ptr
+ * @member: name of the member variable in struct @type
+ *
+ * Return: @type pointer of object containing ptr
+ */
+
+#define container_of(ptr, type, member) __extension__ ({ \
+ const __typeof__(((type *)0)->member) *__pmember = (ptr); \
+ (type *)((char *)__pmember - offsetof(type, member)); })
+
+/**
+ * struct list_head - Head and node of a double-linked list
+ * @prev: pointer to the previous node in the list
+ * @next: pointer to the next node in the list
+ *
+ * The simple double-linked list consists of a head and nodes attached to
+ * this head. Both node and head share the same struct type. The list_*
+ * functions and macros can be used to access and modify this data structure.
+ *
+ * The @prev pointer of the list head points to the last list node of the
+ * list and @next points to the first list node of the list. For an empty list,
+ * both member variables point to the head.
+ *
+ * The list nodes are usually embedded in a container structure which holds the
+ * actual data. Such an container object is called entry. The helper list_entry
+ * can be used to calculate the object address from the address of the node.
+ */
+struct list_head {
+ struct list_head *prev;
+ struct list_head *next;
+};
+
+/**
+ * LIST_HEAD - Declare list head and initialize it
+ * @head: name of the new object
+ */
+#define LIST_HEAD(head) \
+ struct list_head head = { &(head), &(head) }
+
+/**
+ * INIT_LIST_HEAD() - Initialize empty list head
+ * @head: pointer to list head
+ *
+ * This can also be used to initialize a unlinked list node.
+ *
+ * A node is usually linked inside a list, will be added to a list in
+ * the near future or the entry containing the node will be free'd soon.
+ *
+ * But an unlinked node may be given to a function which uses list_del(_init)
+ * before it ends up in a previously mentioned state. The list_del(_init) on an
+ * initialized node is well defined and safe. But the result of a
+ * list_del(_init) on an uninitialized node is undefined (unrelated memory is
+ * modified, crashes, ...).
+ */
+static __inline__ void INIT_LIST_HEAD(struct list_head *head)
+{
+ head->next = head;
+ head->prev = head;
+}
+
+/**
+ * list_add() - Add a list node to the beginning of the list
+ * @node: pointer to the new node
+ * @head: pointer to the head of the list
+ */
+static __inline__ void list_add(struct list_head *node,
+ struct list_head *head)
+{
+ struct list_head *next = head->next;
+
+ next->prev = node;
+ node->next = next;
+ node->prev = head;
+ head->next = node;
+}
+
+/**
+ * list_add_tail() - Add a list node to the end of the list
+ * @node: pointer to the new node
+ * @head: pointer to the head of the list
+ */
+static __inline__ void list_add_tail(struct list_head *node,
+ struct list_head *head)
+{
+ struct list_head *prev = head->prev;
+
+ prev->next = node;
+ node->next = head;
+ node->prev = prev;
+ head->prev = node;
+}
+
+/**
+ * list_add_before() - Add a list node before another node to the list
+ * @new_node: pointer to the new node
+ * @node: pointer to the reference node in the list
+ *
+ * WARNING this functionality is not available in the Linux list implementation
+ */
+#define list_add_before(new_node, node) \
+ list_add_tail(new_node, node)
+
+/**
+ * list_add_behind() - Add a list node behind another node to the list
+ * @new_node: pointer to the new node
+ * @node: pointer to the reference node in the list
+ *
+ * WARNING this functionality is not available in the Linux list implementation
+ */
+#define list_add_behind(new_node, node) \
+ list_add(new_node, node)
+
+/**
+ * list_del() - Remove a list node from the list
+ * @node: pointer to the node
+ *
+ * The node is only removed from the list. Neither the memory of the removed
+ * node nor the memory of the entry containing the node is free'd. The node
+ * has to be handled like an uninitialized node. Accessing the next or prev
+ * pointer of the node is not safe.
+ *
+ * Unlinked, initialized nodes are also uninitialized after list_del.
+ *
+ * LIST_POISONING can be enabled during build-time to provoke an invalid memory
+ * access when the memory behind the next/prev pointer is used after a list_del.
+ * This only works on systems which prohibit access to the predefined memory
+ * addresses.
+ */
+static __inline__ void list_del(struct list_head *node)
+{
+ struct list_head *next = node->next;
+ struct list_head *prev = node->prev;
+
+ next->prev = prev;
+ prev->next = next;
+
+#ifdef LIST_POISONING
+ node->prev = (struct list_head *)(0x00100100);
+ node->next = (struct list_head *)(0x00200200);
+#endif
+}
+
+/**
+ * list_del_init() - Remove a list node from the list and reinitialize it
+ * @node: pointer to the node
+ *
+ * The removed node will not end up in an uninitialized state like when using
+ * list_del. Instead the node is initialized again to the unlinked state.
+ */
+static __inline__ void list_del_init(struct list_head *node)
+{
+ list_del(node);
+ INIT_LIST_HEAD(node);
+}
+
+/**
+ * list_empty() - Check if list head has no nodes attached
+ * @head: pointer to the head of the list
+ *
+ * Return: 0 - list is not empty !0 - list is empty
+ */
+static __inline__ int list_empty(const struct list_head *head)
+{
+ return (head->next == head);
+}
+
+/**
+ * list_is_singular() - Check if list head has exactly one node attached
+ * @head: pointer to the head of the list
+ *
+ * Return: 0 - list is not singular !0 -list has exactly one entry
+ */
+static __inline__ int list_is_singular(const struct list_head *head)
+{
+ return (!list_empty(head) && head->prev == head->next);
+}
+
+/**
+ * list_splice() - Add list nodes from a list to beginning of another list
+ * @list: pointer to the head of the list with the node entries
+ * @head: pointer to the head of the list
+ *
+ * All nodes from @list are added to to the beginning of the list of @head.
+ * It is similar to list_add but for multiple nodes. The @list head is not
+ * modified and has to be initialized to be used as a valid list head/node
+ * again.
+ */
+static __inline__ void list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *head_first = head->next;
+ struct list_head *list_first = list->next;
+ struct list_head *list_last = list->prev;
+
+ if (list_empty(list))
+ return;
+
+ head->next = list_first;
+ list_first->prev = head;
+
+ list_last->next = head_first;
+ head_first->prev = list_last;
+}
+
+/**
+ * list_splice_tail() - Add list nodes from a list to end of another list
+ * @list: pointer to the head of the list with the node entries
+ * @head: pointer to the head of the list
+ *
+ * All nodes from @list are added to to the end of the list of @head.
+ * It is similar to list_add_tail but for multiple nodes. The @list head is not
+ * modified and has to be initialized to be used as a valid list head/node
+ * again.
+ */
+static __inline__ void list_splice_tail(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *head_last = head->prev;
+ struct list_head *list_first = list->next;
+ struct list_head *list_last = list->prev;
+
+ if (list_empty(list))
+ return;
+
+ head->prev = list_last;
+ list_last->next = head;
+
+ list_first->prev = head_last;
+ head_last->next = list_first;
+}
+
+/**
+ * list_splice_init() - Move list nodes from a list to beginning of another list
+ * @list: pointer to the head of the list with the node entries
+ * @head: pointer to the head of the list
+ *
+ * All nodes from @list are added to to the beginning of the list of @head.
+ * It is similar to list_add but for multiple nodes.
+ *
+ * The @list head will not end up in an uninitialized state like when using
+ * list_splice. Instead the @list is initialized again to the an empty
+ * list/unlinked state.
+ */
+static __inline__ void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ list_splice(list, head);
+ INIT_LIST_HEAD(list);
+}
+
+/**
+ * list_splice_tail_init() - Move list nodes from a list to end of another list
+ * @list: pointer to the head of the list with the node entries
+ * @head: pointer to the head of the list
+ *
+ * All nodes from @list are added to to the end of the list of @head.
+ * It is similar to list_add_tail but for multiple nodes.
+ *
+ * The @list head will not end up in an uninitialized state like when using
+ * list_splice. Instead the @list is initialized again to the an empty
+ * list/unlinked state.
+ */
+static __inline__ void list_splice_tail_init(struct list_head *list,
+ struct list_head *head)
+{
+ list_splice_tail(list, head);
+ INIT_LIST_HEAD(list);
+}
+
+/**
+ * list_cut_position() - Move beginning of a list to another list
+ * @head_to: pointer to the head of the list which receives nodes
+ * @head_from: pointer to the head of the list
+ * @node: pointer to the node in which defines the cutting point
+ *
+ * All entries from the beginning of the list @head_from to (including) the
+ * @node is moved to @head_from.
+ *
+ * @head_to is replaced when @head_from is not empty. @node must be a real
+ * list node from @head_from or the behavior is undefined.
+ */
+static __inline__ void list_cut_position(struct list_head *head_to,
+ struct list_head *head_from,
+ struct list_head *node)
+{
+ struct list_head *head_from_first = head_from->next;
+
+ if (list_empty(head_from))
+ return;
+
+ if (head_from == node) {
+ INIT_LIST_HEAD(head_to);
+ return;
+ }
+
+ head_from->next = node->next;
+ head_from->next->prev = head_from;
+
+ head_to->prev = node;
+ node->next = head_to;
+ head_to->next = head_from_first;
+ head_to->next->prev = head_to;
+}
+
+/**
+ * list_move() - Move a list node to the beginning of the list
+ * @node: pointer to the node
+ * @head: pointer to the head of the list
+ *
+ * The @node is removed from its old position/node and add to the beginning of
+ * @head
+ */
+static __inline__ void list_move(struct list_head *node, struct list_head *head)
+{
+ list_del(node);
+ list_add(node, head);
+}
+
+/**
+ * list_move_tail() - Move a list node to the end of the list
+ * @node: pointer to the node
+ * @head: pointer to the head of the list
+ *
+ * The @node is removed from its old position/node and add to the end of @head
+ */
+static __inline__ void list_move_tail(struct list_head *node,
+ struct list_head *head)
+{
+ list_del(node);
+ list_add_tail(node, head);
+}
+
+/**
+ * list_entry() - Calculate address of entry that contains list node
+ * @node: pointer to list node
+ * @type: type of the entry containing the list node
+ * @member: name of the list_head member variable in struct @type
+ *
+ * Return: @type pointer of entry containing node
+ */
+#define list_entry(node, type, member) container_of(node, type, member)
+
+/**
+ * list_first_entry() - get first entry of the list
+ * @head: pointer to the head of the list
+ * @type: type of the entry containing the list node
+ * @member: name of the list_head member variable in struct @type
+ *
+ * Return: @type pointer of first entry in list
+ */
+#define list_first_entry(head, type, member) \
+ list_entry((head)->next, type, member)
+
+/**
+ * list_last_entry() - get last entry of the list
+ * @head: pointer to the head of the list
+ * @type: type of the entry containing the list node
+ * @member: name of the list_head member variable in struct @type
+ *
+ * Return: @type pointer of last entry in list
+ */
+#define list_last_entry(head, type, member) \
+ list_entry((head)->prev, type, member)
+
+/**
+ * list_for_each - iterate over list nodes
+ * @node: list_head pointer used as iterator
+ * @head: pointer to the head of the list
+ *
+ * The nodes and the head of the list must must be kept unmodified while
+ * iterating through it. Any modifications to the the list will cause undefined
+ * behavior.
+ */
+#define list_for_each(node, head) \
+ for (node = (head)->next; \
+ node != (head); \
+ node = node->next)
+
+/**
+ * list_for_each_entry_t - iterate over list entries
+ * @entry: @type pointer used as iterator
+ * @head: pointer to the head of the list
+ * @type: type of the entries containing the list nodes
+ * @member: name of the list_head member variable in struct @type
+ *
+ * The nodes and the head of the list must must be kept unmodified while
+ * iterating through it. Any modifications to the the list will cause undefined
+ * behavior.
+ *
+ * WARNING this functionality is not available in the Linux list implementation
+ */
+#define list_for_each_entry_t(entry, head, type, member) \
+ for (entry = list_entry((head)->next, type, member); \
+ &entry->member != (head); \
+ entry = list_entry(entry->member.next, type, member))
+
+/**
+ * list_for_each_entry - iterate over list entries
+ * @entry: pointer used as iterator
+ * @head: pointer to the head of the list
+ * @member: name of the list_head member variable in struct type of @entry
+ *
+ * The nodes and the head of the list must must be kept unmodified while
+ * iterating through it. Any modifications to the the list will cause undefined
+ * behavior.
+ */
+#define list_for_each_entry(entry, head, member) \
+ list_for_each_entry_t(entry, head, __typeof__(*entry), member)
+
+/**
+ * list_for_each_safe - iterate over list nodes and allow deletes
+ * @node: list_head pointer used as iterator
+ * @safe: list_head pointer used to store info for next entry in list
+ * @head: pointer to the head of the list
+ *
+ * The current node (iterator) is allowed to be removed from the list. Any
+ * other modifications to the the list will cause undefined behavior.
+ */
+#define list_for_each_safe(node, safe, head) \
+ for (node = (head)->next, safe = node->next; \
+ node != (head); \
+ node = safe, safe = node->next)
+
+/**
+ * list_for_each_entry_safe_t - iterate over list entries and allow deletes
+ * @entry: @type pointer used as iterator
+ * @safe: @type pointer used to store info for next entry in list
+ * @head: pointer to the head of the list
+ * @type: type of the entries containing the list nodes
+ * @member: name of the list_head member variable in struct @type
+ *
+ * The current node (iterator) is allowed to be removed from the list. Any
+ * other modifications to the the list will cause undefined behavior.
+ *
+ * WARNING this functionality is not available in the Linux list implementation
+ */
+#define list_for_each_entry_safe_t(entry, safe, head, type, member) \
+ for (entry = list_entry((head)->next, type, member), \
+ safe = list_entry(entry->member.next, type, member); \
+ &entry->member != (head); \
+ entry = safe, \
+ safe = list_entry(safe->member.next, type, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list entries and allow deletes
+ * @entry: pointer used as iterator
+ * @safe: @type pointer used to store info for next entry in list
+ * @head: pointer to the head of the list
+ * @member: name of the list_head member variable in struct type of @entry
+ *
+ * The current node (iterator) is allowed to be removed from the list. Any
+ * other modifications to the the list will cause undefined behavior.
+ */
+#define list_for_each_entry_safe(entry, safe, head, member) \
+ list_for_each_entry_safe_t(entry, safe, head, __typeof__(*entry), \
+ member)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/spinlock.h b/riscv/riscv-probe/libfemto/include/spinlock.h
new file mode 100644
index 0000000..c11200f
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/spinlock.h
@@ -0,0 +1,6 @@
+// See LICENSE for license details.
+#pragma once
+
+#ifdef __riscv
+#include <arch/riscv/spinlock.h>
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/stdarg.h b/riscv/riscv-probe/libfemto/include/stdarg.h
new file mode 100644
index 0000000..7383c4a
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stdarg.h
@@ -0,0 +1,8 @@
+#pragma once
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+#define va_copy(d,s) __builtin_va_copy(d,s)
diff --git a/riscv/riscv-probe/libfemto/include/stdatomic.h b/riscv/riscv-probe/libfemto/include/stdatomic.h
new file mode 100644
index 0000000..8073868
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stdatomic.h
@@ -0,0 +1,61 @@
+// See LICENSE for license details.
+#pragma once
+
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+#ifdef __cplusplus
+typedef _Atomic(bool) atomic_bool;
+#else
+typedef _Atomic(_Bool) atomic_bool;
+#endif
+typedef _Atomic(char) atomic_char;
+typedef _Atomic(signed char) atomic_schar;
+typedef _Atomic(unsigned char) atomic_uchar;
+typedef _Atomic(short) atomic_short;
+typedef _Atomic(unsigned short) atomic_ushort;
+typedef _Atomic(int) atomic_int;
+typedef _Atomic(unsigned int) atomic_uint;
+typedef _Atomic(long) atomic_long;
+typedef _Atomic(unsigned long) atomic_ulong;
+typedef _Atomic(long long) atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+typedef _Atomic(uint_least16_t) atomic_char16_t;
+typedef _Atomic(uint_least32_t) atomic_char32_t;
+typedef _Atomic(wchar_t) atomic_wchar_t;
+typedef _Atomic(int_least8_t) atomic_int_least8_t;
+typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
+typedef _Atomic(int_least16_t) atomic_int_least16_t;
+typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
+typedef _Atomic(int_least32_t) atomic_int_least32_t;
+typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
+typedef _Atomic(int_least64_t) atomic_int_least64_t;
+typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
+typedef _Atomic(intptr_t) atomic_intptr_t;
+typedef _Atomic(uintptr_t) atomic_uintptr_t;
+typedef _Atomic(size_t) atomic_size_t;
+typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
+typedef _Atomic(intmax_t) atomic_intmax_t;
+typedef _Atomic(uintmax_t) atomic_uintmax_t;
+
+typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
+
+#define ATOMIC_FLAG_INIT { 0 }
+
+#ifdef __riscv
+#include <arch/riscv/stdatomic.h>
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/stdbits.h b/riscv/riscv-probe/libfemto/include/stdbits.h
new file mode 100644
index 0000000..2985381
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stdbits.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#define clz(val) ({ \
+ int result; \
+ switch(sizeof(val)) { \
+ case 1: result = clz8(val); break; \
+ case 2: result = clz16(val); break; \
+ case 4: result = clz32(val); break; \
+ case 8: result = clz64(val); break; \
+ } \
+ result; \
+})
+
+#define ctz(val) ({ \
+ int result; \
+ switch(sizeof(val)) { \
+ case 1: result = ctz8(val); break; \
+ case 2: result = ctz16(val); break; \
+ case 4: result = ctz32(val); break; \
+ case 8: result = ctz64(val); break; \
+ } \
+ result; \
+})
+
+int clz8(int8_t val);
+int clz16(int16_t val);
+int clz32(int32_t val);
+int clz64(int64_t val);
+
+int ctz8(int8_t val);
+int ctz16(int16_t val);
+int ctz32(int32_t val);
+int ctz64(int64_t val);
+
+static inline int ispow2(uintptr_t val)
+{
+ return val && !(val & (val-1));
+}
+
+static inline uintptr_t roundpow2(uintptr_t val)
+{
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+#if __SIZE_WIDTH__ == 64
+ val |= val >> 32;
+#endif
+ val++;
+ return val;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/stddef.h b/riscv/riscv-probe/libfemto/include/stddef.h
new file mode 100644
index 0000000..3799f2a
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stddef.h
@@ -0,0 +1,8 @@
+#pragma once
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+
+#define NULL 0L
+#define offsetof(type, member) __builtin_offsetof(type, member)
diff --git a/riscv/riscv-probe/libfemto/include/stdint.h b/riscv/riscv-probe/libfemto/include/stdint.h
new file mode 100644
index 0000000..bef5c2f
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stdint.h
@@ -0,0 +1,52 @@
+#pragma once
+
+typedef __INT8_TYPE__ int8_t;
+typedef __INT16_TYPE__ int16_t;
+typedef __INT32_TYPE__ int32_t;
+typedef __INT64_TYPE__ int64_t;
+
+typedef __INT_FAST8_TYPE__ int_fast8_t;
+typedef __INT_FAST16_TYPE__ int_fast16_t;
+typedef __INT_FAST32_TYPE__ int_fast32_t;
+typedef __INT_FAST64_TYPE__ int_fast64_t;
+
+typedef __INT_LEAST16_TYPE__ int_least16_t;
+typedef __INT_LEAST32_TYPE__ int_least32_t;
+typedef __INT_LEAST64_TYPE__ int_least64_t;
+typedef __INT_LEAST8_TYPE__ int_least8_t;
+
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __INTPTR_TYPE__ intptr_t;
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef __UINT64_TYPE__ uint64_t;
+
+typedef __UINT_FAST8_TYPE__ uint_fast8_t;
+typedef __UINT_FAST16_TYPE__ uint_fast16_t;
+typedef __UINT_FAST32_TYPE__ uint_fast32_t;
+typedef __UINT_FAST64_TYPE__ uint_fast64_t;
+
+typedef __UINT_LEAST8_TYPE__ uint_least8_t;
+typedef __UINT_LEAST16_TYPE__ uint_least16_t;
+typedef __UINT_LEAST32_TYPE__ uint_least32_t;
+typedef __UINT_LEAST64_TYPE__ uint_least64_t;
+
+typedef __UINTMAX_TYPE__ uintmax_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+#define INT8_MAX __INT8_MAX__
+#define INT16_MAX __INT16_MAX__
+#define INT32_MAX __INT32_MAX__
+#define INT64_MAX __INT64_MAX__
+
+#define UINT8_MAX __UINT8_MAX__
+#define UINT16_MAX __UINT16_MAX__
+#define UINT32_MAX __UINT32_MAX__
+#define UINT64_MAX __UINT64_MAX__
+
+#define INTPTR_MAX __INTPTR_MAX__
+#define UINTPTR_MAX __UINTPTR_MAX__
+#define PTRDIFF_MAX __PTRDIFF_MAX__
+#define SIZE_MAX __SIZE_MAX__
diff --git a/riscv/riscv-probe/libfemto/include/stdio.h b/riscv/riscv-probe/libfemto/include/stdio.h
new file mode 100644
index 0000000..f97e6e1
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stdio.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <stddef.h>
+
+int getchar(void);
+int printf(const char *, ...);
+int putchar(int);
+int puts(const char *);
+int snprintf(char *, size_t, const char *, ...);
+int vprintf(const char *, va_list);
+int vsnprintf(char *, size_t, const char *, va_list);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/stdlib.h b/riscv/riscv-probe/libfemto/include/stdlib.h
new file mode 100644
index 0000000..7552a1c
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/stdlib.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+__attribute__((noreturn)) void abort(void);
+__attribute__((noreturn)) void exit(int status);
+void* malloc(size_t size);
+void free(void* ptr);
+void _malloc_addblock(void* addr, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/riscv/riscv-probe/libfemto/include/string.h b/riscv/riscv-probe/libfemto/include/string.h
new file mode 100644
index 0000000..6572d23
--- /dev/null
+++ b/riscv/riscv-probe/libfemto/include/string.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+void *memchr(const void *s, int c, size_t n);
+int memcmp(const void *, const void *, size_t);
+void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
+char *strchr(const char *s, int c);
+int strcmp(const char *, const char *);
+size_t strlen(const char *);
+int strncmp(const char *, const char *, size_t);
+char *strncpy(char *, const char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif