1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  */
5 #ifndef MM_PGT_CACHE_H
6 #define MM_PGT_CACHE_H
7 
8 #ifdef CFG_WITH_LPAE
9 #define PGT_SIZE	(4 * 1024)
10 #define PGT_NUM_PGT_PER_PAGE	1
11 #else
12 #define PGT_SIZE	(1 * 1024)
13 #define PGT_NUM_PGT_PER_PAGE	4
14 #endif
15 
16 #include <assert.h>
17 #include <kernel/tee_ta_manager.h>
18 #include <sys/queue.h>
19 #include <types_ext.h>
20 #include <util.h>
21 
22 struct ts_ctx;
23 
24 struct pgt {
25 	void *tbl;
26 	vaddr_t vabase;
27 #if !defined(CFG_CORE_PREALLOC_EL0_TBLS)
28 	struct ts_ctx *ctx;
29 #endif
30 	bool populated;
31 #if defined(CFG_PAGED_USER_TA)
32 	uint16_t num_used_entries;
33 #endif
34 #if defined(CFG_CORE_PREALLOC_EL0_TBLS) || \
35 	(defined(CFG_WITH_PAGER) && !defined(CFG_WITH_LPAE))
36 	struct pgt_parent *parent;
37 #endif
38 	SLIST_ENTRY(pgt) link;
39 };
40 
41 /*
42  * A proper value for PGT_CACHE_SIZE depends on many factors: CFG_WITH_LPAE,
43  * CFG_TA_ASLR, size of TA, size of memrefs passed to TA, CFG_ULIBS_SHARED and
44  * possibly others. The value is based on the number of threads as an indicator
45  * on how large the system might be.
46  */
47 #if CFG_NUM_THREADS < 2
48 #define PGT_CACHE_SIZE	4
49 #elif (CFG_NUM_THREADS == 2 && !defined(CFG_WITH_LPAE))
50 #define PGT_CACHE_SIZE	8
51 #else
52 #define PGT_CACHE_SIZE	ROUNDUP(CFG_NUM_THREADS * 2, PGT_NUM_PGT_PER_PAGE)
53 #endif
54 
55 SLIST_HEAD(pgt_cache, pgt);
56 struct user_mode_ctx;
57 
58 bool pgt_check_avail(struct user_mode_ctx *uctx);
59 
60 /*
61  * pgt_get_all() - makes all needed translation tables available
62  * @uctx:	the context to own the tables
63  *
64  * Guaranteed to succeed, but may need to sleep for a while to get all the
65  * needed translation tables.
66  */
67 #if defined(CFG_CORE_PREALLOC_EL0_TBLS)
pgt_get_all(struct user_mode_ctx * uctx __unused)68 static inline void pgt_get_all(struct user_mode_ctx *uctx __unused) { }
69 #else
70 void pgt_get_all(struct user_mode_ctx *uctx);
71 #endif
72 
73 /*
74  * pgt_put_all() - informs the translation table manager that these tables
75  *		   will not be needed for a while
76  * @uctx:	the context owning the tables to make inactive
77  */
78 #if defined(CFG_CORE_PREALLOC_EL0_TBLS)
pgt_put_all(struct user_mode_ctx * uctx __unused)79 static inline void pgt_put_all(struct user_mode_ctx *uctx __unused) { }
80 #else
81 void pgt_put_all(struct user_mode_ctx *uctx);
82 #endif
83 
84 void pgt_clear_range(struct user_mode_ctx *uctx, vaddr_t begin, vaddr_t end);
85 void pgt_flush_range(struct user_mode_ctx *uctx, vaddr_t begin, vaddr_t last);
86 
87 #if defined(CFG_CORE_PREALLOC_EL0_TBLS)
pgt_pop_from_cache_list(vaddr_t vabase __unused,struct ts_ctx * ctx __unused)88 static inline struct pgt *pgt_pop_from_cache_list(vaddr_t vabase __unused,
89 						  struct ts_ctx *ctx __unused)
90 { return NULL; }
pgt_push_to_cache_list(struct pgt * pgt __unused)91 static inline void pgt_push_to_cache_list(struct pgt *pgt __unused) { }
92 #else
93 struct pgt *pgt_pop_from_cache_list(vaddr_t vabase, struct ts_ctx *ctx);
94 void pgt_push_to_cache_list(struct pgt *pgt);
95 #endif
96 
97 #if defined(CFG_CORE_PREALLOC_EL0_TBLS)
pgt_init(void)98 static inline void pgt_init(void) { }
99 #else
100 void pgt_init(void);
101 #endif
102 
103 void pgt_flush(struct user_mode_ctx *uctx);
104 
105 #if defined(CFG_PAGED_USER_TA)
pgt_inc_used_entries(struct pgt * pgt)106 static inline void pgt_inc_used_entries(struct pgt *pgt)
107 {
108 	pgt->num_used_entries++;
109 	assert(pgt->num_used_entries);
110 }
111 
pgt_dec_used_entries(struct pgt * pgt)112 static inline void pgt_dec_used_entries(struct pgt *pgt)
113 {
114 	assert(pgt->num_used_entries);
115 	pgt->num_used_entries--;
116 }
117 
pgt_set_used_entries(struct pgt * pgt,size_t val)118 static inline void pgt_set_used_entries(struct pgt *pgt, size_t val)
119 {
120 	pgt->num_used_entries = val;
121 }
122 
123 #else
pgt_inc_used_entries(struct pgt * pgt __unused)124 static inline void pgt_inc_used_entries(struct pgt *pgt __unused)
125 {
126 }
127 
pgt_dec_used_entries(struct pgt * pgt __unused)128 static inline void pgt_dec_used_entries(struct pgt *pgt __unused)
129 {
130 }
131 
pgt_set_used_entries(struct pgt * pgt __unused,size_t val __unused)132 static inline void pgt_set_used_entries(struct pgt *pgt __unused,
133 					size_t val __unused)
134 {
135 }
136 
137 #endif
138 
139 #endif /*MM_PGT_CACHE_H*/
140