0001
0002
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
0020
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
0028 if (reg & CC_FIPS_SYNC_TEE_STATUS)
0029
0030 return (reg & CC_FIPS_SYNC_MODULE_OK);
0031
0032
0033 return true;
0034 }
0035
0036
0037
0038
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
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
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
0101
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
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
0124
0125
0126 val = (CC_REG(HOST_IMR) & ~irq);
0127 cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
0128 }
0129
0130
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 }