]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/x86/sys/pkru.c
libc: Fix most issues reported by mandoc
[FreeBSD/FreeBSD.git] / lib / libc / x86 / sys / pkru.c
1 /*-
2  * Copyright (c) 2019 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * Portions of this software were developed by Konstantin Belousov
6  * under sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <machine/cpufunc.h>
35 #include <machine/specialreg.h>
36 #include <machine/sysarch.h>
37 #include <x86/ifunc.h>
38 #include <errno.h>
39 #include <string.h>
40
41 #define MAX_PKRU_IDX    0xf
42 #ifdef __i386__
43 #define X86_SET_PKRU    I386_SET_PKRU
44 #define X86_CLEAR_PKRU  I386_CLEAR_PKRU
45 #else
46 #define X86_SET_PKRU    AMD64_SET_PKRU
47 #define X86_CLEAR_PKRU  AMD64_CLEAR_PKRU
48 #endif
49
50 static int
51 x86_pkru_get_perm_unsup(u_int keyidx, int *access, int *modify)
52 {
53
54         errno = EOPNOTSUPP;
55         return (-1);
56 }
57
58 static int
59 x86_pkru_get_perm_hw(u_int keyidx, int *access, int *modify)
60 {
61         uint32_t pkru;
62
63         if (keyidx > MAX_PKRU_IDX) {
64                 errno = EINVAL;
65                 return (-1);
66         }
67         keyidx *= 2;
68         pkru = rdpkru();
69         *access = (pkru & (1 << keyidx)) == 0;
70         *modify = (pkru & (2 << keyidx)) == 0;
71         return (0);
72 }
73
74 DEFINE_UIFUNC(, int, x86_pkru_get_perm, (u_int, int *, int *))
75 {
76
77         return ((cpu_stdext_feature2 & CPUID_STDEXT2_OSPKE) == 0 ?
78             x86_pkru_get_perm_unsup : x86_pkru_get_perm_hw);
79 }
80
81 static int
82 x86_pkru_set_perm_unsup(u_int keyidx, int access, int modify)
83 {
84
85         errno = EOPNOTSUPP;
86         return (-1);
87 }
88
89 static int
90 x86_pkru_set_perm_hw(u_int keyidx, int access, int modify)
91 {
92         uint32_t pkru;
93
94         if (keyidx > MAX_PKRU_IDX) {
95                 errno = EINVAL;
96                 return (-1);
97         }
98         keyidx *= 2;
99         pkru = rdpkru();
100         pkru &= ~(3 << keyidx);
101         if (!access)
102                 pkru |= 1 << keyidx;
103         if (!modify)
104                 pkru |= 2 << keyidx;
105         wrpkru(pkru);
106         return (0);
107 }
108
109 DEFINE_UIFUNC(, int, x86_pkru_set_perm, (u_int, int, int))
110 {
111
112         return ((cpu_stdext_feature2 & CPUID_STDEXT2_OSPKE) == 0 ?
113             x86_pkru_set_perm_unsup : x86_pkru_set_perm_hw);
114 }
115
116 int
117 x86_pkru_protect_range(void *addr, unsigned long len, u_int keyidx, int flags)
118 {
119         struct amd64_set_pkru a64pkru;
120
121         memset(&a64pkru, 0, sizeof(a64pkru));
122         a64pkru.addr = addr;
123         a64pkru.len = len;
124         a64pkru.keyidx = keyidx;
125         a64pkru.flags = flags;
126         return (sysarch(X86_SET_PKRU, &a64pkru));
127 }
128
129 int
130 x86_pkru_unprotect_range(void *addr, unsigned long len)
131 {
132         struct amd64_set_pkru a64pkru;
133
134         memset(&a64pkru, 0, sizeof(a64pkru));
135         a64pkru.addr = addr;
136         a64pkru.len = len;
137         return (sysarch(X86_CLEAR_PKRU, &a64pkru));
138 }