|
@@ -0,0 +1,116 @@
|
|
|
+/*
|
|
|
+ * 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 <rtthread.h>
|
|
|
+#include <mmu.h>
|
|
|
+#include <lwp_user_mm.h>
|
|
|
+
|
|
|
+#include "vdso.h"
|
|
|
+#include "vdso_datapage.h"
|
|
|
+#define DBG_TAG "vdso"
|
|
|
+#define DBG_LVL DBG_INFO
|
|
|
+#include <rtdbg.h>
|
|
|
+
|
|
|
+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);
|