linux/drivers/crypto/xilinx/zynqmp-aes-gcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx ZynqMP AES Driver.
   4 * Copyright (c) 2020 Xilinx Inc.
   5 */
   6
   7#include <crypto/aes.h>
   8#include <crypto/engine.h>
   9#include <crypto/gcm.h>
  10#include <crypto/internal/aead.h>
  11#include <crypto/scatterwalk.h>
  12
  13#include <linux/dma-mapping.h>
  14#include <linux/module.h>
  15#include <linux/of_device.h>
  16#include <linux/platform_device.h>
  17
  18#include <linux/firmware/xlnx-zynqmp.h>
  19
  20#define ZYNQMP_DMA_BIT_MASK     32U
  21
  22#define ZYNQMP_AES_KEY_SIZE             AES_KEYSIZE_256
  23#define ZYNQMP_AES_AUTH_SIZE            16U
  24#define ZYNQMP_KEY_SRC_SEL_KEY_LEN      1U
  25#define ZYNQMP_AES_BLK_SIZE             1U
  26#define ZYNQMP_AES_MIN_INPUT_BLK_SIZE   4U
  27#define ZYNQMP_AES_WORD_LEN             4U
  28
  29#define ZYNQMP_AES_GCM_TAG_MISMATCH_ERR         0x01
  30#define ZYNQMP_AES_WRONG_KEY_SRC_ERR            0x13
  31#define ZYNQMP_AES_PUF_NOT_PROGRAMMED           0xE300
  32
  33enum zynqmp_aead_op {
  34        ZYNQMP_AES_DECRYPT = 0,
  35        ZYNQMP_AES_ENCRYPT
  36};
  37
  38enum zynqmp_aead_keysrc {
  39        ZYNQMP_AES_KUP_KEY = 0,
  40        ZYNQMP_AES_DEV_KEY,
  41        ZYNQMP_AES_PUF_KEY
  42};
  43
  44struct zynqmp_aead_drv_ctx {
  45        union {
  46                struct aead_alg aead;
  47        } alg;
  48        struct device *dev;
  49        struct crypto_engine *engine;
  50};
  51
  52struct zynqmp_aead_hw_req {
  53        u64 src;
  54        u64 iv;
  55        u64 key;
  56        u64 dst;
  57        u64 size;
  58        u64 op;
  59        u64 keysrc;
  60};
  61
  62struct zynqmp_aead_tfm_ctx {
  63        struct crypto_engine_ctx engine_ctx;
  64        struct device *dev;
  65        u8 key[ZYNQMP_AES_KEY_SIZE];
  66        u8 *iv;
  67        u32 keylen;
  68        u32 authsize;
  69        enum zynqmp_aead_keysrc keysrc;
  70        struct crypto_aead *fbk_cipher;
  71};
  72
  73struct zynqmp_aead_req_ctx {
  74        enum zynqmp_aead_op op;
  75};
  76
  77static int zynqmp_aes_aead_cipher(struct aead_request *req)
  78{
  79        struct crypto_aead *aead = crypto_aead_reqtfm(req);
  80        struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
  81        struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
  82        struct device *dev = tfm_ctx->dev;
  83        struct zynqmp_aead_hw_req *hwreq;
  84        dma_addr_t dma_addr_data, dma_addr_hw_req;
  85        unsigned int data_size;
  86        unsigned int status;
  87        int ret;
  88        size_t dma_size;
  89        char *kbuf;
  90        int err;
  91
  92        if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY)
  93                dma_size = req->cryptlen + ZYNQMP_AES_KEY_SIZE
  94                           + GCM_AES_IV_SIZE;
  95        else
  96                dma_size = req->cryptlen + GCM_AES_IV_SIZE;
  97
  98        kbuf = dma_alloc_coherent(dev, dma_size, &dma_addr_data, GFP_KERNEL);
  99        if (!kbuf)
 100                return -ENOMEM;
 101
 102        hwreq = dma_alloc_coherent(dev, sizeof(struct zynqmp_aead_hw_req),
 103                                   &dma_addr_hw_req, GFP_KERNEL);
 104        if (!hwreq) {
 105                dma_free_coherent(dev, dma_size, kbuf, dma_addr_data);
 106                return -ENOMEM;
 107        }
 108
 109        data_size = req->cryptlen;
 110        scatterwalk_map_and_copy(kbuf, req->src, 0, req->cryptlen, 0);
 111        memcpy(kbuf + data_size, req->iv, GCM_AES_IV_SIZE);
 112
 113        hwreq->src = dma_addr_data;
 114        hwreq->dst = dma_addr_data;
 115        hwreq->iv = hwreq->src + data_size;
 116        hwreq->keysrc = tfm_ctx->keysrc;
 117        hwreq->op = rq_ctx->op;
 118
 119        if (hwreq->op == ZYNQMP_AES_ENCRYPT)
 120                hwreq->size = data_size;
 121        else
 122                hwreq->size = data_size - ZYNQMP_AES_AUTH_SIZE;
 123
 124        if (hwreq->keysrc == ZYNQMP_AES_KUP_KEY) {
 125                memcpy(kbuf + data_size + GCM_AES_IV_SIZE,
 126                       tfm_ctx->key, ZYNQMP_AES_KEY_SIZE);
 127
 128                hwreq->key = hwreq->src + data_size + GCM_AES_IV_SIZE;
 129        } else {
 130                hwreq->key = 0;
 131        }
 132
 133        ret = zynqmp_pm_aes_engine(dma_addr_hw_req, &status);
 134
 135        if (ret) {
 136                dev_err(dev, "ERROR: AES PM API failed\n");
 137                err = ret;
 138        } else if (status) {
 139                switch (status) {
 140                case ZYNQMP_AES_GCM_TAG_MISMATCH_ERR:
 141                        dev_err(dev, "ERROR: Gcm Tag mismatch\n");
 142                        break;
 143                case ZYNQMP_AES_WRONG_KEY_SRC_ERR:
 144                        dev_err(dev, "ERROR: Wrong KeySrc, enable secure mode\n");
 145                        break;
 146                case ZYNQMP_AES_PUF_NOT_PROGRAMMED:
 147                        dev_err(dev, "ERROR: PUF is not registered\n");
 148                        break;
 149                default:
 150                        dev_err(dev, "ERROR: Unknown error\n");
 151                        break;
 152                }
 153                err = -status;
 154        } else {
 155                if (hwreq->op == ZYNQMP_AES_ENCRYPT)
 156                        data_size = data_size + ZYNQMP_AES_AUTH_SIZE;
 157                else
 158                        data_size = data_size - ZYNQMP_AES_AUTH_SIZE;
 159
 160                sg_copy_from_buffer(req->dst, sg_nents(req->dst),
 161                                    kbuf, data_size);
 162                err = 0;
 163        }
 164
 165        if (kbuf) {
 166                memzero_explicit(kbuf, dma_size);
 167                dma_free_coherent(dev, dma_size, kbuf, dma_addr_data);
 168        }
 169        if (hwreq) {
 170                memzero_explicit(hwreq, sizeof(struct zynqmp_aead_hw_req));
 171                dma_free_coherent(dev, sizeof(struct zynqmp_aead_hw_req),
 172                                  hwreq, dma_addr_hw_req);
 173        }
 174        return err;
 175}
 176
 177static int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx,
 178                                 struct aead_request *req)
 179{
 180        int need_fallback = 0;
 181        struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 182
 183        if (tfm_ctx->authsize != ZYNQMP_AES_AUTH_SIZE)
 184                need_fallback = 1;
 185
 186        if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY &&
 187            tfm_ctx->keylen != ZYNQMP_AES_KEY_SIZE) {
 188                need_fallback = 1;
 189        }
 190        if (req->assoclen != 0 ||
 191            req->cryptlen < ZYNQMP_AES_MIN_INPUT_BLK_SIZE) {
 192                need_fallback = 1;
 193        }
 194        if ((req->cryptlen % ZYNQMP_AES_WORD_LEN) != 0)
 195                need_fallback = 1;
 196
 197        if (rq_ctx->op == ZYNQMP_AES_DECRYPT &&
 198            req->cryptlen <= ZYNQMP_AES_AUTH_SIZE) {
 199                need_fallback = 1;
 200        }
 201        return need_fallback;
 202}
 203
 204static int zynqmp_handle_aes_req(struct crypto_engine *engine,
 205                                 void *req)
 206{
 207        struct aead_request *areq =
 208                                container_of(req, struct aead_request, base);
 209        struct crypto_aead *aead = crypto_aead_reqtfm(req);
 210        struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead);
 211        struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(areq);
 212        struct aead_request *subreq = aead_request_ctx(req);
 213        int need_fallback;
 214        int err;
 215
 216        need_fallback = zynqmp_fallback_check(tfm_ctx, areq);
 217
 218        if (need_fallback) {
 219                aead_request_set_tfm(subreq, tfm_ctx->fbk_cipher);
 220
 221                aead_request_set_callback(subreq, areq->base.flags,
 222                                          NULL, NULL);
 223                aead_request_set_crypt(subreq, areq->src, areq->dst,
 224                                       areq->cryptlen, areq->iv);
 225                aead_request_set_ad(subreq, areq->assoclen);
 226                if (rq_ctx->op == ZYNQMP_AES_ENCRYPT)
 227                        err = crypto_aead_encrypt(subreq);
 228                else
 229                        err = crypto_aead_decrypt(subreq);
 230        } else {
 231                err = zynqmp_aes_aead_cipher(areq);
 232        }
 233
 234        crypto_finalize_aead_request(engine, areq, err);
 235        return 0;
 236}
 237
 238static int zynqmp_aes_aead_setkey(struct crypto_aead *aead, const u8 *key,
 239                                  unsigned int keylen)
 240{
 241        struct crypto_tfm *tfm = crypto_aead_tfm(aead);
 242        struct zynqmp_aead_tfm_ctx *tfm_ctx =
 243                        (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 244        unsigned char keysrc;
 245
 246        if (keylen == ZYNQMP_KEY_SRC_SEL_KEY_LEN) {
 247                keysrc = *key;
 248                if (keysrc == ZYNQMP_AES_KUP_KEY ||
 249                    keysrc == ZYNQMP_AES_DEV_KEY ||
 250                    keysrc == ZYNQMP_AES_PUF_KEY) {
 251                        tfm_ctx->keysrc = (enum zynqmp_aead_keysrc)keysrc;
 252                } else {
 253                        tfm_ctx->keylen = keylen;
 254                }
 255        } else {
 256                tfm_ctx->keylen = keylen;
 257                if (keylen == ZYNQMP_AES_KEY_SIZE) {
 258                        tfm_ctx->keysrc = ZYNQMP_AES_KUP_KEY;
 259                        memcpy(tfm_ctx->key, key, keylen);
 260                }
 261        }
 262
 263        tfm_ctx->fbk_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
 264        tfm_ctx->fbk_cipher->base.crt_flags |= (aead->base.crt_flags &
 265                                        CRYPTO_TFM_REQ_MASK);
 266
 267        return crypto_aead_setkey(tfm_ctx->fbk_cipher, key, keylen);
 268}
 269
 270static int zynqmp_aes_aead_setauthsize(struct crypto_aead *aead,
 271                                       unsigned int authsize)
 272{
 273        struct crypto_tfm *tfm = crypto_aead_tfm(aead);
 274        struct zynqmp_aead_tfm_ctx *tfm_ctx =
 275                        (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 276
 277        tfm_ctx->authsize = authsize;
 278        return crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize);
 279}
 280
 281static int zynqmp_aes_aead_encrypt(struct aead_request *req)
 282{
 283        struct zynqmp_aead_drv_ctx *drv_ctx;
 284        struct crypto_aead *aead = crypto_aead_reqtfm(req);
 285        struct aead_alg *alg = crypto_aead_alg(aead);
 286        struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 287
 288        rq_ctx->op = ZYNQMP_AES_ENCRYPT;
 289        drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead);
 290
 291        return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
 292}
 293
 294static int zynqmp_aes_aead_decrypt(struct aead_request *req)
 295{
 296        struct zynqmp_aead_drv_ctx *drv_ctx;
 297        struct crypto_aead *aead = crypto_aead_reqtfm(req);
 298        struct aead_alg *alg = crypto_aead_alg(aead);
 299        struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req);
 300
 301        rq_ctx->op = ZYNQMP_AES_DECRYPT;
 302        drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead);
 303
 304        return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req);
 305}
 306
 307static int zynqmp_aes_aead_init(struct crypto_aead *aead)
 308{
 309        struct crypto_tfm *tfm = crypto_aead_tfm(aead);
 310        struct zynqmp_aead_tfm_ctx *tfm_ctx =
 311                (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 312        struct zynqmp_aead_drv_ctx *drv_ctx;
 313        struct aead_alg *alg = crypto_aead_alg(aead);
 314
 315        drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead);
 316        tfm_ctx->dev = drv_ctx->dev;
 317
 318        tfm_ctx->engine_ctx.op.do_one_request = zynqmp_handle_aes_req;
 319        tfm_ctx->engine_ctx.op.prepare_request = NULL;
 320        tfm_ctx->engine_ctx.op.unprepare_request = NULL;
 321
 322        tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->alg.aead.base.cra_name,
 323                                                0,
 324                                                CRYPTO_ALG_NEED_FALLBACK);
 325
 326        if (IS_ERR(tfm_ctx->fbk_cipher)) {
 327                pr_err("%s() Error: failed to allocate fallback for %s\n",
 328                       __func__, drv_ctx->alg.aead.base.cra_name);
 329                return PTR_ERR(tfm_ctx->fbk_cipher);
 330        }
 331
 332        crypto_aead_set_reqsize(aead,
 333                                max(sizeof(struct zynqmp_aead_req_ctx),
 334                                    sizeof(struct aead_request) +
 335                                    crypto_aead_reqsize(tfm_ctx->fbk_cipher)));
 336        return 0;
 337}
 338
 339static void zynqmp_aes_aead_exit(struct crypto_aead *aead)
 340{
 341        struct crypto_tfm *tfm = crypto_aead_tfm(aead);
 342        struct zynqmp_aead_tfm_ctx *tfm_ctx =
 343                        (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm);
 344
 345        if (tfm_ctx->fbk_cipher) {
 346                crypto_free_aead(tfm_ctx->fbk_cipher);
 347                tfm_ctx->fbk_cipher = NULL;
 348        }
 349        memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx));
 350}
 351
 352static struct zynqmp_aead_drv_ctx aes_drv_ctx = {
 353        .alg.aead = {
 354                .setkey         = zynqmp_aes_aead_setkey,
 355                .setauthsize    = zynqmp_aes_aead_setauthsize,
 356                .encrypt        = zynqmp_aes_aead_encrypt,
 357                .decrypt        = zynqmp_aes_aead_decrypt,
 358                .init           = zynqmp_aes_aead_init,
 359                .exit           = zynqmp_aes_aead_exit,
 360                .ivsize         = GCM_AES_IV_SIZE,
 361                .maxauthsize    = ZYNQMP_AES_AUTH_SIZE,
 362                .base = {
 363                .cra_name               = "gcm(aes)",
 364                .cra_driver_name        = "xilinx-zynqmp-aes-gcm",
 365                .cra_priority           = 200,
 366                .cra_flags              = CRYPTO_ALG_TYPE_AEAD |
 367                                          CRYPTO_ALG_ASYNC |
 368                                          CRYPTO_ALG_ALLOCATES_MEMORY |
 369                                          CRYPTO_ALG_KERN_DRIVER_ONLY |
 370                                          CRYPTO_ALG_NEED_FALLBACK,
 371                .cra_blocksize          = ZYNQMP_AES_BLK_SIZE,
 372                .cra_ctxsize            = sizeof(struct zynqmp_aead_tfm_ctx),
 373                .cra_module             = THIS_MODULE,
 374                }
 375        }
 376};
 377
 378static int zynqmp_aes_aead_probe(struct platform_device *pdev)
 379{
 380        struct device *dev = &pdev->dev;
 381        int err;
 382
 383        /* ZynqMP AES driver supports only one instance */
 384        if (!aes_drv_ctx.dev)
 385                aes_drv_ctx.dev = dev;
 386        else
 387                return -ENODEV;
 388
 389        err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(ZYNQMP_DMA_BIT_MASK));
 390        if (err < 0) {
 391                dev_err(dev, "No usable DMA configuration\n");
 392                return err;
 393        }
 394
 395        aes_drv_ctx.engine = crypto_engine_alloc_init(dev, 1);
 396        if (!aes_drv_ctx.engine) {
 397                dev_err(dev, "Cannot alloc AES engine\n");
 398                err = -ENOMEM;
 399                goto err_engine;
 400        }
 401
 402        err = crypto_engine_start(aes_drv_ctx.engine);
 403        if (err) {
 404                dev_err(dev, "Cannot start AES engine\n");
 405                goto err_engine;
 406        }
 407
 408        err = crypto_register_aead(&aes_drv_ctx.alg.aead);
 409        if (err < 0) {
 410                dev_err(dev, "Failed to register AEAD alg.\n");
 411                goto err_aead;
 412        }
 413        return 0;
 414
 415err_aead:
 416        crypto_unregister_aead(&aes_drv_ctx.alg.aead);
 417
 418err_engine:
 419        if (aes_drv_ctx.engine)
 420                crypto_engine_exit(aes_drv_ctx.engine);
 421
 422        return err;
 423}
 424
 425static int zynqmp_aes_aead_remove(struct platform_device *pdev)
 426{
 427        crypto_engine_exit(aes_drv_ctx.engine);
 428        crypto_unregister_aead(&aes_drv_ctx.alg.aead);
 429
 430        return 0;
 431}
 432
 433static const struct of_device_id zynqmp_aes_dt_ids[] = {
 434        { .compatible = "xlnx,zynqmp-aes" },
 435        { /* sentinel */ }
 436};
 437MODULE_DEVICE_TABLE(of, zynqmp_aes_dt_ids);
 438
 439static struct platform_driver zynqmp_aes_driver = {
 440        .probe  = zynqmp_aes_aead_probe,
 441        .remove = zynqmp_aes_aead_remove,
 442        .driver = {
 443                .name           = "zynqmp-aes",
 444                .of_match_table = zynqmp_aes_dt_ids,
 445        },
 446};
 447
 448module_platform_driver(zynqmp_aes_driver);
 449MODULE_LICENSE("GPL");
 450