]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/ccree/ssi_fips_local.c
8f5df925e295aa16b737de4e70cd4154d813edfc
[linux.git] / drivers / staging / ccree / ssi_fips_local.c
1 /*
2  * Copyright (C) 2012-2017 ARM Limited or its affiliates.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  */
16
17 /**************************************************************
18 This file defines the driver FIPS internal function, used by the driver itself.
19 ***************************************************************/
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <crypto/des.h>
24
25 #include "ssi_config.h"
26 #include "ssi_driver.h"
27 #include "cc_hal.h"
28
29
30 #define FIPS_POWER_UP_TEST_CIPHER       1
31 #define FIPS_POWER_UP_TEST_CMAC         1
32 #define FIPS_POWER_UP_TEST_HASH         1
33 #define FIPS_POWER_UP_TEST_HMAC         1
34 #define FIPS_POWER_UP_TEST_CCM          1
35 #define FIPS_POWER_UP_TEST_GCM          1
36
37 static bool ssi_fips_support = 1;
38 module_param(ssi_fips_support, bool, 0644);
39 MODULE_PARM_DESC(ssi_fips_support, "FIPS supported flag: 0 - off , 1 - on (default)");
40
41 static void fips_dsr(unsigned long devarg);
42
43 struct ssi_fips_handle {
44 #ifdef COMP_IN_WQ
45         struct workqueue_struct *workq;
46         struct delayed_work fipswork;
47 #else
48         struct tasklet_struct fipstask;
49 #endif
50 };
51
52
53 extern int ssi_fips_get_state(ssi_fips_state_t *p_state);
54 extern int ssi_fips_get_error(ssi_fips_error_t *p_err);
55 extern int ssi_fips_ext_set_state(ssi_fips_state_t state);
56 extern int ssi_fips_ext_set_error(ssi_fips_error_t err);
57
58 /* FIPS power-up tests */
59 extern ssi_fips_error_t ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
60 extern ssi_fips_error_t ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
61 extern ssi_fips_error_t ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
62 extern ssi_fips_error_t ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
63 extern ssi_fips_error_t ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
64 extern ssi_fips_error_t ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
65 extern size_t ssi_fips_max_mem_alloc_size(void);
66
67
68 /* The function called once at driver entry point to check whether TEE FIPS error occured.*/
69 static enum ssi_fips_error ssi_fips_get_tee_error(struct ssi_drvdata *drvdata)
70 {
71         uint32_t regVal;
72         void __iomem *cc_base = drvdata->cc_base;
73
74         regVal = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST));
75         if (regVal == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) {
76                 return CC_REE_FIPS_ERROR_OK;
77         }
78         return CC_REE_FIPS_ERROR_FROM_TEE;
79 }
80
81
82 /*
83  This function should push the FIPS REE library status towards the TEE library.
84  By writing the error state to HOST_GPR0 register. The function is called from                                                  .
85  driver entry point so no need to protect by mutex.
86 */
87 static void ssi_fips_update_tee_upon_ree_status(struct ssi_drvdata *drvdata, ssi_fips_error_t err)
88 {
89         void __iomem *cc_base = drvdata->cc_base;
90         if (err == CC_REE_FIPS_ERROR_OK) {
91                 CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS|CC_FIPS_SYNC_MODULE_OK));
92         } else {
93                 CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS|CC_FIPS_SYNC_MODULE_ERROR));
94         }
95 }
96
97
98
99 void ssi_fips_fini(struct ssi_drvdata *drvdata)
100 {
101         struct ssi_fips_handle *fips_h = drvdata->fips_handle;
102
103         if (fips_h == NULL)
104                 return; /* Not allocated */
105
106 #ifdef COMP_IN_WQ
107         if (fips_h->workq != NULL) {
108                 flush_workqueue(fips_h->workq);
109                 destroy_workqueue(fips_h->workq);
110         }
111 #else
112         /* Kill tasklet */
113         tasklet_kill(&fips_h->fipstask);
114 #endif
115         memset(fips_h, 0, sizeof(struct ssi_fips_handle));
116         kfree(fips_h);
117         drvdata->fips_handle = NULL;
118 }
119
120 void fips_handler(struct ssi_drvdata *drvdata)
121 {
122         struct ssi_fips_handle *fips_handle_ptr =
123                                                 drvdata->fips_handle;
124 #ifdef COMP_IN_WQ
125         queue_delayed_work(fips_handle_ptr->workq, &fips_handle_ptr->fipswork, 0);
126 #else
127         tasklet_schedule(&fips_handle_ptr->fipstask);
128 #endif
129 }
130
131
132
133 #ifdef COMP_IN_WQ
134 static void fips_wq_handler(struct work_struct *work)
135 {
136         struct ssi_drvdata *drvdata =
137                 container_of(work, struct ssi_drvdata, fipswork.work);
138
139         fips_dsr((unsigned long)drvdata);
140 }
141 #endif
142
143 /* Deferred service handler, run as interrupt-fired tasklet */
144 static void fips_dsr(unsigned long devarg)
145 {
146         struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg;
147         void __iomem *cc_base = drvdata->cc_base;
148         uint32_t irq;
149         uint32_t teeFipsError = 0;
150
151         irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK));
152
153         if (irq & SSI_GPR0_IRQ_MASK) {
154                 teeFipsError = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST));
155                 if (teeFipsError != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) {
156                         ssi_fips_set_error(drvdata, CC_REE_FIPS_ERROR_FROM_TEE);
157                 }
158         }
159
160         /* after verifing that there is nothing to do, Unmask AXI completion interrupt */
161         CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR),
162                 CC_HAL_READ_REGISTER(
163                 CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq);
164 }
165
166
167 ssi_fips_error_t cc_fips_run_power_up_tests(struct ssi_drvdata *drvdata)
168 {
169         ssi_fips_error_t fips_error = CC_REE_FIPS_ERROR_OK;
170         void * cpu_addr_buffer = NULL;
171         dma_addr_t dma_handle;
172         size_t alloc_buff_size = ssi_fips_max_mem_alloc_size();
173         struct device *dev = &drvdata->plat_dev->dev;
174
175         // allocate memory using dma_alloc_coherent - for phisical, consecutive and cache coherent buffer (memory map is not needed)
176         // the return value is the virtual address - use it to copy data into the buffer
177         // the dma_handle is the returned phy address - use it in the HW descriptor
178         FIPS_DBG("dma_alloc_coherent \n");
179         cpu_addr_buffer = dma_alloc_coherent(dev, alloc_buff_size, &dma_handle, GFP_KERNEL);
180         if (cpu_addr_buffer == NULL) {
181                 return CC_REE_FIPS_ERROR_GENERAL;
182         }
183         FIPS_DBG("allocated coherent buffer - addr 0x%08X , size = %d \n", (size_t)cpu_addr_buffer, alloc_buff_size);
184
185 #if FIPS_POWER_UP_TEST_CIPHER
186         FIPS_DBG("ssi_cipher_fips_power_up_tests ...\n");
187         fips_error = ssi_cipher_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
188         FIPS_DBG("ssi_cipher_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
189 #endif
190 #if FIPS_POWER_UP_TEST_CMAC
191         if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
192                 FIPS_DBG("ssi_cmac_fips_power_up_tests ...\n");
193                 fips_error = ssi_cmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
194                 FIPS_DBG("ssi_cmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
195         }
196 #endif
197 #if FIPS_POWER_UP_TEST_HASH
198         if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
199                 FIPS_DBG("ssi_hash_fips_power_up_tests ...\n");
200                 fips_error = ssi_hash_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
201                 FIPS_DBG("ssi_hash_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
202         }
203 #endif
204 #if FIPS_POWER_UP_TEST_HMAC
205         if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
206                 FIPS_DBG("ssi_hmac_fips_power_up_tests ...\n");
207                 fips_error = ssi_hmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
208                 FIPS_DBG("ssi_hmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
209         }
210 #endif
211 #if FIPS_POWER_UP_TEST_CCM
212         if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
213                 FIPS_DBG("ssi_ccm_fips_power_up_tests ...\n");
214                 fips_error = ssi_ccm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
215                 FIPS_DBG("ssi_ccm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
216         }
217 #endif
218 #if FIPS_POWER_UP_TEST_GCM
219         if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
220                 FIPS_DBG("ssi_gcm_fips_power_up_tests ...\n");
221                 fips_error = ssi_gcm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
222                 FIPS_DBG("ssi_gcm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
223         }
224 #endif
225         /* deallocate the buffer when all tests are done... */
226         FIPS_DBG("dma_free_coherent \n");
227         dma_free_coherent(dev, alloc_buff_size, cpu_addr_buffer, dma_handle);
228
229         return fips_error;
230 }
231
232
233
234 /* The function checks if FIPS supported and FIPS error exists.*
235 *  It should be used in every driver API.*/
236 int ssi_fips_check_fips_error(void)
237 {
238         ssi_fips_state_t fips_state;
239
240         if (ssi_fips_get_state(&fips_state) != 0) {
241                 FIPS_LOG("ssi_fips_get_state FAILED, returning.. \n");
242                 return -ENOEXEC;
243         }
244         if (fips_state == CC_FIPS_STATE_ERROR) {
245                 FIPS_LOG("ssi_fips_get_state: fips_state is %d, returning.. \n", fips_state);
246                 return -ENOEXEC;
247         }
248         return 0;
249 }
250
251
252 /* The function sets the REE FIPS state.*
253 *  It should be used while driver is being loaded .*/
254 int ssi_fips_set_state(ssi_fips_state_t state)
255 {
256         return ssi_fips_ext_set_state(state);
257 }
258
259 /* The function sets the REE FIPS error, and pushes the error to TEE library. *
260 *  It should be used when any of the KAT tests fails .*/
261 int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, ssi_fips_error_t err)
262 {
263         int rc = 0;
264         ssi_fips_error_t current_err;
265
266         FIPS_LOG("ssi_fips_set_error - fips_error = %d \n", err);
267
268         // setting no error is not allowed
269         if (err == CC_REE_FIPS_ERROR_OK) {
270                 return -ENOEXEC;
271         }
272         // If error exists, do not set new error
273         if (ssi_fips_get_error(&current_err) != 0) {
274                 return -ENOEXEC;
275         }
276         if (current_err != CC_REE_FIPS_ERROR_OK) {
277                 return -ENOEXEC;
278         }
279         // set REE internal error and state
280         rc = ssi_fips_ext_set_error(err);
281         if (rc != 0) {
282                 return -ENOEXEC;
283         }
284         rc = ssi_fips_ext_set_state(CC_FIPS_STATE_ERROR);
285         if (rc != 0) {
286                 return -ENOEXEC;
287         }
288
289         // push error towards TEE libraray, if it's not TEE error
290         if (err != CC_REE_FIPS_ERROR_FROM_TEE) {
291                 ssi_fips_update_tee_upon_ree_status(p_drvdata, err);
292         }
293         return rc;
294 }
295
296
297 /* The function called once at driver entry point .*/
298 int ssi_fips_init(struct ssi_drvdata *p_drvdata)
299 {
300         ssi_fips_error_t rc = CC_REE_FIPS_ERROR_OK;
301         struct ssi_fips_handle *fips_h;
302
303         FIPS_DBG("CC FIPS code ..  (fips=%d) \n", ssi_fips_support);
304
305         fips_h = kzalloc(sizeof(struct ssi_fips_handle),GFP_KERNEL);
306         if (fips_h == NULL) {
307                 ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
308                 return -ENOMEM;
309         }
310
311         p_drvdata->fips_handle = fips_h;
312
313 #ifdef COMP_IN_WQ
314         SSI_LOG_DEBUG("Initializing fips workqueue\n");
315         fips_h->workq = create_singlethread_workqueue("arm_cc7x_fips_wq");
316         if (unlikely(fips_h->workq == NULL)) {
317                 SSI_LOG_ERR("Failed creating fips work queue\n");
318                 ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
319                 rc = -ENOMEM;
320                 goto ssi_fips_init_err;
321         }
322         INIT_DELAYED_WORK(&fips_h->fipswork, fips_wq_handler);
323 #else
324         SSI_LOG_DEBUG("Initializing fips tasklet\n");
325         tasklet_init(&fips_h->fipstask, fips_dsr, (unsigned long)p_drvdata);
326 #endif
327
328         /* init fips driver data */
329         rc = ssi_fips_set_state((ssi_fips_support == 0)? CC_FIPS_STATE_NOT_SUPPORTED : CC_FIPS_STATE_SUPPORTED);
330         if (unlikely(rc != 0)) {
331                 ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
332                 rc = -EAGAIN;
333                 goto ssi_fips_init_err;
334         }
335
336         /* Run power up tests (before registration and operating the HW engines) */
337         FIPS_DBG("ssi_fips_get_tee_error \n");
338         rc = ssi_fips_get_tee_error(p_drvdata);
339         if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) {
340                 ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_FROM_TEE);
341                 rc = -EAGAIN;
342                 goto ssi_fips_init_err;
343         }
344
345         FIPS_DBG("cc_fips_run_power_up_tests \n");
346         rc = cc_fips_run_power_up_tests(p_drvdata);
347         if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) {
348                 ssi_fips_set_error(p_drvdata, rc);
349                 rc = -EAGAIN;
350                 goto ssi_fips_init_err;
351         }
352         FIPS_LOG("cc_fips_run_power_up_tests - done  ...  fips_error = %d \n", rc);
353
354         /* when all tests passed, update TEE with fips OK status after power up tests */
355         ssi_fips_update_tee_upon_ree_status(p_drvdata, CC_REE_FIPS_ERROR_OK);
356
357         if (unlikely(rc != 0)) {
358                 rc = -EAGAIN;
359                 ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
360                 goto ssi_fips_init_err;
361         }
362
363         return 0;
364
365 ssi_fips_init_err:
366         ssi_fips_fini(p_drvdata);
367         return rc;
368 }
369