Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/fips.h>
0006 #include <linux/notifier.h>
0007 
0008 #include "cc_driver.h"
0009 #include "cc_fips.h"
0010 
0011 static void fips_dsr(unsigned long devarg);
0012 
0013 struct cc_fips_handle {
0014     struct tasklet_struct tasklet;
0015     struct notifier_block nb;
0016     struct cc_drvdata *drvdata;
0017 };
0018 
0019 /* The function called once at driver entry point to check
0020  * whether TEE FIPS error occurred.
0021  */
0022 static bool cc_get_tee_fips_status(struct cc_drvdata *drvdata)
0023 {
0024     u32 reg;
0025 
0026     reg = cc_ioread(drvdata, CC_REG(GPR_HOST));
0027     /* Did the TEE report status? */
0028     if (reg & CC_FIPS_SYNC_TEE_STATUS)
0029         /* Yes. Is it OK? */
0030         return (reg & CC_FIPS_SYNC_MODULE_OK);
0031 
0032     /* No. It's either not in use or will be reported later */
0033     return true;
0034 }
0035 
0036 /*
0037  * This function should push the FIPS REE library status towards the TEE library
0038  * by writing the error state to HOST_GPR0 register.
0039  */
0040 void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status)
0041 {
0042     int val = CC_FIPS_SYNC_REE_STATUS;
0043 
0044     if (drvdata->hw_rev < CC_HW_REV_712)
0045         return;
0046 
0047     val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR);
0048 
0049     cc_iowrite(drvdata, CC_REG(HOST_GPR0), val);
0050 }
0051 
0052 /* Push REE side FIPS test failure to TEE side */
0053 static int cc_ree_fips_failure(struct notifier_block *nb, unsigned long unused1,
0054                    void *unused2)
0055 {
0056     struct cc_fips_handle *fips_h =
0057                 container_of(nb, struct cc_fips_handle, nb);
0058     struct cc_drvdata *drvdata = fips_h->drvdata;
0059     struct device *dev = drvdata_to_dev(drvdata);
0060 
0061     cc_set_ree_fips_status(drvdata, false);
0062     dev_info(dev, "Notifying TEE of FIPS test failure...\n");
0063 
0064     return NOTIFY_OK;
0065 }
0066 
0067 void cc_fips_fini(struct cc_drvdata *drvdata)
0068 {
0069     struct cc_fips_handle *fips_h = drvdata->fips_handle;
0070 
0071     if (drvdata->hw_rev < CC_HW_REV_712 || !fips_h)
0072         return;
0073 
0074     atomic_notifier_chain_unregister(&fips_fail_notif_chain, &fips_h->nb);
0075 
0076     /* Kill tasklet */
0077     tasklet_kill(&fips_h->tasklet);
0078     drvdata->fips_handle = NULL;
0079 }
0080 
0081 void fips_handler(struct cc_drvdata *drvdata)
0082 {
0083     struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle;
0084 
0085     if (drvdata->hw_rev < CC_HW_REV_712)
0086         return;
0087 
0088     tasklet_schedule(&fips_handle_ptr->tasklet);
0089 }
0090 
0091 static inline void tee_fips_error(struct device *dev)
0092 {
0093     if (fips_enabled)
0094         panic("ccree: TEE reported cryptographic error in fips mode!\n");
0095     else
0096         dev_err(dev, "TEE reported error!\n");
0097 }
0098 
0099 /*
0100  * This function check if cryptocell tee fips error occurred
0101  * and in such case triggers system error
0102  */
0103 void cc_tee_handle_fips_error(struct cc_drvdata *p_drvdata)
0104 {
0105     struct device *dev = drvdata_to_dev(p_drvdata);
0106 
0107     if (!cc_get_tee_fips_status(p_drvdata))
0108         tee_fips_error(dev);
0109 }
0110 
0111 /* Deferred service handler, run as interrupt-fired tasklet */
0112 static void fips_dsr(unsigned long devarg)
0113 {
0114     struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg;
0115     u32 irq, val;
0116 
0117     irq = (drvdata->irq & (CC_GPR0_IRQ_MASK));
0118 
0119     if (irq) {
0120         cc_tee_handle_fips_error(drvdata);
0121     }
0122 
0123     /* after verifying that there is nothing to do,
0124      * unmask AXI completion interrupt.
0125      */
0126     val = (CC_REG(HOST_IMR) & ~irq);
0127     cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
0128 }
0129 
0130 /* The function called once at driver entry point .*/
0131 int cc_fips_init(struct cc_drvdata *p_drvdata)
0132 {
0133     struct cc_fips_handle *fips_h;
0134     struct device *dev = drvdata_to_dev(p_drvdata);
0135 
0136     if (p_drvdata->hw_rev < CC_HW_REV_712)
0137         return 0;
0138 
0139     fips_h = devm_kzalloc(dev, sizeof(*fips_h), GFP_KERNEL);
0140     if (!fips_h)
0141         return -ENOMEM;
0142 
0143     p_drvdata->fips_handle = fips_h;
0144 
0145     dev_dbg(dev, "Initializing fips tasklet\n");
0146     tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata);
0147     fips_h->drvdata = p_drvdata;
0148     fips_h->nb.notifier_call = cc_ree_fips_failure;
0149     atomic_notifier_chain_register(&fips_fail_notif_chain, &fips_h->nb);
0150 
0151     cc_tee_handle_fips_error(p_drvdata);
0152 
0153     return 0;
0154 }