summaryrefslogtreecommitdiff
path: root/components/mm/mm_page.h
blob: 9e7f03da1a300ba47b4a62d42dcf40a44f347420 (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
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-11-01     Jesven       The first version
 * 2022-12-13     WangXiaoyao  Hot-pluggable, extensible
 *                             page management algorithm
 */
#ifndef __MM_PAGE_H__
#define __MM_PAGE_H__

#include <rthw.h>
#include <rtthread.h>
#include <stdint.h>

#define GET_FLOOR(type) \
    (1ul << (8 * sizeof(rt_size_t) - __builtin_clzl(2 * sizeof(type) - 1) - 1))
#define DEF_PAGE_T(fields) \
    typedef struct rt_page {\
        union {struct {fields}; char _padding[GET_FLOOR(struct {fields})];};\
    } *rt_page_t

/**
 * @brief PAGE ALLOC FLAGS
 *
 * @info PAGE_ANY_AVAILABLE
 * page allocation default to use lower region, this behavior can change by setting
 * PAGE_ANY_AVAILABLE
 */

#define PAGE_ANY_AVAILABLE 0x1ul

#define RT_PAGE_PICK_AFFID(ptr) \
    ((((long)ptr) & (RT_PAGE_AFFINITY_BLOCK_SIZE - 1)) / ARCH_PAGE_SIZE)

#ifdef RT_DEBUGGING_PAGE_LEAK
#define DEBUG_FIELD struct {    \
    /* trace list */            \
    struct rt_page *tl_next;    \
    struct rt_page *tl_prev;    \
    void *caller;               \
    size_t trace_size;          \
}
#else
#define DEBUG_FIELD
#endif

DEF_PAGE_T(
    struct rt_page *next;   /* same level next */
    struct rt_page *pre;    /* same level pre  */

    DEBUG_FIELD;

    rt_uint32_t size_bits;     /* if is ARCH_ADDRESS_WIDTH_BITS, means not free */
    rt_uint32_t ref_cnt;       /* page group ref count */
);

#undef GET_FLOOR
#undef DEF_PAGE_T
#undef DEBUG_FIELD

typedef struct tag_region
{
    rt_size_t start;
    rt_size_t end;

    const char *name;
} rt_region_t;

#ifdef RT_PAGE_MPR_SIZE_DYNAMIC
const rt_size_t rt_mpr_size_dynamic(void);
#define rt_mpr_size rt_mpr_size_dynamic()
#else
extern const rt_size_t rt_mpr_size;
#endif
extern void *rt_mpr_start;

void rt_page_init(rt_region_t reg);

void rt_page_cleanup(void);

void *rt_pages_alloc(rt_uint32_t size_bits);

void *rt_pages_alloc_ext(rt_uint32_t size_bits, size_t flags);

void *rt_pages_alloc_tagged(rt_uint32_t size_bits, long tag, size_t flags);

rt_bool_t rt_page_is_member(rt_base_t page_pa);

void rt_page_ref_inc(void *addr, rt_uint32_t size_bits);

int rt_page_ref_get(void *addr, rt_uint32_t size_bits);

int rt_pages_free(void *addr, rt_uint32_t size_bits);

int rt_page_list(void);

rt_size_t rt_page_bits(rt_size_t size);

void rt_page_get_info(rt_size_t *total_nr, rt_size_t *free_nr);

void rt_page_high_get_info(rt_size_t *total_nr, rt_size_t *free_nr);

void *rt_page_page2addr(struct rt_page *p);

struct rt_page *rt_page_addr2page(void *addr);

/**
 * @brief Install page frames at run-time
 * Region size must be aligned to 2^(RT_PAGE_MAX_ORDER + ARCH_PAGE_SHIFT - 1)
 * bytes currently (typically 2 MB).
 *
 * !WARNING this API will NOT check whether region is valid or not in list
 *
 * @param region region.start as first page frame(inclusive),
 *               region.end as first page frame after free region
 * @return int 0 on success
 */
int rt_page_install(rt_region_t region);

void rt_page_leak_trace_start(void);

void rt_page_leak_trace_stop(void);

#endif /* __MM_PAGE_H__ */