xref: /freebsd/sys/arm/arm/sys_machdep.c (revision 8826d9047572432b832ff612c07697e931a8bff0)
16fc729afSOlivier Houchard /*-
26fc729afSOlivier Houchard  * Copyright (c) 1990 The Regents of the University of California.
36fc729afSOlivier Houchard  * All rights reserved.
46fc729afSOlivier Houchard  *
56fc729afSOlivier Houchard  * Redistribution and use in source and binary forms, with or without
66fc729afSOlivier Houchard  * modification, are permitted provided that the following conditions
76fc729afSOlivier Houchard  * are met:
86fc729afSOlivier Houchard  * 1. Redistributions of source code must retain the above copyright
96fc729afSOlivier Houchard  *    notice, this list of conditions and the following disclaimer.
106fc729afSOlivier Houchard  * 2. Redistributions in binary form must reproduce the above copyright
116fc729afSOlivier Houchard  *    notice, this list of conditions and the following disclaimer in the
126fc729afSOlivier Houchard  *    documentation and/or other materials provided with the distribution.
13f04f6877SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
146fc729afSOlivier Houchard  *    may be used to endorse or promote products derived from this software
156fc729afSOlivier Houchard  *    without specific prior written permission.
166fc729afSOlivier Houchard  *
176fc729afSOlivier Houchard  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
186fc729afSOlivier Houchard  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
196fc729afSOlivier Houchard  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
206fc729afSOlivier Houchard  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
216fc729afSOlivier Houchard  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
226fc729afSOlivier Houchard  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
236fc729afSOlivier Houchard  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
246fc729afSOlivier Houchard  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
256fc729afSOlivier Houchard  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
266fc729afSOlivier Houchard  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
276fc729afSOlivier Houchard  * SUCH DAMAGE.
286fc729afSOlivier Houchard  *
296fc729afSOlivier Houchard  *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
306fc729afSOlivier Houchard  */
316fc729afSOlivier Houchard 
326fc729afSOlivier Houchard #include <sys/cdefs.h>
336fc729afSOlivier Houchard __FBSDID("$FreeBSD$");
346fc729afSOlivier Houchard 
3524c1c3bfSJonathan Anderson #include "opt_capsicum.h"
3674b5505eSRobert Watson 
376fc729afSOlivier Houchard #include <sys/param.h>
386fc729afSOlivier Houchard #include <sys/systm.h>
394a144410SRobert Watson #include <sys/capsicum.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>
44*8826d904SIan Lepore #include <vm/vm.h>
45*8826d904SIan Lepore #include <vm/vm_extern.h>
466fc729afSOlivier Houchard 
47*8826d904SIan Lepore #include <machine/cpu-v6.h>
48371853e5SOlivier Houchard #include <machine/sysarch.h>
49*8826d904SIan Lepore #include <machine/vmparam.h>
50371853e5SOlivier Houchard 
516fc729afSOlivier Houchard #ifndef _SYS_SYSPROTO_H_
526fc729afSOlivier Houchard struct sysarch_args {
536fc729afSOlivier Houchard 	int op;
546fc729afSOlivier Houchard 	char *parms;
556fc729afSOlivier Houchard };
566fc729afSOlivier Houchard #endif
576fc729afSOlivier Houchard 
58371853e5SOlivier Houchard /* Prototypes */
59371853e5SOlivier Houchard static int arm32_sync_icache (struct thread *, void *);
60371853e5SOlivier Houchard static int arm32_drain_writebuf(struct thread *, void *);
61371853e5SOlivier Houchard 
62*8826d904SIan Lepore #if __ARM_ARCH >= 6
63*8826d904SIan Lepore static int
64*8826d904SIan Lepore sync_icache(uintptr_t addr, size_t len)
65*8826d904SIan Lepore {
66*8826d904SIan Lepore 	size_t size;
67*8826d904SIan Lepore 	vm_offset_t rv;
68*8826d904SIan Lepore 
69*8826d904SIan Lepore 	/*
70*8826d904SIan Lepore 	 * Align starting address to even number because value of "1"
71*8826d904SIan Lepore 	 * is used as return value for success.
72*8826d904SIan Lepore 	 */
73*8826d904SIan Lepore 	len += addr & 1;
74*8826d904SIan Lepore 	addr &= ~1;
75*8826d904SIan Lepore 
76*8826d904SIan Lepore 	/* Break whole range to pages. */
77*8826d904SIan Lepore 	do {
78*8826d904SIan Lepore 		size = PAGE_SIZE - (addr & PAGE_MASK);
79*8826d904SIan Lepore 		size = min(size, len);
80*8826d904SIan Lepore 		rv = dcache_wb_pou_checked(addr, size);
81*8826d904SIan Lepore 		if (rv == 1) /* see dcache_wb_pou_checked() */
82*8826d904SIan Lepore 			rv = icache_inv_pou_checked(addr, size);
83*8826d904SIan Lepore 		if (rv != 1) {
84*8826d904SIan Lepore 			if (!useracc((void *)addr, size, VM_PROT_READ)) {
85*8826d904SIan Lepore 				/* Invalid access */
86*8826d904SIan Lepore 				return (rv);
87*8826d904SIan Lepore 			}
88*8826d904SIan Lepore 			/* Valid but unmapped page - skip it. */
89*8826d904SIan Lepore 		}
90*8826d904SIan Lepore 		len -= size;
91*8826d904SIan Lepore 		addr += size;
92*8826d904SIan Lepore 	} while (len > 0);
93*8826d904SIan Lepore 
94*8826d904SIan Lepore 	/* Invalidate branch predictor buffer. */
95*8826d904SIan Lepore 	bpb_inv_all();
96*8826d904SIan Lepore 	return (1);
97*8826d904SIan Lepore }
98*8826d904SIan Lepore #endif
99*8826d904SIan Lepore 
100371853e5SOlivier Houchard static int
101371853e5SOlivier Houchard arm32_sync_icache(struct thread *td, void *args)
102371853e5SOlivier Houchard {
103371853e5SOlivier Houchard 	struct arm_sync_icache_args ua;
104371853e5SOlivier Houchard 	int error;
105*8826d904SIan Lepore 	ksiginfo_t ksi;
106*8826d904SIan Lepore #if __ARM_ARCH >= 6
107*8826d904SIan Lepore 	vm_offset_t rv;
108*8826d904SIan Lepore #endif
109371853e5SOlivier Houchard 
110371853e5SOlivier Houchard 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
111371853e5SOlivier Houchard 		return (error);
112371853e5SOlivier Houchard 
113*8826d904SIan Lepore 	if  (ua.len == 0) {
114*8826d904SIan Lepore 		td->td_retval[0] = 0;
115*8826d904SIan Lepore 		return (0);
116*8826d904SIan Lepore 	}
117*8826d904SIan Lepore 
118*8826d904SIan Lepore 	/*
119*8826d904SIan Lepore 	 * Validate arguments. Address and length are unsigned,
120*8826d904SIan Lepore 	 * so we can use wrapped overflow check.
121*8826d904SIan Lepore 	 */
122*8826d904SIan Lepore 	if (((ua.addr + ua.len) < ua.addr) ||
123*8826d904SIan Lepore 	    ((ua.addr + ua.len) > VM_MAXUSER_ADDRESS)) {
124*8826d904SIan Lepore 		ksiginfo_init_trap(&ksi);
125*8826d904SIan Lepore 		ksi.ksi_signo = SIGSEGV;
126*8826d904SIan Lepore 		ksi.ksi_code = SEGV_ACCERR;
127*8826d904SIan Lepore 		ksi.ksi_addr = (void *)max(ua.addr, VM_MAXUSER_ADDRESS);
128*8826d904SIan Lepore 		trapsignal(td, &ksi);
129*8826d904SIan Lepore 		return (EINVAL);
130*8826d904SIan Lepore 	}
131*8826d904SIan Lepore 
132*8826d904SIan Lepore #if __ARM_ARCH >= 6
133*8826d904SIan Lepore 	rv = sync_icache(ua.addr, ua.len);
134*8826d904SIan Lepore 	if (rv != 1) {
135*8826d904SIan Lepore 		ksiginfo_init_trap(&ksi);
136*8826d904SIan Lepore 		ksi.ksi_signo = SIGSEGV;
137*8826d904SIan Lepore 		ksi.ksi_code = SEGV_MAPERR;
138*8826d904SIan Lepore 		ksi.ksi_addr = (void *)rv;
139*8826d904SIan Lepore 		trapsignal(td, &ksi);
140*8826d904SIan Lepore 		return (EINVAL);
141*8826d904SIan Lepore 	}
142*8826d904SIan Lepore #else
143371853e5SOlivier Houchard 	cpu_icache_sync_range(ua.addr, ua.len);
144*8826d904SIan Lepore #endif
145371853e5SOlivier Houchard 
146371853e5SOlivier Houchard 	td->td_retval[0] = 0;
147371853e5SOlivier Houchard 	return (0);
148371853e5SOlivier Houchard }
149371853e5SOlivier Houchard 
150371853e5SOlivier Houchard static int
151371853e5SOlivier Houchard arm32_drain_writebuf(struct thread *td, void *args)
152371853e5SOlivier Houchard {
153371853e5SOlivier Houchard 	/* No args. */
154371853e5SOlivier Houchard 
155371853e5SOlivier Houchard 	td->td_retval[0] = 0;
156371853e5SOlivier Houchard 	cpu_drain_writebuf();
157371853e5SOlivier Houchard 	return (0);
158371853e5SOlivier Houchard }
159371853e5SOlivier Houchard 
160a74985cdSOlivier Houchard static int
161a74985cdSOlivier Houchard arm32_set_tp(struct thread *td, void *args)
162a74985cdSOlivier Houchard {
163a74985cdSOlivier Houchard 
164ae5b8077SWarner Losh 	td->td_md.md_tp = (register_t)args;
165cf1a573fSOleksandr Tymoshenko #ifndef ARM_TP_ADDRESS
166cf1a573fSOleksandr Tymoshenko 	set_tls(args);
167cf1a573fSOleksandr Tymoshenko #else
168cf1a573fSOleksandr Tymoshenko 	*(register_t *)ARM_TP_ADDRESS = (register_t)args;
169cf1a573fSOleksandr Tymoshenko #endif
170a74985cdSOlivier Houchard 	return (0);
171a74985cdSOlivier Houchard }
172a74985cdSOlivier Houchard 
173a74985cdSOlivier Houchard static int
174a74985cdSOlivier Houchard arm32_get_tp(struct thread *td, void *args)
175a74985cdSOlivier Houchard {
176a74985cdSOlivier Houchard 
177cf1a573fSOleksandr Tymoshenko #ifndef ARM_TP_ADDRESS
1782647339fSIan Lepore 	td->td_retval[0] = td->td_md.md_tp;
179cf1a573fSOleksandr Tymoshenko #else
180cf1a573fSOleksandr Tymoshenko 	td->td_retval[0] = *(register_t *)ARM_TP_ADDRESS;
181cf1a573fSOleksandr Tymoshenko #endif
182a74985cdSOlivier Houchard 	return (0);
183a74985cdSOlivier Houchard }
184a74985cdSOlivier Houchard 
1856fc729afSOlivier Houchard int
1866fc729afSOlivier Houchard sysarch(td, uap)
1876fc729afSOlivier Houchard 	struct thread *td;
1886fc729afSOlivier Houchard 	register struct sysarch_args *uap;
1896fc729afSOlivier Houchard {
190371853e5SOlivier Houchard 	int error;
191371853e5SOlivier Houchard 
19224c1c3bfSJonathan Anderson #ifdef CAPABILITY_MODE
19374b5505eSRobert Watson 	/*
19412bc222eSJonathan Anderson 	 * When adding new operations, add a new case statement here to
19512bc222eSJonathan Anderson 	 * explicitly indicate whether or not the operation is safe to
19612bc222eSJonathan Anderson 	 * perform in capability mode.
19774b5505eSRobert Watson 	 */
19874b5505eSRobert Watson 	if (IN_CAPABILITY_MODE(td)) {
19974b5505eSRobert Watson 		switch (uap->op) {
20074b5505eSRobert Watson 		case ARM_SYNC_ICACHE:
20174b5505eSRobert Watson 		case ARM_DRAIN_WRITEBUF:
20274b5505eSRobert Watson 		case ARM_SET_TP:
20374b5505eSRobert Watson 		case ARM_GET_TP:
20474b5505eSRobert Watson 			break;
20574b5505eSRobert Watson 
20674b5505eSRobert Watson 		default:
207a417d4a4SDag-Erling Smørgrav #ifdef KTRACE
208a417d4a4SDag-Erling Smørgrav 			if (KTRPOINT(td, KTR_CAPFAIL))
2093fded357SPawel Jakub Dawidek 				ktrcapfail(CAPFAIL_SYSCALL, NULL, NULL);
210a417d4a4SDag-Erling Smørgrav #endif
21174b5505eSRobert Watson 			return (ECAPMODE);
21274b5505eSRobert Watson 		}
21374b5505eSRobert Watson 	}
21474b5505eSRobert Watson #endif
21574b5505eSRobert Watson 
216371853e5SOlivier Houchard 	switch (uap->op) {
217371853e5SOlivier Houchard 	case ARM_SYNC_ICACHE:
218371853e5SOlivier Houchard 		error = arm32_sync_icache(td, uap->parms);
219371853e5SOlivier Houchard 		break;
220371853e5SOlivier Houchard 	case ARM_DRAIN_WRITEBUF:
221371853e5SOlivier Houchard 		error = arm32_drain_writebuf(td, uap->parms);
222371853e5SOlivier Houchard 		break;
223a74985cdSOlivier Houchard 	case ARM_SET_TP:
224a74985cdSOlivier Houchard 		error = arm32_set_tp(td, uap->parms);
225a74985cdSOlivier Houchard 		break;
226a74985cdSOlivier Houchard 	case ARM_GET_TP:
227a74985cdSOlivier Houchard 		error = arm32_get_tp(td, uap->parms);
228a74985cdSOlivier Houchard 		break;
229371853e5SOlivier Houchard 	default:
230371853e5SOlivier Houchard 		error = EINVAL;
231371853e5SOlivier Houchard 		break;
232371853e5SOlivier Houchard 	}
233371853e5SOlivier Houchard 	return (error);
2346fc729afSOlivier Houchard }
235