summaryrefslogtreecommitdiff
path: root/components/lwp/arch/common/vdso.c
blob: 823fd5b61e984901c6842c0dcebd3738aef9662a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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);