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