xref: /aosp_15_r20/trusty/kernel/lib/extmem/external_memory.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1*344aa361SAndroid Build Coastguard Worker /*
2*344aa361SAndroid Build Coastguard Worker  * Copyright (c) 2020 LK Trusty Authors. All Rights Reserved.
3*344aa361SAndroid Build Coastguard Worker  *
4*344aa361SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining
5*344aa361SAndroid Build Coastguard Worker  * a copy of this software and associated documentation files
6*344aa361SAndroid Build Coastguard Worker  * (the "Software"), to deal in the Software without restriction,
7*344aa361SAndroid Build Coastguard Worker  * including without limitation the rights to use, copy, modify, merge,
8*344aa361SAndroid Build Coastguard Worker  * publish, distribute, sublicense, and/or sell copies of the Software,
9*344aa361SAndroid Build Coastguard Worker  * and to permit persons to whom the Software is furnished to do so,
10*344aa361SAndroid Build Coastguard Worker  * subject to the following conditions:
11*344aa361SAndroid Build Coastguard Worker  *
12*344aa361SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be
13*344aa361SAndroid Build Coastguard Worker  * included in all copies or substantial portions of the Software.
14*344aa361SAndroid Build Coastguard Worker  *
15*344aa361SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*344aa361SAndroid Build Coastguard Worker  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*344aa361SAndroid Build Coastguard Worker  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18*344aa361SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19*344aa361SAndroid Build Coastguard Worker  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20*344aa361SAndroid Build Coastguard Worker  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21*344aa361SAndroid Build Coastguard Worker  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*344aa361SAndroid Build Coastguard Worker  */
23*344aa361SAndroid Build Coastguard Worker 
24*344aa361SAndroid Build Coastguard Worker #include <err.h>
25*344aa361SAndroid Build Coastguard Worker #include <inttypes.h>
26*344aa361SAndroid Build Coastguard Worker #include <kernel/vm.h>
27*344aa361SAndroid Build Coastguard Worker #include <lib/extmem/extmem.h>
28*344aa361SAndroid Build Coastguard Worker #include <sys/types.h>
29*344aa361SAndroid Build Coastguard Worker #include <trace.h>
30*344aa361SAndroid Build Coastguard Worker 
31*344aa361SAndroid Build Coastguard Worker #define LOCAL_TRACE 0
32*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_from_vmm_obj(struct vmm_obj * vmm_obj)33*344aa361SAndroid Build Coastguard Worker static struct ext_mem_obj* ext_mem_obj_from_vmm_obj(struct vmm_obj* vmm_obj) {
34*344aa361SAndroid Build Coastguard Worker     return containerof(vmm_obj, struct ext_mem_obj, vmm_obj);
35*344aa361SAndroid Build Coastguard Worker }
36*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_from_bst_node(struct bst_node * node)37*344aa361SAndroid Build Coastguard Worker static struct ext_mem_obj* ext_mem_obj_from_bst_node(struct bst_node* node) {
38*344aa361SAndroid Build Coastguard Worker     return containerof(node, struct ext_mem_obj, node);
39*344aa361SAndroid Build Coastguard Worker }
40*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_cmp(struct bst_node * a_bst,struct bst_node * b_bst)41*344aa361SAndroid Build Coastguard Worker static int ext_mem_obj_cmp(struct bst_node* a_bst, struct bst_node* b_bst) {
42*344aa361SAndroid Build Coastguard Worker     struct ext_mem_obj* a = ext_mem_obj_from_bst_node(a_bst);
43*344aa361SAndroid Build Coastguard Worker     struct ext_mem_obj* b = ext_mem_obj_from_bst_node(b_bst);
44*344aa361SAndroid Build Coastguard Worker 
45*344aa361SAndroid Build Coastguard Worker     return a->id < b->id ? 1 : a->id > b->id ? -1 : 0;
46*344aa361SAndroid Build Coastguard Worker }
47*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_initialize(struct ext_mem_obj * obj,struct obj_ref * ref,ext_mem_obj_id_t id,uint64_t tag,struct vmm_obj_ops * ops,uint arch_mmu_flags,size_t page_run_count)48*344aa361SAndroid Build Coastguard Worker void ext_mem_obj_initialize(struct ext_mem_obj* obj,
49*344aa361SAndroid Build Coastguard Worker                             struct obj_ref* ref,
50*344aa361SAndroid Build Coastguard Worker                             ext_mem_obj_id_t id,
51*344aa361SAndroid Build Coastguard Worker                             uint64_t tag,
52*344aa361SAndroid Build Coastguard Worker                             struct vmm_obj_ops* ops,
53*344aa361SAndroid Build Coastguard Worker                             uint arch_mmu_flags,
54*344aa361SAndroid Build Coastguard Worker                             size_t page_run_count) {
55*344aa361SAndroid Build Coastguard Worker     obj->id = id;
56*344aa361SAndroid Build Coastguard Worker     obj->tag = tag;
57*344aa361SAndroid Build Coastguard Worker     obj->match_tag = 0;
58*344aa361SAndroid Build Coastguard Worker     obj->vmm_obj.ops = ops;
59*344aa361SAndroid Build Coastguard Worker     obj->arch_mmu_flags = arch_mmu_flags;
60*344aa361SAndroid Build Coastguard Worker     obj->page_run_count = page_run_count;
61*344aa361SAndroid Build Coastguard Worker     obj_init(&obj->vmm_obj.obj, ref);
62*344aa361SAndroid Build Coastguard Worker     bst_node_initialize(&obj->node);
63*344aa361SAndroid Build Coastguard Worker }
64*344aa361SAndroid Build Coastguard Worker 
ext_mem_insert(struct bst_root * objs,struct ext_mem_obj * obj)65*344aa361SAndroid Build Coastguard Worker bool ext_mem_insert(struct bst_root* objs, struct ext_mem_obj* obj) {
66*344aa361SAndroid Build Coastguard Worker     return bst_insert(objs, &obj->node, ext_mem_obj_cmp);
67*344aa361SAndroid Build Coastguard Worker }
68*344aa361SAndroid Build Coastguard Worker 
ext_mem_lookup(struct bst_root * objs,ext_mem_obj_id_t id)69*344aa361SAndroid Build Coastguard Worker struct ext_mem_obj* ext_mem_lookup(struct bst_root* objs, ext_mem_obj_id_t id) {
70*344aa361SAndroid Build Coastguard Worker     struct ext_mem_obj ref_obj;
71*344aa361SAndroid Build Coastguard Worker     ref_obj.id = id;
72*344aa361SAndroid Build Coastguard Worker     return bst_search_type(objs, &ref_obj, ext_mem_obj_cmp, struct ext_mem_obj,
73*344aa361SAndroid Build Coastguard Worker                            node);
74*344aa361SAndroid Build Coastguard Worker }
75*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_set_match_tag(struct vmm_obj * obj,uint64_t match_tag)76*344aa361SAndroid Build Coastguard Worker void ext_mem_obj_set_match_tag(struct vmm_obj* obj, uint64_t match_tag) {
77*344aa361SAndroid Build Coastguard Worker     struct ext_mem_obj* ext_obj = ext_mem_obj_from_vmm_obj(obj);
78*344aa361SAndroid Build Coastguard Worker 
79*344aa361SAndroid Build Coastguard Worker     ext_obj->match_tag = match_tag;
80*344aa361SAndroid Build Coastguard Worker }
81*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_check_flags(struct vmm_obj * obj,uint * arch_mmu_flags)82*344aa361SAndroid Build Coastguard Worker int ext_mem_obj_check_flags(struct vmm_obj* obj, uint* arch_mmu_flags) {
83*344aa361SAndroid Build Coastguard Worker     struct ext_mem_obj* ext_obj = ext_mem_obj_from_vmm_obj(obj);
84*344aa361SAndroid Build Coastguard Worker 
85*344aa361SAndroid Build Coastguard Worker     LTRACEF("obj 0x%" PRIx64 ", obj arch_mmu_flags 0x%x, arch_mmu_flags 0x%x\n",
86*344aa361SAndroid Build Coastguard Worker             ext_obj->id, ext_obj->arch_mmu_flags, *arch_mmu_flags);
87*344aa361SAndroid Build Coastguard Worker 
88*344aa361SAndroid Build Coastguard Worker     if (ext_obj->match_tag != ext_obj->tag) {
89*344aa361SAndroid Build Coastguard Worker         TRACEF("WARNING: tag mismatch: 0x%" PRIx64 " != 0x%" PRIx64 "\n",
90*344aa361SAndroid Build Coastguard Worker                ext_obj->match_tag, ext_obj->tag);
91*344aa361SAndroid Build Coastguard Worker         return ERR_ACCESS_DENIED;
92*344aa361SAndroid Build Coastguard Worker     }
93*344aa361SAndroid Build Coastguard Worker 
94*344aa361SAndroid Build Coastguard Worker     if (!(*arch_mmu_flags & ARCH_MMU_FLAG_PERM_RO) &&
95*344aa361SAndroid Build Coastguard Worker         (ext_obj->arch_mmu_flags & ARCH_MMU_FLAG_PERM_RO)) {
96*344aa361SAndroid Build Coastguard Worker         TRACEF("rw access denied. arch_mmu_flags=0x%x, ext_obj->flags=0x%x\n",
97*344aa361SAndroid Build Coastguard Worker                *arch_mmu_flags, ext_obj->arch_mmu_flags);
98*344aa361SAndroid Build Coastguard Worker         return ERR_ACCESS_DENIED;
99*344aa361SAndroid Build Coastguard Worker     }
100*344aa361SAndroid Build Coastguard Worker 
101*344aa361SAndroid Build Coastguard Worker     if (!(*arch_mmu_flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE) &&
102*344aa361SAndroid Build Coastguard Worker         (ext_obj->arch_mmu_flags & ARCH_MMU_FLAG_PERM_NO_EXECUTE)) {
103*344aa361SAndroid Build Coastguard Worker         TRACEF("exec access denied. arch_mmu_flags=0x%x, ext_obj->flags=0x%x\n",
104*344aa361SAndroid Build Coastguard Worker                *arch_mmu_flags, ext_obj->arch_mmu_flags);
105*344aa361SAndroid Build Coastguard Worker         return ERR_ACCESS_DENIED;
106*344aa361SAndroid Build Coastguard Worker     }
107*344aa361SAndroid Build Coastguard Worker 
108*344aa361SAndroid Build Coastguard Worker     /*
109*344aa361SAndroid Build Coastguard Worker      * Memory types must be consistent with external mappings, so don't allow
110*344aa361SAndroid Build Coastguard Worker      * the caller to specify them.
111*344aa361SAndroid Build Coastguard Worker      */
112*344aa361SAndroid Build Coastguard Worker     if (*arch_mmu_flags & ARCH_MMU_FLAG_CACHE_MASK) {
113*344aa361SAndroid Build Coastguard Worker         TRACEF("cache attributes should come from vmm_obj, not from caller\n");
114*344aa361SAndroid Build Coastguard Worker         return ERR_INVALID_ARGS;
115*344aa361SAndroid Build Coastguard Worker     }
116*344aa361SAndroid Build Coastguard Worker 
117*344aa361SAndroid Build Coastguard Worker     if (*arch_mmu_flags & ARCH_MMU_FLAG_NS) {
118*344aa361SAndroid Build Coastguard Worker         TRACEF("ARCH_MMU_FLAG_NS should come from vmm_obj, not from caller\n");
119*344aa361SAndroid Build Coastguard Worker         return ERR_INVALID_ARGS;
120*344aa361SAndroid Build Coastguard Worker     }
121*344aa361SAndroid Build Coastguard Worker 
122*344aa361SAndroid Build Coastguard Worker     *arch_mmu_flags |= ext_obj->arch_mmu_flags;
123*344aa361SAndroid Build Coastguard Worker 
124*344aa361SAndroid Build Coastguard Worker     return 0;
125*344aa361SAndroid Build Coastguard Worker }
126*344aa361SAndroid Build Coastguard Worker 
ext_mem_obj_get_page(struct vmm_obj * obj,size_t offset,paddr_t * paddr,size_t * paddr_size)127*344aa361SAndroid Build Coastguard Worker int ext_mem_obj_get_page(struct vmm_obj* obj,
128*344aa361SAndroid Build Coastguard Worker                          size_t offset,
129*344aa361SAndroid Build Coastguard Worker                          paddr_t* paddr,
130*344aa361SAndroid Build Coastguard Worker                          size_t* paddr_size) {
131*344aa361SAndroid Build Coastguard Worker     struct ext_mem_obj* ext_obj = ext_mem_obj_from_vmm_obj(obj);
132*344aa361SAndroid Build Coastguard Worker     size_t index;
133*344aa361SAndroid Build Coastguard Worker     size_t page_offset;
134*344aa361SAndroid Build Coastguard Worker 
135*344aa361SAndroid Build Coastguard Worker     LTRACEF("offset %zd page_run_count %zd\n", offset, ext_obj->page_run_count);
136*344aa361SAndroid Build Coastguard Worker 
137*344aa361SAndroid Build Coastguard Worker     page_offset = offset;
138*344aa361SAndroid Build Coastguard Worker     index = 0;
139*344aa361SAndroid Build Coastguard Worker     while (index < ext_obj->page_run_count &&
140*344aa361SAndroid Build Coastguard Worker            ext_obj->page_runs[index].size <= page_offset) {
141*344aa361SAndroid Build Coastguard Worker         page_offset -= ext_obj->page_runs[index].size;
142*344aa361SAndroid Build Coastguard Worker         index++;
143*344aa361SAndroid Build Coastguard Worker     }
144*344aa361SAndroid Build Coastguard Worker 
145*344aa361SAndroid Build Coastguard Worker     if (index >= ext_obj->page_run_count) {
146*344aa361SAndroid Build Coastguard Worker         TRACEF("offset %zd out of range index %zd >= %zd\n", offset, index,
147*344aa361SAndroid Build Coastguard Worker                ext_obj->page_run_count);
148*344aa361SAndroid Build Coastguard Worker         return ERR_OUT_OF_RANGE;
149*344aa361SAndroid Build Coastguard Worker     }
150*344aa361SAndroid Build Coastguard Worker 
151*344aa361SAndroid Build Coastguard Worker     *paddr = ext_obj->page_runs[index].paddr + page_offset;
152*344aa361SAndroid Build Coastguard Worker     *paddr_size = ext_obj->page_runs[index].size - page_offset;
153*344aa361SAndroid Build Coastguard Worker     LTRACEF("offset %zd, index %zd/%zd -> paddr 0x%" PRIxPADDR ", size %zu\n",
154*344aa361SAndroid Build Coastguard Worker             offset, index, ext_obj->page_run_count, *paddr, *paddr_size);
155*344aa361SAndroid Build Coastguard Worker 
156*344aa361SAndroid Build Coastguard Worker     return 0;
157*344aa361SAndroid Build Coastguard Worker }
158*344aa361SAndroid Build Coastguard Worker 
ext_mem_map_obj_id(vmm_aspace_t * aspace,const char * name,ext_mem_client_id_t client_id,ext_mem_obj_id_t mem_obj_id,uint64_t tag,size_t offset,size_t size,void ** ptr,uint8_t align_log2,uint vmm_flags,uint arch_mmu_flags)159*344aa361SAndroid Build Coastguard Worker status_t ext_mem_map_obj_id(vmm_aspace_t* aspace,
160*344aa361SAndroid Build Coastguard Worker                             const char* name,
161*344aa361SAndroid Build Coastguard Worker                             ext_mem_client_id_t client_id,
162*344aa361SAndroid Build Coastguard Worker                             ext_mem_obj_id_t mem_obj_id,
163*344aa361SAndroid Build Coastguard Worker                             uint64_t tag,
164*344aa361SAndroid Build Coastguard Worker                             size_t offset,
165*344aa361SAndroid Build Coastguard Worker                             size_t size,
166*344aa361SAndroid Build Coastguard Worker                             void** ptr,
167*344aa361SAndroid Build Coastguard Worker                             uint8_t align_log2,
168*344aa361SAndroid Build Coastguard Worker                             uint vmm_flags,
169*344aa361SAndroid Build Coastguard Worker                             uint arch_mmu_flags) {
170*344aa361SAndroid Build Coastguard Worker     status_t err;
171*344aa361SAndroid Build Coastguard Worker     struct vmm_obj* vmm_obj = NULL;
172*344aa361SAndroid Build Coastguard Worker     struct obj_ref vmm_obj_ref = OBJ_REF_INITIAL_VALUE(vmm_obj_ref);
173*344aa361SAndroid Build Coastguard Worker 
174*344aa361SAndroid Build Coastguard Worker     DEBUG_ASSERT(IS_PAGE_ALIGNED(size));
175*344aa361SAndroid Build Coastguard Worker 
176*344aa361SAndroid Build Coastguard Worker     err = ext_mem_get_vmm_obj(client_id, mem_obj_id, tag, size + offset,
177*344aa361SAndroid Build Coastguard Worker                               &vmm_obj, &vmm_obj_ref);
178*344aa361SAndroid Build Coastguard Worker     if (err) {
179*344aa361SAndroid Build Coastguard Worker         TRACEF("failed to get object, 0x%" PRIx64 ":0x%" PRIx64
180*344aa361SAndroid Build Coastguard Worker                ", to map for %s\n",
181*344aa361SAndroid Build Coastguard Worker                client_id, mem_obj_id, name);
182*344aa361SAndroid Build Coastguard Worker         return err;
183*344aa361SAndroid Build Coastguard Worker     }
184*344aa361SAndroid Build Coastguard Worker 
185*344aa361SAndroid Build Coastguard Worker     /* If tag is not 0, match_tag must be set before the object can be mapped */
186*344aa361SAndroid Build Coastguard Worker     ext_mem_obj_set_match_tag(vmm_obj, tag);
187*344aa361SAndroid Build Coastguard Worker 
188*344aa361SAndroid Build Coastguard Worker     err = vmm_alloc_obj(aspace, name, vmm_obj, offset, size, ptr, align_log2,
189*344aa361SAndroid Build Coastguard Worker                         vmm_flags, arch_mmu_flags);
190*344aa361SAndroid Build Coastguard Worker     vmm_obj_del_ref(vmm_obj, &vmm_obj_ref);
191*344aa361SAndroid Build Coastguard Worker     if (err) {
192*344aa361SAndroid Build Coastguard Worker         TRACEF("failed to map object, 0x%" PRIx64 ":0x%" PRIx64 ", for %s\n",
193*344aa361SAndroid Build Coastguard Worker                client_id, mem_obj_id, name);
194*344aa361SAndroid Build Coastguard Worker         return err;
195*344aa361SAndroid Build Coastguard Worker     }
196*344aa361SAndroid Build Coastguard Worker     LTRACEF("mapped 0x%" PRIx64 ":0x%" PRIx64 " at %p\n", client_id, mem_obj_id,
197*344aa361SAndroid Build Coastguard Worker             *ptr);
198*344aa361SAndroid Build Coastguard Worker     return err;
199*344aa361SAndroid Build Coastguard Worker }
200