1 /*
2  * Copyright (c) 2020 LK Trusty Authors. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #pragma once
25 
26 #include <kernel/vm_obj.h>
27 #include <lib/binary_search_tree.h>
28 #include <lk/reflist.h>
29 #include <sys/types.h>
30 
31 struct vmm_obj;
32 struct obj_ref;
33 struct vmm_aspace;
34 
35 /**
36  * typedef ext_mem_client_id_t - External client identifier.
37  *
38  * Type use to store a 64 bit external client identifier.
39  */
40 typedef uint64_t ext_mem_client_id_t;
41 
42 /**
43  * typedef ext_mem_obj_id_t - External memory identifier.
44  *
45  * Type use to store a 64 bit external memory identifier. The value is chosen
46  * by the specific external memory implementation, but must be unique for the
47  * namespace it is used in (@objs argument of ext_mem_insert).
48  */
49 typedef uint64_t ext_mem_obj_id_t;
50 
51 /**
52  * struct ext_mem_page_run - Contiguous region of physical memory.
53  * @paddr:  Physical address where region starts.
54  * @size:   Number of bytes in region. Should be a multiple of PAGE_SIZE for the
55  *          region to be mappable.
56  */
57 struct ext_mem_page_run {
58     paddr_t paddr;
59     size_t size;
60 };
61 
62 /**
63  * struct ext_mem_obj - Memory object for external sources.
64  * @id:             Unique id used for lookup.
65  * @tag:            Metadata used by some systems. Set to 0 if unused.
66  * @match_tag:      Metadata used by some systems. Set to 0 if unused.
67  *                  Must match @tag before the object can be mapped. An object
68  *                  attached to an ipc message can be created before sending it
69  *                  to the app but only be mapable after the tag has been
70  *                  matched.
71  * @vmm_obj:        VMM object.
72  * @node:           Search tree node.
73  * @arch_mmu_flags: Memory type and required permission flags.
74  * @page_run_count: Number of entries in @page_runs.
75  * @page_runs:      Array of physically contiguous regions.
76  */
77 struct ext_mem_obj {
78     ext_mem_obj_id_t id;
79     uint64_t tag;
80     uint64_t match_tag;
81     struct vmm_obj vmm_obj;
82     struct bst_node node;
83     uint arch_mmu_flags;
84     size_t page_run_count;
85     struct ext_mem_page_run page_runs[];
86 };
87 
88 /**
89  * ext_mem_obj_page_runs_size - Get size of page_runs.
90  * @page_run_count: Number if page runs.
91  *
92  * Calculate size of page_runs array. This can be added by the caller to the
93  * size of struct ext_mem_obj, or the size of a struct that embeds struct
94  * ext_mem_obj at the end, to get the number of bytes to allocate.
95  *
96  * Return: Size of ext_mem_obj page_runs array in bytes.
97  */
ext_mem_obj_page_runs_size(size_t page_run_count)98 static inline size_t ext_mem_obj_page_runs_size(size_t page_run_count) {
99     return sizeof(struct ext_mem_page_run) * page_run_count;
100 }
101 
102 /**
103  * ext_mem_obj_initialize - Initialize struct ext_mem_obj.
104  * @obj:            Object to initialize.
105  * @ref:            Initial reference.
106  * @id:             Unique id used by ext_mem_insert and ext_mem_lookup.
107  * @tag:            Extra metadata used by some systems. Set to 0 if unused.
108  * @ops:            Pointer to &struct vmm_obj_ops. @ops->check_flags can point
109  *                  directly to ext_mem_obj_check_flags. @ops->get_page can
110  *                  point directly to ext_mem_obj_get_page. @ops->destroy must
111  *                  point to a function supplied by the caller.
112  * @arch_mmu_flags: Memory type and required permission flags.
113  * @page_run_count: Number of entries in @page_runs.
114  */
115 void ext_mem_obj_initialize(struct ext_mem_obj* obj,
116                             struct obj_ref* ref,
117                             ext_mem_obj_id_t id,
118                             uint64_t tag,
119                             struct vmm_obj_ops* ops,
120                             uint arch_mmu_flags,
121                             size_t page_run_count);
122 
123 /**
124  * ext_mem_insert - Insert ext_mem_obj.
125  * @objs:   Root of search tree to insert @obj into.
126  * @obj:    ext_mem_obj to insert.
127  *
128  * Insert @obj into @objs.
129  * Caller is responsible for locking.
130  *
131  * Return: %true if @obj was inserted. %false if a node with the same id as
132  *         @obj->id is already in @objs.
133  */
134 bool ext_mem_insert(struct bst_root* objs, struct ext_mem_obj* obj);
135 
136 /**
137  * ext_mem_delete - Remove ext_mem_obj.
138  * @objs:   Root of search tree that contains @obj.
139  * @obj:    ext_mem_obj to delete.
140  *
141  * Delete @obj from @objs.
142  * Caller is responsible for locking.
143  */
ext_mem_delete(struct bst_root * objs,struct ext_mem_obj * obj)144 static inline void ext_mem_delete(struct bst_root* objs,
145                                   struct ext_mem_obj* obj) {
146     bst_delete(objs, &obj->node);
147 }
148 
149 /**
150  * ext_mem_lookup - Lookup ext_mem_obj by id.
151  * @objs:   Root of search tree that might contain and object with id @id.
152  * @id:     Id of object to return.
153  *
154  * Caller is responsible for locking.
155  *
156  * Return: ext_mem_obj in @objs matching @id, or %NULL if no matching
157  *         ext_mem_obj is found.
158  */
159 struct ext_mem_obj* ext_mem_lookup(struct bst_root* objs, ext_mem_obj_id_t id);
160 
161 /**
162  * ext_mem_obj_set_match_tag - Set match tag on ext_mem_obj.
163  * @obj:            &ext_mem_obj->vmm_obj.
164  * @match_tag:      Set match_tag on @obj. The object can only be mapped if this
165  *                  matches the tag used when creating @obj. Pass 0 to return to
166  *                  initial state.
167  */
168 void ext_mem_obj_set_match_tag(struct vmm_obj* obj, uint64_t match_tag);
169 
170 /**
171  * ext_mem_obj_check_flags - vmm_obj_ops->check_flags for ext_mem_obj.
172  * @obj:            &ext_mem_obj->vmm_obj.
173  * @arch_mmu_flags: arch_mmu_flags to check and modify.
174  *
175  * Compare @arch_mmu_flags against &ext_mem_obj->arch_mmu_flags. Return
176  * ERR_ACCESS_DENIED if permissions &ext_mem_obj->arch_mmu_flags are more
177  * restrictive than @arch_mmu_flags. Copy memory type flags from
178  * &ext_mem_obj->arch_mmu_flags to @arch_mmu_flags.
179  *
180  * Return: 0 on success, error code on failure.
181  */
182 int ext_mem_obj_check_flags(struct vmm_obj* obj, uint* arch_mmu_flags);
183 
184 /**
185  * ext_mem_obj_get_page - vmm_obj_ops->get_page for ext_mem_obj.
186  * @obj:        &ext_mem_obj->vmm_obj.
187  * @offset:     Byte offset into @obj.
188  * @paddr:      Pointer to return physical address in.
189  * @paddr_size: Pointer to return size of physically contiguous region at
190  *              @offset.
191  *
192  * Get single page or physically contiguous region at @offset bytes from
193  * start of @obj.
194  *
195  * Return: 0 on success, error code on failure.
196  */
197 int ext_mem_obj_get_page(struct vmm_obj* obj,
198                          size_t offset,
199                          paddr_t* paddr,
200                          size_t* paddr_size);
201 
202 /**
203  * ext_mem_map_obj_id - Lookup and map external memory object.
204  * @aspace:         Pass-through to vmm_alloc_obj.
205  * @name:           Pass-through to vmm_alloc_obj.
206  * @client_id:      Id of external entity where the memory originated.
207  * @mem_obj_id:     Id of shared memory object to lookup and map.
208  * @tag:            Tag of the memory. If a non-FF-A object, use 0.
209  * @offset:         Pass-through to vmm_alloc_obj.
210  * @size:           Pass-through to vmm_alloc_obj.
211  * @ptr:            Pass-through to vmm_alloc_obj.
212  * @align_log2:     Pass-through to vmm_alloc_obj.
213  * @vmm_flags:      Pass-through to vmm_alloc_obj.
214  * @arch_mmu_flags: Pass-through to vmm_alloc_obj.
215  *
216  * Return: 0 on success, negative error code if object could not be mapped.
217  */
218 status_t ext_mem_map_obj_id(struct vmm_aspace* aspace,
219                             const char* name,
220                             ext_mem_client_id_t client_id,
221                             ext_mem_obj_id_t mem_obj_id,
222                             uint64_t tag,
223                             size_t offset,
224                             size_t size,
225                             void** ptr,
226                             uint8_t align_log2,
227                             uint vmm_flags,
228                             uint arch_mmu_flags);
229 
230 /**
231  * ext_mem_get_vmm_obj - Lookup shared memory object.
232  * @client_id:      Id of external entity where the memory originated.
233  * @mem_obj_id:     Id of shared memory object to lookup and return.
234  * @tag:            Tag of the memory. If a non-FF-A object, use 0.
235  * @size:           Size hint for object. Caller expects an object at least this
236  *                  big.
237  * @objp:           Pointer to return object in.
238  * @obj_ref:        Reference to *@objp.
239  *
240  * Not provided by ext_mem.
241  *
242  * Return: 0 on success. ERR_NOT_FOUND if @id does not exist.
243  */
244 status_t ext_mem_get_vmm_obj(ext_mem_client_id_t client_id,
245                              ext_mem_obj_id_t mem_obj_id,
246                              uint64_t tag,
247                              size_t size,
248                              struct vmm_obj** objp,
249                              struct obj_ref* obj_ref);
250