iPXE
aesni.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/** @file
28 *
29 * AES-NI hardware acceleration
30 *
31 * The AES-NI instructions use SSE registers. For the sake of not
32 * having to think about the possible consequences across all various
33 * runtime environments (BIOS/UEFI/Linux), we choose not to enable
34 * "-msse" in CFLAGS for this file. We include ".arch" directives to
35 * ensure that the assembler knows that it is permitted to emit the
36 * SSE2 and AES-NI instructions, and use a fixed "%xmm0" rather than
37 * an "x" constraint (which GCC would consider to be impossible
38 * without "-msse").
39 *
40 * We rely upon the runtime environment to guarantee that using the
41 * "%xmm0" register is a safe operation:
42 *
43 * - For UEFI and Linux, the runtime environment guarantees that SSE
44 * registers are saved and restored across any context switch that
45 * occurs in the middle of the AES calculation.
46 *
47 * - For BIOS, all C code in iPXE runs with interrupts disabled
48 * (unless it enables interrupts itself, e.g. by calling currticks()
49 * or by executing an explicit "sti" instruction), which guarantees
50 * that no other code will unexpectedly modify the SSE registers in
51 * the middle of the AES operation.
52 *
53 * We restore the "%xmm0" register after use, to satisfy the
54 * constraints of the IA-32 UEFI ABI (which defines all FPU/MMX/SSE
55 * registers as callee-saved). This is the most restrictive of the
56 * ABIs for which this file can be built:
57 *
58 * - IA32 UEFI requires all XMM registers to be preserved
59 *
60 * - X64 UEFI would allow us to modify any of "%xmm0"-"%xmm5"
61 *
62 * - BIOS via virt_call() would allow us to modify any of
63 * "%xmm0"-"%xmm7"
64 *
65 * - System V i386 would allow us to modify any of "%xmm0"-"%xmm7"
66 *
67 * - System V x86_64 would allow us to modify any of "%xmm0"-"%xmm15"
68 *
69 */
70
71#include <assert.h>
72#include <ipxe/cpuid.h>
73#include <ipxe/aes.h>
74
75/**
76 * Encrypt data
77 *
78 * @v cipher Cipher algorithm
79 * @v ctx Context
80 * @v src Data to encrypt
81 * @v dst Buffer for encrypted data
82 * @v len Length of data
83 */
84static void aesni_encrypt ( struct cipher_algorithm *cipher __unused,
85 void *ctx, const void *src, void *dst,
86 size_t len ) {
87 struct aes_context *aes = aes_context ( ctx );
88 const union aes_matrix *key = aes->encrypt.key;
89 const union aes_matrix *in = src;
90 union aes_matrix *out = dst;
91 union aes_matrix save;
92
93 /* Sanity check */
94 assert ( len == sizeof ( *in ) );
95 assert ( len == sizeof ( *out ) );
96
97 /* Encrypt */
98 asm ( /* Allow SSE2 and AES-NI instructions */
99 ".arch .sse2\n\t"
100 ".arch .aes\n\t"
101 /* Preserve XMM register */
102 "movdqu %%xmm0, %1\n\t"
103 /* Initial round (AddRoundKey) */
104 "movdqu %3, %%xmm0\n\t"
105 "pxor (%0), %%xmm0\n\t"
106 /* Intermediate rounds (ShiftRows, SubBytes, MixColumns,
107 * AddRoundKey).
108 */
109 "cmpb $13, %b4\n\t"
110 "jb 2f\n\t"
111 "je 1f\n\t"
112 /* 15 rounds (13 intermediate rounds) */
113 "aesenc 0x10(%0), %%xmm0\n\t"
114 "aesenc 0x20(%0), %%xmm0\n\t"
115 "lea 0x20(%0), %0\n\t"
116 "\n1:\n\t"
117 /* 13+ rounds (11+ intermediate rounds) */
118 "aesenc 0x10(%0), %%xmm0\n\t"
119 "aesenc 0x20(%0), %%xmm0\n\t"
120 "lea 0x20(%0), %0\n\t"
121 "\n2:\n\t"
122 /* 11+ rounds (9+ intermediate rounds) */
123 "aesenc 0x10(%0), %%xmm0\n\t"
124 "aesenc 0x20(%0), %%xmm0\n\t"
125 "aesenc 0x30(%0), %%xmm0\n\t"
126 "aesenc 0x40(%0), %%xmm0\n\t"
127 "aesenc 0x50(%0), %%xmm0\n\t"
128 "aesenc 0x60(%0), %%xmm0\n\t"
129 "aesenc 0x70(%0), %%xmm0\n\t"
130 "aesenc 0x80(%0), %%xmm0\n\t"
131 "aesenc 0x90(%0), %%xmm0\n\t"
132 /* Final round (ShiftRows, SubBytes, AddRoundKey) */
133 "aesenclast 0xa0(%0), %%xmm0\n\t"
134 "movdqu %%xmm0, %2\n\t"
135 /* Restore XMM register */
136 "movdqu %1, %%xmm0\n\t"
137 : "+r" ( key ), "=m" ( save ), "=m" ( *out )
138 : "m" ( *in ), "rm" ( aes->rounds ), "m" ( aes->encrypt ) );
139}
140
141/**
142 * Decrypt data
143 *
144 * @v cipher Cipher algorithm
145 * @v ctx Context
146 * @v src Data to encrypt
147 * @v dst Buffer for encrypted data
148 * @v len Length of data
149 */
150static void aesni_decrypt ( struct cipher_algorithm *cipher __unused,
151 void *ctx, const void *src, void *dst,
152 size_t len ) {
153 struct aes_context *aes = aes_context ( ctx );
154 const union aes_matrix *key = aes->decrypt.key;
155 const union aes_matrix *in = src;
156 union aes_matrix *out = dst;
157 union aes_matrix save;
158
159 /* Sanity check */
160 assert ( len == sizeof ( *in ) );
161 assert ( len == sizeof ( *out ) );
162
163 /* Decrypt */
164 asm ( /* Allow SSE2 and AES-NI instructions */
165 ".arch .sse2\n\t"
166 ".arch .aes\n\t"
167 /* Preserve XMM register */
168 "movdqu %%xmm0, %1\n\t"
169 /* Initial round (AddRoundKey) */
170 "movdqu %3, %%xmm0\n\t"
171 "pxor (%0), %%xmm0\n\t"
172 /* Intermediate rounds (InvShiftRows, InvSubBytes,
173 * InvMixColumns, AddRoundKey).
174 */
175 "cmpb $13, %b4\n\t"
176 "jb 2f\n\t"
177 "je 1f\n\t"
178 /* 15 rounds (13 intermediate rounds) */
179 "aesdec 0x10(%0), %%xmm0\n\t"
180 "aesdec 0x20(%0), %%xmm0\n\t"
181 "lea 0x20(%0), %0\n\t"
182 "\n1:\n\t"
183 /* 13+ rounds (11+ intermediate rounds) */
184 "aesdec 0x10(%0), %%xmm0\n\t"
185 "aesdec 0x20(%0), %%xmm0\n\t"
186 "lea 0x20(%0), %0\n\t"
187 "\n2:\n\t"
188 /* 11+ rounds (9+ intermediate rounds) */
189 "aesdec 0x10(%0), %%xmm0\n\t"
190 "aesdec 0x20(%0), %%xmm0\n\t"
191 "aesdec 0x30(%0), %%xmm0\n\t"
192 "aesdec 0x40(%0), %%xmm0\n\t"
193 "aesdec 0x50(%0), %%xmm0\n\t"
194 "aesdec 0x60(%0), %%xmm0\n\t"
195 "aesdec 0x70(%0), %%xmm0\n\t"
196 "aesdec 0x80(%0), %%xmm0\n\t"
197 "aesdec 0x90(%0), %%xmm0\n\t"
198 /* Final round (InvShiftRows, InvSubBytes, AddRoundKey) */
199 "aesdeclast 0xa0(%0), %%xmm0\n\t"
200 "movdqu %%xmm0, %2\n\t"
201 /* Restore XMM register */
202 "movdqu %1, %%xmm0\n\t"
203 : "+r" ( key ), "=m" ( save ), "=m" ( *out )
204 : "m" ( *in ), "rm" ( aes->rounds ), "m" ( aes->decrypt ) );
205}
206
207/**
208 * Enable hardware acceleration (if supported)
209 *
210 */
211void aes_accelerate ( void ) {
212 struct x86_features features;
213
214 /* Detect AES-NI support */
216 if ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_AESNI ) {
217 DBGC ( &aes_algorithm, "AES enabled AES-NI acceleration\n" );
220 }
221}
struct golan_eq_context ctx
Definition CIB_PRM.h:0
__be32 out[4]
Definition CIB_PRM.h:8
__be32 in[4]
Definition CIB_PRM.h:7
union @162305117151260234136356364136041353210355154177 key
struct cipher_algorithm aes_algorithm
Basic AES algorithm.
Definition aes.c:847
void aes_accelerate(void)
Enable hardware acceleration (if supported).
Definition aesni.c:211
static void aesni_decrypt(struct cipher_algorithm *cipher __unused, void *ctx, const void *src, void *dst, size_t len)
Decrypt data.
Definition aesni.c:150
static void aesni_encrypt(struct cipher_algorithm *cipher __unused, void *ctx, const void *src, void *dst, size_t len)
Encrypt data.
Definition aesni.c:84
static const void * src
Definition string.h:48
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
void x86_features(struct x86_features *features)
Get x86 CPU features.
Definition cpuid.c:164
x86 CPU feature detection
#define CPUID_FEATURES_INTEL_ECX_AESNI
AES-NI instructions are supported.
Definition cpuid.h:47
ring len
Length.
Definition dwmac.h:226
uint32_t features
Supported features.
Definition ena.h:5
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:598
#define DBGC(...)
Definition compiler.h:530
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
AES algorithm.
static struct aes_context * aes_context(void *ctx)
Align AES context.
Definition aes.h:55
AES context.
Definition aes.h:37
struct aes_round_keys decrypt
Decryption keys.
Definition aes.h:41
uint8_t rounds
Number of rounds.
Definition aes.h:43
struct aes_round_keys encrypt
Encryption keys.
Definition aes.h:39
union aes_matrix key[AES_MAX_ROUNDS]
Round keys.
Definition aes.h:33
A cipher algorithm.
Definition crypto.h:58
x86 CPU features
Definition cpuid.h:24
AES matrix.
Definition aes.h:23