1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AES routines supporting VMX instructions on the Power 8 |
4 | * |
5 | * Copyright (C) 2015 International Business Machines Inc. |
6 | * |
7 | * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com> |
8 | */ |
9 | |
10 | #include <linux/types.h> |
11 | #include <linux/err.h> |
12 | #include <linux/crypto.h> |
13 | #include <linux/delay.h> |
14 | #include <asm/simd.h> |
15 | #include <asm/switch_to.h> |
16 | #include <crypto/aes.h> |
17 | #include <crypto/internal/cipher.h> |
18 | #include <crypto/internal/simd.h> |
19 | |
20 | #include "aesp8-ppc.h" |
21 | |
22 | struct p8_aes_ctx { |
23 | struct crypto_cipher *fallback; |
24 | struct aes_key enc_key; |
25 | struct aes_key dec_key; |
26 | }; |
27 | |
28 | static int p8_aes_init(struct crypto_tfm *tfm) |
29 | { |
30 | const char *alg = crypto_tfm_alg_name(tfm); |
31 | struct crypto_cipher *fallback; |
32 | struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); |
33 | |
34 | fallback = crypto_alloc_cipher(alg_name: alg, type: 0, CRYPTO_ALG_NEED_FALLBACK); |
35 | if (IS_ERR(ptr: fallback)) { |
36 | printk(KERN_ERR |
37 | "Failed to allocate transformation for '%s': %ld\n" , |
38 | alg, PTR_ERR(fallback)); |
39 | return PTR_ERR(ptr: fallback); |
40 | } |
41 | |
42 | crypto_cipher_set_flags(tfm: fallback, |
43 | flags: crypto_cipher_get_flags(tfm: (struct |
44 | crypto_cipher *) |
45 | tfm)); |
46 | ctx->fallback = fallback; |
47 | |
48 | return 0; |
49 | } |
50 | |
51 | static void p8_aes_exit(struct crypto_tfm *tfm) |
52 | { |
53 | struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); |
54 | |
55 | if (ctx->fallback) { |
56 | crypto_free_cipher(tfm: ctx->fallback); |
57 | ctx->fallback = NULL; |
58 | } |
59 | } |
60 | |
61 | static int p8_aes_setkey(struct crypto_tfm *tfm, const u8 *key, |
62 | unsigned int keylen) |
63 | { |
64 | int ret; |
65 | struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); |
66 | |
67 | preempt_disable(); |
68 | pagefault_disable(); |
69 | enable_kernel_vsx(); |
70 | ret = aes_p8_set_encrypt_key(userKey: key, bits: keylen * 8, key: &ctx->enc_key); |
71 | ret |= aes_p8_set_decrypt_key(userKey: key, bits: keylen * 8, key: &ctx->dec_key); |
72 | disable_kernel_vsx(); |
73 | pagefault_enable(); |
74 | preempt_enable(); |
75 | |
76 | ret |= crypto_cipher_setkey(tfm: ctx->fallback, key, keylen); |
77 | |
78 | return ret ? -EINVAL : 0; |
79 | } |
80 | |
81 | static void p8_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) |
82 | { |
83 | struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); |
84 | |
85 | if (!crypto_simd_usable()) { |
86 | crypto_cipher_encrypt_one(tfm: ctx->fallback, dst, src); |
87 | } else { |
88 | preempt_disable(); |
89 | pagefault_disable(); |
90 | enable_kernel_vsx(); |
91 | aes_p8_encrypt(in: src, out: dst, key: &ctx->enc_key); |
92 | disable_kernel_vsx(); |
93 | pagefault_enable(); |
94 | preempt_enable(); |
95 | } |
96 | } |
97 | |
98 | static void p8_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) |
99 | { |
100 | struct p8_aes_ctx *ctx = crypto_tfm_ctx(tfm); |
101 | |
102 | if (!crypto_simd_usable()) { |
103 | crypto_cipher_decrypt_one(tfm: ctx->fallback, dst, src); |
104 | } else { |
105 | preempt_disable(); |
106 | pagefault_disable(); |
107 | enable_kernel_vsx(); |
108 | aes_p8_decrypt(in: src, out: dst, key: &ctx->dec_key); |
109 | disable_kernel_vsx(); |
110 | pagefault_enable(); |
111 | preempt_enable(); |
112 | } |
113 | } |
114 | |
115 | struct crypto_alg p8_aes_alg = { |
116 | .cra_name = "aes" , |
117 | .cra_driver_name = "p8_aes" , |
118 | .cra_module = THIS_MODULE, |
119 | .cra_priority = 1000, |
120 | .cra_type = NULL, |
121 | .cra_flags = CRYPTO_ALG_TYPE_CIPHER | CRYPTO_ALG_NEED_FALLBACK, |
122 | .cra_alignmask = 0, |
123 | .cra_blocksize = AES_BLOCK_SIZE, |
124 | .cra_ctxsize = sizeof(struct p8_aes_ctx), |
125 | .cra_init = p8_aes_init, |
126 | .cra_exit = p8_aes_exit, |
127 | .cra_cipher = { |
128 | .cia_min_keysize = AES_MIN_KEY_SIZE, |
129 | .cia_max_keysize = AES_MAX_KEY_SIZE, |
130 | .cia_setkey = p8_aes_setkey, |
131 | .cia_encrypt = p8_aes_encrypt, |
132 | .cia_decrypt = p8_aes_decrypt, |
133 | }, |
134 | }; |
135 | |