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 
caam_sgt_cache_op(enum utee_cache_operation op,struct caamsgtbuf * insgt,size_t length)18 void caam_sgt_cache_op(enum utee_cache_operation op, struct caamsgtbuf *insgt,
19 		       size_t length)
20 {
21 	unsigned int idx = 0;
22 	size_t op_size = 0;
23 	size_t rem_length = length;
24 
25 	cache_operation(TEE_CACHECLEAN, (void *)insgt->sgt,
26 			ROUNDUP(insgt->number, CFG_CAAM_SGT_ALIGN) *
27 				sizeof(union caamsgt));
28 
29 	SGT_TRACE("SGT @%p %d entries", insgt, insgt->number);
30 	for (idx = 0; idx < insgt->number && rem_length; idx++) {
31 		op_size = MIN(rem_length, insgt->buf[idx].length);
32 		if (!insgt->buf[idx].nocache)
33 			cache_operation(op, (void *)insgt->buf[idx].data,
34 					op_size);
35 		rem_length -= op_size;
36 	}
37 }
38 
caam_sgt_fill_table(struct caamsgtbuf * sgt)39 void caam_sgt_fill_table(struct caamsgtbuf *sgt)
40 {
41 	unsigned int idx = 0;
42 
43 	SGT_TRACE("Create %d SGT entries", sgt->number);
44 
45 	for (idx = 0; idx < sgt->number - 1; idx++) {
46 		CAAM_SGT_ENTRY(&sgt->sgt[idx], sgt->buf[idx].paddr,
47 			       sgt->buf[idx].length);
48 		sgt_entry_trace(idx, sgt);
49 	}
50 
51 	CAAM_SGT_ENTRY_FINAL(&sgt->sgt[idx], sgt->buf[idx].paddr,
52 			     sgt->buf[idx].length);
53 	sgt_entry_trace(idx, sgt);
54 }
55 
caam_sgt_derive(struct caamsgtbuf * sgt,const struct caamsgtbuf * from,size_t offset,size_t length)56 enum caam_status caam_sgt_derive(struct caamsgtbuf *sgt,
57 				 const struct caamsgtbuf *from, size_t offset,
58 				 size_t length)
59 {
60 	enum caam_status retstatus = CAAM_FAILURE;
61 	unsigned int idx = 0;
62 	unsigned int st_idx = 0;
63 	size_t off = offset;
64 	size_t rlength = length;
65 
66 	SGT_TRACE("Derive from %p - offset %zu, %d SGT entries", from, offset,
67 		  from->number);
68 
69 	if (from->length - offset < length) {
70 		SGT_TRACE("From SGT/Buffer too short (%zu)", from->length);
71 		return CAAM_SHORT_BUFFER;
72 	}
73 
74 	for (; idx < from->number && off >= from->buf[idx].length; idx++)
75 		off -= from->buf[idx].length;
76 
77 	st_idx = idx;
78 	sgt->number = 1;
79 	rlength -= MIN(rlength, from->buf[idx].length - off);
80 
81 	for (idx++; idx < from->number && rlength; idx++) {
82 		rlength -= MIN(rlength, from->buf[idx].length);
83 		sgt->number++;
84 	}
85 
86 	sgt->sgt_type = (sgt->number > 1) ? true : false;
87 
88 	/* Allocate a new SGT/Buffer object */
89 	retstatus = caam_sgtbuf_alloc(sgt);
90 	SGT_TRACE("Allocate %d SGT entries ret 0x%" PRIx32, sgt->number,
91 		  retstatus);
92 	if (retstatus != CAAM_NO_ERROR)
93 		return retstatus;
94 
95 	memcpy(sgt->buf, &from->buf[st_idx], sgt->number * sizeof(*sgt->buf));
96 
97 	if (sgt->sgt_type) {
98 		memcpy(sgt->sgt, &from->sgt[st_idx],
99 		       sgt->number * sizeof(*sgt->sgt));
100 
101 		/* Set the offset of the first sgt entry */
102 		sgt_entry_offset(sgt->sgt, off);
103 
104 		/*
105 		 * Push the SGT Table into memory now because
106 		 * derived objects are not pushed.
107 		 */
108 		cache_operation(TEE_CACHECLEAN, sgt->sgt,
109 				sgt->number * sizeof(*sgt->sgt));
110 
111 		sgt->paddr = virt_to_phys(sgt->sgt);
112 	} else {
113 		sgt->paddr = sgt->buf->paddr + off;
114 	}
115 
116 	sgt->length = length;
117 
118 	return CAAM_NO_ERROR;
119 }
120 
caam_sgtbuf_free(struct caamsgtbuf * data)121 void caam_sgtbuf_free(struct caamsgtbuf *data)
122 {
123 	if (data->sgt_type)
124 		caam_free(data->sgt);
125 	else
126 		caam_free(data->buf);
127 
128 	data->sgt = NULL;
129 	data->buf = NULL;
130 }
131 
caam_sgtbuf_alloc(struct caamsgtbuf * data)132 enum caam_status caam_sgtbuf_alloc(struct caamsgtbuf *data)
133 {
134 	unsigned int nb_sgt = 0;
135 
136 	if (!data || !data->number)
137 		return CAAM_BAD_PARAM;
138 
139 	if (data->sgt_type) {
140 		nb_sgt = ROUNDUP(data->number, CFG_CAAM_SGT_ALIGN);
141 		data->sgt = caam_calloc(nb_sgt * (sizeof(union caamsgt) +
142 						  sizeof(struct caambuf)));
143 		data->buf = (void *)(((uint8_t *)data->sgt) +
144 				     (nb_sgt * sizeof(union caamsgt)));
145 	} else {
146 		data->buf = caam_calloc(data->number * sizeof(struct caambuf));
147 		data->sgt = NULL;
148 	}
149 
150 	if (!data->buf || (!data->sgt && data->sgt_type)) {
151 		caam_sgtbuf_free(data);
152 		return CAAM_OUT_MEMORY;
153 	}
154 
155 	return CAAM_NO_ERROR;
156 }
157