1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2018-2019, 2021 NXP
4 *
5 * Brief Scatter-Gatter Table management utilities.
6 */
7 #include <caam_common.h>
8 #include <caam_io.h>
9 #include <caam_utils_mem.h>
10 #include <caam_utils_sgt.h>
11 #include <caam_trace.h>
12 #include <mm/core_memprot.h>
13 #include <mm/core_mmu.h>
14 #include <string.h>
15 #include <tee/cache.h>
16 #include <util.h>
17
18 /*
19 * Perform cache management clean operation on the SGT table entry
20 *
21 * @sgtbuf SGT table to manage
22 */
caam_sgt_entries_cache_clean(const struct caamsgtbuf * sgtbuf)23 static void caam_sgt_entries_cache_clean(const struct caamsgtbuf *sgtbuf)
24 {
25 cache_operation(TEE_CACHECLEAN, (void *)sgtbuf->sgt,
26 ROUNDUP(sgtbuf->number, CFG_CAAM_SGT_ALIGN) *
27 sizeof(*sgtbuf->sgt));
28 }
29
caam_sgt_cache_op(enum utee_cache_operation op,struct caamsgtbuf * insgt,size_t length)30 void caam_sgt_cache_op(enum utee_cache_operation op, struct caamsgtbuf *insgt,
31 size_t length)
32 {
33 unsigned int idx = 0;
34 size_t op_size = 0;
35 size_t rem_length = length;
36
37 caam_sgt_entries_cache_clean(insgt);
38
39 SGT_TRACE("SGT @%p %d entries", insgt, insgt->number);
40 for (idx = 0; idx < insgt->number && rem_length; idx++) {
41 op_size = MIN(rem_length, insgt->buf[idx].length);
42 if (!insgt->buf[idx].nocache)
43 cache_operation(op, (void *)insgt->buf[idx].data,
44 op_size);
45 rem_length -= op_size;
46 }
47 }
48
caam_sgt_fill_table(struct caamsgtbuf * sgt)49 void caam_sgt_fill_table(struct caamsgtbuf *sgt)
50 {
51 unsigned int idx = 0;
52
53 SGT_TRACE("Create %d SGT entries", sgt->number);
54
55 for (idx = 0; idx < sgt->number - 1; idx++) {
56 CAAM_SGT_ENTRY(&sgt->sgt[idx], sgt->buf[idx].paddr,
57 sgt->buf[idx].length);
58 sgt_entry_trace(idx, sgt);
59 }
60
61 CAAM_SGT_ENTRY_FINAL(&sgt->sgt[idx], sgt->buf[idx].paddr,
62 sgt->buf[idx].length);
63 sgt_entry_trace(idx, sgt);
64 }
65
caam_sgt_derive(struct caamsgtbuf * sgt,const struct caamsgtbuf * from,size_t offset,size_t length)66 enum caam_status caam_sgt_derive(struct caamsgtbuf *sgt,
67 const struct caamsgtbuf *from, size_t offset,
68 size_t length)
69 {
70 enum caam_status retstatus = CAAM_FAILURE;
71 unsigned int idx = 0;
72 unsigned int st_idx = 0;
73 size_t off = offset;
74 size_t rlength = length;
75
76 SGT_TRACE("Derive from %p - offset %zu, %d SGT entries", from, offset,
77 from->number);
78
79 if (from->length - offset < length) {
80 SGT_TRACE("From SGT/Buffer too short (%zu)", from->length);
81 return CAAM_SHORT_BUFFER;
82 }
83
84 for (; idx < from->number && off >= from->buf[idx].length; idx++)
85 off -= from->buf[idx].length;
86
87 st_idx = idx;
88 sgt->number = 1;
89 rlength -= MIN(rlength, from->buf[idx].length - off);
90
91 for (idx++; idx < from->number && rlength; idx++) {
92 rlength -= MIN(rlength, from->buf[idx].length);
93 sgt->number++;
94 }
95
96 sgt->sgt_type = (sgt->number > 1) ? true : false;
97
98 /* Allocate a new SGT/Buffer object */
99 retstatus = caam_sgtbuf_alloc(sgt);
100 SGT_TRACE("Allocate %d SGT entries ret 0x%" PRIx32, sgt->number,
101 retstatus);
102 if (retstatus != CAAM_NO_ERROR)
103 return retstatus;
104
105 memcpy(sgt->buf, &from->buf[st_idx], sgt->number * sizeof(*sgt->buf));
106
107 if (sgt->sgt_type) {
108 memcpy(sgt->sgt, &from->sgt[st_idx],
109 sgt->number * sizeof(*sgt->sgt));
110
111 /* Set the offset of the first sgt entry */
112 sgt_entry_offset(sgt->sgt, off);
113
114 /*
115 * Push the SGT Table into memory now because
116 * derived objects are not pushed.
117 */
118 caam_sgt_entries_cache_clean(sgt);
119
120 sgt->paddr = virt_to_phys(sgt->sgt);
121 } else {
122 sgt->paddr = sgt->buf->paddr + off;
123 }
124
125 sgt->length = length;
126
127 return CAAM_NO_ERROR;
128 }
129
caam_sgtbuf_free(struct caamsgtbuf * data)130 void caam_sgtbuf_free(struct caamsgtbuf *data)
131 {
132 if (data->sgt_type)
133 caam_free(data->sgt);
134 else
135 caam_free(data->buf);
136
137 data->sgt = NULL;
138 data->buf = NULL;
139 }
140
caam_sgtbuf_alloc(struct caamsgtbuf * data)141 enum caam_status caam_sgtbuf_alloc(struct caamsgtbuf *data)
142 {
143 unsigned int nb_sgt = 0;
144
145 if (!data || !data->number)
146 return CAAM_BAD_PARAM;
147
148 if (data->sgt_type) {
149 nb_sgt = ROUNDUP(data->number, CFG_CAAM_SGT_ALIGN);
150 data->sgt = caam_calloc(nb_sgt * (sizeof(union caamsgt) +
151 sizeof(struct caambuf)));
152 data->buf = (void *)(((uint8_t *)data->sgt) +
153 (nb_sgt * sizeof(union caamsgt)));
154 } else {
155 data->buf = caam_calloc(data->number * sizeof(struct caambuf));
156 data->sgt = NULL;
157 }
158
159 if (!data->buf || (!data->sgt && data->sgt_type)) {
160 caam_sgtbuf_free(data);
161 return CAAM_OUT_MEMORY;
162 }
163
164 return CAAM_NO_ERROR;
165 }
166