first commit for chrg
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
arguments = sys.argv[2]
|
||||
vdso_usr = arguments
|
||||
vdso_path = os.path.join(vdso_usr, '..', '..', '..')
|
||||
|
||||
EXEC_PATH = os.getenv('RTT_EXEC_PATH') or '/usr/bin'
|
||||
PREFIX = os.getenv('RTT_CC_PREFIX') or 'riscv64-none-elf-'
|
||||
|
||||
def get_riscv64_default_arch_abi(gcc_bin):
|
||||
try:
|
||||
result = subprocess.check_output(
|
||||
[gcc_bin, '-Q', '--help=target'],
|
||||
universal_newlines=True
|
||||
)
|
||||
arch = None
|
||||
abi = None
|
||||
for line in result.splitlines():
|
||||
if '-march=' in line:
|
||||
arch = line.strip().split()[1]
|
||||
arch = arch.split('_')[0] # Get the base architecture, e.g., rv64imafdc
|
||||
if '-mabi=' in line and 'option' not in line:
|
||||
abi = line.strip().split()[1]
|
||||
return arch, abi
|
||||
except Exception as e:
|
||||
print("Error getting arch/abi:", e)
|
||||
return None, None
|
||||
|
||||
# get the gcc path
|
||||
CC_BIN = PREFIX + 'gcc'
|
||||
arch, abi = get_riscv64_default_arch_abi(CC_BIN)
|
||||
if arch and abi:
|
||||
DEVICE = f' -march={arch} -mabi={abi} '
|
||||
else:
|
||||
DEVICE = ' -march=rv64imafdc -mabi=lp64' # fallback
|
||||
|
||||
CC = PREFIX + 'gcc'
|
||||
CPP = PREFIX + 'cpp'
|
||||
AS = PREFIX + 'gcc'
|
||||
AR = PREFIX + 'ar'
|
||||
LINK = PREFIX + 'gcc'
|
||||
|
||||
AFLAGS = ' -x assembler-with-cpp'
|
||||
CFLAGS = DEVICE + ' -Wall -Wno-cpp -std=gnu99 -fdiagnostics-color=always -fPIC -O2'
|
||||
LFLAGS = DEVICE + ' -Bsymbolic -Wl,--gc-sections -T {path}/vdso.lds'.format(path=vdso_usr)
|
||||
CFLAGS += " -I . -I {vdso_path} ".format(vdso_path=vdso_path)
|
||||
|
||||
src = Glob('*.c')
|
||||
env = Environment(tools=['gcc', 'link'],
|
||||
AS = AS, ASFLAGS = AFLAGS,
|
||||
CC = CC, CFLAGS = CFLAGS,
|
||||
CPP = CPP, AR = AR,
|
||||
LINK = LINK, LINKFLAGS = LFLAGS)
|
||||
env.PrependENVPath('PATH', EXEC_PATH)
|
||||
|
||||
target = os.path.join(vdso_path, 'user', 'build', 'libvdso.so')
|
||||
shared_lib = env.SharedLibrary(target=target, source=src)
|
||||
Clean(shared_lib, '{vdso_usr}/vdso.lds'.format(vdso_usr=vdso_usr))
|
||||
Clean(shared_lib, '.sconsign.dblite')
|
||||
env.Default(shared_lib)
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-04-22 ScuDays Add VDSO functionality under the riscv64 architecture.
|
||||
*/
|
||||
|
||||
#include <vdso_config.h>
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
PROVIDE(_vdso_data = . - __VVAR_PAGES * VDSO_PAGE_SIZE);
|
||||
. = SIZEOF_HEADERS;
|
||||
|
||||
.hash : { *(.hash) } :text
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
|
||||
.dynamic : { *(.dynamic) } :text :dynamic
|
||||
.rela.dyn : ALIGN(8) { *(.rela .rela*) }
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
*(.got)
|
||||
*(.got.plt)
|
||||
*(.plt)
|
||||
*(.plt.*)
|
||||
*(.iplt)
|
||||
*(.igot .igot.plt)
|
||||
} :text
|
||||
/DISCARD/ : {
|
||||
*(.data .data.* .sdata*)
|
||||
*(.bss .sbss .dynbss .dynsbss)
|
||||
}
|
||||
}
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5) FILEHDR PHDRS;
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
VERSION
|
||||
{
|
||||
LINUX_2.6 {
|
||||
global:
|
||||
__vdso_clock_gettime;
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-04-22 ScuDays Add VDSO functionality under the riscv64 architecture.
|
||||
* 2025-05-10 Bernard Move __arch_get_hw_frq() to vdso_sys.c as a weak function.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <vdso_sys.h>
|
||||
|
||||
#ifndef rt_vdso_cycles_ready
|
||||
static inline bool rt_vdso_cycles_ready(uint64_t cycles)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef rt_vdso_get_ns
|
||||
/* Implement as a weak function because there is no CPU cycle for RISCV */
|
||||
__attribute__((weak)) uint64_t __arch_get_hw_frq()
|
||||
{
|
||||
return 10000000;
|
||||
}
|
||||
|
||||
static inline uint64_t rt_vdso_get_ns(uint64_t cycles, uint64_t last)
|
||||
{
|
||||
return (cycles - last) * NSEC_PER_SEC / __arch_get_hw_frq();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
__rt_vdso_getcoarse(struct timespec *ts, clockid_t clock, const struct vdso_data *vdns)
|
||||
{
|
||||
const struct vdso_data *vd;
|
||||
const struct timespec *vdso_ts;
|
||||
uint32_t seq;
|
||||
uint64_t sec, last, ns, cycles;
|
||||
|
||||
if (clock != CLOCK_MONOTONIC_RAW)
|
||||
vd = &vdns[CS_HRES_COARSE];
|
||||
else
|
||||
vd = &vdns[CS_RAW];
|
||||
|
||||
vdso_ts = &vd->basetime[clock];
|
||||
|
||||
do {
|
||||
seq = rt_vdso_read_begin(vd);
|
||||
cycles = __arch_get_hw_counter();
|
||||
if (unlikely(!rt_vdso_cycles_ready(cycles)))
|
||||
return -1;
|
||||
ns = vdso_ts->tv_nsec;
|
||||
last = vd->cycle_last;
|
||||
ns += rt_vdso_get_ns(cycles, last);
|
||||
sec = vdso_ts->tv_sec;
|
||||
} while (unlikely(rt_vdso_read_retry(vd, seq)));
|
||||
|
||||
ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
|
||||
ts->tv_nsec = ns;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__vdso_clock_gettime_common(const struct vdso_data *vd, clockid_t clock,
|
||||
struct timespec *ts)
|
||||
{
|
||||
u_int32_t msk;
|
||||
|
||||
if (unlikely((u_int32_t)clock >= MAX_CLOCKS))
|
||||
return -1;
|
||||
|
||||
msk = 1U << clock;
|
||||
if (likely(msk & VDSO_REALTIME))
|
||||
return __rt_vdso_getcoarse(ts, CLOCK_REALTIME, vd);
|
||||
else if (msk & VDSO_MONOTIME)
|
||||
return __rt_vdso_getcoarse(ts, CLOCK_MONOTONIC, vd);
|
||||
else
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
static __maybe_unused int
|
||||
rt_vdso_clock_gettime_data(const struct vdso_data *vd, clockid_t clock,
|
||||
struct timespec *ts)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = __vdso_clock_gettime_common(vd, clock, ts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
|
||||
{
|
||||
return rt_vdso_clock_gettime_data(__arch_get_vdso_data(), clock, ts);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2025-04-22 ScuDays Add VDSO functionality under the riscv64 architecture.
|
||||
*/
|
||||
|
||||
#ifndef ASM_VDSO_SYS_H
|
||||
#define ASM_VDSO_SYS_H
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <vdso_config.h>
|
||||
#include <vdso_datapage.h>
|
||||
|
||||
#define __always_unused __attribute__((__unused__))
|
||||
#define __maybe_unused __attribute__((__unused__))
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#define arch_counter_enforce_ordering \
|
||||
__asm__ volatile("fence rw, rw" ::: "memory")
|
||||
|
||||
static inline uint64_t __arch_get_hw_counter(void)
|
||||
{
|
||||
uint64_t res;
|
||||
__asm__ volatile("rdtime %0" : "=r"(res));
|
||||
arch_counter_enforce_ordering;
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
__iter_div_u64_rem(uint64_t dividend, uint32_t divisor, uint64_t *remainder)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
while (dividend >= divisor)
|
||||
{
|
||||
/* The following asm() prevents the compiler from
|
||||
optimising this loop into a modulo operation. */
|
||||
__asm__("" : "+rm"(dividend));
|
||||
|
||||
dividend -= divisor;
|
||||
ret++;
|
||||
}
|
||||
|
||||
*remainder = dividend;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define __RT_STRINGIFY(x...) #x
|
||||
#define RT_STRINGIFY(x...) __RT_STRINGIFY(x)
|
||||
#define rt_hw_barrier(cmd, ...) \
|
||||
__asm__ volatile(RT_STRINGIFY(cmd) " " RT_STRINGIFY(__VA_ARGS__)::: "memory")
|
||||
|
||||
#define rt_hw_isb() rt_hw_barrier(fence.i)
|
||||
#define rt_hw_dmb() rt_hw_barrier(fence, rw, rw)
|
||||
#define rt_hw_wmb() rt_hw_barrier(fence, w, w)
|
||||
#define rt_hw_rmb() rt_hw_barrier(fence, r, r)
|
||||
#define rt_hw_dsb() rt_hw_barrier(fence, rw, rw)
|
||||
|
||||
#ifndef barrier
|
||||
|
||||
#define barrier() __asm__ __volatile__("fence" : : : "memory")
|
||||
#endif
|
||||
|
||||
static inline void cpu_relax(void)
|
||||
{
|
||||
__asm__ volatile("nop" ::: "memory");
|
||||
}
|
||||
|
||||
#define __READ_ONCE_SIZE \
|
||||
({ \
|
||||
switch (size) \
|
||||
{ \
|
||||
case 1: \
|
||||
*(__u8 *)res = *(volatile __u8 *)p; \
|
||||
break; \
|
||||
case 2: \
|
||||
*(__u16 *)res = *(volatile __u16 *)p; \
|
||||
break; \
|
||||
case 4: \
|
||||
*(__u32 *)res = *(volatile __u32 *)p; \
|
||||
break; \
|
||||
case 8: \
|
||||
*(__u64 *)res = *(volatile __u64 *)p; \
|
||||
break; \
|
||||
default: \
|
||||
barrier(); \
|
||||
__builtin_memcpy((void *)res, (const void *)p, size); \
|
||||
barrier(); \
|
||||
} \
|
||||
})
|
||||
|
||||
static inline void __read_once_size(const volatile void *p, void *res, int size)
|
||||
{
|
||||
__READ_ONCE_SIZE;
|
||||
}
|
||||
|
||||
#define __READ_ONCE(x, check) \
|
||||
({ \
|
||||
union { \
|
||||
typeof(x) __val; \
|
||||
char __c[1]; \
|
||||
} __u; \
|
||||
if (check) \
|
||||
__read_once_size(&(x), __u.__c, sizeof(x)); \
|
||||
smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \
|
||||
__u.__val; \
|
||||
})
|
||||
#define READ_ONCE(x) __READ_ONCE(x, 1)
|
||||
|
||||
extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden")));
|
||||
static inline struct vdso_data *__arch_get_vdso_data(void)
|
||||
{
|
||||
return _vdso_data;
|
||||
}
|
||||
|
||||
static inline uint32_t rt_vdso_read_begin(const struct vdso_data *vd)
|
||||
{
|
||||
uint32_t seq;
|
||||
|
||||
while (unlikely((seq = READ_ONCE(vd->seq)) & 1))
|
||||
cpu_relax();
|
||||
|
||||
rt_hw_rmb();
|
||||
return seq;
|
||||
}
|
||||
|
||||
static inline uint32_t rt_vdso_read_retry(const struct vdso_data *vd,
|
||||
uint32_t start)
|
||||
{
|
||||
uint32_t seq;
|
||||
|
||||
rt_hw_rmb();
|
||||
seq = READ_ONCE(vd->seq);
|
||||
return seq != start;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user