xref: /aosp_15_r20/trusty/kernel/lib/memlog/memlog.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1*344aa361SAndroid Build Coastguard Worker /*
2*344aa361SAndroid Build Coastguard Worker  * Copyright (c) 2015 Google, Inc.
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 <arch/ops.h>
25*344aa361SAndroid Build Coastguard Worker #include <debug.h>
26*344aa361SAndroid Build Coastguard Worker #include <err.h>
27*344aa361SAndroid Build Coastguard Worker #include <kernel/thread.h>
28*344aa361SAndroid Build Coastguard Worker #include <kernel/vm.h>
29*344aa361SAndroid Build Coastguard Worker #include <lib/io.h>
30*344aa361SAndroid Build Coastguard Worker #include <lib/sm.h>
31*344aa361SAndroid Build Coastguard Worker #include <lib/sm/sm_err.h>
32*344aa361SAndroid Build Coastguard Worker #include <lib/sm/smcall.h>
33*344aa361SAndroid Build Coastguard Worker #include <list.h>
34*344aa361SAndroid Build Coastguard Worker #include <lk/init.h>
35*344aa361SAndroid Build Coastguard Worker #include <platform.h>
36*344aa361SAndroid Build Coastguard Worker #include <pow2.h>
37*344aa361SAndroid Build Coastguard Worker #include <stdio.h>
38*344aa361SAndroid Build Coastguard Worker #include <stdlib.h>
39*344aa361SAndroid Build Coastguard Worker #include <string.h>
40*344aa361SAndroid Build Coastguard Worker 
41*344aa361SAndroid Build Coastguard Worker #include "trusty-log.h"
42*344aa361SAndroid Build Coastguard Worker 
43*344aa361SAndroid Build Coastguard Worker #define LOG_LOCK_FLAGS SPIN_LOCK_FLAG_IRQ_FIQ
44*344aa361SAndroid Build Coastguard Worker 
45*344aa361SAndroid Build Coastguard Worker struct memlog {
46*344aa361SAndroid Build Coastguard Worker     struct log_rb* rb;
47*344aa361SAndroid Build Coastguard Worker     size_t rb_sz;
48*344aa361SAndroid Build Coastguard Worker 
49*344aa361SAndroid Build Coastguard Worker     ext_mem_client_id_t client_id;
50*344aa361SAndroid Build Coastguard Worker     ext_mem_obj_id_t buf_id;
51*344aa361SAndroid Build Coastguard Worker     size_t buf_sz;
52*344aa361SAndroid Build Coastguard Worker 
53*344aa361SAndroid Build Coastguard Worker     print_callback_t cb;
54*344aa361SAndroid Build Coastguard Worker     struct list_node entry;
55*344aa361SAndroid Build Coastguard Worker };
56*344aa361SAndroid Build Coastguard Worker 
57*344aa361SAndroid Build Coastguard Worker static spin_lock_t log_lock;
58*344aa361SAndroid Build Coastguard Worker static struct list_node log_list = LIST_INITIAL_VALUE(log_list);
59*344aa361SAndroid Build Coastguard Worker 
memlog_get_by_id(ext_mem_client_id_t client_id,ext_mem_obj_id_t buf_id)60*344aa361SAndroid Build Coastguard Worker static struct memlog* memlog_get_by_id(ext_mem_client_id_t client_id,
61*344aa361SAndroid Build Coastguard Worker                                        ext_mem_obj_id_t buf_id) {
62*344aa361SAndroid Build Coastguard Worker     struct memlog* log;
63*344aa361SAndroid Build Coastguard Worker     list_for_every_entry(&log_list, log, struct memlog, entry) {
64*344aa361SAndroid Build Coastguard Worker         if (log->client_id == client_id && log->buf_id == buf_id) {
65*344aa361SAndroid Build Coastguard Worker             return log;
66*344aa361SAndroid Build Coastguard Worker         }
67*344aa361SAndroid Build Coastguard Worker     }
68*344aa361SAndroid Build Coastguard Worker 
69*344aa361SAndroid Build Coastguard Worker     return NULL;
70*344aa361SAndroid Build Coastguard Worker }
71*344aa361SAndroid Build Coastguard Worker 
lower_pow2(uint32_t v)72*344aa361SAndroid Build Coastguard Worker static uint32_t lower_pow2(uint32_t v) {
73*344aa361SAndroid Build Coastguard Worker     return 1u << (31 - __builtin_clz(v));
74*344aa361SAndroid Build Coastguard Worker }
75*344aa361SAndroid Build Coastguard Worker 
__memlog_write(struct memlog * log,const char * str,size_t len)76*344aa361SAndroid Build Coastguard Worker static void __memlog_write(struct memlog* log, const char* str, size_t len) {
77*344aa361SAndroid Build Coastguard Worker     size_t i;
78*344aa361SAndroid Build Coastguard Worker     uint32_t log_offset;
79*344aa361SAndroid Build Coastguard Worker     struct log_rb* rb = log->rb;
80*344aa361SAndroid Build Coastguard Worker 
81*344aa361SAndroid Build Coastguard Worker     log_offset = rb->alloc;
82*344aa361SAndroid Build Coastguard Worker 
83*344aa361SAndroid Build Coastguard Worker     __builtin_add_overflow(rb->alloc, len, &rb->alloc);
84*344aa361SAndroid Build Coastguard Worker 
85*344aa361SAndroid Build Coastguard Worker     /* Updates to alloc should be visible before the data is written. */
86*344aa361SAndroid Build Coastguard Worker     wmb();
87*344aa361SAndroid Build Coastguard Worker 
88*344aa361SAndroid Build Coastguard Worker     for (i = 0; i < len; i++) {
89*344aa361SAndroid Build Coastguard Worker         uint32_t offset;
90*344aa361SAndroid Build Coastguard Worker         __builtin_add_overflow(log_offset, i, &offset);
91*344aa361SAndroid Build Coastguard Worker         offset &= (log->rb_sz - 1);
92*344aa361SAndroid Build Coastguard Worker         volatile char* ptr = &rb->data[offset];
93*344aa361SAndroid Build Coastguard Worker         *ptr = str[i];
94*344aa361SAndroid Build Coastguard Worker     }
95*344aa361SAndroid Build Coastguard Worker }
96*344aa361SAndroid Build Coastguard Worker 
memlog_write(struct memlog * log,const char * str,size_t len)97*344aa361SAndroid Build Coastguard Worker static void memlog_write(struct memlog* log, const char* str, size_t len) {
98*344aa361SAndroid Build Coastguard Worker     size_t i;
99*344aa361SAndroid Build Coastguard Worker     const int chunk_size = 128;
100*344aa361SAndroid Build Coastguard Worker     size_t rem;
101*344aa361SAndroid Build Coastguard Worker     spin_lock_saved_state_t state;
102*344aa361SAndroid Build Coastguard Worker 
103*344aa361SAndroid Build Coastguard Worker     spin_lock_save(&log_lock, &state, LOG_LOCK_FLAGS);
104*344aa361SAndroid Build Coastguard Worker     for (i = 0; i < len / chunk_size; i++) {
105*344aa361SAndroid Build Coastguard Worker         __memlog_write(log, &str[i * chunk_size], chunk_size);
106*344aa361SAndroid Build Coastguard Worker     }
107*344aa361SAndroid Build Coastguard Worker     rem = len - i * chunk_size;
108*344aa361SAndroid Build Coastguard Worker     if (rem)
109*344aa361SAndroid Build Coastguard Worker         __memlog_write(log, &str[i * chunk_size], rem);
110*344aa361SAndroid Build Coastguard Worker     spin_unlock_restore(&log_lock, state, LOG_LOCK_FLAGS);
111*344aa361SAndroid Build Coastguard Worker }
112*344aa361SAndroid Build Coastguard Worker 
113*344aa361SAndroid Build Coastguard Worker /* Signal that the buffered data is ready to read. */
memlog_commit(struct memlog * log)114*344aa361SAndroid Build Coastguard Worker static void memlog_commit(struct memlog* log) {
115*344aa361SAndroid Build Coastguard Worker     spin_lock_saved_state_t state;
116*344aa361SAndroid Build Coastguard Worker     spin_lock_save(&log_lock, &state, LOG_LOCK_FLAGS);
117*344aa361SAndroid Build Coastguard Worker 
118*344aa361SAndroid Build Coastguard Worker     /*
119*344aa361SAndroid Build Coastguard Worker      * Updates to the data should be visible before put is written.
120*344aa361SAndroid Build Coastguard Worker      * Arguably the existing spinlock implementations should take care of the
121*344aa361SAndroid Build Coastguard Worker      * ordering, but spinlocks for a non-SMP version of Trusty would not be
122*344aa361SAndroid Build Coastguard Worker      * required to use barriers. This code needs a barrier, however, because it
123*344aa361SAndroid Build Coastguard Worker      * is synchonizing with code that runs outside of Trusty, possibly on a
124*344aa361SAndroid Build Coastguard Worker      * different processor. (Even if Trusty itself is non-SMP.)
125*344aa361SAndroid Build Coastguard Worker      */
126*344aa361SAndroid Build Coastguard Worker     wmb();
127*344aa361SAndroid Build Coastguard Worker 
128*344aa361SAndroid Build Coastguard Worker     log->rb->put = log->rb->alloc;
129*344aa361SAndroid Build Coastguard Worker 
130*344aa361SAndroid Build Coastguard Worker     spin_unlock_restore(&log_lock, state, LOG_LOCK_FLAGS);
131*344aa361SAndroid Build Coastguard Worker }
132*344aa361SAndroid Build Coastguard Worker 
map_rb(ext_mem_client_id_t client_id,ext_mem_obj_id_t mem_obj_id,size_t sz,vaddr_t * va)133*344aa361SAndroid Build Coastguard Worker static status_t map_rb(ext_mem_client_id_t client_id,
134*344aa361SAndroid Build Coastguard Worker                        ext_mem_obj_id_t mem_obj_id,
135*344aa361SAndroid Build Coastguard Worker                        size_t sz,
136*344aa361SAndroid Build Coastguard Worker                        vaddr_t* va) {
137*344aa361SAndroid Build Coastguard Worker     return ext_mem_map_obj_id(vmm_get_kernel_aspace(), "logmem", client_id,
138*344aa361SAndroid Build Coastguard Worker                               mem_obj_id, 0, 0, sz, (void**)va, PAGE_SIZE_SHIFT,
139*344aa361SAndroid Build Coastguard Worker                               0, ARCH_MMU_FLAG_PERM_NO_EXECUTE);
140*344aa361SAndroid Build Coastguard Worker }
141*344aa361SAndroid Build Coastguard Worker 
args_get_id(struct smc32_args * args)142*344aa361SAndroid Build Coastguard Worker static ext_mem_obj_id_t args_get_id(struct smc32_args* args) {
143*344aa361SAndroid Build Coastguard Worker     return (((uint64_t)args->params[1] << 32) | args->params[0]);
144*344aa361SAndroid Build Coastguard Worker }
145*344aa361SAndroid Build Coastguard Worker 
args_get_sz(struct smc32_args * args)146*344aa361SAndroid Build Coastguard Worker static size_t args_get_sz(struct smc32_args* args) {
147*344aa361SAndroid Build Coastguard Worker     return (size_t)args->params[2];
148*344aa361SAndroid Build Coastguard Worker }
149*344aa361SAndroid Build Coastguard Worker 
memlog_print_callback(print_callback_t * cb,const char * str,size_t len)150*344aa361SAndroid Build Coastguard Worker void memlog_print_callback(print_callback_t* cb, const char* str, size_t len) {
151*344aa361SAndroid Build Coastguard Worker     struct memlog* log = containerof(cb, struct memlog, cb);
152*344aa361SAndroid Build Coastguard Worker     memlog_write(log, str, len);
153*344aa361SAndroid Build Coastguard Worker }
154*344aa361SAndroid Build Coastguard Worker 
memlog_commit_callback(print_callback_t * cb)155*344aa361SAndroid Build Coastguard Worker void memlog_commit_callback(print_callback_t* cb) {
156*344aa361SAndroid Build Coastguard Worker     struct memlog* log = containerof(cb, struct memlog, cb);
157*344aa361SAndroid Build Coastguard Worker     memlog_commit(log);
158*344aa361SAndroid Build Coastguard Worker }
159*344aa361SAndroid Build Coastguard Worker 
memlog_add(ext_mem_client_id_t client_id,ext_mem_obj_id_t buf_id,size_t sz)160*344aa361SAndroid Build Coastguard Worker static long memlog_add(ext_mem_client_id_t client_id,
161*344aa361SAndroid Build Coastguard Worker                        ext_mem_obj_id_t buf_id,
162*344aa361SAndroid Build Coastguard Worker                        size_t sz) {
163*344aa361SAndroid Build Coastguard Worker     struct memlog* log;
164*344aa361SAndroid Build Coastguard Worker     vaddr_t va;
165*344aa361SAndroid Build Coastguard Worker     long status;
166*344aa361SAndroid Build Coastguard Worker     status_t result;
167*344aa361SAndroid Build Coastguard Worker     struct log_rb* rb;
168*344aa361SAndroid Build Coastguard Worker 
169*344aa361SAndroid Build Coastguard Worker     if (!IS_PAGE_ALIGNED(sz) || sz == 0) {
170*344aa361SAndroid Build Coastguard Worker         return SM_ERR_INVALID_PARAMETERS;
171*344aa361SAndroid Build Coastguard Worker     }
172*344aa361SAndroid Build Coastguard Worker 
173*344aa361SAndroid Build Coastguard Worker     log = malloc(sizeof(*log));
174*344aa361SAndroid Build Coastguard Worker     if (!log) {
175*344aa361SAndroid Build Coastguard Worker         return SM_ERR_INTERNAL_FAILURE;
176*344aa361SAndroid Build Coastguard Worker     }
177*344aa361SAndroid Build Coastguard Worker     memset(log, 0, sizeof(*log));
178*344aa361SAndroid Build Coastguard Worker     log->client_id = client_id;
179*344aa361SAndroid Build Coastguard Worker     log->buf_id = buf_id;
180*344aa361SAndroid Build Coastguard Worker     log->buf_sz = sz;
181*344aa361SAndroid Build Coastguard Worker 
182*344aa361SAndroid Build Coastguard Worker     result = map_rb(client_id, buf_id, sz, &va);
183*344aa361SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
184*344aa361SAndroid Build Coastguard Worker         status = SM_ERR_INTERNAL_FAILURE;
185*344aa361SAndroid Build Coastguard Worker         goto error_failed_to_map;
186*344aa361SAndroid Build Coastguard Worker     }
187*344aa361SAndroid Build Coastguard Worker     rb = (struct log_rb*)va;
188*344aa361SAndroid Build Coastguard Worker     log->rb = rb;
189*344aa361SAndroid Build Coastguard Worker     log->rb_sz = lower_pow2(log->buf_sz - offsetof(struct log_rb, data));
190*344aa361SAndroid Build Coastguard Worker 
191*344aa361SAndroid Build Coastguard Worker     rb->sz = log->rb_sz;
192*344aa361SAndroid Build Coastguard Worker     rb->alloc = 0;
193*344aa361SAndroid Build Coastguard Worker     rb->put = 0;
194*344aa361SAndroid Build Coastguard Worker 
195*344aa361SAndroid Build Coastguard Worker     list_add_head(&log_list, &log->entry);
196*344aa361SAndroid Build Coastguard Worker 
197*344aa361SAndroid Build Coastguard Worker     log->cb.print = memlog_print_callback;
198*344aa361SAndroid Build Coastguard Worker     log->cb.commit = memlog_commit_callback;
199*344aa361SAndroid Build Coastguard Worker     register_print_callback(&log->cb);
200*344aa361SAndroid Build Coastguard Worker     return 0;
201*344aa361SAndroid Build Coastguard Worker 
202*344aa361SAndroid Build Coastguard Worker error_failed_to_map:
203*344aa361SAndroid Build Coastguard Worker     free(log);
204*344aa361SAndroid Build Coastguard Worker     return status;
205*344aa361SAndroid Build Coastguard Worker }
206*344aa361SAndroid Build Coastguard Worker 
memlog_rm(ext_mem_client_id_t client_id,ext_mem_obj_id_t buf_id)207*344aa361SAndroid Build Coastguard Worker static long memlog_rm(ext_mem_client_id_t client_id, ext_mem_obj_id_t buf_id) {
208*344aa361SAndroid Build Coastguard Worker     struct memlog* log;
209*344aa361SAndroid Build Coastguard Worker     status_t result;
210*344aa361SAndroid Build Coastguard Worker 
211*344aa361SAndroid Build Coastguard Worker     log = memlog_get_by_id(client_id, buf_id);
212*344aa361SAndroid Build Coastguard Worker     if (!log) {
213*344aa361SAndroid Build Coastguard Worker         return SM_ERR_INVALID_PARAMETERS;
214*344aa361SAndroid Build Coastguard Worker     }
215*344aa361SAndroid Build Coastguard Worker     unregister_print_callback(&log->cb);
216*344aa361SAndroid Build Coastguard Worker     list_delete(&log->entry);
217*344aa361SAndroid Build Coastguard Worker     result = vmm_free_region(vmm_get_kernel_aspace(), (vaddr_t)log->rb);
218*344aa361SAndroid Build Coastguard Worker     free(log);
219*344aa361SAndroid Build Coastguard Worker     if (result != NO_ERROR) {
220*344aa361SAndroid Build Coastguard Worker         return SM_ERR_INTERNAL_FAILURE;
221*344aa361SAndroid Build Coastguard Worker     }
222*344aa361SAndroid Build Coastguard Worker     return 0;
223*344aa361SAndroid Build Coastguard Worker }
224*344aa361SAndroid Build Coastguard Worker 
memlog_stdcall(struct smc32_args * args)225*344aa361SAndroid Build Coastguard Worker static long memlog_stdcall(struct smc32_args* args) {
226*344aa361SAndroid Build Coastguard Worker     switch (args->smc_nr) {
227*344aa361SAndroid Build Coastguard Worker     case SMC_SC_SHARED_LOG_VERSION:
228*344aa361SAndroid Build Coastguard Worker         return TRUSTY_LOG_API_VERSION;
229*344aa361SAndroid Build Coastguard Worker     case SMC_SC_SHARED_LOG_ADD:
230*344aa361SAndroid Build Coastguard Worker         return memlog_add(args->client_id, args_get_id(args),
231*344aa361SAndroid Build Coastguard Worker                           args_get_sz(args));
232*344aa361SAndroid Build Coastguard Worker     case SMC_SC_SHARED_LOG_RM:
233*344aa361SAndroid Build Coastguard Worker         return memlog_rm(args->client_id, args_get_id(args));
234*344aa361SAndroid Build Coastguard Worker     default:
235*344aa361SAndroid Build Coastguard Worker         return SM_ERR_UNDEFINED_SMC;
236*344aa361SAndroid Build Coastguard Worker     }
237*344aa361SAndroid Build Coastguard Worker     return 0;
238*344aa361SAndroid Build Coastguard Worker }
239*344aa361SAndroid Build Coastguard Worker 
240*344aa361SAndroid Build Coastguard Worker static struct smc32_entity log_sm_entity = {
241*344aa361SAndroid Build Coastguard Worker         .stdcall_handler = memlog_stdcall,
242*344aa361SAndroid Build Coastguard Worker };
243*344aa361SAndroid Build Coastguard Worker 
memlog_init(uint level)244*344aa361SAndroid Build Coastguard Worker static void memlog_init(uint level) {
245*344aa361SAndroid Build Coastguard Worker     int err;
246*344aa361SAndroid Build Coastguard Worker 
247*344aa361SAndroid Build Coastguard Worker     err = sm_register_entity(SMC_ENTITY_LOGGING, &log_sm_entity);
248*344aa361SAndroid Build Coastguard Worker     if (err) {
249*344aa361SAndroid Build Coastguard Worker         printf("trusty error register entity: %d\n", err);
250*344aa361SAndroid Build Coastguard Worker     }
251*344aa361SAndroid Build Coastguard Worker }
252*344aa361SAndroid Build Coastguard Worker LK_INIT_HOOK(memlog, memlog_init, LK_INIT_LEVEL_APPS);
253