1 /*- 2 * Copyright (c) 2014 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Matt Thomas of 3am Software Foundry. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 32 __RCSID("$NetBSD: netbsd32_machdep.c,v 1.3 2017/03/16 16:13:21 chs Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/ucontext.h> 36 37 #include <uvm/uvm_extern.h> 38 39 #include <compat/netbsd32/netbsd32.h> 40 #include <compat/netbsd32/netbsd32_syscallargs.h> 41 42 #include <riscv/locore.h> 43 44 char machine_arch32[] = MACHINE_ARCH32; 45 char machine32[] = MACHINE; 46 47 void 48 netbsd32_setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack) 49 { 50 l->l_proc->p_flag |= PK_32; 51 setregs(l, pack, stack); 52 } 53 54 /* 55 * Start a new LWP 56 */ 57 void 58 startlwp32(void *arg) 59 { 60 ucontext32_t * const uc = arg; 61 int error __diagused; 62 63 error = cpu_setmcontext32(curlwp, &uc->uc_mcontext, uc->uc_flags); 64 KASSERT(error == 0); 65 66 // Even though this is a ucontext32_t, the space allocated was for a 67 // full ucontext_t 68 kmem_free(uc, sizeof(ucontext_t)); 69 userret(curlwp); 70 } 71 72 // We've worked hard to make sure struct reg32 and __gregset32_t are the same. 73 // Ditto for struct fpreg and fregset_t. 74 75 CTASSERT(sizeof(struct reg32) == sizeof(__gregset32_t)); 76 CTASSERT(sizeof(struct fpreg) == sizeof(__fregset_t)); 77 78 void 79 cpu_getmcontext32(struct lwp *l, mcontext32_t *mcp, unsigned int *flags) 80 { 81 const struct trapframe * const tf = l->l_md.md_utf; 82 83 /* Save register context. */ 84 for (size_t i = _X_RA; i <= _X_GP; i++) { 85 mcp->__gregs[i] = tf->tf_reg[i]; 86 } 87 mcp->__gregs[_REG_PC] = tf->tf_pc; 88 89 mcp->__private = (intptr_t)l->l_private; 90 91 *flags |= _UC_CPU | _UC_TLSBASE; 92 93 /* Save floating point register context, if any. */ 94 KASSERT(l == curlwp); 95 if (fpu_valid_p(l)) { 96 /* 97 * If this process is the current FP owner, dump its 98 * context to the PCB first. 99 */ 100 fpu_save(l); 101 102 struct pcb * const pcb = lwp_getpcb(l); 103 *(struct fpreg *)mcp->__fregs = pcb->pcb_fpregs; 104 *flags |= _UC_FPU; 105 } 106 } 107 108 int 109 cpu_mcontext32_validate(struct lwp *l, const mcontext32_t *mcp) 110 { 111 /* 112 * Verify that at least the PC and SP are user addresses. 113 */ 114 if ((int32_t) mcp->__gregs[_REG_PC] < 0 115 || (int32_t) mcp->__gregs[_REG_SP] < 0 116 || (mcp->__gregs[_REG_PC] & 1)) 117 return EINVAL; 118 119 return 0; 120 } 121 122 int 123 cpu_setmcontext32(struct lwp *l, const mcontext32_t *mcp, unsigned int flags) 124 { 125 struct trapframe * const tf = l->l_md.md_utf; 126 struct proc * const p = l->l_proc; 127 const __greg32_t * const gr = mcp->__gregs; 128 int error; 129 130 /* Restore register context, if any. */ 131 if (flags & _UC_CPU) { 132 error = cpu_mcontext32_validate(l, mcp); 133 if (error) 134 return error; 135 136 /* Save register context. */ 137 for (size_t i = _X_RA; i <= _X_GP; i++) { 138 tf->tf_reg[i] = (int32_t)gr[i]; 139 } 140 tf->tf_pc = (int32_t) gr[_REG_PC]; 141 } 142 143 /* Restore the private thread context */ 144 if (flags & _UC_TLSBASE) { 145 lwp_setprivate(l, (void *)(intptr_t)(int32_t)mcp->__private); 146 } 147 148 /* Restore floating point register context, if any. */ 149 if (flags & _UC_FPU) { 150 KASSERT(l == curlwp); 151 /* Tell PCU we are replacing the FPU contents. */ 152 fpu_replace(l); 153 154 /* 155 * The PCB FP regs struct includes the FP CSR, so use the 156 * proper size of fpreg when copying. 157 */ 158 struct pcb * const pcb = lwp_getpcb(l); 159 pcb->pcb_fpregs = *(const struct fpreg *)mcp->__fregs; 160 } 161 162 mutex_enter(p->p_lock); 163 if (flags & _UC_SETSTACK) 164 l->l_sigstk.ss_flags |= SS_ONSTACK; 165 if (flags & _UC_CLRSTACK) 166 l->l_sigstk.ss_flags &= ~SS_ONSTACK; 167 mutex_exit(p->p_lock); 168 169 return (0); 170 } 171 172 int 173 netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap, 174 register_t *retval) 175 { 176 return ENOSYS; 177 } 178 179 vaddr_t 180 netbsd32_vm_default_addr(struct proc *p, vaddr_t base, vsize_t size, 181 int topdown) 182 { 183 if (topdown) 184 return VM_DEFAULT_ADDRESS32_TOPDOWN(base, size); 185 else 186 return VM_DEFAULT_ADDRESS32_BOTTOMUP(base, size); 187 } 188