xref: /freebsd/sys/arm/arm/sys_machdep.c (revision 51369649b03ece2aed3eb61b0c8214b9aa5b2fa2)
16fc729afSOlivier Houchard /*-
2*51369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*51369649SPedro 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  *	from: @(#)sys_machdep.c	5.5 (Berkeley) 1/19/91
326fc729afSOlivier Houchard  */
336fc729afSOlivier Houchard 
346fc729afSOlivier Houchard #include <sys/cdefs.h>
356fc729afSOlivier Houchard __FBSDID("$FreeBSD$");
366fc729afSOlivier Houchard 
3724c1c3bfSJonathan Anderson #include "opt_capsicum.h"
3874b5505eSRobert Watson 
396fc729afSOlivier Houchard #include <sys/param.h>
406fc729afSOlivier Houchard #include <sys/systm.h>
414a144410SRobert Watson #include <sys/capsicum.h>
426fc729afSOlivier Houchard #include <sys/proc.h>
436fc729afSOlivier Houchard #include <sys/sysproto.h>
446fc729afSOlivier Houchard #include <sys/syscall.h>
456fc729afSOlivier Houchard #include <sys/sysent.h>
468826d904SIan Lepore #include <vm/vm.h>
478826d904SIan Lepore #include <vm/vm_extern.h>
486fc729afSOlivier Houchard 
493025d19dSMichal Meloun #include <machine/cpu.h>
50371853e5SOlivier Houchard #include <machine/sysarch.h>
51a86d7982SMichal Meloun #include <machine/machdep.h>
528826d904SIan Lepore #include <machine/vmparam.h>
53371853e5SOlivier Houchard 
546fc729afSOlivier Houchard #ifndef _SYS_SYSPROTO_H_
556fc729afSOlivier Houchard struct sysarch_args {
566fc729afSOlivier Houchard 	int op;
576fc729afSOlivier Houchard 	char *parms;
586fc729afSOlivier Houchard };
596fc729afSOlivier Houchard #endif
606fc729afSOlivier Houchard 
61371853e5SOlivier Houchard /* Prototypes */
62371853e5SOlivier Houchard static int arm32_sync_icache (struct thread *, void *);
63371853e5SOlivier Houchard static int arm32_drain_writebuf(struct thread *, void *);
64371853e5SOlivier Houchard 
658826d904SIan Lepore #if __ARM_ARCH >= 6
668826d904SIan Lepore static int
678826d904SIan Lepore sync_icache(uintptr_t addr, size_t len)
688826d904SIan Lepore {
698826d904SIan Lepore 	size_t size;
708826d904SIan Lepore 	vm_offset_t rv;
718826d904SIan Lepore 
728826d904SIan Lepore 	/*
738826d904SIan Lepore 	 * Align starting address to even number because value of "1"
748826d904SIan Lepore 	 * is used as return value for success.
758826d904SIan Lepore 	 */
768826d904SIan Lepore 	len += addr & 1;
778826d904SIan Lepore 	addr &= ~1;
788826d904SIan Lepore 
798826d904SIan Lepore 	/* Break whole range to pages. */
808826d904SIan Lepore 	do {
818826d904SIan Lepore 		size = PAGE_SIZE - (addr & PAGE_MASK);
828826d904SIan Lepore 		size = min(size, len);
838826d904SIan Lepore 		rv = dcache_wb_pou_checked(addr, size);
848826d904SIan Lepore 		if (rv == 1) /* see dcache_wb_pou_checked() */
858826d904SIan Lepore 			rv = icache_inv_pou_checked(addr, size);
868826d904SIan Lepore 		if (rv != 1) {
878826d904SIan Lepore 			if (!useracc((void *)addr, size, VM_PROT_READ)) {
888826d904SIan Lepore 				/* Invalid access */
898826d904SIan Lepore 				return (rv);
908826d904SIan Lepore 			}
918826d904SIan Lepore 			/* Valid but unmapped page - skip it. */
928826d904SIan Lepore 		}
938826d904SIan Lepore 		len -= size;
948826d904SIan Lepore 		addr += size;
958826d904SIan Lepore 	} while (len > 0);
968826d904SIan Lepore 
978826d904SIan Lepore 	/* Invalidate branch predictor buffer. */
988826d904SIan Lepore 	bpb_inv_all();
998826d904SIan Lepore 	return (1);
1008826d904SIan Lepore }
1018826d904SIan Lepore #endif
1028826d904SIan Lepore 
103371853e5SOlivier Houchard static int
104371853e5SOlivier Houchard arm32_sync_icache(struct thread *td, void *args)
105371853e5SOlivier Houchard {
106371853e5SOlivier Houchard 	struct arm_sync_icache_args ua;
107371853e5SOlivier Houchard 	int error;
1088826d904SIan Lepore 	ksiginfo_t ksi;
1098826d904SIan Lepore #if __ARM_ARCH >= 6
1108826d904SIan Lepore 	vm_offset_t rv;
1118826d904SIan Lepore #endif
112371853e5SOlivier Houchard 
113371853e5SOlivier Houchard 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
114371853e5SOlivier Houchard 		return (error);
115371853e5SOlivier Houchard 
1168826d904SIan Lepore 	if  (ua.len == 0) {
1178826d904SIan Lepore 		td->td_retval[0] = 0;
1188826d904SIan Lepore 		return (0);
1198826d904SIan Lepore 	}
1208826d904SIan Lepore 
1218826d904SIan Lepore 	/*
1228826d904SIan Lepore 	 * Validate arguments. Address and length are unsigned,
1238826d904SIan Lepore 	 * so we can use wrapped overflow check.
1248826d904SIan Lepore 	 */
1258826d904SIan Lepore 	if (((ua.addr + ua.len) < ua.addr) ||
1268826d904SIan Lepore 	    ((ua.addr + ua.len) > VM_MAXUSER_ADDRESS)) {
1278826d904SIan Lepore 		ksiginfo_init_trap(&ksi);
1288826d904SIan Lepore 		ksi.ksi_signo = SIGSEGV;
1298826d904SIan Lepore 		ksi.ksi_code = SEGV_ACCERR;
1308826d904SIan Lepore 		ksi.ksi_addr = (void *)max(ua.addr, VM_MAXUSER_ADDRESS);
1318826d904SIan Lepore 		trapsignal(td, &ksi);
1328826d904SIan Lepore 		return (EINVAL);
1338826d904SIan Lepore 	}
1348826d904SIan Lepore 
1358826d904SIan Lepore #if __ARM_ARCH >= 6
1368826d904SIan Lepore 	rv = sync_icache(ua.addr, ua.len);
1378826d904SIan Lepore 	if (rv != 1) {
1388826d904SIan Lepore 		ksiginfo_init_trap(&ksi);
1398826d904SIan Lepore 		ksi.ksi_signo = SIGSEGV;
1408826d904SIan Lepore 		ksi.ksi_code = SEGV_MAPERR;
1418826d904SIan Lepore 		ksi.ksi_addr = (void *)rv;
1428826d904SIan Lepore 		trapsignal(td, &ksi);
1438826d904SIan Lepore 		return (EINVAL);
1448826d904SIan Lepore 	}
1458826d904SIan Lepore #else
146371853e5SOlivier Houchard 	cpu_icache_sync_range(ua.addr, ua.len);
1478826d904SIan Lepore #endif
148371853e5SOlivier Houchard 
149371853e5SOlivier Houchard 	td->td_retval[0] = 0;
150371853e5SOlivier Houchard 	return (0);
151371853e5SOlivier Houchard }
152371853e5SOlivier Houchard 
153371853e5SOlivier Houchard static int
154371853e5SOlivier Houchard arm32_drain_writebuf(struct thread *td, void *args)
155371853e5SOlivier Houchard {
156371853e5SOlivier Houchard 	/* No args. */
157371853e5SOlivier Houchard 
158a89156f5SMichal Meloun #if __ARM_ARCH < 6
159371853e5SOlivier Houchard 	cpu_drain_writebuf();
160a89156f5SMichal Meloun #else
161a89156f5SMichal Meloun 	dsb();
162a89156f5SMichal Meloun 	cpu_l2cache_drain_writebuf();
163a89156f5SMichal Meloun #endif
164a89156f5SMichal Meloun 	td->td_retval[0] = 0;
165371853e5SOlivier Houchard 	return (0);
166371853e5SOlivier Houchard }
167371853e5SOlivier Houchard 
168a74985cdSOlivier Houchard static int
169a74985cdSOlivier Houchard arm32_set_tp(struct thread *td, void *args)
170a74985cdSOlivier Houchard {
171a74985cdSOlivier Houchard 
172173cd467SAndrew Turner #if __ARM_ARCH >= 6
173cf1a573fSOleksandr Tymoshenko 	set_tls(args);
174cf1a573fSOleksandr Tymoshenko #else
175fa878ec3SEd Schouten 	td->td_md.md_tp = (register_t)args;
176cf1a573fSOleksandr Tymoshenko 	*(register_t *)ARM_TP_ADDRESS = (register_t)args;
177cf1a573fSOleksandr Tymoshenko #endif
178a74985cdSOlivier Houchard 	return (0);
179a74985cdSOlivier Houchard }
180a74985cdSOlivier Houchard 
181a74985cdSOlivier Houchard static int
182a74985cdSOlivier Houchard arm32_get_tp(struct thread *td, void *args)
183a74985cdSOlivier Houchard {
184a74985cdSOlivier Houchard 
185173cd467SAndrew Turner #if __ARM_ARCH >= 6
186fa878ec3SEd Schouten 	td->td_retval[0] = (register_t)get_tls();
187cf1a573fSOleksandr Tymoshenko #else
188cf1a573fSOleksandr Tymoshenko 	td->td_retval[0] = *(register_t *)ARM_TP_ADDRESS;
189cf1a573fSOleksandr Tymoshenko #endif
190a74985cdSOlivier Houchard 	return (0);
191a74985cdSOlivier Houchard }
192a74985cdSOlivier Houchard 
1936fc729afSOlivier Houchard int
1943e85b721SEd Maste sysarch(struct thread *td, struct sysarch_args *uap)
1956fc729afSOlivier Houchard {
196371853e5SOlivier Houchard 	int error;
197371853e5SOlivier Houchard 
19824c1c3bfSJonathan Anderson #ifdef CAPABILITY_MODE
19974b5505eSRobert Watson 	/*
20012bc222eSJonathan Anderson 	 * When adding new operations, add a new case statement here to
20112bc222eSJonathan Anderson 	 * explicitly indicate whether or not the operation is safe to
20212bc222eSJonathan Anderson 	 * perform in capability mode.
20374b5505eSRobert Watson 	 */
20474b5505eSRobert Watson 	if (IN_CAPABILITY_MODE(td)) {
20574b5505eSRobert Watson 		switch (uap->op) {
20674b5505eSRobert Watson 		case ARM_SYNC_ICACHE:
20774b5505eSRobert Watson 		case ARM_DRAIN_WRITEBUF:
20874b5505eSRobert Watson 		case ARM_SET_TP:
20974b5505eSRobert Watson 		case ARM_GET_TP:
210a86d7982SMichal Meloun 		case ARM_GET_VFPSTATE:
21174b5505eSRobert Watson 			break;
21274b5505eSRobert Watson 
21374b5505eSRobert Watson 		default:
214a417d4a4SDag-Erling Smørgrav #ifdef KTRACE
215a417d4a4SDag-Erling Smørgrav 			if (KTRPOINT(td, KTR_CAPFAIL))
2163fded357SPawel Jakub Dawidek 				ktrcapfail(CAPFAIL_SYSCALL, NULL, NULL);
217a417d4a4SDag-Erling Smørgrav #endif
21874b5505eSRobert Watson 			return (ECAPMODE);
21974b5505eSRobert Watson 		}
22074b5505eSRobert Watson 	}
22174b5505eSRobert Watson #endif
22274b5505eSRobert Watson 
223371853e5SOlivier Houchard 	switch (uap->op) {
224371853e5SOlivier Houchard 	case ARM_SYNC_ICACHE:
225371853e5SOlivier Houchard 		error = arm32_sync_icache(td, uap->parms);
226371853e5SOlivier Houchard 		break;
227371853e5SOlivier Houchard 	case ARM_DRAIN_WRITEBUF:
228371853e5SOlivier Houchard 		error = arm32_drain_writebuf(td, uap->parms);
229371853e5SOlivier Houchard 		break;
230a74985cdSOlivier Houchard 	case ARM_SET_TP:
231a74985cdSOlivier Houchard 		error = arm32_set_tp(td, uap->parms);
232a74985cdSOlivier Houchard 		break;
233a74985cdSOlivier Houchard 	case ARM_GET_TP:
234a74985cdSOlivier Houchard 		error = arm32_get_tp(td, uap->parms);
235a74985cdSOlivier Houchard 		break;
236a86d7982SMichal Meloun 	case ARM_GET_VFPSTATE:
237a86d7982SMichal Meloun 		error = arm_get_vfpstate(td, uap->parms);
238a86d7982SMichal Meloun 		break;
239371853e5SOlivier Houchard 	default:
240371853e5SOlivier Houchard 		error = EINVAL;
241371853e5SOlivier Houchard 		break;
242371853e5SOlivier Houchard 	}
243371853e5SOlivier Houchard 	return (error);
2446fc729afSOlivier Houchard }
245