|
9 | 9 | #ifndef LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_ |
10 | 10 | #define LLVM_SYS_MMAN_LINUX_X86_64_PKEY_COMMON_H_ |
11 | 11 |
|
| 12 | +#include <immintrin.h> |
| 13 | + |
12 | 14 | #include "hdr/errno_macros.h" // For ENOSYS |
13 | 15 | #include "hdr/stdint_proxy.h" |
14 | 16 | #include "src/__support/common.h" |
|
20 | 22 |
|
21 | 23 | namespace LIBC_NAMESPACE_DECL { |
22 | 24 | namespace pkey_common { |
23 | | -namespace internal { |
24 | 25 |
|
25 | | -constexpr int MAX_KEY = 15; |
| 26 | +constexpr int KEY_COUNT = 16; |
26 | 27 | constexpr int KEY_MASK = 0x3; |
27 | 28 | constexpr int BITS_PER_KEY = 2; |
28 | 29 |
|
29 | | -// This will SIGILL on CPUs that don't support PKU / OSPKE, |
30 | | -// but this case should never be reached as a prior pkey_alloc invocation |
31 | | -// would have failed more gracefully. |
32 | | -LIBC_INLINE uint32_t read_prku() { |
33 | | - uint32_t pkru = 0; |
34 | | - uint32_t edx = 0; |
35 | | - asm volatile("rdpkru" : "=a"(pkru), "=d"(edx) : "c"(0)); |
36 | | - return pkru; |
37 | | -} |
38 | | - |
39 | | -// This will SIGILL on CPUs that don't support PKU / OSPKE, |
40 | | -// but this case should never be reached as a prior pkey_alloc invocation |
41 | | -// would have failed more gracefully. |
42 | | -LIBC_INLINE void write_prku(uint32_t pkru) { |
43 | | - asm volatile("wrpkru" : : "a"(pkru), "d"(0), "c"(0)); |
44 | | -} |
45 | | - |
46 | | -} // namespace internal |
47 | | - |
48 | 30 | // x86_64 implementation of pkey_get. |
49 | 31 | // Returns the access rights for the given pkey on success, errno otherwise. |
| 32 | +[[gnu::target("pku")]] |
50 | 33 | LIBC_INLINE ErrorOr<int> pkey_get(int pkey) { |
51 | | - if (pkey < 0 || pkey > internal::MAX_KEY) { |
| 34 | + if (pkey < 0 || pkey >= KEY_COUNT) { |
52 | 35 | return Error(EINVAL); |
53 | 36 | } |
54 | 37 |
|
55 | | - uint32_t pkru = internal::read_prku(); |
56 | | - return (pkru >> (pkey * internal::BITS_PER_KEY)) & internal::KEY_MASK; |
| 38 | + uint32_t pkru = _rdpkru_u32(); |
| 39 | + return (pkru >> (pkey * BITS_PER_KEY)) & KEY_MASK; |
57 | 40 | } |
58 | 41 |
|
59 | 42 | // x86_64 implementation of pkey_set. |
60 | 43 | // Returns 0 on success, errno otherwise. |
| 44 | +[[gnu::target("pku")]] |
61 | 45 | LIBC_INLINE ErrorOr<int> pkey_set(int pkey, unsigned int access_rights) { |
62 | | - if (pkey < 0 || pkey > internal::MAX_KEY || |
63 | | - access_rights > internal::KEY_MASK) { |
| 46 | + if (pkey < 0 || pkey >= KEY_COUNT || access_rights > KEY_MASK) { |
64 | 47 | return Error(EINVAL); |
65 | 48 | } |
66 | 49 |
|
67 | | - uint32_t pkru = internal::read_prku(); |
68 | | - pkru &= ~(internal::KEY_MASK << (pkey * internal::BITS_PER_KEY)); |
69 | | - pkru |= |
70 | | - ((access_rights & internal::KEY_MASK) << (pkey * internal::BITS_PER_KEY)); |
71 | | - internal::write_prku(pkru); |
| 50 | + uint32_t pkru = _rdpkru_u32(); |
| 51 | + pkru &= ~(KEY_MASK << (pkey * BITS_PER_KEY)); |
| 52 | + pkru |= ((access_rights & KEY_MASK) << (pkey * BITS_PER_KEY)); |
| 53 | + _wrpkru(pkru); |
72 | 54 |
|
73 | 55 | return 0; |
74 | 56 | } |
|
0 commit comments