diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c index 5e89097b275..3e1ea77fd75 100644 --- a/components/libc/compilers/common/ctime.c +++ b/components/libc/compilers/common/ctime.c @@ -52,6 +52,10 @@ #define _WARNING_NO_RTC "Cannot find a RTC device!" +#if defined(RT_USING_SMART) && defined(RT_USING_VDSO) +#include +#endif + /* days per month -- nonleap! */ static const short __spm[13] = { @@ -519,12 +523,26 @@ int settimeofday(const struct timeval *tv, const struct timezone *tz) { if (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMEVAL, (void *)tv) == RT_EOK) { +#if defined(RT_USING_SMART) && defined(RT_USING_VDSO) + struct timespec ts = { + .tv_sec = tv->tv_sec, + .tv_nsec = tv->tv_usec * 1000L, + }; + rt_vdso_set_realtime(&ts); +#endif return 0; } else { if (_control_rtc(RT_DEVICE_CTRL_RTC_SET_TIME, (void *)&tv->tv_sec) == RT_EOK) { +#if defined(RT_USING_SMART) && defined(RT_USING_VDSO) + struct timespec ts = { + .tv_sec = tv->tv_sec, + .tv_nsec = 0, + }; + rt_vdso_set_realtime(&ts); +#endif return 0; } } @@ -736,7 +754,16 @@ int clock_settime(clockid_t clockid, const struct timespec *tp) { #ifdef RT_USING_RTC case CLOCK_REALTIME: - return _control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMESPEC, (void *)tp); + { + int ret = _control_rtc(RT_DEVICE_CTRL_RTC_SET_TIMESPEC, (void *)tp); + if (ret == RT_EOK) + { +#if defined(RT_USING_SMART) && defined(RT_USING_VDSO) + rt_vdso_set_realtime(tp); +#endif + } + return ret; + } #endif /* RT_USING_RTC */ case CLOCK_REALTIME_COARSE: diff --git a/components/lwp/SConscript b/components/lwp/SConscript index c53b3f483c7..56279cb9980 100644 --- a/components/lwp/SConscript +++ b/components/lwp/SConscript @@ -26,11 +26,13 @@ if platform in platform_file.keys(): # support platforms asm_path = 'arch/' + arch + '/' + cpu + '/*_' + platform_file[platform] arch_common = 'arch/' + arch + '/' + 'common/*.c' common = 'arch/common/*.c' + common_excluded = [] 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] - src += [f for f in Glob(common) if os.path.basename(str(f)) not in vdso_files] + common_excluded.append('vdso_kernel.c') + src += Glob(arch_common) + src += [f for f in Glob(common) if os.path.basename(str(f)) not in common_excluded] else: + CPPPATH += [cwd + '/vdso', cwd + '/vdso/kernel'] src += Glob(arch_common) src += Glob(common) if not GetDepend('ARCH_MM_MMU'): diff --git a/components/lwp/arch/aarch64/common/vdso_data.c b/components/lwp/arch/aarch64/common/vdso_data.c deleted file mode 100644 index b33094db9db..00000000000 --- a/components/lwp/arch/aarch64/common/vdso_data.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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_clock_boottime_get_ns(vdso_ts); - vdso_ts->tv_sec = initdata + vdso_ts->tv_sec; - - vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC]; - rt_clock_boottime_get_ns(vdso_ts); - - vdata->cycle_last = rt_hw_get_cntpct_val(); - rt_vdso_write_end(vdata); -} diff --git a/components/lwp/arch/common/vdso.c b/components/lwp/arch/common/vdso.c deleted file mode 100644 index 823fd5b61e9..00000000000 --- a/components/lwp/arch/common/vdso.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2006-2025 RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2024-07-04 rcitach init ver. - * 2025-04-22 ScuDays Add VDSO functionality under the riscv64 architecture. - */ - -#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_COMMON, -}; - -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_COMMON] = { - .name = "vdso_common", - .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_COMMON, 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_COMMON].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_COMMON].vdso_pages = (vdso_info[VDSO_ABI_COMMON].vdso_code_end - vdso_info[VDSO_ABI_COMMON].vdso_code_start) >> ARCH_PAGE_SHIFT; - - __initdata(); - return RT_EOK; -} -INIT_COMPONENT_EXPORT(validate_vdso_elf); diff --git a/components/lwp/arch/common/vdso_kernel.c b/components/lwp/arch/common/vdso_kernel.c new file mode 100644 index 00000000000..5eeab70897f --- /dev/null +++ b/components/lwp/arch/common/vdso_kernel.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-07-04 rcitach init ver. + * 2025-04-22 ScuDays Add VDSO functionality under the riscv64 architecture. + * 2026-04-21 rcitach Refactor vDSO runtime around the clock data page. + */ + +#include +#include +#include +#include +#include +#include +#ifdef RT_USING_RTC +#include +#endif + +#include +#include +#define DBG_TAG "vdso" +#define DBG_LVL DBG_INFO +#include + +enum rt_vdso_binary_id +{ + RT_VDSO_BINARY_COMMON, +}; + +struct rt_vdso_binary_info +{ + const char *name; + const char *image_start; + const char *image_end; + unsigned long page_count; +}; + +static struct rt_vdso_binary_info rt_vdso_binaries[] = { + [RT_VDSO_BINARY_COMMON] = { + .name = "rt_vdso_common", + .image_start = __rt_vdso_image_start, + .image_end = __rt_vdso_image_end, + }, +}; + +static union +{ + struct rt_vdso_data_page data_page; + uint8_t raw[RT_VDSO_DATA_PAGE_COUNT * ARCH_PAGE_SIZE]; +} rt_vdso_data_page_store RT_VDSO_DATA_PAGE_ALIGNED; +struct rt_vdso_data_page *rt_vdso_kernel_data_page = &rt_vdso_data_page_store.data_page; +RT_DEFINE_HW_SPINLOCK(rt_vdso_data_page_lock); +static int rt_vdso_runtime_status = RT_EOK; + +static struct timespec rt_vdso_realtime_offset; +static rt_bool_t rt_vdso_realtime_offset_ready; + +#ifndef MMU_MAP_U_ROCB +#define MMU_MAP_U_ROCB MMU_MAP_U_RWCB +#endif + +#ifndef MMU_MAP_U_RWCB_XN +#define MMU_MAP_U_RWCB_XN MMU_MAP_U_RWCB +#endif + +#ifdef MMU_MAP_U_ROCB_XN +#define RT_VDSO_DATA_PAGE_ATTR MMU_MAP_U_ROCB_XN +#elif defined(MMU_MAP_U_RWCB_XN) +#define RT_VDSO_DATA_PAGE_ATTR MMU_MAP_U_RWCB_XN +#else +#define RT_VDSO_DATA_PAGE_ATTR MMU_MAP_U_ROCB +#endif + +#define RT_VDSO_IMAGE_PAGE_ATTR MMU_MAP_U_ROCB + +static void rt_vdso_normalize_timespec(struct timespec *ts) +{ + while (ts->tv_nsec >= RT_VDSO_NSEC_PER_SEC) + { + ts->tv_sec += 1; + ts->tv_nsec -= RT_VDSO_NSEC_PER_SEC; + } + + while (ts->tv_nsec < 0) + { + ts->tv_sec -= 1; + ts->tv_nsec += RT_VDSO_NSEC_PER_SEC; + } +} + +static void rt_vdso_counter_to_timespec(rt_uint64_t counter_value, + struct timespec *ts) +{ + rt_uint64_t monotonic_ns; + + monotonic_ns = rt_clock_time_counter_to_ns(counter_value); + ts->tv_sec = monotonic_ns / RT_VDSO_NSEC_PER_SEC; + ts->tv_nsec = monotonic_ns % RT_VDSO_NSEC_PER_SEC; +} + +static rt_uint64_t rt_vdso_read_arch_counter(void) +{ + rt_uint64_t counter; + +#if defined(__aarch64__) + __asm__ volatile("mrs %0, CNTVCT_EL0" : "=r"(counter)); +#elif defined(__arm__) + rt_uint32_t lo; + rt_uint32_t hi; + + __asm__ volatile("mrrc p15, 1, %0, %1, c14" : "=r"(lo), "=r"(hi)); + counter = ((rt_uint64_t)hi << 32) | lo; +#elif defined(__riscv) + __asm__ volatile("rdtime %0" : "=r"(counter)); +#else + counter = rt_clock_time_get_counter(); +#endif + + return counter; +} + +static struct timespec rt_vdso_timespec_subtract(const struct timespec *lhs, + const struct timespec *rhs) +{ + struct timespec ret; + + ret.tv_sec = lhs->tv_sec - rhs->tv_sec; + ret.tv_nsec = lhs->tv_nsec - rhs->tv_nsec; + rt_vdso_normalize_timespec(&ret); + + return ret; +} + +static struct timespec rt_vdso_add_timespec(const struct timespec *lhs, + const struct timespec *rhs) +{ + struct timespec ret; + + ret.tv_sec = lhs->tv_sec + rhs->tv_sec; + ret.tv_nsec = lhs->tv_nsec + rhs->tv_nsec; + rt_vdso_normalize_timespec(&ret); + + return ret; +} + +static int rt_vdso_read_monotonic_snapshot(struct timespec *monotonic_time, + rt_uint64_t *counter_value, + rt_uint64_t *counter_freq) +{ + rt_uint64_t monotonic_counter; + + monotonic_counter = rt_clock_time_get_counter(); + *counter_freq = rt_clock_time_get_freq(); + if (*counter_freq == 0) + { + return -RT_ERROR; + } + + /* User vDSO computes deltas from the raw architecture counter. */ + *counter_value = rt_vdso_read_arch_counter(); + rt_vdso_counter_to_timespec(monotonic_counter, monotonic_time); + + return RT_EOK; +} + +static void rt_vdso_update_data_page_flags(void) +{ + rt_uint64_t flags = 0; + + if (rt_vdso_realtime_offset_ready) + { + flags |= RT_VDSO_FLAG_REALTIME_VALID; + } + + rt_vdso_kernel_data_page->flags = flags; +} + +static void rt_vdso_store_clock_snapshot(const struct timespec *monotonic_time, + rt_uint64_t counter_value, + rt_uint64_t counter_freq) +{ + rt_vdso_kernel_data_page->counter_last = counter_value; + rt_vdso_kernel_data_page->counter_freq = counter_freq; + rt_vdso_update_data_page_flags(); + rt_vdso_kernel_data_page->base_time[RT_VDSO_CLOCK_MONOTONIC_INDEX] = *monotonic_time; + if (rt_vdso_realtime_offset_ready) + { + rt_vdso_kernel_data_page->base_time[RT_VDSO_CLOCK_REALTIME_INDEX] = + rt_vdso_add_timespec(monotonic_time, &rt_vdso_realtime_offset); + } + else + { + rt_vdso_kernel_data_page->base_time[RT_VDSO_CLOCK_REALTIME_INDEX] = *monotonic_time; + } +} + +void rt_vdso_set_realtime(const struct timespec *realtime) +{ + struct timespec monotonic; + rt_uint64_t counter; + rt_uint64_t freq; + + if (rt_vdso_runtime_status != RT_EOK || realtime == RT_NULL) + { + return; + } + + if (rt_vdso_read_monotonic_snapshot(&monotonic, &counter, &freq) != RT_EOK) + { + return; + } + + rt_hw_spin_lock(&rt_vdso_data_page_lock); + rt_vdso_data_page_write_begin(rt_vdso_kernel_data_page); + rt_vdso_realtime_offset = rt_vdso_timespec_subtract(realtime, &monotonic); + rt_vdso_realtime_offset_ready = RT_TRUE; + rt_vdso_store_clock_snapshot(&monotonic, counter, freq); + rt_vdso_data_page_write_end(rt_vdso_kernel_data_page); + rt_hw_spin_unlock(&rt_vdso_data_page_lock); +} + +static void *rt_vdso_map_physical_pages(struct rt_lwp *lwp, void *user_va, + void *kernel_pa, size_t map_size, + rt_size_t attr) +{ + int err; + char *va; + size_t offset = 0; + + if (!map_size) + { + return RT_NULL; + } + + if (user_va) + { + if (((size_t)user_va & ARCH_PAGE_MASK) != + ((size_t)kernel_pa & ARCH_PAGE_MASK)) + { + return RT_NULL; + } + } + + offset = (size_t)kernel_pa & ARCH_PAGE_MASK; + map_size += offset + ARCH_PAGE_SIZE - 1; + map_size &= ~ARCH_PAGE_MASK; + kernel_pa = (void *)((size_t)kernel_pa & ~ARCH_PAGE_MASK); + struct rt_mm_va_hint hint = { + .flags = 0, + .limit_range_size = lwp->aspace->size, + .limit_start = lwp->aspace->start, + .prefer = user_va, + .map_size = map_size, + }; + + if (user_va != RT_NULL) + { + hint.flags |= MMF_MAP_FIXED; + } + + err = rt_aspace_map_phy(lwp->aspace, &hint, attr, MM_PA_TO_OFF(kernel_pa), + (void **)&va); + if (err != RT_EOK) + { + return RT_NULL; + } + + return va + offset; +} + + +static int rt_vdso_map_binary_pages(enum rt_vdso_binary_id binary_id, + struct rt_lwp *lwp) +{ + void *data_page_base = RT_NULL; + void *image_base = RT_NULL; + unsigned long data_page_len; + unsigned long image_len; + + RT_ASSERT(lwp != RT_NULL); + + data_page_len = RT_VDSO_DATA_PAGE_COUNT * ARCH_PAGE_SIZE; + image_len = rt_vdso_binaries[binary_id].page_count << ARCH_PAGE_SHIFT; + + data_page_base = rt_vdso_map_physical_pages( + lwp, RT_NULL, rt_kmem_v2p((void *)rt_vdso_get_kernel_data_page()), + data_page_len, RT_VDSO_DATA_PAGE_ATTR); + if (data_page_base == RT_NULL) + { + lwp->vdso_vbase = RT_NULL; + return -RT_ERROR; + } + + image_base = (uint8_t *)data_page_base + data_page_len; + image_base = rt_vdso_map_physical_pages( + lwp, image_base, + rt_kmem_v2p((void *)rt_vdso_binaries[binary_id].image_start), + image_len, RT_VDSO_IMAGE_PAGE_ATTR); + if (image_base == RT_NULL) + { + lwp_unmap_user_phy(lwp, data_page_base); + lwp->vdso_vbase = RT_NULL; + return -RT_ERROR; + } + + lwp->vdso_vbase = image_base; + return RT_EOK; +} + +int rt_vdso_map_process_image(struct rt_lwp *lwp) +{ + if (rt_vdso_runtime_status != RT_EOK) + { + return -RT_ERROR; + } + + return rt_vdso_map_binary_pages(RT_VDSO_BINARY_COMMON, lwp); +} + +void rt_vdso_sync_clock_data(void) +{ + struct timespec monotonic; + rt_uint64_t counter; + rt_uint64_t freq; + + if (rt_vdso_runtime_status != RT_EOK) + { + return; + } + + if (rt_vdso_read_monotonic_snapshot(&monotonic, &counter, &freq) != RT_EOK) + { + return; + } + + rt_hw_spin_lock(&rt_vdso_data_page_lock); + rt_vdso_data_page_write_begin(rt_vdso_kernel_data_page); + rt_vdso_store_clock_snapshot(&monotonic, counter, freq); + rt_vdso_data_page_write_end(rt_vdso_kernel_data_page); + rt_hw_spin_unlock(&rt_vdso_data_page_lock); +} + +static int rt_vdso_validate_elf_header(const void *image) +{ + const unsigned char *ident = (const unsigned char *)image; + +#if defined(__aarch64__) + const Elf64_Ehdr *ehdr = (const Elf64_Ehdr *)image; + + if (ident[EI_CLASS] != ELFCLASS64) + { + LOG_E("vDSO ELF class mismatch: expect ELF64"); + return -RT_ERROR; + } + + if (ehdr->e_type != ET_DYN) + { + LOG_E("vDSO ELF type mismatch!"); + return -RT_ERROR; + } + + if (ehdr->e_machine != EM_AARCH64) + { + LOG_E("vDSO machine mismatch: expect AArch64"); + return -RT_ERROR; + } +#elif defined(__arm__) + const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)image; + + if (ident[EI_CLASS] != ELFCLASS32) + { + LOG_E("vDSO ELF class mismatch: expect ELF32"); + return -RT_ERROR; + } + + if (ehdr->e_type != ET_DYN) + { + LOG_E("vDSO ELF type mismatch!"); + return -RT_ERROR; + } + + if (ehdr->e_machine != EM_ARM) + { + LOG_E("vDSO machine mismatch: expect ARM"); + return -RT_ERROR; + } +#elif defined(__riscv) + const Elf64_Ehdr *ehdr = (const Elf64_Ehdr *)image; + + if (ident[EI_CLASS] != ELFCLASS64) + { + LOG_E("vDSO ELF class mismatch: expect ELF64"); + return -RT_ERROR; + } + + if (ehdr->e_type != ET_DYN) + { + LOG_E("vDSO ELF type mismatch!"); + return -RT_ERROR; + } + + if (ehdr->e_machine != EM_RISCV) + { + LOG_E("vDSO machine mismatch: expect RISC-V"); + return -RT_ERROR; + } +#else + LOG_E("vDSO unsupported architecture!"); + return -RT_ERROR; +#endif + + return RT_EOK; +} + +static int rt_vdso_validate_image(void) +{ + const void *image = rt_vdso_binaries[RT_VDSO_BINARY_COMMON].image_start; + + rt_memset(rt_vdso_data_page_store.raw, 0, sizeof(rt_vdso_data_page_store.raw)); + rt_vdso_realtime_offset_ready = RT_FALSE; + rt_memset(&rt_vdso_realtime_offset, 0, sizeof(rt_vdso_realtime_offset)); + + if (rt_memcmp(image, RT_VDSO_IMAGE_ELF_MAGIC, RT_VDSO_IMAGE_ELF_MAGIC_LEN)) + { + LOG_E("vDSO is not a valid ELF object!"); + rt_vdso_runtime_status = -RT_ERROR; + return -RT_ERROR; + } + + if (rt_vdso_validate_elf_header(image) != RT_EOK) + { + rt_vdso_runtime_status = -RT_ERROR; + return -RT_ERROR; + } + + rt_vdso_binaries[RT_VDSO_BINARY_COMMON].page_count = + (rt_vdso_binaries[RT_VDSO_BINARY_COMMON].image_end - + rt_vdso_binaries[RT_VDSO_BINARY_COMMON].image_start) >> + ARCH_PAGE_SHIFT; + if (rt_vdso_binaries[RT_VDSO_BINARY_COMMON].page_count == 0) + { + LOG_E("vDSO image is empty!"); + rt_vdso_runtime_status = -RT_ERROR; + return -RT_ERROR; + } + + return RT_EOK; +} +INIT_COMPONENT_EXPORT(rt_vdso_validate_image); diff --git a/components/lwp/arch/risc-v/common/vdso_data.c b/components/lwp/arch/risc-v/common/vdso_data.c deleted file mode 100644 index b457c1f7eec..00000000000 --- a/components/lwp/arch/risc-v/common/vdso_data.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 -#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_clock_boottime_get_ns(vdso_ts); - vdso_ts->tv_sec = initdata + vdso_ts->tv_sec; - - vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC]; - rt_clock_boottime_get_ns(vdso_ts); - - vdata->cycle_last = rdtime(); - rt_vdso_write_end(vdata); -} diff --git a/components/lwp/lwp_elf.c b/components/lwp/lwp_elf.c index 93aa082d2bf..c6809f8cae2 100644 --- a/components/lwp/lwp_elf.c +++ b/components/lwp/lwp_elf.c @@ -26,7 +26,7 @@ #endif #ifdef RT_USING_VDSO -#include +#include #endif #define DBG_TAG "load.elf" @@ -37,27 +37,27 @@ #endif #include -#define ELF_INVALID_FD -1 +#define ELF_INVALID_FD -1 #define ELF_PHDR_NUM_MAX 128 -#define FILE_LENGTH_MAX 0xC0000000 -#define MEM_SIZE_MAX 0xC0000000 -#define ELF_PATH_MAX 256 -#define FLF_PATH_MIN 1 +#define FILE_LENGTH_MAX 0xC0000000 +#define MEM_SIZE_MAX 0xC0000000 +#define ELF_PATH_MAX 256 +#define FLF_PATH_MIN 1 -#define ELF_PAGESTART(_v) ((_v) & ~(rt_ubase_t)(ARCH_PAGE_SIZE - 1)) +#define ELF_PAGESTART(_v) ((_v) & ~(rt_ubase_t)(ARCH_PAGE_SIZE - 1)) #define ELF_PAGEOFFSET(_v) ((_v) & (ARCH_PAGE_SIZE - 1)) -#define ELF_PAGEALIGN(_v) (((_v) + ARCH_PAGE_SIZE - 1) & ~(ARCH_PAGE_SIZE - 1)) +#define ELF_PAGEALIGN(_v) (((_v) + ARCH_PAGE_SIZE - 1) & ~(ARCH_PAGE_SIZE - 1)) -#define ELF_EXEC_LOAD_ADDR USER_VADDR_START +#define ELF_EXEC_LOAD_ADDR USER_VADDR_START #define ELF_INTERP_LOAD_ADDR LDSO_LOAD_VADDR -#define ELF_AUX_ENT(aux, id, val) \ - do \ - { \ - rt_base_t a = id; \ - lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \ - a = val; \ - lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \ +#define ELF_AUX_ENT(aux, id, val) \ + do \ + { \ + rt_base_t a = id; \ + lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \ + a = val; \ + lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \ } while (0) /** @@ -127,10 +127,10 @@ static void elf_user_dump(struct rt_lwp *lwp, void *va, size_t len) for (size_t i = 0; i < len; i += 16) { - rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x ", k_va[i], k_va[i+1], k_va[i+2], k_va[i+3], - k_va[i+4], k_va[i+5], k_va[i+6], k_va[i+7]); - rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x \n", k_va[i+8], k_va[i+9], k_va[i+10], k_va[i+11], - k_va[i+12], k_va[i+13], k_va[i+14], k_va[i+15]); + rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x ", k_va[i], k_va[i + 1], k_va[i + 2], k_va[i + 3], + k_va[i + 4], k_va[i + 5], k_va[i + 6], k_va[i + 7]); + rt_kprintf(" %02x %02x %02x %02x %02x %02x %02x %02x \n", k_va[i + 8], k_va[i + 9], k_va[i + 10], k_va[i + 11], + k_va[i + 12], k_va[i + 13], k_va[i + 14], k_va[i + 15]); } rt_kprintf("\r\n"); rt_free(k_va); @@ -169,7 +169,7 @@ rt_ubase_t elf_random_offset(void) * @return Virtual address where the file is mapped on success, NULL on failure. */ static void *file_mmap(struct rt_lwp *lwp, int fd, rt_ubase_t load_addr, - rt_ubase_t map_size, size_t prot, size_t flags, rt_ubase_t offset) + rt_ubase_t map_size, size_t prot, size_t flags, rt_ubase_t offset) { uint8_t *map_va; @@ -478,7 +478,7 @@ static int elf_load_interp(elf_load_info_t *load_info) } ret = elf_file_read(load_info->exec_info.fd, (rt_uint8_t *)load_info->interp_info.filename, - phdr->p_filesz, phdr->p_offset); + phdr->p_filesz, phdr->p_offset); if (ret != RT_EOK) { LOG_E("%s : elf_file_read failed, ret = %d", __func__, ret); @@ -543,7 +543,7 @@ static int total_mapping_size(elf_info_t *elf_info) return -1; elf_info->map_size = elf_info->phdr[last_idx].p_vaddr + elf_info->phdr[last_idx].p_memsz - - ELF_PAGESTART(elf_info->phdr[first_idx].p_vaddr); + ELF_PAGESTART(elf_info->phdr[first_idx].p_vaddr); return 0; } @@ -592,7 +592,7 @@ static rt_ubase_t elf_map(struct rt_lwp *lwp, const Elf_Phdr *elf_phdr, int fd, } static int elf_zero_bss(struct rt_lwp *lwp, int fd, const Elf_Phdr *phdr, rt_ubase_t bss_start, - rt_ubase_t bss_end) + rt_ubase_t bss_end) { lwp_data_set(lwp, (void *)bss_start, 0, bss_end - bss_start); @@ -617,7 +617,7 @@ static int elf_zero_bss(struct rt_lwp *lwp, int fd, const Elf_Phdr *phdr, rt_uba * @return -ENOMEM if memory allocation fails. */ static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ubase_t *elfload_addr, - rt_uint32_t map_size, rt_ubase_t *load_base) + rt_uint32_t map_size, rt_ubase_t *load_base) { int ret, i; rt_ubase_t map_va, bss_start, bss_end; @@ -688,7 +688,7 @@ static int elf_file_mmap(elf_load_info_t *load_info, elf_info_t *elf_info, rt_ub { *elfload_addr = map_va + ELF_PAGEOFFSET(tmp_phdr->p_vaddr); LOG_D("%s elf_load_addr : %p, vAddr : %p, load_base : %p, map_va : %p", __func__, - *elfload_addr, tmp_phdr->p_vaddr, *load_base, map_va); + *elfload_addr, tmp_phdr->p_vaddr, *load_base, map_va); } if ((*load_base == 0) && (ehdr->e_type == ET_DYN)) @@ -722,7 +722,7 @@ static int load_elf_interp(elf_load_info_t *load_info, rt_ubase_t *interp_base) LOG_D("%s : total_mapping_size 0x%x", __func__, load_info->interp_info.map_size); return elf_file_mmap(load_info, &load_info->interp_info, interp_base, - load_info->interp_info.map_size, &load_base); + load_info->interp_info.map_size, &load_base); } /** @@ -783,13 +783,13 @@ static int elf_aux_fill(elf_load_info_t *load_info) ELF_AUX_ENT(aux_info, AT_SECURE, 0); #ifdef RT_USING_VDSO - if(RT_EOK == arch_setup_additional_pages(load_info->lwp)) + if (RT_EOK == rt_vdso_map_process_image(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!"); + LOG_W("vdso map error, skip AT_SYSINFO_EHDR setup"); } #endif @@ -834,7 +834,7 @@ static int elf_load_segment(elf_load_info_t *load_info) /* Map the segments of the ELF file into memory */ ret = elf_file_mmap(load_info, &load_info->exec_info, &load_info->load_addr, - load_info->exec_info.map_size, &app_load_base); + load_info->exec_info.map_size, &app_load_base); elf_file_close(load_info->exec_info.fd); if (ret != RT_EOK) { @@ -1015,7 +1015,7 @@ static int elf_file_load(elf_load_info_t *load_info) * @see dfs_normalize_path, elf_file_load */ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, - struct process_aux *aux_ua) + struct process_aux *aux_ua) { elf_load_info_t load_info = { 0 }; int len; @@ -1072,4 +1072,4 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_ return RT_EOK; } -#endif \ No newline at end of file +#endif diff --git a/components/lwp/vdso/Kconfig b/components/lwp/vdso/Kconfig index 883414dd973..46adb369a34 100644 --- a/components/lwp/vdso/Kconfig +++ b/components/lwp/vdso/Kconfig @@ -1,4 +1,6 @@ config RT_USING_VDSO bool "vDSO (Virtual Dynamic Shared Object)" - depends on (ARCH_ARMV8 || ARCH_RISCV) + depends on RT_USING_CLOCK_TIME + depends on (ARCH_ARM_CORTEX_A || ARCH_ARMV8 || ARCH_RISCV64) + depends on (!(ARCH_ARM_CORTEX_A || ARCH_ARMV8) || ARCH_CPU_64BIT || RT_CLOCK_TIME_ARM_ARCH) default y diff --git a/components/lwp/vdso/SConscript b/components/lwp/vdso/SConscript index 07889d73a9d..e28390303db 100644 --- a/components/lwp/vdso/SConscript +++ b/components/lwp/vdso/SConscript @@ -12,19 +12,14 @@ src = Glob('kernel/*.c') + Glob('kernel/*.S') if not GetDepend(['RT_USING_VDSO']): Return('group') -if rtconfig.ARCH != "aarch64" and rtconfig.ARCH != "risc-v": +if rtconfig.ARCH != "aarch64" and rtconfig.ARCH != "risc-v" and rtconfig.ARCH != "arm": + # not supported arch + src = [] +elif rtconfig.ARCH == "arm" and rtconfig.CPU != "cortex-a": # not supported arch src = [] else: - if not hasattr(rtconfig, 'CPP') or rtconfig.CPP is None: - rtconfig.CPP = rtconfig.PREFIX + 'cpp' - if not hasattr(rtconfig, 'CPPFLAGS') or rtconfig.CPPFLAGS is None: - rtconfig.CPPFLAGS = ' -E -P -x assembler-with-cpp' - - if not os.path.exists(cwd + "/user" + "/arch" +"/" + rtconfig.ARCH + "/vdso.lds"): - Preprocessing("user/arch/" + rtconfig.ARCH + "/vdso.lds.S", ".lds", CPPPATH=[cwd]) - - vdso_arch = os.path.join(cwd, 'user',"arch", rtconfig.ARCH) + vdso_user = os.path.join(cwd, 'user') process_env = os.environ.copy() if hasattr(rtconfig, 'EXEC_PATH') and rtconfig.EXEC_PATH is not None: @@ -34,9 +29,9 @@ else: if hasattr(rtconfig, 'DEVICE') and rtconfig.DEVICE is not None: process_env['RTT_DEVICE'] = rtconfig.DEVICE - command = ["scons", "-C", vdso_arch] + command = ["scons", "-C", vdso_user, "RTT_VDSO_ARCH=%s" % rtconfig.ARCH] if GetOption('clean'): - command = ["scons", "-C", vdso_arch, "--clean"] + command = ["scons", "-C", vdso_user, "RTT_VDSO_ARCH=%s" % rtconfig.ARCH, "--clean"] try: result = subprocess.run(command, env=process_env, check=True) diff --git a/components/lwp/vdso/kernel/vdso.h b/components/lwp/vdso/kernel/vdso.h deleted file mode 100644 index 1cb3b44e8ca..00000000000 --- a/components/lwp/vdso/kernel/vdso.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 deleted file mode 100644 index 5d077e4a9ef..00000000000 --- a/components/lwp/vdso/kernel/vdso_data.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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_image.S similarity index 52% rename from components/lwp/vdso/kernel/vdso_text.S rename to components/lwp/vdso/kernel/vdso_image.S index a8c771682dd..4ca5d51a55c 100644 --- a/components/lwp/vdso/kernel/vdso_text.S +++ b/components/lwp/vdso/kernel/vdso_image.S @@ -8,14 +8,14 @@ * 2024-07-04 rcitach init ver. */ -#include +#include - .globl __vdso_text_start, __vdso_text_end + .globl __rt_vdso_image_start, __rt_vdso_image_end .section .rodata - .balign VDSO_PAGE_SIZE -__vdso_text_start: - .incbin VDSO_PATH - .balign VDSO_PAGE_SIZE -__vdso_text_end: + .balign RT_VDSO_PAGE_SIZE +__rt_vdso_image_start: + .incbin RT_VDSO_IMAGE_PATH + .balign RT_VDSO_PAGE_SIZE +__rt_vdso_image_end: .previous diff --git a/components/lwp/vdso/kernel/vdso_kernel.h b/components/lwp/vdso/kernel/vdso_kernel.h new file mode 100644 index 00000000000..75696e77c62 --- /dev/null +++ b/components/lwp/vdso/kernel/vdso_kernel.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 RT_VDSO_KERNEL_H +#define RT_VDSO_KERNEL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern char __rt_vdso_image_start[]; +extern char __rt_vdso_image_end[]; + +#define RT_VDSO_IMAGE_ELF_MAGIC "\177ELF" +#define RT_VDSO_IMAGE_ELF_MAGIC_LEN 4 +#define RT_VDSO_DATA_PAGE_ALIGNED \ + __attribute__((section(".data.vdso.datapage"))) \ + __attribute__((aligned(RT_VDSO_PAGE_SIZE))) + +int rt_vdso_map_process_image(struct rt_lwp *lwp); +void rt_vdso_sync_clock_data(void); +void rt_vdso_set_realtime(const struct timespec *realtime); + +#ifdef __cplusplus +} +#endif + +#endif /* RT_VDSO_KERNEL_H */ diff --git a/components/lwp/vdso/kernel/vdso_kernel_internal.h b/components/lwp/vdso/kernel/vdso_kernel_internal.h new file mode 100644 index 00000000000..d24488a9ab6 --- /dev/null +++ b/components/lwp/vdso/kernel/vdso_kernel_internal.h @@ -0,0 +1,44 @@ +/* + * 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 RT_VDSO_KERNEL_INTERNAL_H +#define RT_VDSO_KERNEL_INTERNAL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct rt_vdso_data_page *rt_vdso_kernel_data_page; + +rt_inline struct rt_vdso_data_page *rt_vdso_get_kernel_data_page(void) +{ + return rt_vdso_kernel_data_page; +} + +rt_inline void rt_vdso_data_page_write_begin(struct rt_vdso_data_page *data_page) +{ + data_page->seq_counter += 1; + rt_hw_dmb(); +} + +rt_inline void rt_vdso_data_page_write_end(struct rt_vdso_data_page *data_page) +{ + rt_hw_dmb(); + data_page->seq_counter += 1; +} + +#ifdef __cplusplus +} +#endif + +#endif /* RT_VDSO_KERNEL_INTERNAL_H */ diff --git a/components/lwp/vdso/user/SConstruct b/components/lwp/vdso/user/SConstruct new file mode 100644 index 00000000000..778b8752796 --- /dev/null +++ b/components/lwp/vdso/user/SConstruct @@ -0,0 +1,102 @@ +import os +import subprocess + +arch = ARGUMENTS.get('RTT_VDSO_ARCH') or os.getenv('RTT_VDSO_ARCH') +user_dir = os.path.normpath(Dir('.').abspath) +vdso_root = os.path.normpath(os.path.join(user_dir, '..')) + +arch_def_config = { + 'aarch64': { + 'prefix': 'aarch64-none-elf-', + 'device': '-march=armv8-a -mtune=cortex-a53', + 'linker': os.path.join(user_dir, 'arch', 'aarch64', 'vdso.lds.S'), + }, + 'arm': { + 'prefix': 'arm-none-eabi-', + 'device': '-march=armv7-a -marm', + 'linker': os.path.join(user_dir, 'arch', 'arm', 'vdso.lds.S'), + }, + 'risc-v': { + 'prefix': 'riscv64-none-elf-', + 'device': '-march=rv64imafdc -mabi=lp64', + 'linker': os.path.join(user_dir, 'arch', 'risc-v', 'vdso.lds.S'), + }, +} + +if arch not in arch_def_config: + raise RuntimeError('Unsupported vDSO arch: %s' % arch) + +exec_path = os.getenv('RTT_EXEC_PATH') or '/usr/bin' +prefix = os.getenv('RTT_CC_PREFIX') or arch_def_config[arch]['prefix'] +device = os.getenv('RTT_DEVICE') or arch_def_config[arch]['device'] +linker_script_src = arch_def_config[arch]['linker'] + +cc = prefix + 'gcc' +cpp = prefix + 'cpp' +ar = prefix + 'ar' + +common_dir = os.path.join(user_dir, 'common') +arch_dir = os.path.join(user_dir, 'arch', arch) +build_dir = os.path.join(user_dir, 'build', arch) +os.makedirs(build_dir, exist_ok=True) +linker_script = os.path.join(build_dir, 'vdso.lds') + +cflags = ' '.join([ + device, + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wno-cpp', + '-std=gnu99', + '-O2', + '-fPIC', + '-ffreestanding', + '-fno-builtin', + '-fvisibility=hidden', + '-nostdlib', + '-nostartfiles', +]) + +linkflags = ' '.join([ + device, + '-nostdlib', + '-nostartfiles', + '-shared', + '-Wl,--gc-sections', + '-Wl,--build-id=none', + '-Wl,-soname=rtt-vdso.so.1', + '-T %s' % linker_script, +]) + +env = Environment( + tools=['gcc', 'link'], + AS=cc, + ASFLAGS='-x assembler-with-cpp', + CC=cc, + CFLAGS=cflags, + CPP=cpp, + AR=ar, + LINK=cc, + LINKFLAGS=linkflags, + CPPPATH=[user_dir, common_dir, arch_dir, vdso_root], +) +env.PrependENVPath('PATH', exec_path) + +def preprocess_linker_script(target, source, env): + cmd = [env['CC'], '-E', '-P', '-x', 'assembler-with-cpp'] + for include_dir in env['CPPPATH']: + cmd.append('-I' + include_dir) + cmd.extend([str(source[0]), '-o', str(target[0])]) + return subprocess.call(cmd) + +preprocessed_linker = env.Command(linker_script, linker_script_src, preprocess_linker_script) + +target = os.path.join(build_dir, 'libvdso.so') +source = os.path.join(common_dir, 'vdso_clock_gettime.c') +objects = [env.SharedObject(target=os.path.join(build_dir, 'vdso_clock_gettime'), source=source)] +shared_lib = env.SharedLibrary(target=target, source=objects) +env.Depends(shared_lib, preprocessed_linker) + +Clean(shared_lib, build_dir) +Clean(shared_lib, '.sconsign.dblite') +env.Default(shared_lib) diff --git a/components/lwp/vdso/user/arch/aarch64/SConstruct b/components/lwp/vdso/user/arch/aarch64/SConstruct deleted file mode 100644 index 56bd014926e..00000000000 --- a/components/lwp/vdso/user/arch/aarch64/SConstruct +++ /dev/null @@ -1,35 +0,0 @@ -import os -import sys - -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 'aarch64-none-elf-' -DEVICE = os.getenv('RTT_DEVICE') or ' -march=armv8-a -mtune=cortex-a53' - -CC = PREFIX + 'gcc' -CPP = PREFIX + 'cpp' -AS = PREFIX + 'gcc' -AR = PREFIX + 'ar' -LINK = PREFIX + 'gcc' - -AFLAGS = ' -x assembler-with-cpp' -CFLAGS = DEVICE + ' -ftree-vectorize -ffast-math -funwind-tables -fno-strict-aliasing -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 . -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) diff --git a/components/lwp/vdso/user/arch/aarch64/vdso.lds.S b/components/lwp/vdso/user/arch/aarch64/vdso.lds.S index 8b0038ee2dd..4b9dace298f 100644 --- a/components/lwp/vdso/user/arch/aarch64/vdso.lds.S +++ b/components/lwp/vdso/user/arch/aarch64/vdso.lds.S @@ -1,53 +1,38 @@ -/* - * 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 +#include OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") OUTPUT_ARCH(aarch64) SECTIONS { - PROVIDE(_vdso_data = . - __VVAR_PAGES * VDSO_PAGE_SIZE); + PROVIDE(__rt_vdso_data_page = . - (RT_VDSO_DATA_PAGE_COUNT * RT_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) } + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } :text + .dynsym : { *(.dynsym) } :text + .dynstr : { *(.dynstr) } :text + .gnu.version : { *(.gnu.version) } :text + .gnu.version_d : { *(.gnu.version_d) } :text + .gnu.version_r : { *(.gnu.version_r) } :text + .dynamic : { *(.dynamic) } :text :dynamic + .rodata : ALIGN(16) { *(.rodata*) } :text + .text : ALIGN(16) { *(.text*) } :text - .dynamic : { *(.dynamic) } :text :dynamic - .rela.dyn : ALIGN(8) { *(.rela .rela*) } - - .rodata : { - *(.rodata*) - *(.got) - *(.got.plt) - *(.plt) - *(.plt.*) - *(.iplt) - *(.igot .igot.plt) - } :text - /DISCARD/ : { + /DISCARD/ : { *(.data .data.* .sdata*) - *(.bss .sbss .dynbss .dynsbss) + *(.bss .bss.* .sbss .sbss.*) + *(.comment*) + *(.note*) + *(.eh_frame*) + *(.interp) } } PHDRS { - text PT_LOAD FLAGS(5) FILEHDR PHDRS; - dynamic PT_DYNAMIC FLAGS(4); + text PT_LOAD FLAGS(5) FILEHDR PHDRS; + dynamic PT_DYNAMIC FLAGS(4); } VERSION @@ -55,6 +40,7 @@ VERSION LINUX_2.6.39 { global: __kernel_clock_gettime; - local: *; + local: + *; }; } diff --git a/components/lwp/vdso/user/arch/aarch64/vdso_arch.h b/components/lwp/vdso/user/arch/aarch64/vdso_arch.h new file mode 100644 index 00000000000..2d4a31c4d05 --- /dev/null +++ b/components/lwp/vdso/user/arch/aarch64/vdso_arch.h @@ -0,0 +1,38 @@ +#ifndef RT_VDSO_ARCH_H +#define RT_VDSO_ARCH_H + +#include + +#define __RT_STRINGIFY(x...) #x +#define RT_STRINGIFY(x...) __RT_STRINGIFY(x) + +#define rt_vdso_arch_barrier(cmd, ...) \ + __asm__ volatile(RT_STRINGIFY(cmd) " " RT_STRINGIFY(__VA_ARGS__)::: "memory") + +static inline uint64_t rt_vdso_arch_read_counter(void) +{ + uint64_t value; + uint64_t tmp; + + __asm__ volatile("mrs %0, CNTVCT_EL0" : "=r"(value)); + __asm__ volatile( + "eor %0, %1, %1\n" + "add %0, sp, %0\n" + "ldr xzr, [%0]" + : "=r"(tmp) + : "r"(value)); + + return value; +} + +static inline void rt_vdso_arch_cpu_relax(void) +{ + __asm__ volatile("yield" ::: "memory"); +} + +static inline void rt_vdso_arch_rmb(void) +{ + rt_vdso_arch_barrier(dmb, ishld); +} + +#endif diff --git a/components/lwp/vdso/user/arch/aarch64/vdso_sys.c b/components/lwp/vdso/user/arch/aarch64/vdso_sys.c deleted file mode 100644 index d30e7bbccc4..00000000000 --- a/components/lwp/vdso/user/arch/aarch64/vdso_sys.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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(); - 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/arch/aarch64/vdso_sys.h b/components/lwp/vdso/user/arch/aarch64/vdso_sys.h deleted file mode 100644 index 60fb12fccb4..00000000000 --- a/components/lwp/vdso/user/arch/aarch64/vdso_sys.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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(void) -{ - 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/arch/arm/vdso.lds.S b/components/lwp/vdso/user/arch/arm/vdso.lds.S new file mode 100644 index 00000000000..8b058412d25 --- /dev/null +++ b/components/lwp/vdso/user/arch/arm/vdso.lds.S @@ -0,0 +1,46 @@ +#include + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +SECTIONS +{ + PROVIDE(__rt_vdso_data_page = . - (RT_VDSO_DATA_PAGE_COUNT * RT_VDSO_PAGE_SIZE)); + . = SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } :text + .dynsym : { *(.dynsym) } :text + .dynstr : { *(.dynstr) } :text + .gnu.version : { *(.gnu.version) } :text + .gnu.version_d : { *(.gnu.version_d) } :text + .gnu.version_r : { *(.gnu.version_r) } :text + .dynamic : { *(.dynamic) } :text :dynamic + .rodata : ALIGN(16) { *(.rodata*) } :text + .text : ALIGN(16) { *(.text*) } :text + + /DISCARD/ : { + *(.data .data.* .sdata*) + *(.bss .bss.* .sbss .sbss.*) + *(.comment*) + *(.note*) + *(.eh_frame*) + *(.interp) + } +} + +PHDRS +{ + text PT_LOAD FLAGS(5) FILEHDR PHDRS; + dynamic PT_DYNAMIC FLAGS(4); +} + +VERSION +{ + LINUX_2.6 { + global: + __vdso_clock_gettime; + local: + *; + }; +} diff --git a/components/lwp/vdso/user/arch/arm/vdso_arch.h b/components/lwp/vdso/user/arch/arm/vdso_arch.h new file mode 100644 index 00000000000..5dd0e38ffe9 --- /dev/null +++ b/components/lwp/vdso/user/arch/arm/vdso_arch.h @@ -0,0 +1,33 @@ +#ifndef RT_VDSO_ARCH_H +#define RT_VDSO_ARCH_H + +#include + +#define __RT_STRINGIFY(x...) #x +#define RT_STRINGIFY(x...) __RT_STRINGIFY(x) + +#define rt_vdso_arch_barrier(cmd, ...) \ + __asm__ volatile(RT_STRINGIFY(cmd) " " RT_STRINGIFY(__VA_ARGS__)::: "memory") + +static inline uint64_t rt_vdso_arch_read_counter(void) +{ + uint32_t lo; + uint32_t hi; + + __asm__ volatile("mrrc p15, 1, %0, %1, c14" : "=r"(lo), "=r"(hi)); + rt_vdso_arch_barrier(dmb, ish); + + return ((uint64_t)hi << 32) | lo; +} + +static inline void rt_vdso_arch_cpu_relax(void) +{ + __asm__ volatile("yield" ::: "memory"); +} + +static inline void rt_vdso_arch_rmb(void) +{ + rt_vdso_arch_barrier(dmb, ish); +} + +#endif diff --git a/components/lwp/vdso/user/arch/risc-v/SConstruct b/components/lwp/vdso/user/arch/risc-v/SConstruct deleted file mode 100644 index 4680384ca08..00000000000 --- a/components/lwp/vdso/user/arch/risc-v/SConstruct +++ /dev/null @@ -1,62 +0,0 @@ -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) diff --git a/components/lwp/vdso/user/arch/risc-v/vdso.lds.S b/components/lwp/vdso/user/arch/risc-v/vdso.lds.S index 956366e93ea..b7f51ed8879 100644 --- a/components/lwp/vdso/user/arch/risc-v/vdso.lds.S +++ b/components/lwp/vdso/user/arch/risc-v/vdso.lds.S @@ -1,53 +1,38 @@ -/* - * 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 +#include OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv") OUTPUT_ARCH(riscv) SECTIONS { - PROVIDE(_vdso_data = . - __VVAR_PAGES * VDSO_PAGE_SIZE); + PROVIDE(__rt_vdso_data_page = . - (RT_VDSO_DATA_PAGE_COUNT * RT_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) } + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } :text + .dynsym : { *(.dynsym) } :text + .dynstr : { *(.dynstr) } :text + .gnu.version : { *(.gnu.version) } :text + .gnu.version_d : { *(.gnu.version_d) } :text + .gnu.version_r : { *(.gnu.version_r) } :text + .dynamic : { *(.dynamic) } :text :dynamic + .rodata : ALIGN(16) { *(.rodata*) } :text + .text : ALIGN(16) { *(.text*) } :text - .dynamic : { *(.dynamic) } :text :dynamic - .rela.dyn : ALIGN(8) { *(.rela .rela*) } - - .rodata : { - *(.rodata*) - *(.got) - *(.got.plt) - *(.plt) - *(.plt.*) - *(.iplt) - *(.igot .igot.plt) - } :text - /DISCARD/ : { + /DISCARD/ : { *(.data .data.* .sdata*) - *(.bss .sbss .dynbss .dynsbss) + *(.bss .bss.* .sbss .sbss.*) + *(.comment*) + *(.note*) + *(.eh_frame*) + *(.interp) } } PHDRS { - text PT_LOAD FLAGS(5) FILEHDR PHDRS; - dynamic PT_DYNAMIC FLAGS(4); + text PT_LOAD FLAGS(5) FILEHDR PHDRS; + dynamic PT_DYNAMIC FLAGS(4); } VERSION @@ -55,6 +40,7 @@ VERSION LINUX_2.6 { global: __vdso_clock_gettime; - local: *; + local: + *; }; } diff --git a/components/lwp/vdso/user/arch/risc-v/vdso_arch.h b/components/lwp/vdso/user/arch/risc-v/vdso_arch.h new file mode 100644 index 00000000000..f6a8760debf --- /dev/null +++ b/components/lwp/vdso/user/arch/risc-v/vdso_arch.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-21 rcitach init ver. + */ + +#ifndef RT_VDSO_ARCH_H +#define RT_VDSO_ARCH_H + +#include + +#define __RT_STRINGIFY(x...) #x +#define RT_STRINGIFY(x...) __RT_STRINGIFY(x) + +#define rt_vdso_arch_barrier(cmd, ...) \ + __asm__ volatile(RT_STRINGIFY(cmd) " " RT_STRINGIFY(__VA_ARGS__)::: "memory") + +static inline uint64_t rt_vdso_arch_read_counter(void) +{ + uint64_t value; + + __asm__ volatile("rdtime %0" : "=r"(value)); + rt_vdso_arch_barrier(fence, rw, rw); + + return value; +} + +static inline void rt_vdso_arch_cpu_relax(void) +{ + __asm__ volatile("nop" ::: "memory"); +} + +static inline void rt_vdso_arch_rmb(void) +{ + rt_vdso_arch_barrier(fence, r, r); +} + +#endif diff --git a/components/lwp/vdso/user/arch/risc-v/vdso_sys.c b/components/lwp/vdso/user/arch/risc-v/vdso_sys.c deleted file mode 100644 index bb697aa0094..00000000000 --- a/components/lwp/vdso/user/arch/risc-v/vdso_sys.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 -#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 -/* 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); -} diff --git a/components/lwp/vdso/user/arch/risc-v/vdso_sys.h b/components/lwp/vdso/user/arch/risc-v/vdso_sys.h deleted file mode 100644 index fe326c19d01..00000000000 --- a/components/lwp/vdso/user/arch/risc-v/vdso_sys.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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 -#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 \ - __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 diff --git a/components/lwp/vdso/user/common/vdso_clock_gettime.c b/components/lwp/vdso/user/common/vdso_clock_gettime.c new file mode 100644 index 00000000000..5f8ff668692 --- /dev/null +++ b/components/lwp/vdso/user/common/vdso_clock_gettime.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-21 rcitach init ver. + */ +#include "vdso_user_internal.h" + +static int rt_vdso_resolve_clock_index(clockid_t clock, unsigned int *index) +{ + switch (clock) + { + case CLOCK_REALTIME: + case CLOCK_REALTIME_COARSE: + *index = RT_VDSO_CLOCK_REALTIME_INDEX; + return 0; + + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + case CLOCK_BOOTTIME: + *index = RT_VDSO_CLOCK_MONOTONIC_INDEX; + return 0; + + default: + if ((unsigned int)clock >= RT_VDSO_CLOCK_ID_MAX) + { + return -EINVAL; + } + return -ENOSYS; + } +} + +int rt_vdso_clock_gettime_impl(clockid_t clock, struct timespec *ts) +{ + const struct rt_vdso_data_page *data_page = rt_vdso_get_data_page(); + uint32_t seq; + unsigned int index; + uint64_t last; + uint64_t freq; + uint64_t now; + uint64_t delta_ns; + struct timespec base_time; + int ret; + + ret = rt_vdso_resolve_clock_index(clock, &index); + if (ret != 0) + { + return ret; + } + + do + { + seq = rt_vdso_data_read_begin(data_page); + if (index == RT_VDSO_CLOCK_REALTIME_INDEX && + !(data_page->flags & RT_VDSO_FLAG_REALTIME_VALID)) + { + return -ENOSYS; + } + base_time = data_page->base_time[index]; + last = data_page->counter_last; + freq = data_page->counter_freq; + now = rt_vdso_arch_read_counter(); + } while (unlikely(rt_vdso_data_read_retry(data_page, seq))); + + if (freq == 0) + { + return -ENOSYS; + } + + delta_ns = rt_vdso_counter_delta_to_ns(now, last, freq); + rt_vdso_timespec_add_nanoseconds(&base_time, delta_ns); + *ts = base_time; + + return 0; +} + +int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) + __attribute__((alias("rt_vdso_clock_gettime_impl"), visibility("default"))); + +int __kernel_clock_gettime(clockid_t clock, struct timespec *ts) + __attribute__((alias("rt_vdso_clock_gettime_impl"), visibility("default"))); diff --git a/components/lwp/vdso/user/common/vdso_user_internal.h b/components/lwp/vdso/user/common/vdso_user_internal.h new file mode 100644 index 00000000000..7e2244b56d3 --- /dev/null +++ b/components/lwp/vdso/user/common/vdso_user_internal.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-04-21 rcitach init ver. + */ + +#ifndef RT_VDSO_USER_INTERNAL_H +#define RT_VDSO_USER_INTERNAL_H + +#include +#include +#include +#include +#include + +#include +#include + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#ifndef barrier +#define barrier() __asm__ __volatile__("" : : : "memory") +#endif + +static inline void rt_vdso_read_once_size(const volatile void *ptr, void *dst, int size) +{ + switch (size) + { + case 1: + *(uint8_t *)dst = *(const volatile uint8_t *)ptr; + break; + case 2: + *(uint16_t *)dst = *(const volatile uint16_t *)ptr; + break; + case 4: + *(uint32_t *)dst = *(const volatile uint32_t *)ptr; + break; + case 8: + *(uint64_t *)dst = *(const volatile uint64_t *)ptr; + break; + default: + barrier(); + __builtin_memcpy(dst, (const void *)ptr, size); + barrier(); + break; + } +} + +#define READ_ONCE(x) \ + ({ \ + union \ + { \ + typeof(x) value; \ + char bytes[sizeof(x)]; \ + } once; \ + rt_vdso_read_once_size(&(x), once.bytes, sizeof(x)); \ + once.value; \ + }) + +extern const struct rt_vdso_data_page __rt_vdso_data_page[] __attribute__((visibility("hidden"))); + +static inline const struct rt_vdso_data_page *rt_vdso_get_data_page(void) +{ + return __rt_vdso_data_page; +} + +static inline uint32_t rt_vdso_data_read_begin(const struct rt_vdso_data_page *data_page) +{ + uint32_t seq; + + while (unlikely((seq = READ_ONCE(data_page->seq_counter)) & 1U)) + { + rt_vdso_arch_cpu_relax(); + } + + rt_vdso_arch_rmb(); + return seq; +} + +static inline uint32_t rt_vdso_data_read_retry(const struct rt_vdso_data_page *data_page, + uint32_t start) +{ + rt_vdso_arch_rmb(); + return READ_ONCE(data_page->seq_counter) != start; +} + +static inline uint64_t rt_vdso_counter_delta_to_ns(uint64_t now, uint64_t last, + uint64_t freq) +{ + if (freq == 0) + { + return 0; + } + + return (now - last) * RT_VDSO_NSEC_PER_SEC / freq; +} + +static inline void rt_vdso_timespec_add_nanoseconds(struct timespec *ts, uint64_t ns) +{ + ts->tv_sec += (time_t)(ns / RT_VDSO_NSEC_PER_SEC); + ns = (uint64_t)ts->tv_nsec + (ns % RT_VDSO_NSEC_PER_SEC); + if (ns >= RT_VDSO_NSEC_PER_SEC) + { + ts->tv_sec += 1; + ns -= RT_VDSO_NSEC_PER_SEC; + } + ts->tv_nsec = (long)ns; +} + +#endif /* RT_VDSO_USER_INTERNAL_H */ diff --git a/components/lwp/vdso/vdso_config.h b/components/lwp/vdso/vdso_config.h deleted file mode 100644 index fd79b46b022..00000000000 --- a/components/lwp/vdso/vdso_config.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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/libvdso.so" - -#ifdef __cplusplus -} -#endif - -#endif /* __ASM_VDSO_H */ diff --git a/components/lwp/vdso/vdso_constants.h b/components/lwp/vdso/vdso_constants.h new file mode 100644 index 00000000000..bbd78a8725d --- /dev/null +++ b/components/lwp/vdso/vdso_constants.h @@ -0,0 +1,47 @@ +/* + * 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 RT_VDSO_CONSTANTS_H +#define RT_VDSO_CONSTANTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define RT_VDSO_DATA_PAGE_COUNT 1 +#define RT_VDSO_PAGE_SHIFT 12 +#define RT_VDSO_PAGE_SIZE (1 << RT_VDSO_PAGE_SHIFT) + +#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 + +#if defined(__aarch64__) +#define RT_VDSO_IMAGE_PATH "../user/build/aarch64/libvdso.so" +#elif defined(__arm__) +#define RT_VDSO_IMAGE_PATH "../user/build/arm/libvdso.so" +#elif defined(__riscv) +#define RT_VDSO_IMAGE_PATH "../user/build/risc-v/libvdso.so" +#else +#error "Unsupported architecture for vDSO" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RT_VDSO_CONSTANTS_H */ diff --git a/components/lwp/vdso/vdso_data_page.h b/components/lwp/vdso/vdso_data_page.h new file mode 100644 index 00000000000..a1c962c54da --- /dev/null +++ b/components/lwp/vdso/vdso_data_page.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 RT_VDSO_DATA_PAGE_H +#define RT_VDSO_DATA_PAGE_H + +#include +#include +#include +#include "vdso_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RT_VDSO_CLOCK_ID_MAX 16 +#define RT_VDSO_NSEC_PER_SEC 1000000000ULL +#define RT_VDSO_FLAG_REALTIME_VALID (1ULL << 0) + +enum rt_vdso_clock_data_index +{ + RT_VDSO_CLOCK_REALTIME_INDEX = 0, + RT_VDSO_CLOCK_MONOTONIC_INDEX, + RT_VDSO_CLOCK_DATA_COUNT, +}; + +struct rt_vdso_data_page +{ + uint32_t seq_counter; + uint32_t reserved0; + uint64_t flags; + uint64_t counter_last; + uint64_t counter_freq; + struct timespec base_time[RT_VDSO_CLOCK_DATA_COUNT]; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* RT_VDSO_DATA_PAGE_H */ diff --git a/components/lwp/vdso/vdso_datapage.h b/components/lwp/vdso/vdso_datapage.h deleted file mode 100644 index 243af48bf1d..00000000000 --- a/components/lwp/vdso/vdso_datapage.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 deleted file mode 100644 index d6282121899..00000000000 --- a/components/lwp/vdso/vdso_weak.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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) -{ - return ; -} diff --git a/src/clock.c b/src/clock.c index 68cc009417e..56aa1aceb82 100644 --- a/src/clock.c +++ b/src/clock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2024 RT-Thread Development Team + * Copyright (c) 2006-2026, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -24,7 +24,7 @@ #include #if defined(RT_USING_SMART) && defined(RT_USING_VDSO) -#include +#include "vdso_kernel.h" #endif #ifdef RT_USING_SMP @@ -77,7 +77,7 @@ RTM_EXPORT(rt_tick_get); * @brief This function will return delta tick from base. * * @param base to consider - * + * * @return Return delta tick. */ rt_tick_t rt_tick_get_delta(rt_tick_t base) @@ -197,7 +197,7 @@ void rt_tick_increase_tick(rt_tick_t tick) rt_timer_check(); #ifdef RT_USING_VDSO - rt_vdso_update_glob_time(); + rt_vdso_sync_clock_data(); #endif } @@ -252,10 +252,11 @@ rt_weak rt_tick_t rt_tick_get_millisecond(void) #if 1000 % RT_TICK_PER_SECOND == 0u return rt_tick_get() * (1000u / RT_TICK_PER_SECOND); #else - #warning "rt-thread cannot provide a correct 1ms-based tick any longer,\ +#warning "rt-thread cannot provide a correct 1ms-based tick any longer,\ please redefine this function in another file by using a high-precision hard-timer." return 0; #endif /* 1000 % RT_TICK_PER_SECOND == 0u */ } /**@}*/ +