xref: /openbmc/linux/drivers/crypto/ccree/cc_fips.c (revision 8dd06ef34b6e2f41b29fbf5fc1663780f2524285)
1ab8ec965SGilad Ben-Yossef // SPDX-License-Identifier: GPL-2.0
203963caeSGilad Ben-Yossef /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
3ab8ec965SGilad Ben-Yossef 
4ab8ec965SGilad Ben-Yossef #include <linux/kernel.h>
5ab8ec965SGilad Ben-Yossef #include <linux/fips.h>
6452c53d7SGilad Ben-Yossef #include <linux/notifier.h>
7ab8ec965SGilad Ben-Yossef 
8ab8ec965SGilad Ben-Yossef #include "cc_driver.h"
9ab8ec965SGilad Ben-Yossef #include "cc_fips.h"
10ab8ec965SGilad Ben-Yossef 
11ab8ec965SGilad Ben-Yossef static void fips_dsr(unsigned long devarg);
12ab8ec965SGilad Ben-Yossef 
13ab8ec965SGilad Ben-Yossef struct cc_fips_handle {
14ab8ec965SGilad Ben-Yossef 	struct tasklet_struct tasklet;
15452c53d7SGilad Ben-Yossef 	struct notifier_block nb;
16452c53d7SGilad Ben-Yossef 	struct cc_drvdata *drvdata;
17ab8ec965SGilad Ben-Yossef };
18ab8ec965SGilad Ben-Yossef 
19ab8ec965SGilad Ben-Yossef /* The function called once at driver entry point to check
20ab8ec965SGilad Ben-Yossef  * whether TEE FIPS error occurred.
21ab8ec965SGilad Ben-Yossef  */
cc_get_tee_fips_status(struct cc_drvdata * drvdata)22ab8ec965SGilad Ben-Yossef static bool cc_get_tee_fips_status(struct cc_drvdata *drvdata)
23ab8ec965SGilad Ben-Yossef {
24ab8ec965SGilad Ben-Yossef 	u32 reg;
25ab8ec965SGilad Ben-Yossef 
26ab8ec965SGilad Ben-Yossef 	reg = cc_ioread(drvdata, CC_REG(GPR_HOST));
2776a95bd8SGilad Ben-Yossef 	/* Did the TEE report status? */
2876a95bd8SGilad Ben-Yossef 	if (reg & CC_FIPS_SYNC_TEE_STATUS)
2976a95bd8SGilad Ben-Yossef 		/* Yes. Is it OK? */
3076a95bd8SGilad Ben-Yossef 		return (reg & CC_FIPS_SYNC_MODULE_OK);
3176a95bd8SGilad Ben-Yossef 
3276a95bd8SGilad Ben-Yossef 	/* No. It's either not in use or will be reported later */
3376a95bd8SGilad Ben-Yossef 	return true;
34ab8ec965SGilad Ben-Yossef }
35ab8ec965SGilad Ben-Yossef 
36ab8ec965SGilad Ben-Yossef /*
37ab8ec965SGilad Ben-Yossef  * This function should push the FIPS REE library status towards the TEE library
38ab8ec965SGilad Ben-Yossef  * by writing the error state to HOST_GPR0 register.
39ab8ec965SGilad Ben-Yossef  */
cc_set_ree_fips_status(struct cc_drvdata * drvdata,bool status)40ab8ec965SGilad Ben-Yossef void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status)
41ab8ec965SGilad Ben-Yossef {
42ab8ec965SGilad Ben-Yossef 	int val = CC_FIPS_SYNC_REE_STATUS;
43ab8ec965SGilad Ben-Yossef 
4427b3b22dSGilad Ben-Yossef 	if (drvdata->hw_rev < CC_HW_REV_712)
4527b3b22dSGilad Ben-Yossef 		return;
4627b3b22dSGilad Ben-Yossef 
47ab8ec965SGilad Ben-Yossef 	val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR);
48ab8ec965SGilad Ben-Yossef 
49ab8ec965SGilad Ben-Yossef 	cc_iowrite(drvdata, CC_REG(HOST_GPR0), val);
50ab8ec965SGilad Ben-Yossef }
51ab8ec965SGilad Ben-Yossef 
52452c53d7SGilad Ben-Yossef /* Push REE side FIPS test failure to TEE side */
cc_ree_fips_failure(struct notifier_block * nb,unsigned long unused1,void * unused2)53452c53d7SGilad Ben-Yossef static int cc_ree_fips_failure(struct notifier_block *nb, unsigned long unused1,
54452c53d7SGilad Ben-Yossef 			       void *unused2)
55452c53d7SGilad Ben-Yossef {
56452c53d7SGilad Ben-Yossef 	struct cc_fips_handle *fips_h =
57452c53d7SGilad Ben-Yossef 				container_of(nb, struct cc_fips_handle, nb);
58452c53d7SGilad Ben-Yossef 	struct cc_drvdata *drvdata = fips_h->drvdata;
59452c53d7SGilad Ben-Yossef 	struct device *dev = drvdata_to_dev(drvdata);
60452c53d7SGilad Ben-Yossef 
61452c53d7SGilad Ben-Yossef 	cc_set_ree_fips_status(drvdata, false);
62452c53d7SGilad Ben-Yossef 	dev_info(dev, "Notifying TEE of FIPS test failure...\n");
63452c53d7SGilad Ben-Yossef 
64452c53d7SGilad Ben-Yossef 	return NOTIFY_OK;
65452c53d7SGilad Ben-Yossef }
66452c53d7SGilad Ben-Yossef 
cc_fips_fini(struct cc_drvdata * drvdata)67ab8ec965SGilad Ben-Yossef void cc_fips_fini(struct cc_drvdata *drvdata)
68ab8ec965SGilad Ben-Yossef {
69ab8ec965SGilad Ben-Yossef 	struct cc_fips_handle *fips_h = drvdata->fips_handle;
70ab8ec965SGilad Ben-Yossef 
7127b3b22dSGilad Ben-Yossef 	if (drvdata->hw_rev < CC_HW_REV_712 || !fips_h)
7227b3b22dSGilad Ben-Yossef 		return;
73ab8ec965SGilad Ben-Yossef 
74452c53d7SGilad Ben-Yossef 	atomic_notifier_chain_unregister(&fips_fail_notif_chain, &fips_h->nb);
75452c53d7SGilad Ben-Yossef 
76ab8ec965SGilad Ben-Yossef 	/* Kill tasklet */
77ab8ec965SGilad Ben-Yossef 	tasklet_kill(&fips_h->tasklet);
78ab8ec965SGilad Ben-Yossef 	drvdata->fips_handle = NULL;
79ab8ec965SGilad Ben-Yossef }
80ab8ec965SGilad Ben-Yossef 
fips_handler(struct cc_drvdata * drvdata)81ab8ec965SGilad Ben-Yossef void fips_handler(struct cc_drvdata *drvdata)
82ab8ec965SGilad Ben-Yossef {
83ab8ec965SGilad Ben-Yossef 	struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle;
84ab8ec965SGilad Ben-Yossef 
8527b3b22dSGilad Ben-Yossef 	if (drvdata->hw_rev < CC_HW_REV_712)
8627b3b22dSGilad Ben-Yossef 		return;
8727b3b22dSGilad Ben-Yossef 
88ab8ec965SGilad Ben-Yossef 	tasklet_schedule(&fips_handle_ptr->tasklet);
89ab8ec965SGilad Ben-Yossef }
90ab8ec965SGilad Ben-Yossef 
tee_fips_error(struct device * dev)91ab8ec965SGilad Ben-Yossef static inline void tee_fips_error(struct device *dev)
92ab8ec965SGilad Ben-Yossef {
93ab8ec965SGilad Ben-Yossef 	if (fips_enabled)
94ab8ec965SGilad Ben-Yossef 		panic("ccree: TEE reported cryptographic error in fips mode!\n");
95ab8ec965SGilad Ben-Yossef 	else
96ab8ec965SGilad Ben-Yossef 		dev_err(dev, "TEE reported error!\n");
97ab8ec965SGilad Ben-Yossef }
98ab8ec965SGilad Ben-Yossef 
99897ab231SOfir Drang /*
100897ab231SOfir Drang  * This function check if cryptocell tee fips error occurred
101897ab231SOfir Drang  * and in such case triggers system error
102897ab231SOfir Drang  */
cc_tee_handle_fips_error(struct cc_drvdata * p_drvdata)103897ab231SOfir Drang void cc_tee_handle_fips_error(struct cc_drvdata *p_drvdata)
104897ab231SOfir Drang {
105897ab231SOfir Drang 	struct device *dev = drvdata_to_dev(p_drvdata);
106897ab231SOfir Drang 
107897ab231SOfir Drang 	if (!cc_get_tee_fips_status(p_drvdata))
108897ab231SOfir Drang 		tee_fips_error(dev);
109897ab231SOfir Drang }
110897ab231SOfir Drang 
111ab8ec965SGilad Ben-Yossef /* Deferred service handler, run as interrupt-fired tasklet */
fips_dsr(unsigned long devarg)112ab8ec965SGilad Ben-Yossef static void fips_dsr(unsigned long devarg)
113ab8ec965SGilad Ben-Yossef {
114ab8ec965SGilad Ben-Yossef 	struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg;
115897ab231SOfir Drang 	u32 irq, val;
116ab8ec965SGilad Ben-Yossef 
117ab8ec965SGilad Ben-Yossef 	irq = (drvdata->irq & (CC_GPR0_IRQ_MASK));
118ab8ec965SGilad Ben-Yossef 
119ab8ec965SGilad Ben-Yossef 	if (irq) {
120897ab231SOfir Drang 		cc_tee_handle_fips_error(drvdata);
121ab8ec965SGilad Ben-Yossef 	}
122ab8ec965SGilad Ben-Yossef 
123*e86eca41SHadar Gat 	/* after verifying that there is nothing to do,
124ab8ec965SGilad Ben-Yossef 	 * unmask AXI completion interrupt.
125ab8ec965SGilad Ben-Yossef 	 */
126ab8ec965SGilad Ben-Yossef 	val = (CC_REG(HOST_IMR) & ~irq);
127ab8ec965SGilad Ben-Yossef 	cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
128ab8ec965SGilad Ben-Yossef }
129ab8ec965SGilad Ben-Yossef 
130ab8ec965SGilad Ben-Yossef /* The function called once at driver entry point .*/
cc_fips_init(struct cc_drvdata * p_drvdata)131ab8ec965SGilad Ben-Yossef int cc_fips_init(struct cc_drvdata *p_drvdata)
132ab8ec965SGilad Ben-Yossef {
133ab8ec965SGilad Ben-Yossef 	struct cc_fips_handle *fips_h;
134ab8ec965SGilad Ben-Yossef 	struct device *dev = drvdata_to_dev(p_drvdata);
135ab8ec965SGilad Ben-Yossef 
13627b3b22dSGilad Ben-Yossef 	if (p_drvdata->hw_rev < CC_HW_REV_712)
13727b3b22dSGilad Ben-Yossef 		return 0;
13827b3b22dSGilad Ben-Yossef 
139dcb2cf1dSGilad Ben-Yossef 	fips_h = devm_kzalloc(dev, sizeof(*fips_h), GFP_KERNEL);
140ab8ec965SGilad Ben-Yossef 	if (!fips_h)
141ab8ec965SGilad Ben-Yossef 		return -ENOMEM;
142ab8ec965SGilad Ben-Yossef 
143ab8ec965SGilad Ben-Yossef 	p_drvdata->fips_handle = fips_h;
144ab8ec965SGilad Ben-Yossef 
145ab8ec965SGilad Ben-Yossef 	dev_dbg(dev, "Initializing fips tasklet\n");
146ab8ec965SGilad Ben-Yossef 	tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata);
147452c53d7SGilad Ben-Yossef 	fips_h->drvdata = p_drvdata;
148452c53d7SGilad Ben-Yossef 	fips_h->nb.notifier_call = cc_ree_fips_failure;
149452c53d7SGilad Ben-Yossef 	atomic_notifier_chain_register(&fips_fail_notif_chain, &fips_h->nb);
150ab8ec965SGilad Ben-Yossef 
151897ab231SOfir Drang 	cc_tee_handle_fips_error(p_drvdata);
152ab8ec965SGilad Ben-Yossef 
153ab8ec965SGilad Ben-Yossef 	return 0;
154ab8ec965SGilad Ben-Yossef }
155