zynqmp-sha.c (6906B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Xilinx ZynqMP SHA Driver. 4 * Copyright (c) 2022 Xilinx Inc. 5 */ 6#include <linux/cacheflush.h> 7#include <crypto/hash.h> 8#include <crypto/internal/hash.h> 9#include <crypto/sha3.h> 10#include <linux/crypto.h> 11#include <linux/device.h> 12#include <linux/dma-mapping.h> 13#include <linux/firmware/xlnx-zynqmp.h> 14#include <linux/init.h> 15#include <linux/io.h> 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/of_device.h> 19#include <linux/platform_device.h> 20 21#define ZYNQMP_DMA_BIT_MASK 32U 22#define ZYNQMP_DMA_ALLOC_FIXED_SIZE 0x1000U 23 24enum zynqmp_sha_op { 25 ZYNQMP_SHA3_INIT = 1, 26 ZYNQMP_SHA3_UPDATE = 2, 27 ZYNQMP_SHA3_FINAL = 4, 28}; 29 30struct zynqmp_sha_drv_ctx { 31 struct shash_alg sha3_384; 32 struct device *dev; 33}; 34 35struct zynqmp_sha_tfm_ctx { 36 struct device *dev; 37 struct crypto_shash *fbk_tfm; 38}; 39 40struct zynqmp_sha_desc_ctx { 41 struct shash_desc fbk_req; 42}; 43 44static dma_addr_t update_dma_addr, final_dma_addr; 45static char *ubuf, *fbuf; 46 47static int zynqmp_sha_init_tfm(struct crypto_shash *hash) 48{ 49 const char *fallback_driver_name = crypto_shash_alg_name(hash); 50 struct zynqmp_sha_tfm_ctx *tfm_ctx = crypto_shash_ctx(hash); 51 struct shash_alg *alg = crypto_shash_alg(hash); 52 struct crypto_shash *fallback_tfm; 53 struct zynqmp_sha_drv_ctx *drv_ctx; 54 55 drv_ctx = container_of(alg, struct zynqmp_sha_drv_ctx, sha3_384); 56 tfm_ctx->dev = drv_ctx->dev; 57 58 /* Allocate a fallback and abort if it failed. */ 59 fallback_tfm = crypto_alloc_shash(fallback_driver_name, 0, 60 CRYPTO_ALG_NEED_FALLBACK); 61 if (IS_ERR(fallback_tfm)) 62 return PTR_ERR(fallback_tfm); 63 64 tfm_ctx->fbk_tfm = fallback_tfm; 65 hash->descsize += crypto_shash_descsize(tfm_ctx->fbk_tfm); 66 67 return 0; 68} 69 70static void zynqmp_sha_exit_tfm(struct crypto_shash *hash) 71{ 72 struct zynqmp_sha_tfm_ctx *tfm_ctx = crypto_shash_ctx(hash); 73 74 if (tfm_ctx->fbk_tfm) { 75 crypto_free_shash(tfm_ctx->fbk_tfm); 76 tfm_ctx->fbk_tfm = NULL; 77 } 78 79 memzero_explicit(tfm_ctx, sizeof(struct zynqmp_sha_tfm_ctx)); 80} 81 82static int zynqmp_sha_init(struct shash_desc *desc) 83{ 84 struct zynqmp_sha_desc_ctx *dctx = shash_desc_ctx(desc); 85 struct zynqmp_sha_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); 86 87 dctx->fbk_req.tfm = tctx->fbk_tfm; 88 return crypto_shash_init(&dctx->fbk_req); 89} 90 91static int zynqmp_sha_update(struct shash_desc *desc, const u8 *data, unsigned int length) 92{ 93 struct zynqmp_sha_desc_ctx *dctx = shash_desc_ctx(desc); 94 95 return crypto_shash_update(&dctx->fbk_req, data, length); 96} 97 98static int zynqmp_sha_final(struct shash_desc *desc, u8 *out) 99{ 100 struct zynqmp_sha_desc_ctx *dctx = shash_desc_ctx(desc); 101 102 return crypto_shash_final(&dctx->fbk_req, out); 103} 104 105static int zynqmp_sha_finup(struct shash_desc *desc, const u8 *data, unsigned int length, u8 *out) 106{ 107 struct zynqmp_sha_desc_ctx *dctx = shash_desc_ctx(desc); 108 109 return crypto_shash_finup(&dctx->fbk_req, data, length, out); 110} 111 112static int zynqmp_sha_import(struct shash_desc *desc, const void *in) 113{ 114 struct zynqmp_sha_desc_ctx *dctx = shash_desc_ctx(desc); 115 struct zynqmp_sha_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); 116 117 dctx->fbk_req.tfm = tctx->fbk_tfm; 118 return crypto_shash_import(&dctx->fbk_req, in); 119} 120 121static int zynqmp_sha_export(struct shash_desc *desc, void *out) 122{ 123 struct zynqmp_sha_desc_ctx *dctx = shash_desc_ctx(desc); 124 125 return crypto_shash_export(&dctx->fbk_req, out); 126} 127 128static int zynqmp_sha_digest(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) 129{ 130 unsigned int remaining_len = len; 131 int update_size; 132 int ret; 133 134 ret = zynqmp_pm_sha_hash(0, 0, ZYNQMP_SHA3_INIT); 135 if (ret) 136 return ret; 137 138 while (remaining_len != 0) { 139 memzero_explicit(ubuf, ZYNQMP_DMA_ALLOC_FIXED_SIZE); 140 if (remaining_len >= ZYNQMP_DMA_ALLOC_FIXED_SIZE) { 141 update_size = ZYNQMP_DMA_ALLOC_FIXED_SIZE; 142 remaining_len -= ZYNQMP_DMA_ALLOC_FIXED_SIZE; 143 } else { 144 update_size = remaining_len; 145 remaining_len = 0; 146 } 147 memcpy(ubuf, data, update_size); 148 flush_icache_range((unsigned long)ubuf, (unsigned long)ubuf + update_size); 149 ret = zynqmp_pm_sha_hash(update_dma_addr, update_size, ZYNQMP_SHA3_UPDATE); 150 if (ret) 151 return ret; 152 153 data += update_size; 154 } 155 156 ret = zynqmp_pm_sha_hash(final_dma_addr, SHA3_384_DIGEST_SIZE, ZYNQMP_SHA3_FINAL); 157 memcpy(out, fbuf, SHA3_384_DIGEST_SIZE); 158 memzero_explicit(fbuf, SHA3_384_DIGEST_SIZE); 159 160 return ret; 161} 162 163static struct zynqmp_sha_drv_ctx sha3_drv_ctx = { 164 .sha3_384 = { 165 .init = zynqmp_sha_init, 166 .update = zynqmp_sha_update, 167 .final = zynqmp_sha_final, 168 .finup = zynqmp_sha_finup, 169 .digest = zynqmp_sha_digest, 170 .export = zynqmp_sha_export, 171 .import = zynqmp_sha_import, 172 .init_tfm = zynqmp_sha_init_tfm, 173 .exit_tfm = zynqmp_sha_exit_tfm, 174 .descsize = sizeof(struct zynqmp_sha_desc_ctx), 175 .statesize = sizeof(struct sha3_state), 176 .digestsize = SHA3_384_DIGEST_SIZE, 177 .base = { 178 .cra_name = "sha3-384", 179 .cra_driver_name = "zynqmp-sha3-384", 180 .cra_priority = 300, 181 .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 182 CRYPTO_ALG_ALLOCATES_MEMORY | 183 CRYPTO_ALG_NEED_FALLBACK, 184 .cra_blocksize = SHA3_384_BLOCK_SIZE, 185 .cra_ctxsize = sizeof(struct zynqmp_sha_tfm_ctx), 186 .cra_alignmask = 3, 187 .cra_module = THIS_MODULE, 188 } 189 } 190}; 191 192static int zynqmp_sha_probe(struct platform_device *pdev) 193{ 194 struct device *dev = &pdev->dev; 195 int err; 196 u32 v; 197 198 /* Verify the hardware is present */ 199 err = zynqmp_pm_get_api_version(&v); 200 if (err) 201 return err; 202 203 204 err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(ZYNQMP_DMA_BIT_MASK)); 205 if (err < 0) { 206 dev_err(dev, "No usable DMA configuration\n"); 207 return err; 208 } 209 210 err = crypto_register_shash(&sha3_drv_ctx.sha3_384); 211 if (err < 0) { 212 dev_err(dev, "Failed to register shash alg.\n"); 213 return err; 214 } 215 216 sha3_drv_ctx.dev = dev; 217 platform_set_drvdata(pdev, &sha3_drv_ctx); 218 219 ubuf = dma_alloc_coherent(dev, ZYNQMP_DMA_ALLOC_FIXED_SIZE, &update_dma_addr, GFP_KERNEL); 220 if (!ubuf) { 221 err = -ENOMEM; 222 goto err_shash; 223 } 224 225 fbuf = dma_alloc_coherent(dev, SHA3_384_DIGEST_SIZE, &final_dma_addr, GFP_KERNEL); 226 if (!fbuf) { 227 err = -ENOMEM; 228 goto err_mem; 229 } 230 231 return 0; 232 233err_mem: 234 dma_free_coherent(sha3_drv_ctx.dev, ZYNQMP_DMA_ALLOC_FIXED_SIZE, ubuf, update_dma_addr); 235 236err_shash: 237 crypto_unregister_shash(&sha3_drv_ctx.sha3_384); 238 239 return err; 240} 241 242static int zynqmp_sha_remove(struct platform_device *pdev) 243{ 244 sha3_drv_ctx.dev = platform_get_drvdata(pdev); 245 246 dma_free_coherent(sha3_drv_ctx.dev, ZYNQMP_DMA_ALLOC_FIXED_SIZE, ubuf, update_dma_addr); 247 dma_free_coherent(sha3_drv_ctx.dev, SHA3_384_DIGEST_SIZE, fbuf, final_dma_addr); 248 crypto_unregister_shash(&sha3_drv_ctx.sha3_384); 249 250 return 0; 251} 252 253static struct platform_driver zynqmp_sha_driver = { 254 .probe = zynqmp_sha_probe, 255 .remove = zynqmp_sha_remove, 256 .driver = { 257 .name = "zynqmp-sha3-384", 258 }, 259}; 260 261module_platform_driver(zynqmp_sha_driver); 262MODULE_DESCRIPTION("ZynqMP SHA3 hardware acceleration support."); 263MODULE_LICENSE("GPL v2"); 264MODULE_AUTHOR("Harsha <harsha.harsha@xilinx.com>");