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