• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include <linux/slab.h>
20 #include <linux/dma-mapping.h>
21 #include <linux/semaphore.h>
22 #include <linux/semaphore.h>
23 #include <asm/cacheflush.h>
24 #include <linux/securec.h>
25 #include "drv_mmz.h"
26 #include "drv_tzsmmu.h"
27 #include "drv_media_mem.h"
28 
29 #define HI_ZERO 0
30 
31 #define MAX_MEMBLOCK_NUM (1024 * 1024)
32 
33 /* func: set secure flag and create sec smmu map
34  * input no-secure mem info(smmu addr or phys addr,indicated by iommu),
35  * and return secure address( sec smmu addr or phys addr)
36  */
secmem_alloc(mmb_addr_t phyaddr,unsigned int iommu)37 u32 secmem_alloc(mmb_addr_t phyaddr, unsigned int iommu)
38 {
39     u32 size;
40     int ret;
41     struct tee_mem_info teebuf = {0};
42     struct tee_mem_addr mem_addr = {0};
43     u32 base_addr = 0;
44 
45     teebuf.table = get_meminfo(phyaddr, iommu, &size, &base_addr);
46     if (teebuf.table == NULL) {
47         hi_mmz_warn("Cannot get meminfo and check parameter!\n");
48         goto out;
49     }
50     teebuf.size = PAGE_ALIGN(size);
51 
52     mem_addr.iommu = iommu;
53     mem_addr.addr = base_addr;
54     ret = hisi_secmem_alloc(&teebuf, &mem_addr, NULL, 0); /* 0 do not used */
55     if (ret || !mem_addr.sec_addr) {
56         goto out;
57     }
58 
59     /* set mmb flag to indicate that the mem is secure */
60     set_sec_mmb_flag(phyaddr, iommu);
61     sec_mmb_get(phyaddr, iommu, mem_addr.sec_addr);
62 
63     return iommu ? mem_addr.sec_addr : phyaddr;
64 
65 out:
66     return MMB_ADDR_INVALID;
67 }
68 
69 /* func: clear secure flag and unmap the sec smmu
70  * input sec mem info (sec smmu addr or phys addr, indicated by iommu),
71  * and output non-sec info (smmu addr or phys addr)
72  */
secmem_free(mmb_addr_t sec_addr,unsigned int iommu)73 u32 secmem_free(mmb_addr_t sec_addr, unsigned int iommu)
74 {
75     int ret;
76     u32 addr;
77     int sec_smmu_ref;
78     struct tee_mem_info teebuf = {0};
79     u32 size = 0;
80     u32 base_addr = 0;
81     u32 offset;
82     u32 sec_base_addr;
83 
84     if (iommu) {
85         addr = (u32)get_nonsecsmmu_by_secsmmu(sec_addr);
86     } else {
87         addr = (u32)sec_addr;
88     }
89 
90     teebuf.table = get_meminfo(addr, iommu, &size, &base_addr);
91     if (teebuf.table == NULL) {
92         hi_mmz_warn("Cannot get meminfo and check parameter!\n");
93         goto exit;
94     }
95     offset = addr - base_addr;
96     sec_base_addr = sec_addr - offset;
97     sec_smmu_ref = sec_mmb_put(base_addr, iommu);
98     if (sec_smmu_ref) {
99         /*
100          * free later. warning: map sec-smmu many times
101          */
102         goto exit;
103     }
104 
105     ret = hisi_secmem_free(sec_base_addr, iommu);
106     if (ret) {
107         hi_mmz_warn("hisi_secmem_free failed!\n");
108         goto out;
109     }
110 
111     clr_sec_mmb_flag(base_addr, iommu);
112 
113     return base_addr;
114 
115 out:
116     sec_mmb_get(addr, iommu, sec_base_addr);
117 exit:
118     return MMB_ADDR_INVALID;
119 }
120 
121 /* func: map to sec smmu
122  * addr:input, smmu or phy address in normal world
123  * iommu: address type
124  * sec smmu address is returned when exec success
125  * MMB_ADDR_INVALID is returned when exec failed
126  */
secmem_map_to_secsmmu(HI_U32 phyaddr,int iommu)127 u32 secmem_map_to_secsmmu(HI_U32 phyaddr, int iommu)
128 {
129     struct tee_mem_info teebuf = {0};
130     struct tee_mem_addr mem_addr = {0};
131     u32 base_addr = 0;
132     u32 size = 0;
133     int ret;
134     u32 offset;
135 
136     if (iommu) {
137         mem_addr.sec_addr = get_sec_smmu_by_nosmmu(phyaddr);
138     } else {
139         mem_addr.sec_addr = get_sec_smmu_by_phys(phyaddr);
140     }
141     if (mem_addr.sec_addr != MMB_ADDR_INVALID) {
142         /* map to sec smmu before,and give the previous value */
143         offset = 0;
144         goto out;
145     }
146 
147     teebuf.table = get_meminfo(phyaddr, iommu, &size, &base_addr);
148     if (teebuf.table == NULL) {
149         hi_mmz_warn("Cannot get meminfo and check parameter!\n");
150         goto exit;
151     }
152     teebuf.size = PAGE_ALIGN(size);
153 
154     mem_addr.iommu = iommu;
155     mem_addr.addr = base_addr;
156     ret = hisi_secmem_mapto_secsmmu(&teebuf, &mem_addr, NULL, 0); /* 0 not used */
157     if (ret) {
158         hi_mmz_warn("hisi_secmem_mapto_secsmmu failed!\n");
159         goto exit;
160     }
161     offset = phyaddr - mem_addr.addr;
162 out:
163     sec_mmb_get(phyaddr, iommu, mem_addr.sec_addr);
164 
165     return (mem_addr.sec_addr + offset);
166 
167 exit:
168     return MMB_ADDR_INVALID;
169 }
170 
171 /* func: unmap from sec smmu
172  * secsmmu:input, smmu address in sec world
173  * iommu: memtype indicate the mem attr(mmz or system)
174  * 0 is returned when exec success
175  * non-zero is returned when exec failed
176  */
secmem_unmap_from_secsmmu(HI_U32 sec_addr,int iommu)177 int secmem_unmap_from_secsmmu(HI_U32 sec_addr, int iommu)
178 {
179     int ret;
180     int sec_smmu_ref;
181     unsigned int addr;
182     struct tee_mem_info teebuf = {0};
183     u32 size = 0;
184     u32 base_addr = 0;
185     u32 sec_addr_base;
186 
187     if (iommu) {
188         /* the mem is system mem */
189         addr = get_nonsecsmmu_by_secsmmu(sec_addr);
190     } else {
191         /* the mem is system mem */
192         addr = get_phys_by_secsmmu(sec_addr);
193     }
194     teebuf.table = get_meminfo(addr, iommu, &size, &base_addr);
195     if (teebuf.table == NULL) {
196         hi_mmz_warn("Cannot get meminfo and check parameter!\n");
197         goto err;
198     }
199 
200     sec_addr_base = sec_addr - (addr - base_addr);
201     sec_smmu_ref = sec_mmb_put(base_addr, iommu);
202     if (sec_smmu_ref) {
203         /* free later. warning: map sec-smmu many times */
204         goto out;
205     }
206 
207     if (is_sec_mem(base_addr, iommu)) {
208         /* mem is secure mem, and should be clear sec flag and unmap sec smmu. */
209         ret = hisi_secmem_free(sec_addr_base, 1);
210         if (ret != 0) {
211             hi_mmz_warn("hisi_secmem_free failed!\n");
212             goto exit;
213         }
214         clr_sec_mmb_flag(base_addr, iommu);
215     } else {
216         /*
217          * mem is normal mem, and just should be unmap sec smmu.
218          */
219         ret = hisi_secmem_unmap_from_secsmmu(sec_addr_base);
220         if (ret) {
221             hi_mmz_warn("hisi_secmem_unmap_from_secsmmu failed!\n");
222             goto exit;
223         }
224     }
225 
226     /*
227      * the mem may not be free here, but it is just a repair the mistake for the exceptional calling order like:
228      * 1 secmem_alloc --- secmem_map_to_secsmmu --- secmem_free --- secmem_unmap_from_secsmmu
229      * 2 nomal alloc --- secmem_map_to_secsmmu --- normal free --- secmem_unmap_from_secsmmu
230      */
231     sec_delay_release_for_mem(base_addr, iommu);
232 out:
233     return 0;
234 exit:
235     sec_mmb_get(base_addr, iommu, sec_addr_base);
236 err:
237     return -1;
238 }
239 
hi_tee_agent_end(void)240 int hi_tee_agent_end(void)
241 {
242     return hisi_secmem_agent_end();
243 }
244 
sec_mem_get(HI_U32 sec_addr,int iommu)245 int sec_mem_get(HI_U32 sec_addr, int iommu)
246 {
247     HI_U32 addr = MMB_ADDR_INVALID;
248 
249     if (iommu) {
250         addr = get_nonsecsmmu_by_secsmmu(sec_addr);
251     } else {
252         addr = sec_addr;
253     }
254 
255     if (addr == MMB_ADDR_INVALID) {
256         hi_mmz_warn("err args:addr:0x%x iommu:%d!\n", sec_addr, iommu);
257         return HI_FAILURE;
258     }
259 
260     if (!is_sec_mem(addr, iommu)) {
261         hi_mmz_warn("The mem should be sec!\n");
262         return HI_FAILURE;
263     }
264 
265     /* mem sec_smmu_ref is not 0, ignore sec_addr */
266     return sec_mmb_get(addr, iommu, sec_addr);
267 }
268 
sec_mem_put(HI_U32 sec_addr,int iommu)269 int sec_mem_put(HI_U32 sec_addr, int iommu)
270 {
271     HI_U32 addr = MMB_ADDR_INVALID;
272     int ret;
273 
274     if (iommu) {
275         addr = get_nonsecsmmu_by_secsmmu(sec_addr);
276     } else {
277         addr = sec_addr;
278     }
279 
280     if (addr == MMB_ADDR_INVALID) {
281         hi_mmz_warn("err args: addr:0x%x iommu:%d!\n", sec_addr, iommu);
282         return HI_FAILURE;
283     }
284 
285     if (!is_sec_mem(addr, iommu)) {
286         hi_mmz_warn("The mem should be sec!\n");
287         return HI_FAILURE;
288     }
289 
290     ret = sec_mmb_put(addr, iommu);
291     if (ret < 0) {
292         hi_mmz_warn("call wrong times, the sec ref is %d.\n", ret);
293         return HI_FAILURE;
294     } else if (ret > 0) {
295         /* just decrement the ref */
296         return HI_SUCCESS;
297     } else {
298         ret = hisi_secmem_free(sec_addr, iommu);
299         if (ret) {
300             hi_mmz_warn("hisi_secmem_free failed!\n");
301             return HI_FAILURE;
302         }
303 
304         clr_sec_mmb_flag(addr, iommu);
305         delete_mmb(addr, iommu);
306     }
307 
308     return HI_SUCCESS;
309 }
310 
sec_mem_buf_query_ref(HI_U32 sec_addr,int iommu,HI_U32 * ref)311 int sec_mem_buf_query_ref(HI_U32 sec_addr, int iommu, HI_U32 *ref)
312 {
313     if (ref == NULL) {
314         hi_mmz_warn("ref should not be null!\n");
315         return HI_FAILURE;
316     }
317 
318     return sec_mmb_query_ref(sec_addr, iommu, ref);
319 }
320 
321 EXPORT_SYMBOL(secmem_alloc);
322 EXPORT_SYMBOL(secmem_free);
323 EXPORT_SYMBOL(secmem_map_to_secsmmu);
324 EXPORT_SYMBOL(secmem_unmap_from_secsmmu);
325 EXPORT_SYMBOL(hi_tee_agent_end);
326 EXPORT_SYMBOL(sec_mem_get);
327 EXPORT_SYMBOL(sec_mem_put);
328 EXPORT_SYMBOL(sec_mem_buf_query_ref);
329 
330