From 14fb55933b173811467159df3e80e314b2e4415c Mon Sep 17 00:00:00 2001 From: rcitachi Date: Mon, 15 Jul 2024 17:58:29 +0800 Subject: [PATCH] [lwp][vdso] Add VDSO functionality under the aarch64 architecture (#9176) Add VDSO functionality under the aarch64 architecture --- .gitignore | 4 + components/lwp/Kconfig | 1 + components/lwp/SConscript | 10 +- components/lwp/arch/aarch64/common/vdso.c | 110 +++++++++++++ .../lwp/arch/aarch64/common/vdso_data.c | 34 ++++ components/lwp/lwp.h | 5 + components/lwp/lwp_elf.c | 15 ++ components/lwp/vdso/Kconfig | 5 + components/lwp/vdso/SConscript | 48 ++++++ components/lwp/vdso/kernel/vdso.h | 39 +++++ components/lwp/vdso/kernel/vdso_data.h | 48 ++++++ components/lwp/vdso/kernel/vdso_text.S | 21 +++ components/lwp/vdso/user/SConstruct | 39 +++++ components/lwp/vdso/user/vdso.lds.S | 60 +++++++ components/lwp/vdso/user/vdso_sys.c | 95 +++++++++++ components/lwp/vdso/user/vdso_sys.h | 153 ++++++++++++++++++ components/lwp/vdso/user/xmake.lua | 58 +++++++ components/lwp/vdso/vdso_config.h | 38 +++++ components/lwp/vdso/vdso_datapage.h | 75 +++++++++ components/lwp/vdso/vdso_weak.c | 23 +++ libcpu/aarch64/cortex-a/entry_point.S | 4 + src/clock.c | 8 + 22 files changed, 891 insertions(+), 2 deletions(-) create mode 100644 components/lwp/arch/aarch64/common/vdso.c create mode 100644 components/lwp/arch/aarch64/common/vdso_data.c create mode 100644 components/lwp/vdso/Kconfig create mode 100644 components/lwp/vdso/SConscript create mode 100644 components/lwp/vdso/kernel/vdso.h create mode 100644 components/lwp/vdso/kernel/vdso_data.h create mode 100644 components/lwp/vdso/kernel/vdso_text.S create mode 100644 components/lwp/vdso/user/SConstruct create mode 100644 components/lwp/vdso/user/vdso.lds.S create mode 100644 components/lwp/vdso/user/vdso_sys.c create mode 100644 components/lwp/vdso/user/vdso_sys.h create mode 100644 components/lwp/vdso/user/xmake.lua create mode 100644 components/lwp/vdso/vdso_config.h create mode 100644 components/lwp/vdso/vdso_datapage.h create mode 100644 components/lwp/vdso/vdso_weak.c diff --git a/.gitignore b/.gitignore index 9ddfece39e..cff9ff536b 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ tags CMakeLists.txt cmake-build-debug *.mk + +# vDSO +vdso_sys.os +vdso.lds diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig index 22cfbea47c..d88a0b6a9d 100644 --- a/components/lwp/Kconfig +++ b/components/lwp/Kconfig @@ -81,5 +81,6 @@ if RT_USING_LWP endif rsource "terminal/Kconfig" +rsource "vdso/Kconfig" endif diff --git a/components/lwp/SConscript b/components/lwp/SConscript index 5f4a618d48..be7b4f7b64 100644 --- a/components/lwp/SConscript +++ b/components/lwp/SConscript @@ -26,11 +26,16 @@ if platform in platform_file.keys(): # support platforms if arch in support_arch.keys() and cpu in support_arch[arch]: asm_path = 'arch/' + arch + '/' + cpu + '/*_' + platform_file[platform] arch_common = 'arch/' + arch + '/' + 'common/*.c' + if not GetDepend('RT_USING_VDSO'): + vdso_files = ['vdso_data.c', 'vdso.c'] + src += [f for f in Glob(arch_common) if os.path.basename(str(f)) not in vdso_files] + else: + src += Glob(arch_common) if not GetDepend('ARCH_MM_MMU'): excluded_files = ['ioremap.c', 'lwp_futex.c', 'lwp_mm_area.c', 'lwp_pmutex.c', 'lwp_shm.c', 'lwp_user_mm.c'] - src += [f for f in Glob('*.c') if os.path.basename(str(f)) not in excluded_files] + Glob(asm_path) + Glob(arch_common) + src += [f for f in Glob('*.c') if os.path.basename(str(f)) not in excluded_files] + Glob(asm_path) else: - src += Glob('*.c') + Glob(asm_path) + Glob(arch_common) + src += Glob('*.c') + Glob(asm_path) src += Glob('arch/' + arch + '/' + cpu + '/*.c') CPPPATH = [cwd] CPPPATH += [cwd + '/arch/' + arch + '/' + cpu] @@ -43,4 +48,5 @@ CPPPATH += ['./terminal/'] group = DefineGroup('lwP', src, depend = ['RT_USING_SMART'], CPPPATH = CPPPATH) +group = group + SConscript(os.path.join('vdso', 'SConscript')) Return('group') diff --git a/components/lwp/arch/aarch64/common/vdso.c b/components/lwp/arch/aarch64/common/vdso.c new file mode 100644 index 0000000000..41b0a6d8f0 --- /dev/null +++ b/components/lwp/arch/aarch64/common/vdso.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#include +#include +#include +#include + +#include "vdso.h" +#include "vdso_datapage.h" +#define DBG_TAG "vdso" +#define DBG_LVL DBG_INFO +#include + +enum vdso_abi { + VDSO_ABI_AA64, +}; +enum vvar_pages { + VVAR_DATA_PAGE_OFFSET, + VVAR_TIMENS_PAGE_OFFSET, + VVAR_NR_PAGES, +}; +struct vdso_abi_info { + const char *name; + const char *vdso_code_start; + const char *vdso_code_end; + unsigned long vdso_pages; + +}; + +static struct vdso_abi_info vdso_info[] = { + [VDSO_ABI_AA64] = { + .name = "vdso_aarch64", + .vdso_code_start = __vdso_text_start, + .vdso_code_end = __vdso_text_end, + }, +}; + +static union { + struct vdso_data data[CS_BASES]; + uint8_t page[ARCH_PAGE_SIZE]; +} vdso_data_store __page_aligned_data; +struct vdso_data *vdso_data = vdso_data_store.data; +int init_ret_flag = RT_EOK; + +static int __setup_additional_pages(enum vdso_abi abi, struct rt_lwp *lwp) +{ + RT_ASSERT(lwp != RT_NULL); + + int ret; + void *vdso_base = RT_NULL; + unsigned long vdso_data_len, vdso_text_len; + + vdso_data_len = VVAR_NR_PAGES * ARCH_PAGE_SIZE; + vdso_text_len = vdso_info[abi].vdso_pages << ARCH_PAGE_SHIFT; + + vdso_base = lwp_map_user_phy(lwp, RT_NULL, rt_kmem_v2p((void *)vdso_data), vdso_data_len, 0); + if(vdso_base != RT_NULL) + { + ret = RT_EOK; + } + else + { + ret = RT_ERROR; + } + vdso_base += vdso_data_len; + vdso_base = lwp_map_user_phy(lwp, vdso_base, rt_kmem_v2p((void *)vdso_info[abi].vdso_code_start), vdso_text_len, 0); + + lwp->vdso_vbase = vdso_base; + return ret; +} + +int arch_setup_additional_pages(struct rt_lwp *lwp) +{ + int ret; + if (init_ret_flag != RT_EOK) return -RT_ERROR; + ret = __setup_additional_pages(VDSO_ABI_AA64, lwp); + + return ret; +} + +static void __initdata(void) +{ + struct tm time_vdso = SOFT_RTC_VDSOTIME_DEFAULT; + vdso_data->realtime_initdata = timegm(&time_vdso); +} + +static int validate_vdso_elf(void) +{ + if (rt_memcmp(vdso_info[VDSO_ABI_AA64].vdso_code_start, ELF_HEAD, ELF_HEAD_LEN)) { + LOG_E("vDSO is not a valid ELF object!"); + init_ret_flag = -RT_ERROR; + return -RT_ERROR; + } + vdso_info[VDSO_ABI_AA64].vdso_pages = ( + vdso_info[VDSO_ABI_AA64].vdso_code_end - + vdso_info[VDSO_ABI_AA64].vdso_code_start) >> + ARCH_PAGE_SHIFT; + + __initdata(); + return RT_EOK; +} +INIT_COMPONENT_EXPORT(validate_vdso_elf); diff --git a/components/lwp/arch/aarch64/common/vdso_data.c b/components/lwp/arch/aarch64/common/vdso_data.c new file mode 100644 index 0000000000..13c055ec56 --- /dev/null +++ b/components/lwp/arch/aarch64/common/vdso_data.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#include +#include +#include +#include +#include +#include + +void rt_vdso_update_glob_time(void) +{ + struct vdso_data *vdata = get_k_vdso_data(); + struct timespec *vdso_ts; + uint64_t initdata = vdata->realtime_initdata; + rt_vdso_write_begin(vdata); + + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME]; + rt_ktime_boottime_get_ns(vdso_ts); + vdso_ts->tv_sec = initdata + vdso_ts->tv_sec; + + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC]; + rt_ktime_boottime_get_ns(vdso_ts); + + vdata->cycle_last = rt_hw_get_cntpct_val(); + rt_vdso_write_end(vdata); +} diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index e2cf2e8bd7..24b4150270 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -197,6 +197,10 @@ struct rt_lwp unsigned int asid; #endif struct rusage rt_rusage; + +#ifdef RT_USING_VDSO + void *vdso_vbase; +#endif }; @@ -373,6 +377,7 @@ void lwp_jobctrl_on_exit(struct rt_lwp *lwp); #define AT_RANDOM 25 #define AT_HWCAP2 26 #define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 struct process_aux_item { diff --git a/components/lwp/lwp_elf.c b/components/lwp/lwp_elf.c index da698e3674..69021a496d 100644 --- a/components/lwp/lwp_elf.c +++ b/components/lwp/lwp_elf.c @@ -25,6 +25,10 @@ #include #endif +#ifdef RT_USING_VDSO +#include +#endif + #define DBG_TAG "load.elf" #ifdef ELF_DEBUG_ENABLE #define DBG_LVL DBG_LOG @@ -607,6 +611,17 @@ static int elf_aux_fill(elf_load_info_t *load_info) ELF_AUX_ENT(aux_info, AT_CLKTCK, 0); ELF_AUX_ENT(aux_info, AT_SECURE, 0); +#ifdef RT_USING_VDSO + if(RT_EOK == arch_setup_additional_pages(load_info->lwp)) + { + ELF_AUX_ENT(aux_info, AT_SYSINFO_EHDR, (size_t)load_info->lwp->vdso_vbase); + } + else + { + LOG_W("vdso map error,VDSO currently only supports aarch64 architecture!"); + } +#endif + return 0; } diff --git a/components/lwp/vdso/Kconfig b/components/lwp/vdso/Kconfig new file mode 100644 index 0000000000..a10e016271 --- /dev/null +++ b/components/lwp/vdso/Kconfig @@ -0,0 +1,5 @@ +menuconfig RT_USING_VDSO + bool "vDSO" + default y + depends on RT_USING_SMART + diff --git a/components/lwp/vdso/SConscript b/components/lwp/vdso/SConscript new file mode 100644 index 0000000000..addcdfc840 --- /dev/null +++ b/components/lwp/vdso/SConscript @@ -0,0 +1,48 @@ +import os +import rtconfig +import subprocess +from building import * +Import('RTT_ROOT') + +group = [] + +cwd = GetCurrentDir() +CPPPATH = [cwd, cwd + "/kernel"] + +if not GetDepend(['RT_USING_VDSO']): + Return('group') + +if rtconfig.ARCH != "aarch64": + src = Glob('*.c') + group = DefineGroup('VDSO', src, depend = ['RT_USING_SMART','RT_USING_VDSO'], CPPPATH = CPPPATH) + Return('group') + +list = os.listdir(cwd) +src = Glob('kernel/*.c') +src +=Glob('kernel/*.S') + +if not os.path.exists(cwd + "/user/vdso.lds"): + Preprocessing("user/vdso.lds.S", ".lds", CPPPATH=[cwd]) + +#aarch64 vdso xmake +# vdso_file = os.path.join(cwd, 'usr', 'xmake.lua') +# command = ["xmake", "-F", vdso_file] +# clean = ["xmake", "clean"] + +vdso_file = os.path.join(cwd, 'user', 'SConstruct') +command = ["scons", "-f", vdso_file] +clean = ["scons", "-f", vdso_file, "--clean"] + +if not GetOption('clean'): + result = subprocess.run(command) +else: + result = subprocess.run(clean) + +if result.returncode == 0: + print("Command executed successfully") +else: + print("Command failed with exit code:", result.returncode) + exit(1) + +group = DefineGroup('VDSO', src, depend = ['RT_USING_SMART','RT_USING_VDSO'], CPPPATH = CPPPATH) +Return('group') diff --git a/components/lwp/vdso/kernel/vdso.h b/components/lwp/vdso/kernel/vdso.h new file mode 100644 index 0000000000..1cb3b44e8c --- /dev/null +++ b/components/lwp/vdso/kernel/vdso.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#ifndef _VDSO_H +#define _VDSO_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern char __vdso_text_start[]; +extern char __vdso_text_end[]; + +#define ELF_HEAD "\177ELF" +#define ELF_HEAD_LEN 4 +#define MAX_PAGES 5 + +#define __page_aligned_data __attribute__((section(".data.vdso.datapage"))) __attribute__((aligned(VDSO_PAGE_SIZE))) + +int arch_setup_additional_pages(struct rt_lwp *lwp); +void rt_vdso_update_glob_time(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _VDSO_H */ diff --git a/components/lwp/vdso/kernel/vdso_data.h b/components/lwp/vdso/kernel/vdso_data.h new file mode 100644 index 0000000000..5d077e4a9e --- /dev/null +++ b/components/lwp/vdso/kernel/vdso_data.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#ifndef _VDSO_KDATA_H +#define _VDSO_KDATA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct vdso_data *vdso_data; + +rt_inline +struct vdso_data *_get_k_vdso_data(void) +{ + return vdso_data; +} +#define get_k_vdso_data _get_k_vdso_data + +rt_inline +void rt_vdso_write_begin(struct vdso_data *vd) +{ + rt_atomic_add(&vd[CS_HRES_COARSE].seq, 1); + rt_atomic_add(&vd[CS_RAW].seq, 1); +} + +rt_inline +void rt_vdso_write_end(struct vdso_data *vd) +{ + rt_atomic_add(&vd[CS_HRES_COARSE].seq, 1); + rt_atomic_add(&vd[CS_RAW].seq, 1); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _VDSO_KDATA_H */ diff --git a/components/lwp/vdso/kernel/vdso_text.S b/components/lwp/vdso/kernel/vdso_text.S new file mode 100644 index 0000000000..f9c1f8aa72 --- /dev/null +++ b/components/lwp/vdso/kernel/vdso_text.S @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#include + + .globl __vdso_text_start, __vdso_text_end + .section .rodata + .balign VDSO_PAGE_SIZE +__vdso_text_start: + .incbin VDSO_PATH + .balign VDSO_PAGE_SIZE +__vdso_text_end: + + .previous diff --git a/components/lwp/vdso/user/SConstruct b/components/lwp/vdso/user/SConstruct new file mode 100644 index 0000000000..a7cee1127f --- /dev/null +++ b/components/lwp/vdso/user/SConstruct @@ -0,0 +1,39 @@ +import os +import sys +import subprocess + +arguments = sys.argv[2] +vdso_usr = os.path.dirname(arguments) +vdso_root = os.path.dirname(vdso_usr) + + +EXEC_PATH = os.getenv('RTT_EXEC_PATH') or '/usr/bin' +PREFIX = os.getenv('RTT_CC_PREFIX') or 'aarch64-none-elf-' + +CC = PREFIX + 'gcc' +CXX = PREFIX + 'g++' +CPP = PREFIX + 'cpp' +AS = PREFIX + 'gcc' +AR = PREFIX + 'ar' +LINK = PREFIX + 'gcc' + +DEVICE = ' -march=armv8-a -mtune=cortex-a53 -ftree-vectorize -ffast-math -funwind-tables -fno-strict-aliasing' +CXXFLAGS = DEVICE + ' -Wall -fdiagnostics-color=always' +AFLAGS = ' -x assembler-with-cpp' +CFLAGS = DEVICE + ' -Wall -Wno-cpp -std=gnu99 -fdiagnostics-color=always -fPIC -O2' +LFLAGS = DEVICE + ' -Bsymbolic -Wl,--gc-sections,-u,system_vectors -T {path}/vdso.lds'.format(path=vdso_usr) +CFLAGS += " -I {path} -I{path}/user".format(path=vdso_root) + +env = Environment(tools=['gcc', 'link'], + AS = AS, ASFLAGS = AFLAGS, + CC = CC, CFLAGS = CFLAGS, + CXX = CXX, CXXFLAGS = CXXFLAGS, + AR = AR, + LINK = LINK, LINKFLAGS = LFLAGS) +env.PrependENVPath('PATH', EXEC_PATH) + +src = os.path.join(vdso_usr,'vdso_sys.c') +target_name = 'librtos_vdso.so' +target = os.path.join(vdso_usr, "build", target_name) +shared_lib = env.SharedLibrary(target=target, source=src) +env.Default(shared_lib) diff --git a/components/lwp/vdso/user/vdso.lds.S b/components/lwp/vdso/user/vdso.lds.S new file mode 100644 index 0000000000..8b0038ee2d --- /dev/null +++ b/components/lwp/vdso/user/vdso.lds.S @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#include + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) + +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.39 { + global: + __kernel_clock_gettime; + local: *; + }; +} diff --git a/components/lwp/vdso/user/vdso_sys.c b/components/lwp/vdso/user/vdso_sys.c new file mode 100644 index 0000000000..61da379f04 --- /dev/null +++ b/components/lwp/vdso/user/vdso_sys.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#include +#include +#include +#include +#include + +#ifndef rt_vdso_cycles_ready +static inline bool rt_vdso_cycles_ready(uint64_t cycles) +{ + return true; +} +#endif + +#ifndef rt_vdso_get_ns +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(vd->clock_mode, vd); + 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 +__kernel_clock_gettime(clockid_t clock, struct timespec *ts) +{ + return rt_vdso_clock_gettime_data(__arch_get_vdso_data(), clock, ts); +} diff --git a/components/lwp/vdso/user/vdso_sys.h b/components/lwp/vdso/user/vdso_sys.h new file mode 100644 index 0000000000..ecc7b366ad --- /dev/null +++ b/components/lwp/vdso/user/vdso_sys.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#ifndef ASM_VDSO_SYS_H +#define ASM_VDSO_SYS_H + +#include +#include +#include +#include +#include + +#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(val) do { \ + uint64_t tmp, _val = (val); \ + \ + asm volatile( \ + " eor %0, %1, %1\n" \ + " add %0, sp, %0\n" \ + " ldr xzr, [%0]" \ + : "=r" (tmp) : "r" (_val)); \ +} while (0) + +static inline uint64_t __arch_get_hw_counter() +{ + uint64_t res; + + __asm__ volatile("mrs %0, CNTVCT_EL0":"=r"(res)); + + arch_counter_enforce_ordering(res); + return res; +} + +static inline uint64_t __arch_get_hw_frq() +{ + uint64_t res; + + __asm__ volatile("mrs %0, CNTFRQ_EL0":"=r"(res)); + + arch_counter_enforce_ordering(res); + 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(isb) +#define rt_hw_dmb() rt_hw_barrier(dmb, ish) +#define rt_hw_wmb() rt_hw_barrier(dmb, ishst) +#define rt_hw_rmb() rt_hw_barrier(dmb, ishld) +#define rt_hw_dsb() rt_hw_barrier(dsb, ish) + +#ifndef barrier +/* The "volatile" is due to gcc bugs */ +# define barrier() __asm__ __volatile__("": : :"memory") +#endif + +static inline void cpu_relax(void) +{ + __asm__ volatile("yield" ::: "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 diff --git a/components/lwp/vdso/user/xmake.lua b/components/lwp/vdso/user/xmake.lua new file mode 100644 index 0000000000..c36448131f --- /dev/null +++ b/components/lwp/vdso/user/xmake.lua @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +toolchain("aarch64-smart-musleabi") + set_kind("standalone") + + local exec_path = os.getenv("RTT_EXEC_PATH") or "/opt/aarch64-linux-musleabi/bin/" + local sdkdir = exec_path .. "/../" + local incdir = os.curdir() .. "/../include" + local device = '-march=armv8-a -mtune=cortex-a53 -ftree-vectorize -ffast-math -funwind-tables -fno-strict-aliasing' + + set_bindir(exec_path) + set_sdkdir(sdkdir) + + set_toolset("sh", "aarch64-linux-musleabi-gcc") + on_load(function(toolchain) + toolchain:load_cross_toolchain() + toolchain:add("cxflags", device) + toolchain:add("cxflags", "-Wall -Wno-cpp -std=gnu99") + toolchain:add("cxflags", "-fdiagnostics-color=always") + toolchain:add("cxflags", "-O2") + toolchain:add("cxflags", "-I" .. incdir) + + toolchain:add("shflags", device) + toolchain:add("shflags", "-Wl,--gc-sections") + toolchain:add("shflags", "-u,system_vectors") + toolchain:add("shflags", "-T vdso.lds") + end) +toolchain_end() + +set_config("plat", "cross") +set_config("target_os", "rt-smart") +set_config("arch", "aarch64") + +rule("vdso_lds") + set_extensions(".lds.S") + on_buildcmd_file(function (target, batchcmds, sourcefile, opt) + local incdir = os.curdir() .. "/../include" + local targetfile = path.basename(sourcefile) + local prefix = os.getenv("RTT_CC_PREFIX=") or "aarch64-linux-musleabi-" + batchcmds:vrunv(prefix .. "gcc", {"-E", "-P", sourcefile, "-o", targetfile, "-I", incdir}) + end) + +target("rtos_vdso") + set_toolchains("aarch64-smart-musleabi") + add_rules("vdso_lds") + set_kind("shared") + add_files("vdso.lds.S") + add_files("vdso_sys.c") + set_targetdir("build") +target_end() diff --git a/components/lwp/vdso/vdso_config.h b/components/lwp/vdso/vdso_config.h new file mode 100644 index 0000000000..ec5d775a33 --- /dev/null +++ b/components/lwp/vdso/vdso_config.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#ifndef __ASM_VDSO_H +#define __ASM_VDSO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __VVAR_PAGES 2 +#define VDSO_PAGE_SHIFT 12 +#define VDSO_PAGE_SIZE (1 << VDSO_PAGE_SHIFT) + +#define BIT_MASK(nr) ((1) << (nr)) + +#ifndef read_barrier_depends +#define read_barrier_depends() do { } while (0) +#endif + +#ifndef smp_read_barrier_depends +#define smp_read_barrier_depends() read_barrier_depends() +#endif + +#define VDSO_PATH "../user/build/librtos_vdso.so" + +#ifdef __cplusplus +} +#endif + +#endif /* __ASM_VDSO_H */ diff --git a/components/lwp/vdso/vdso_datapage.h b/components/lwp/vdso/vdso_datapage.h new file mode 100644 index 0000000000..243af48bf1 --- /dev/null +++ b/components/lwp/vdso/vdso_datapage.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#ifndef _VDSO_DATAPAGE_H +#define _VDSO_DATAPAGE_H + +#include +#include +#include "vdso_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef signed char __s8; +typedef signed short __s16; +typedef signed int __s32; +typedef signed long __s64; + +typedef unsigned char __u8; +typedef unsigned short __u16; +typedef unsigned int __u32; +typedef unsigned long __u64; + +#define MAX_CLOCKS 16 + +#define VDSO_BASES (CLOCK_TAI + 1) +#define VDSO_REALTIME (BIT_MASK(CLOCK_REALTIME) | \ + BIT_MASK(CLOCK_REALTIME_COARSE)) +#define VDSO_MONOTIME (BIT_MASK(CLOCK_MONOTONIC) | \ + BIT_MASK(CLOCK_MONOTONIC_COARSE) | \ + BIT_MASK(CLOCK_MONOTONIC_RAW) | \ + BIT_MASK(CLOCK_BOOTTIME)) + +#define CS_HRES_COARSE 0 +#define CS_RAW 1 +#define CS_BASES (CS_RAW + 1) + +/* 2018-01-30 14:44:50 = RTC_TIME_INIT(2018, 1, 30, 14, 44, 50) */ +#define RTC_VDSOTIME_INIT(year, month, day, hour, minute, second) \ + {.tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second} + +#ifndef SOFT_RTC_VDSOTIME_DEFAULT +#define SOFT_RTC_VDSOTIME_DEFAULT RTC_VDSOTIME_INIT(2018, 1, 1, 0, 0 ,0) +#endif + +struct vdso_data { + uint32_t seq; + uint32_t clock_mode; + uint64_t realtime_initdata; + uint64_t cycle_last; + struct timespec basetime[VDSO_BASES]; +}; +typedef struct vdso_data *vdso_data_t; + +#define MSEC_PER_SEC 1000L +#define USEC_PER_MSEC 1000L +#define NSEC_PER_USEC 1000L +#define NSEC_PER_MSEC 1000000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000L +#define FSEC_PER_SEC 1000000000000000LL + +#ifdef __cplusplus +} +#endif + +#endif /* _VDSO_DATAPAGE_H */ diff --git a/components/lwp/vdso/vdso_weak.c b/components/lwp/vdso/vdso_weak.c new file mode 100644 index 0000000000..56f452cc87 --- /dev/null +++ b/components/lwp/vdso/vdso_weak.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + */ + +#include +#include +#include "vdso.h" + +rt_weak int arch_setup_additional_pages(struct rt_lwp *lwp) +{ + return -RT_ERROR; +} + +rt_weak void rt_vdso_update_glob_time(void) +{ + +} diff --git a/libcpu/aarch64/cortex-a/entry_point.S b/libcpu/aarch64/cortex-a/entry_point.S index 315e331aac..c0acacb2ca 100644 --- a/libcpu/aarch64/cortex-a/entry_point.S +++ b/libcpu/aarch64/cortex-a/entry_point.S @@ -234,6 +234,10 @@ init_cpu_el: bic x0, x0, #(1 << 1) /* Disable Alignment check */ msr sctlr_el1, x0 + mrs x0, cntkctl_el1 + orr x0, x0, #(1 << 1) /* Set EL0VCTEN, enabling the EL0 Virtual Count Timer */ + msr cntkctl_el1, x0 + /* Avoid trap from SIMD or float point instruction */ mov x0, #0x00300000 /* Don't trap any SIMD/FP instructions in both EL0 and EL1 */ msr cpacr_el1, x0 diff --git a/src/clock.c b/src/clock.c index 6a2366a0ac..34684d2885 100644 --- a/src/clock.c +++ b/src/clock.c @@ -23,6 +23,10 @@ #include #include +#if defined(RT_USING_SMART) && defined(RT_USING_VDSO) +#include +#endif + #ifdef RT_USING_SMP #define rt_tick rt_cpu_index(0)->tick #else @@ -141,6 +145,10 @@ void rt_tick_increase(void) } #endif rt_timer_check(); + +#ifdef RT_USING_VDSO + rt_vdso_update_glob_time(); +#endif } /**