xref: /freebsd/sys/arm/arm/sys_machdep.c (revision f2d48b5e2c3b45850585e4d7aee324fe148afbf2)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include "opt_capsicum.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/capsicum.h>
42 #include <sys/proc.h>
43 #include <sys/sysproto.h>
44 #include <sys/syscall.h>
45 #include <sys/sysent.h>
46 #include <vm/vm.h>
47 #include <vm/vm_extern.h>
48 
49 #include <machine/cpu.h>
50 #include <machine/sysarch.h>
51 #include <machine/machdep.h>
52 #include <machine/vmparam.h>
53 
54 #ifndef _SYS_SYSPROTO_H_
55 struct sysarch_args {
56 	int op;
57 	char *parms;
58 };
59 #endif
60 
61 /* Prototypes */
62 static int arm32_sync_icache (struct thread *, void *);
63 static int arm32_drain_writebuf(struct thread *, void *);
64 
65 static int
66 sync_icache(uintptr_t addr, size_t len)
67 {
68 	size_t size;
69 	vm_offset_t rv;
70 
71 	/*
72 	 * Align starting address to even number because value of "1"
73 	 * is used as return value for success.
74 	 */
75 	len += addr & 1;
76 	addr &= ~1;
77 
78 	/* Break whole range to pages. */
79 	do {
80 		size = PAGE_SIZE - (addr & PAGE_MASK);
81 		size = min(size, len);
82 		rv = dcache_wb_pou_checked(addr, size);
83 		if (rv == 1) /* see dcache_wb_pou_checked() */
84 			rv = icache_inv_pou_checked(addr, size);
85 		if (rv != 1) {
86 			if (!useracc((void *)addr, size, VM_PROT_READ)) {
87 				/* Invalid access */
88 				return (rv);
89 			}
90 			/* Valid but unmapped page - skip it. */
91 		}
92 		len -= size;
93 		addr += size;
94 	} while (len > 0);
95 
96 	/* Invalidate branch predictor buffer. */
97 	bpb_inv_all();
98 	return (1);
99 }
100 
101 static int
102 arm32_sync_icache(struct thread *td, void *args)
103 {
104 	struct arm_sync_icache_args ua;
105 	int error;
106 	ksiginfo_t ksi;
107 	vm_offset_t rv;
108 
109 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
110 		return (error);
111 
112 	if  (ua.len == 0) {
113 		td->td_retval[0] = 0;
114 		return (0);
115 	}
116 
117 	/*
118 	 * Validate arguments. Address and length are unsigned,
119 	 * so we can use wrapped overflow check.
120 	 */
121 	if (((ua.addr + ua.len) < ua.addr) ||
122 	    ((ua.addr + ua.len) > VM_MAXUSER_ADDRESS)) {
123 		ksiginfo_init_trap(&ksi);
124 		ksi.ksi_signo = SIGSEGV;
125 		ksi.ksi_code = SEGV_ACCERR;
126 		ksi.ksi_addr = (void *)max(ua.addr, VM_MAXUSER_ADDRESS);
127 		trapsignal(td, &ksi);
128 		return (EINVAL);
129 	}
130 
131 	rv = sync_icache(ua.addr, ua.len);
132 	if (rv != 1) {
133 		ksiginfo_init_trap(&ksi);
134 		ksi.ksi_signo = SIGSEGV;
135 		ksi.ksi_code = SEGV_MAPERR;
136 		ksi.ksi_addr = (void *)rv;
137 		trapsignal(td, &ksi);
138 		return (EINVAL);
139 	}
140 
141 	td->td_retval[0] = 0;
142 	return (0);
143 }
144 
145 static int
146 arm32_drain_writebuf(struct thread *td, void *args)
147 {
148 	/* No args. */
149 
150 	dsb();
151 	cpu_l2cache_drain_writebuf();
152 	td->td_retval[0] = 0;
153 	return (0);
154 }
155 
156 static int
157 arm32_set_tp(struct thread *td, void *args)
158 {
159 
160 	set_tls(args);
161 	return (0);
162 }
163 
164 static int
165 arm32_get_tp(struct thread *td, void *args)
166 {
167 
168 	td->td_retval[0] = (register_t)get_tls();
169 	return (0);
170 }
171 
172 int
173 sysarch(struct thread *td, struct sysarch_args *uap)
174 {
175 	int error;
176 
177 #ifdef CAPABILITY_MODE
178 	/*
179 	 * When adding new operations, add a new case statement here to
180 	 * explicitly indicate whether or not the operation is safe to
181 	 * perform in capability mode.
182 	 */
183 	if (IN_CAPABILITY_MODE(td)) {
184 		switch (uap->op) {
185 		case ARM_SYNC_ICACHE:
186 		case ARM_DRAIN_WRITEBUF:
187 		case ARM_SET_TP:
188 		case ARM_GET_TP:
189 		case ARM_GET_VFPSTATE:
190 			break;
191 
192 		default:
193 #ifdef KTRACE
194 			if (KTRPOINT(td, KTR_CAPFAIL))
195 				ktrcapfail(CAPFAIL_SYSCALL, NULL, NULL);
196 #endif
197 			return (ECAPMODE);
198 		}
199 	}
200 #endif
201 
202 	switch (uap->op) {
203 	case ARM_SYNC_ICACHE:
204 		error = arm32_sync_icache(td, uap->parms);
205 		break;
206 	case ARM_DRAIN_WRITEBUF:
207 		error = arm32_drain_writebuf(td, uap->parms);
208 		break;
209 	case ARM_SET_TP:
210 		error = arm32_set_tp(td, uap->parms);
211 		break;
212 	case ARM_GET_TP:
213 		error = arm32_get_tp(td, uap->parms);
214 		break;
215 	case ARM_GET_VFPSTATE:
216 		error = arm_get_vfpstate(td, uap->parms);
217 		break;
218 	default:
219 		error = EINVAL;
220 		break;
221 	}
222 	return (error);
223 }
224