xref: /netbsd/sys/arch/mips/mips/cpu_exec.c (revision bf9ec67e)
1 /*	$NetBSD: cpu_exec.c,v 1.32 2002/03/06 00:22:09 simonb Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by Ralph
8  * Campbell.
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)machdep.c	8.3 (Berkeley) 1/12/94
39  */
40 
41 #include "opt_compat_netbsd.h"
42 #include "opt_compat_ultrix.h"
43 #include "opt_execfmt.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/proc.h>
48 #include <sys/malloc.h>
49 #include <sys/vnode.h>
50 #include <sys/exec.h>
51 #include <sys/resourcevar.h>
52 
53 #include <uvm/uvm_extern.h>
54 
55 #ifdef EXEC_ECOFF
56 #include <sys/exec_ecoff.h>
57 #endif
58 #include <sys/exec_elf.h>			/* mandatory */
59 #ifdef COMPAT_09
60 #include <machine/bsd-aout.h>
61 #endif
62 #include <machine/reg.h>
63 #include <mips/regnum.h>			/* symbolic register indices */
64 
65 int	mips_elf_makecmds(struct proc *, struct exec_package *);
66 
67 
68 /*
69  * cpu_exec_aout_makecmds():
70  *	cpu-dependent a.out format hook for execve().
71  *
72  * Determine of the given exec package refers to something which we
73  * understand and, if so, set up the vmcmds for it.
74  *
75  */
76 int
77 cpu_exec_aout_makecmds(p, epp)
78 	struct proc *p;
79 	struct exec_package *epp;
80 {
81 	int error;
82 
83 	/* If COMPAT_09 is defined, allow loading of old-style 4.4bsd a.out
84 	   executables. */
85 #ifdef COMPAT_09
86 	struct bsd_aouthdr *hdr = (struct bsd_aouthdr *)epp->ep_hdr;
87 
88 	/* Only handle paged files (laziness). */
89 	if (hdr->a_magic != BSD_ZMAGIC)
90 #endif
91 	{
92 		/* If that failed, try old NetBSD-1.1 elf format */
93 		error = mips_elf_makecmds (p, epp);
94 		return error;
95 	}
96 
97 
98 
99 #ifdef COMPAT_09
100 	epp->ep_taddr = 0x1000;
101 	epp->ep_entry = hdr->a_entry;
102 	epp->ep_tsize = hdr->a_text;
103 	epp->ep_daddr = epp->ep_taddr + hdr->a_text;
104 	epp->ep_dsize = hdr->a_data + hdr->a_bss;
105 
106 	/*
107 	 * check if vnode is in open for writing, because we want to
108 	 * demand-page out of it.  if it is, don't do it, for various
109 	 * reasons
110 	 */
111 	if ((hdr->a_text != 0 || hdr->a_data != 0)
112 	    && epp->ep_vp->v_writecount != 0) {
113 #ifdef DIAGNOSTIC
114 		if (epp->ep_vp->v_flag & VTEXT)
115 			panic("exec: a VTEXT vnode has writecount != 0\n");
116 #endif
117 		return ETXTBSY;
118 	}
119 	epp->ep_vp->v_flag |= VTEXT;
120 
121 	/* set up command for text segment */
122 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, hdr->a_text,
123 	    epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE);
124 
125 	/* set up command for data segment */
126 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, hdr->a_data,
127 	    epp->ep_daddr, epp->ep_vp, hdr->a_text,
128 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
129 
130 	/* set up command for bss segment */
131 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, hdr->a_bss,
132 	    epp->ep_daddr + hdr->a_data, NULLVP, 0,
133 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
134 
135 	return exec_aout_setup_stack(p, epp);
136 #endif
137 }
138 
139 #ifdef EXEC_ECOFF
140 void
141 cpu_exec_ecoff_setregs(p, epp, stack)
142 	struct proc *p;
143 	struct exec_package *epp;
144 	u_long stack;
145 {
146 	struct ecoff_exechdr *execp = (struct ecoff_exechdr *)epp->ep_hdr;
147 	struct frame *f = (struct frame *)p->p_md.md_regs;
148 
149 	f->f_regs[GP] = (register_t)execp->a.gp_value;
150 }
151 
152 /*
153  * cpu_exec_ecoff_probe()
154  *	cpu-dependent ECOFF format hook for execve().
155  *
156  * Do any machine-dependent diddling of the exec package when doing ECOFF.
157  */
158 int
159 cpu_exec_ecoff_probe(p, epp)
160 	struct proc *p;
161 	struct exec_package *epp;
162 {
163 
164 	/* NetBSD/mips does not have native ECOFF binaries. */
165 	return ENOEXEC;
166 }
167 #endif /* EXEC_ECOFF */
168 
169 /*
170  * mips_elf_makecmds (p, epp)
171  *
172  * Test if an executable is a MIPS ELF executable.   If it is,
173  * try to load it.
174  */
175 
176 int
177 mips_elf_makecmds (p, epp)
178         struct proc *p;
179         struct exec_package *epp;
180 {
181 	Elf32_Ehdr *ex = (Elf32_Ehdr *)epp->ep_hdr;
182 	Elf32_Phdr ph;
183 	int i, error;
184 	size_t resid;
185 
186 	/* Make sure we got enough data to check magic numbers... */
187 	if (epp->ep_hdrvalid < sizeof (Elf32_Ehdr)) {
188 #ifdef DIAGNOSTIC
189 		if (epp->ep_hdrlen < sizeof (Elf32_Ehdr))
190 			printf ("mips_elf_makecmds: execsw hdrsize too short!\n");
191 #endif
192 	    return ENOEXEC;
193 	}
194 
195 	/* See if it's got the basic elf magic number leadin... */
196 	if (memcmp(ex->e_ident, ELFMAG, SELFMAG) != 0) {
197 		return ENOEXEC;
198 	}
199 
200 	/* XXX: Check other magic numbers here. */
201 	if (ex->e_ident[EI_CLASS] != ELFCLASS32) {
202 		return ENOEXEC;
203 	}
204 
205 		/* See if we got any program header information... */
206 	if (!ex->e_phoff || !ex->e_phnum) {
207 		return ENOEXEC;
208 	}
209 
210 	/* Set the entry point... */
211 	epp->ep_entry = ex->e_entry;
212 
213 	/*
214 	 * Check if vnode is open for writing, because we want to
215 	 * demand-page out of it.  If it is, don't do it.
216 	 */
217 	if (epp->ep_vp->v_writecount != 0) {
218 #ifdef DIAGNOSTIC
219 		if (epp->ep_vp->v_flag & VTEXT)
220 			panic("exec: a VTEXT vnode has writecount != 0\n");
221 #endif
222 		return ETXTBSY;
223 	}
224 	epp->ep_vp->v_flag |= VTEXT;
225 
226 	epp->ep_taddr = 0;
227 	epp->ep_tsize = 0;
228 	epp->ep_daddr = 0;
229 	epp->ep_dsize = 0;
230 
231 	for (i = 0; i < ex->e_phnum; i++) {
232 #ifdef DEBUG
233 		/*printf("obsolete elf: mapping %x %x %x\n", resid);*/
234 #endif
235 		if ((error = vn_rdwr(UIO_READ, epp->ep_vp, (caddr_t)&ph,
236 				    sizeof ph, ex->e_phoff + i * sizeof ph,
237 				    UIO_SYSSPACE, IO_NODELOCKED,
238 				    p->p_ucred, &resid, p))
239 		    != 0)
240 			return error;
241 
242 		if (resid != 0) {
243 			return ENOEXEC;
244 		}
245 
246 		/* We only care about loadable sections... */
247 		if (ph.p_type == PT_LOAD) {
248 			int prot = VM_PROT_READ | VM_PROT_EXECUTE;
249 			int residue;
250 			unsigned vaddr, offset, length;
251 
252 			vaddr = ph.p_vaddr;
253 			offset = ph.p_offset;
254 			length = ph.p_filesz;
255 			residue = ph.p_memsz - ph.p_filesz;
256 
257 			if (ph.p_flags & PF_W) {
258 				prot |= VM_PROT_WRITE;
259 				if (!epp->ep_daddr || vaddr < epp->ep_daddr)
260 					epp->ep_daddr = vaddr;
261 				epp->ep_dsize += ph.p_memsz;
262 				/* Read the data from the file... */
263 				NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
264 					  length, vaddr,
265 					  epp->ep_vp, offset, prot);
266 #ifdef OLD_ELF_DEBUG
267 /*XXX*/		printf(
268 	"obsolete elf: NEW_VNCMD len %x va %x off %x prot %x residue %x\n",
269 			length, vaddr, offset, prot, residue);
270 #endif /*ELF_DEBUG*/
271 
272 				if (residue) {
273 					vaddr &= ~(NBPG - 1);
274 					offset &= ~(NBPG - 1);
275 					length = roundup (length + ph.p_vaddr
276 							  - vaddr, NBPG);
277 					residue = (ph.p_vaddr + ph.p_memsz)
278 						  - (vaddr + length);
279 				}
280 			} else {
281 				vaddr &= ~(NBPG - 1);
282 				offset &= ~(NBPG - 1);
283 				length = roundup (length + ph.p_vaddr - vaddr,
284 						  NBPG);
285 				residue = (ph.p_vaddr + ph.p_memsz)
286 					  - (vaddr + length);
287 				if (!epp->ep_taddr || vaddr < epp->ep_taddr)
288 					epp->ep_taddr = vaddr;
289 				epp->ep_tsize += ph.p_memsz;
290 				/* Map the data from the file... */
291 				NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn,
292 					  length, vaddr,
293 					  epp->ep_vp, offset, prot);
294 			}
295 			/* If part of the segment is just zeros (e.g., bss),
296 			   map that. */
297 			if (residue > 0) {
298 #ifdef OLD_ELF_DEBUG
299 /*XXX*/			printf(
300 	"old elf:resid NEW_VNCMD len %x va %x off %x prot %x residue %x\n",
301 				length, vaddr + length, offset, prot, residue);
302 #endif /*ELF_DEBUG*/
303 
304 				NEW_VMCMD (&epp->ep_vmcmds, vmcmd_map_zero,
305 					   residue, vaddr + length,
306 					   NULLVP, 0, prot);
307 			}
308 		}
309 	}
310 
311 	epp->ep_maxsaddr = USRSTACK - MAXSSIZ;
312 	epp->ep_minsaddr = USRSTACK;
313 	epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur;
314 
315 	/*
316 	 * set up commands for stack.  note that this takes *two*, one to
317 	 * map the part of the stack which we can access, and one to map
318 	 * the part which we can't.
319 	 *
320 	 * arguably, it could be made into one, but that would require the
321 	 * addition of another mapping proc, which is unnecessary
322 	 *
323 	 * note that in memory, things assumed to be: 0 ....... ep_maxsaddr
324 	 * <stack> ep_minsaddr
325 	 */
326 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
327 	    ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr),
328 	    epp->ep_maxsaddr, NULLVP, 0, VM_PROT_NONE);
329 	NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize,
330 	    (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0,
331 	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
332 
333 	return 0;
334 }
335