cregit-Linux how code gets into the kernel

Release 4.13 drivers/staging/ccree/ssi_fips_local.c

/*
 * Copyright (C) 2012-2017 ARM Limited or its affiliates.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

/**************************************************************
 * This file defines the driver FIPS internal function, used by the driver itself.
 ***************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <crypto/des.h>

#include "ssi_config.h"
#include "ssi_driver.h"
#include "cc_hal.h"


#define FIPS_POWER_UP_TEST_CIPHER	1

#define FIPS_POWER_UP_TEST_CMAC		1

#define FIPS_POWER_UP_TEST_HASH		1

#define FIPS_POWER_UP_TEST_HMAC		1

#define FIPS_POWER_UP_TEST_CCM		1

#define FIPS_POWER_UP_TEST_GCM		1


static bool ssi_fips_support = 1;
module_param(ssi_fips_support, bool, 0644);
MODULE_PARM_DESC(ssi_fips_support, "FIPS supported flag: 0 - off , 1 - on (default)");

static void fips_dsr(unsigned long devarg);


struct ssi_fips_handle {
#ifdef COMP_IN_WQ
	
struct workqueue_struct *workq;
	
struct delayed_work fipswork;
#else
	struct tasklet_struct fipstask;
#endif
};

extern int ssi_fips_get_state(enum cc_fips_state_t *p_state);
extern int ssi_fips_get_error(enum cc_fips_error *p_err);
extern int ssi_fips_ext_set_state(enum cc_fips_state_t state);
extern int ssi_fips_ext_set_error(enum cc_fips_error err);

/* FIPS power-up tests */
extern enum cc_fips_error ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern enum cc_fips_error ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern enum cc_fips_error ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern enum cc_fips_error ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern enum cc_fips_error ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern enum cc_fips_error ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
extern size_t ssi_fips_max_mem_alloc_size(void);

/* The function called once at driver entry point to check whether TEE FIPS error occured.*/

static enum ssi_fips_error ssi_fips_get_tee_error(struct ssi_drvdata *drvdata) { u32 regVal; void __iomem *cc_base = drvdata->cc_base; regVal = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); if (regVal == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) return CC_REE_FIPS_ERROR_OK; return CC_REE_FIPS_ERROR_FROM_TEE; }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef52100.00%2100.00%
Total52100.00%2100.00%

/* * This function should push the FIPS REE library status towards the TEE library. * By writing the error state to HOST_GPR0 register. The function is called from * driver entry point so no need to protect by mutex. */
static void ssi_fips_update_tee_upon_ree_status(struct ssi_drvdata *drvdata, enum cc_fips_error err) { void __iomem *cc_base = drvdata->cc_base; if (err == CC_REE_FIPS_ERROR_OK) CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS | CC_FIPS_SYNC_MODULE_OK)); else CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS | CC_FIPS_SYNC_MODULE_ERROR)); }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef63100.00%2100.00%
Total63100.00%2100.00%


void ssi_fips_fini(struct ssi_drvdata *drvdata) { struct ssi_fips_handle *fips_h = drvdata->fips_handle; if (!fips_h) return; /* Not allocated */ #ifdef COMP_IN_WQ if (fips_h->workq) { flush_workqueue(fips_h->workq); destroy_workqueue(fips_h->workq); } #else /* Kill tasklet */ tasklet_kill(&fips_h->fipstask); #endif memset(fips_h, 0, sizeof(struct ssi_fips_handle)); kfree(fips_h); drvdata->fips_handle = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef88100.00%2100.00%
Total88100.00%2100.00%


void fips_handler(struct ssi_drvdata *drvdata) { struct ssi_fips_handle *fips_handle_ptr = drvdata->fips_handle; #ifdef COMP_IN_WQ queue_delayed_work(fips_handle_ptr->workq, &fips_handle_ptr->fipswork, 0); #else tasklet_schedule(&fips_handle_ptr->fipstask); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef48100.00%1100.00%
Total48100.00%1100.00%

#ifdef COMP_IN_WQ
static void fips_wq_handler(struct work_struct *work) { struct ssi_drvdata *drvdata = container_of(work, struct ssi_drvdata, fipswork.work); fips_dsr((unsigned long)drvdata); }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef37100.00%1100.00%
Total37100.00%1100.00%

#endif /* Deferred service handler, run as interrupt-fired tasklet */
static void fips_dsr(unsigned long devarg) { struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg; void __iomem *cc_base = drvdata->cc_base; u32 irq; u32 teeFipsError = 0; irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK)); if (irq & SSI_GPR0_IRQ_MASK) { teeFipsError = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); if (teeFipsError != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) ssi_fips_set_error(drvdata, CC_REE_FIPS_ERROR_FROM_TEE); } /* after verifing that there is nothing to do, Unmask AXI completion interrupt */ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), CC_HAL_READ_REGISTER( CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq); }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef112100.00%2100.00%
Total112100.00%2100.00%


enum cc_fips_error cc_fips_run_power_up_tests(struct ssi_drvdata *drvdata) { enum cc_fips_error fips_error = CC_REE_FIPS_ERROR_OK; void *cpu_addr_buffer = NULL; dma_addr_t dma_handle; size_t alloc_buff_size = ssi_fips_max_mem_alloc_size(); struct device *dev = &drvdata->plat_dev->dev; // allocate memory using dma_alloc_coherent - for phisical, consecutive and cache coherent buffer (memory map is not needed) // the return value is the virtual address - use it to copy data into the buffer // the dma_handle is the returned phy address - use it in the HW descriptor FIPS_DBG("dma_alloc_coherent \n"); cpu_addr_buffer = dma_alloc_coherent(dev, alloc_buff_size, &dma_handle, GFP_KERNEL); if (!cpu_addr_buffer) return CC_REE_FIPS_ERROR_GENERAL; FIPS_DBG("allocated coherent buffer - addr 0x%08X , size = %d \n", (size_t)cpu_addr_buffer, alloc_buff_size); #if FIPS_POWER_UP_TEST_CIPHER FIPS_DBG("ssi_cipher_fips_power_up_tests ...\n"); fips_error = ssi_cipher_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); FIPS_DBG("ssi_cipher_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); #endif #if FIPS_POWER_UP_TEST_CMAC if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { FIPS_DBG("ssi_cmac_fips_power_up_tests ...\n"); fips_error = ssi_cmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); FIPS_DBG("ssi_cmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); } #endif #if FIPS_POWER_UP_TEST_HASH if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { FIPS_DBG("ssi_hash_fips_power_up_tests ...\n"); fips_error = ssi_hash_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); FIPS_DBG("ssi_hash_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); } #endif #if FIPS_POWER_UP_TEST_HMAC if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { FIPS_DBG("ssi_hmac_fips_power_up_tests ...\n"); fips_error = ssi_hmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); FIPS_DBG("ssi_hmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); } #endif #if FIPS_POWER_UP_TEST_CCM if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { FIPS_DBG("ssi_ccm_fips_power_up_tests ...\n"); fips_error = ssi_ccm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); FIPS_DBG("ssi_ccm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); } #endif #if FIPS_POWER_UP_TEST_GCM if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) { FIPS_DBG("ssi_gcm_fips_power_up_tests ...\n"); fips_error = ssi_gcm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle); FIPS_DBG("ssi_gcm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error); } #endif /* deallocate the buffer when all tests are done... */ FIPS_DBG("dma_free_coherent \n"); dma_free_coherent(dev, alloc_buff_size, cpu_addr_buffer, dma_handle); return fips_error; }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef329100.00%3100.00%
Total329100.00%3100.00%

/* The function checks if FIPS supported and FIPS error exists.* * It should be used in every driver API. */
int ssi_fips_check_fips_error(void) { enum cc_fips_state_t fips_state; if (ssi_fips_get_state(&fips_state) != 0) { FIPS_LOG("ssi_fips_get_state FAILED, returning.. \n"); return -ENOEXEC; } if (fips_state == CC_FIPS_STATE_ERROR) { FIPS_LOG("ssi_fips_get_state: fips_state is %d, returning.. \n", fips_state); return -ENOEXEC; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef54100.00%2100.00%
Total54100.00%2100.00%

/* The function sets the REE FIPS state.* * It should be used while driver is being loaded. */
int ssi_fips_set_state(enum cc_fips_state_t state) { return ssi_fips_ext_set_state(state); }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef15100.00%2100.00%
Total15100.00%2100.00%

/* The function sets the REE FIPS error, and pushes the error to TEE library. * * It should be used when any of the KAT tests fails. */
int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, enum cc_fips_error err) { int rc = 0; enum cc_fips_error current_err; FIPS_LOG("ssi_fips_set_error - fips_error = %d \n", err); // setting no error is not allowed if (err == CC_REE_FIPS_ERROR_OK) return -ENOEXEC; // If error exists, do not set new error if (ssi_fips_get_error(&current_err) != 0) return -ENOEXEC; if (current_err != CC_REE_FIPS_ERROR_OK) return -ENOEXEC; // set REE internal error and state rc = ssi_fips_ext_set_error(err); if (rc != 0) return -ENOEXEC; rc = ssi_fips_ext_set_state(CC_FIPS_STATE_ERROR); if (rc != 0) return -ENOEXEC; // push error towards TEE libraray, if it's not TEE error if (err != CC_REE_FIPS_ERROR_FROM_TEE) ssi_fips_update_tee_upon_ree_status(p_drvdata, err); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef118100.00%2100.00%
Total118100.00%2100.00%

/* The function called once at driver entry point .*/
int ssi_fips_init(struct ssi_drvdata *p_drvdata) { enum cc_fips_error rc = CC_REE_FIPS_ERROR_OK; struct ssi_fips_handle *fips_h; FIPS_DBG("CC FIPS code .. (fips=%d) \n", ssi_fips_support); fips_h = kzalloc(sizeof(struct ssi_fips_handle), GFP_KERNEL); if (!fips_h) { ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); return -ENOMEM; } p_drvdata->fips_handle = fips_h; #ifdef COMP_IN_WQ SSI_LOG_DEBUG("Initializing fips workqueue\n"); fips_h->workq = create_singlethread_workqueue("arm_cc7x_fips_wq"); if (unlikely(!fips_h->workq)) { SSI_LOG_ERR("Failed creating fips work queue\n"); ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); rc = -ENOMEM; goto ssi_fips_init_err; } INIT_DELAYED_WORK(&fips_h->fipswork, fips_wq_handler); #else SSI_LOG_DEBUG("Initializing fips tasklet\n"); tasklet_init(&fips_h->fipstask, fips_dsr, (unsigned long)p_drvdata); #endif /* init fips driver data */ rc = ssi_fips_set_state((ssi_fips_support == 0) ? CC_FIPS_STATE_NOT_SUPPORTED : CC_FIPS_STATE_SUPPORTED); if (unlikely(rc != 0)) { ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); rc = -EAGAIN; goto ssi_fips_init_err; } /* Run power up tests (before registration and operating the HW engines) */ FIPS_DBG("ssi_fips_get_tee_error \n"); rc = ssi_fips_get_tee_error(p_drvdata); if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) { ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_FROM_TEE); rc = -EAGAIN; goto ssi_fips_init_err; } FIPS_DBG("cc_fips_run_power_up_tests \n"); rc = cc_fips_run_power_up_tests(p_drvdata); if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) { ssi_fips_set_error(p_drvdata, rc); rc = -EAGAIN; goto ssi_fips_init_err; } FIPS_LOG("cc_fips_run_power_up_tests - done ... fips_error = %d \n", rc); /* when all tests passed, update TEE with fips OK status after power up tests */ ssi_fips_update_tee_upon_ree_status(p_drvdata, CC_REE_FIPS_ERROR_OK); if (unlikely(rc != 0)) { rc = -EAGAIN; ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL); goto ssi_fips_init_err; } return 0; ssi_fips_init_err: ssi_fips_fini(p_drvdata); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef322100.00%3100.00%
Total322100.00%3100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Gilad Ben-Yossef150199.60%571.43%
Derek Robson50.33%114.29%
Timothée Isnard10.07%114.29%
Total1507100.00%7100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.