16fc729afSOlivier Houchard /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
46fc729afSOlivier Houchard * Copyright (c) 1990 The Regents of the University of California.
56fc729afSOlivier Houchard * All rights reserved.
66fc729afSOlivier Houchard *
76fc729afSOlivier Houchard * Redistribution and use in source and binary forms, with or without
86fc729afSOlivier Houchard * modification, are permitted provided that the following conditions
96fc729afSOlivier Houchard * are met:
106fc729afSOlivier Houchard * 1. Redistributions of source code must retain the above copyright
116fc729afSOlivier Houchard * notice, this list of conditions and the following disclaimer.
126fc729afSOlivier Houchard * 2. Redistributions in binary form must reproduce the above copyright
136fc729afSOlivier Houchard * notice, this list of conditions and the following disclaimer in the
146fc729afSOlivier Houchard * documentation and/or other materials provided with the distribution.
15f04f6877SWarner Losh * 3. Neither the name of the University nor the names of its contributors
166fc729afSOlivier Houchard * may be used to endorse or promote products derived from this software
176fc729afSOlivier Houchard * without specific prior written permission.
186fc729afSOlivier Houchard *
196fc729afSOlivier Houchard * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
206fc729afSOlivier Houchard * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
216fc729afSOlivier Houchard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
226fc729afSOlivier Houchard * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
236fc729afSOlivier Houchard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
246fc729afSOlivier Houchard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
256fc729afSOlivier Houchard * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
266fc729afSOlivier Houchard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
276fc729afSOlivier Houchard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
286fc729afSOlivier Houchard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
296fc729afSOlivier Houchard * SUCH DAMAGE.
306fc729afSOlivier Houchard */
316fc729afSOlivier Houchard
326fc729afSOlivier Houchard #include <sys/cdefs.h>
3324c1c3bfSJonathan Anderson #include "opt_capsicum.h"
3418282c47SMark Johnston #include "opt_ktrace.h"
3574b5505eSRobert Watson
366fc729afSOlivier Houchard #include <sys/param.h>
376fc729afSOlivier Houchard #include <sys/systm.h>
384a144410SRobert Watson #include <sys/capsicum.h>
3918282c47SMark Johnston #include <sys/ktrace.h>
406fc729afSOlivier Houchard #include <sys/proc.h>
416fc729afSOlivier Houchard #include <sys/sysproto.h>
426fc729afSOlivier Houchard #include <sys/syscall.h>
436fc729afSOlivier Houchard #include <sys/sysent.h>
448826d904SIan Lepore #include <vm/vm.h>
458826d904SIan Lepore #include <vm/vm_extern.h>
466fc729afSOlivier Houchard
473025d19dSMichal Meloun #include <machine/cpu.h>
48371853e5SOlivier Houchard #include <machine/sysarch.h>
49a86d7982SMichal Meloun #include <machine/machdep.h>
508826d904SIan Lepore #include <machine/vmparam.h>
51371853e5SOlivier Houchard
526fc729afSOlivier Houchard #ifndef _SYS_SYSPROTO_H_
536fc729afSOlivier Houchard struct sysarch_args {
546fc729afSOlivier Houchard int op;
556fc729afSOlivier Houchard char *parms;
566fc729afSOlivier Houchard };
576fc729afSOlivier Houchard #endif
586fc729afSOlivier Houchard
59371853e5SOlivier Houchard /* Prototypes */
60371853e5SOlivier Houchard static int arm32_sync_icache (struct thread *, void *);
61371853e5SOlivier Houchard static int arm32_drain_writebuf(struct thread *, void *);
62371853e5SOlivier Houchard
638826d904SIan Lepore static int
sync_icache(uintptr_t addr,size_t len)648826d904SIan Lepore sync_icache(uintptr_t addr, size_t len)
658826d904SIan Lepore {
668826d904SIan Lepore size_t size;
678826d904SIan Lepore vm_offset_t rv;
688826d904SIan Lepore
69ec090f4aSMichal Meloun /* Align starting address to cacheline size */
70ec090f4aSMichal Meloun len += addr & cpuinfo.dcache_line_mask;
71ec090f4aSMichal Meloun addr &= ~cpuinfo.dcache_line_mask;
728826d904SIan Lepore
738826d904SIan Lepore /* Break whole range to pages. */
748826d904SIan Lepore do {
758826d904SIan Lepore size = PAGE_SIZE - (addr & PAGE_MASK);
768826d904SIan Lepore size = min(size, len);
778826d904SIan Lepore rv = dcache_wb_pou_checked(addr, size);
788826d904SIan Lepore if (rv == 1) /* see dcache_wb_pou_checked() */
798826d904SIan Lepore rv = icache_inv_pou_checked(addr, size);
808826d904SIan Lepore if (rv != 1) {
818826d904SIan Lepore if (!useracc((void *)addr, size, VM_PROT_READ)) {
828826d904SIan Lepore /* Invalid access */
838826d904SIan Lepore return (rv);
848826d904SIan Lepore }
858826d904SIan Lepore /* Valid but unmapped page - skip it. */
868826d904SIan Lepore }
878826d904SIan Lepore len -= size;
888826d904SIan Lepore addr += size;
898826d904SIan Lepore } while (len > 0);
908826d904SIan Lepore
918826d904SIan Lepore /* Invalidate branch predictor buffer. */
928826d904SIan Lepore bpb_inv_all();
938826d904SIan Lepore return (1);
948826d904SIan Lepore }
958826d904SIan Lepore
96371853e5SOlivier Houchard static int
arm32_sync_icache(struct thread * td,void * args)97371853e5SOlivier Houchard arm32_sync_icache(struct thread *td, void *args)
98371853e5SOlivier Houchard {
99371853e5SOlivier Houchard struct arm_sync_icache_args ua;
100371853e5SOlivier Houchard int error;
1018826d904SIan Lepore ksiginfo_t ksi;
1028826d904SIan Lepore vm_offset_t rv;
103371853e5SOlivier Houchard
104371853e5SOlivier Houchard if ((error = copyin(args, &ua, sizeof(ua))) != 0)
105371853e5SOlivier Houchard return (error);
106371853e5SOlivier Houchard
1078826d904SIan Lepore if (ua.len == 0) {
1088826d904SIan Lepore td->td_retval[0] = 0;
1098826d904SIan Lepore return (0);
1108826d904SIan Lepore }
1118826d904SIan Lepore
1128826d904SIan Lepore /*
1138826d904SIan Lepore * Validate arguments. Address and length are unsigned,
1148826d904SIan Lepore * so we can use wrapped overflow check.
1158826d904SIan Lepore */
1168826d904SIan Lepore if (((ua.addr + ua.len) < ua.addr) ||
1178826d904SIan Lepore ((ua.addr + ua.len) > VM_MAXUSER_ADDRESS)) {
1188826d904SIan Lepore ksiginfo_init_trap(&ksi);
1198826d904SIan Lepore ksi.ksi_signo = SIGSEGV;
1208826d904SIan Lepore ksi.ksi_code = SEGV_ACCERR;
1218826d904SIan Lepore ksi.ksi_addr = (void *)max(ua.addr, VM_MAXUSER_ADDRESS);
1228826d904SIan Lepore trapsignal(td, &ksi);
1238826d904SIan Lepore return (EINVAL);
1248826d904SIan Lepore }
1258826d904SIan Lepore
1268826d904SIan Lepore rv = sync_icache(ua.addr, ua.len);
1278826d904SIan Lepore if (rv != 1) {
1288826d904SIan Lepore ksiginfo_init_trap(&ksi);
1298826d904SIan Lepore ksi.ksi_signo = SIGSEGV;
1308826d904SIan Lepore ksi.ksi_code = SEGV_MAPERR;
1318826d904SIan Lepore ksi.ksi_addr = (void *)rv;
1328826d904SIan Lepore trapsignal(td, &ksi);
1338826d904SIan Lepore return (EINVAL);
1348826d904SIan Lepore }
135371853e5SOlivier Houchard
136371853e5SOlivier Houchard td->td_retval[0] = 0;
137371853e5SOlivier Houchard return (0);
138371853e5SOlivier Houchard }
139371853e5SOlivier Houchard
140371853e5SOlivier Houchard static int
arm32_drain_writebuf(struct thread * td,void * args)141371853e5SOlivier Houchard arm32_drain_writebuf(struct thread *td, void *args)
142371853e5SOlivier Houchard {
143371853e5SOlivier Houchard /* No args. */
144371853e5SOlivier Houchard
145a89156f5SMichal Meloun dsb();
146a89156f5SMichal Meloun cpu_l2cache_drain_writebuf();
147a89156f5SMichal Meloun td->td_retval[0] = 0;
148371853e5SOlivier Houchard return (0);
149371853e5SOlivier Houchard }
150371853e5SOlivier Houchard
151a74985cdSOlivier Houchard static int
arm32_set_tp(struct thread * td,void * args)152a74985cdSOlivier Houchard arm32_set_tp(struct thread *td, void *args)
153a74985cdSOlivier Houchard {
154a74985cdSOlivier Houchard
155cf1a573fSOleksandr Tymoshenko set_tls(args);
156a74985cdSOlivier Houchard return (0);
157a74985cdSOlivier Houchard }
158a74985cdSOlivier Houchard
159a74985cdSOlivier Houchard static int
arm32_get_tp(struct thread * td,void * args)160a74985cdSOlivier Houchard arm32_get_tp(struct thread *td, void *args)
161a74985cdSOlivier Houchard {
162a74985cdSOlivier Houchard
163fa878ec3SEd Schouten td->td_retval[0] = (register_t)get_tls();
164a74985cdSOlivier Houchard return (0);
165a74985cdSOlivier Houchard }
166a74985cdSOlivier Houchard
1676fc729afSOlivier Houchard int
sysarch(struct thread * td,struct sysarch_args * uap)1683e85b721SEd Maste sysarch(struct thread *td, struct sysarch_args *uap)
1696fc729afSOlivier Houchard {
170371853e5SOlivier Houchard int error;
171371853e5SOlivier Houchard
17224c1c3bfSJonathan Anderson #ifdef CAPABILITY_MODE
17374b5505eSRobert Watson /*
17412bc222eSJonathan Anderson * When adding new operations, add a new case statement here to
17512bc222eSJonathan Anderson * explicitly indicate whether or not the operation is safe to
17612bc222eSJonathan Anderson * perform in capability mode.
17774b5505eSRobert Watson */
17874b5505eSRobert Watson switch (uap->op) {
17974b5505eSRobert Watson case ARM_SYNC_ICACHE:
18074b5505eSRobert Watson case ARM_DRAIN_WRITEBUF:
18174b5505eSRobert Watson case ARM_SET_TP:
18274b5505eSRobert Watson case ARM_GET_TP:
183a86d7982SMichal Meloun case ARM_GET_VFPSTATE:
18474b5505eSRobert Watson break;
18574b5505eSRobert Watson
18674b5505eSRobert Watson default:
18705296a0fSJake Freeland if (CAP_TRACING(td))
18805296a0fSJake Freeland ktrcapfail(CAPFAIL_SYSCALL, &uap->op);
18905296a0fSJake Freeland if (IN_CAPABILITY_MODE(td))
19074b5505eSRobert Watson return (ECAPMODE);
19174b5505eSRobert Watson }
19274b5505eSRobert Watson #endif
19374b5505eSRobert Watson
194371853e5SOlivier Houchard switch (uap->op) {
195371853e5SOlivier Houchard case ARM_SYNC_ICACHE:
196371853e5SOlivier Houchard error = arm32_sync_icache(td, uap->parms);
197371853e5SOlivier Houchard break;
198371853e5SOlivier Houchard case ARM_DRAIN_WRITEBUF:
199371853e5SOlivier Houchard error = arm32_drain_writebuf(td, uap->parms);
200371853e5SOlivier Houchard break;
201a74985cdSOlivier Houchard case ARM_SET_TP:
202a74985cdSOlivier Houchard error = arm32_set_tp(td, uap->parms);
203a74985cdSOlivier Houchard break;
204a74985cdSOlivier Houchard case ARM_GET_TP:
205a74985cdSOlivier Houchard error = arm32_get_tp(td, uap->parms);
206a74985cdSOlivier Houchard break;
207a86d7982SMichal Meloun case ARM_GET_VFPSTATE:
208a86d7982SMichal Meloun error = arm_get_vfpstate(td, uap->parms);
209a86d7982SMichal Meloun break;
210371853e5SOlivier Houchard default:
211371853e5SOlivier Houchard error = EINVAL;
212371853e5SOlivier Houchard break;
213371853e5SOlivier Houchard }
214371853e5SOlivier Houchard return (error);
2156fc729afSOlivier Houchard }
216