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