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