xref: /freebsd-src/crypto/openssl/crypto/async/arch/async_posix.h (revision a8fe2d331be35dcafefa5f706e955f0dde70aa5f)
1e71b7053SJung-uk Kim /*
2b077aed3SPierre Pronchery  * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
3e71b7053SJung-uk Kim  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
8e71b7053SJung-uk Kim  */
9e71b7053SJung-uk Kim 
1017f01e99SJung-uk Kim #ifndef OSSL_CRYPTO_ASYNC_POSIX_H
1117f01e99SJung-uk Kim #define OSSL_CRYPTO_ASYNC_POSIX_H
12e71b7053SJung-uk Kim #include <openssl/e_os2.h>
13e71b7053SJung-uk Kim 
14e71b7053SJung-uk Kim #if defined(OPENSSL_SYS_UNIX) \
15e71b7053SJung-uk Kim     && defined(OPENSSL_THREADS) && !defined(OPENSSL_NO_ASYNC) \
16e71b7053SJung-uk Kim     && !defined(__ANDROID__) && !defined(__OpenBSD__)
17e71b7053SJung-uk Kim 
18e71b7053SJung-uk Kim # include <unistd.h>
19e71b7053SJung-uk Kim 
20c9cf7b5cSJung-uk Kim # if _POSIX_VERSION >= 200112L \
21*a8fe2d33SWarner Losh      && (_POSIX_VERSION < 200809L || defined(__GLIBC__) || defined(__FreeBSD__))
22e71b7053SJung-uk Kim 
23e71b7053SJung-uk Kim # include <pthread.h>
24e71b7053SJung-uk Kim 
25e71b7053SJung-uk Kim #  define ASYNC_POSIX
26e71b7053SJung-uk Kim #  define ASYNC_ARCH
27e71b7053SJung-uk Kim 
28b077aed3SPierre Pronchery #  if defined(__CET__) || defined(__ia64__)
29b077aed3SPierre Pronchery /*
30b077aed3SPierre Pronchery  * When Intel CET is enabled, makecontext will create a different
31b077aed3SPierre Pronchery  * shadow stack for each context.  async_fibre_swapcontext cannot
32b077aed3SPierre Pronchery  * use _longjmp.  It must call swapcontext to swap shadow stack as
33b077aed3SPierre Pronchery  * well as normal stack.
34b077aed3SPierre Pronchery  * On IA64 the register stack engine is not saved across setjmp/longjmp. Here
35b077aed3SPierre Pronchery  * swapcontext() performs correctly.
36b077aed3SPierre Pronchery  */
37b077aed3SPierre Pronchery #   define USE_SWAPCONTEXT
38b077aed3SPierre Pronchery #  endif
39b077aed3SPierre Pronchery #  if defined(__aarch64__) && defined(__clang__) \
40b077aed3SPierre Pronchery     && defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
41b077aed3SPierre Pronchery /*
42b077aed3SPierre Pronchery  * setjmp/longjmp don't currently work with BTI on all libc implementations
43b077aed3SPierre Pronchery  * when compiled by clang. This is because clang doesn't put a BTI after the
44b077aed3SPierre Pronchery  * call to setjmp where it returns the second time. This then fails on libc
45b077aed3SPierre Pronchery  * implementations - notably glibc - which use an indirect jump to there.
46b077aed3SPierre Pronchery  * So use the swapcontext implementation, which does work.
47b077aed3SPierre Pronchery  * See https://github.com/llvm/llvm-project/issues/48888.
48b077aed3SPierre Pronchery  */
49b077aed3SPierre Pronchery #   define USE_SWAPCONTEXT
50b077aed3SPierre Pronchery #  endif
51e71b7053SJung-uk Kim #  include <ucontext.h>
52b077aed3SPierre Pronchery #  ifndef USE_SWAPCONTEXT
53e71b7053SJung-uk Kim #   include <setjmp.h>
54b077aed3SPierre Pronchery #  endif
55e71b7053SJung-uk Kim 
56e71b7053SJung-uk Kim typedef struct async_fibre_st {
57e71b7053SJung-uk Kim     ucontext_t fibre;
58b077aed3SPierre Pronchery #  ifndef USE_SWAPCONTEXT
59e71b7053SJung-uk Kim     jmp_buf env;
60e71b7053SJung-uk Kim     int env_init;
61b077aed3SPierre Pronchery #  endif
62e71b7053SJung-uk Kim } async_fibre;
63e71b7053SJung-uk Kim 
async_fibre_swapcontext(async_fibre * o,async_fibre * n,int r)64e71b7053SJung-uk Kim static ossl_inline int async_fibre_swapcontext(async_fibre *o, async_fibre *n, int r)
65e71b7053SJung-uk Kim {
66b077aed3SPierre Pronchery #  ifdef USE_SWAPCONTEXT
67b077aed3SPierre Pronchery     swapcontext(&o->fibre, &n->fibre);
68b077aed3SPierre Pronchery #  else
69e71b7053SJung-uk Kim     o->env_init = 1;
70e71b7053SJung-uk Kim 
71e71b7053SJung-uk Kim     if (!r || !_setjmp(o->env)) {
72e71b7053SJung-uk Kim         if (n->env_init)
73e71b7053SJung-uk Kim             _longjmp(n->env, 1);
74e71b7053SJung-uk Kim         else
75e71b7053SJung-uk Kim             setcontext(&n->fibre);
76e71b7053SJung-uk Kim     }
77b077aed3SPierre Pronchery #  endif
78e71b7053SJung-uk Kim 
79e71b7053SJung-uk Kim     return 1;
80e71b7053SJung-uk Kim }
81e71b7053SJung-uk Kim 
82e71b7053SJung-uk Kim #  define async_fibre_init_dispatcher(d)
83e71b7053SJung-uk Kim 
84e71b7053SJung-uk Kim int async_fibre_makecontext(async_fibre *fibre);
85e71b7053SJung-uk Kim void async_fibre_free(async_fibre *fibre);
86e71b7053SJung-uk Kim 
87e71b7053SJung-uk Kim # endif
88e71b7053SJung-uk Kim #endif
8917f01e99SJung-uk Kim #endif /* OSSL_CRYPTO_ASYNC_POSIX_H */
90