exec_ecoff.c revision 1.13 1 /* $NetBSD: exec_ecoff.c,v 1.13 2000/08/01 04:57:28 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1994 Adam Glass
5 * Copyright (c) 1993, 1994, 1996, 1999 Christopher G. Demetriou
6 * All rights reserved.
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 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Christopher G. Demetriou
19 * for the NetBSD Project.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/malloc.h>
39 #include <sys/vnode.h>
40 #include <sys/exec.h>
41 #include <sys/resourcevar.h>
42
43 #include <sys/exec_ecoff.h>
44
45 /*
46 * exec_ecoff_makecmds(): Check if it's an ecoff-format executable.
47 *
48 * Given a proc pointer and an exec package pointer, see if the referent
49 * of the epp is in ecoff format. Check 'standard' magic numbers for
50 * this architecture. If that fails, return failure.
51 *
52 * This function is responsible for creating a set of vmcmds which can be
53 * used to build the process's vm space and inserting them into the exec
54 * package.
55 */
56 int
57 exec_ecoff_makecmds(struct proc *p, struct exec_package *epp)
58 {
59 int error;
60 struct ecoff_exechdr *execp = epp->ep_hdr;
61
62 if (epp->ep_hdrvalid < ECOFF_HDR_SIZE)
63 return ENOEXEC;
64
65 if (ECOFF_BADMAG(execp))
66 return ENOEXEC;
67
68 error = cpu_exec_ecoff_hook(p, epp);
69
70 /*
71 * if there was an error or there are already vmcmds set up,
72 * we return. (the latter can happen if cpu_exec_ecoff_hook()
73 * recursively invokes check_exec() to handle loading of a
74 * dynamically linked binary's shared loader.
75 */
76 if (error || epp->ep_vmcmds.evs_cnt)
77 return (error);
78
79 /*
80 * prepare the exec package to map the executable.
81 */
82 switch (execp->a.magic) {
83 case ECOFF_OMAGIC:
84 error = exec_ecoff_prep_omagic(p, epp, epp->ep_hdr,
85 epp->ep_vp);
86 break;
87 case ECOFF_NMAGIC:
88 error = exec_ecoff_prep_nmagic(p, epp, epp->ep_hdr,
89 epp->ep_vp);
90 break;
91 case ECOFF_ZMAGIC:
92 error = exec_ecoff_prep_zmagic(p, epp, epp->ep_hdr,
93 epp->ep_vp);
94 break;
95 default:
96 return ENOEXEC;
97 }
98
99 /* set up the stack */
100 if (!error)
101 error = exec_ecoff_setup_stack(p, epp);
102
103 if (error)
104 kill_vmcmds(&epp->ep_vmcmds);
105
106 return error;
107 }
108
109 /*
110 * exec_ecoff_setup_stack(): Set up the stack segment for an ecoff
111 * executable.
112 *
113 * Note that the ep_ssize parameter must be set to be the current stack
114 * limit; this is adjusted in the body of execve() to yield the
115 * appropriate stack segment usage once the argument length is
116 * calculated.
117 *
118 * This function returns an int for uniformity with other (future) formats'
119 * stack setup functions. They might have errors to return.
120 */
121 int
122 exec_ecoff_setup_stack(struct proc *p, struct exec_package *epp)
123 {
124
125 epp->ep_maxsaddr = USRSTACK - MAXSSIZ;
126 epp->ep_minsaddr = USRSTACK;
127 epp->ep_ssize = p->p_rlimit[RLIMIT_STACK].rlim_cur;
128
129 /*
130 * set up commands for stack. note that this takes *two*, one to
131 * map the part of the stack which we can access, and one to map
132 * the part which we can't.
133 *
134 * arguably, it could be made into one, but that would require the
135 * addition of another mapping proc, which is unnecessary
136 *
137 * note that in memory, things assumed to be: 0 ... ep_maxsaddr
138 * <stack> ep_minsaddr
139 */
140 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero,
141 ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr),
142 epp->ep_maxsaddr, NULLVP, 0, VM_PROT_NONE);
143 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize,
144 (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0,
145 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
146
147 return 0;
148 }
149
150 /*
151 * exec_ecoff_prep_omagic(): Prepare a ECOFF OMAGIC binary's exec package
152 */
153 int
154 exec_ecoff_prep_omagic(struct proc *p, struct exec_package *epp,
155 struct ecoff_exechdr *execp, struct vnode *vp)
156 {
157 struct ecoff_aouthdr *eap = &execp->a;
158
159 epp->ep_taddr = ECOFF_SEGMENT_ALIGN(execp, eap->text_start);
160 epp->ep_tsize = eap->tsize;
161 epp->ep_daddr = ECOFF_SEGMENT_ALIGN(execp, eap->data_start);
162 epp->ep_dsize = eap->dsize + eap->bsize;
163 epp->ep_entry = eap->entry;
164
165 /* set up command for text and data segments */
166 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
167 eap->tsize + eap->dsize, epp->ep_taddr, vp,
168 ECOFF_TXTOFF(execp),
169 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
170
171 /* set up command for bss segment */
172 if (eap->bsize > 0)
173 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, eap->bsize,
174 ECOFF_SEGMENT_ALIGN(execp, eap->bss_start), NULLVP, 0,
175 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
176
177 return 0;
178 }
179
180 /*
181 * exec_ecoff_prep_nmagic(): Prepare a 'native' NMAGIC ECOFF binary's exec
182 * package.
183 */
184 int
185 exec_ecoff_prep_nmagic(struct proc *p, struct exec_package *epp,
186 struct ecoff_exechdr *execp, struct vnode *vp)
187 {
188 struct ecoff_aouthdr *eap = &execp->a;
189
190 epp->ep_taddr = ECOFF_SEGMENT_ALIGN(execp, eap->text_start);
191 epp->ep_tsize = eap->tsize;
192 epp->ep_daddr = ECOFF_ROUND(eap->data_start, ECOFF_LDPGSZ);
193 epp->ep_dsize = eap->dsize + eap->bsize;
194 epp->ep_entry = eap->entry;
195
196 /* set up command for text segment */
197 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_tsize,
198 epp->ep_taddr, vp, ECOFF_TXTOFF(execp),
199 VM_PROT_READ|VM_PROT_EXECUTE);
200
201 /* set up command for data segment */
202 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_dsize,
203 epp->ep_daddr, vp, ECOFF_DATOFF(execp),
204 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
205
206 /* set up command for bss segment */
207 if (eap->bsize > 0)
208 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, eap->bsize,
209 ECOFF_SEGMENT_ALIGN(execp, eap->bss_start), NULLVP, 0,
210 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
211
212 return 0;
213 }
214
215 /*
216 * exec_ecoff_prep_zmagic(): Prepare a ECOFF ZMAGIC binary's exec package
217 *
218 * First, set the various offsets/lengths in the exec package.
219 *
220 * Then, mark the text image busy (so it can be demand paged) or error
221 * out if this is not possible. Finally, set up vmcmds for the
222 * text, data, bss, and stack segments.
223 */
224 int
225 exec_ecoff_prep_zmagic(struct proc *p, struct exec_package *epp,
226 struct ecoff_exechdr *execp, struct vnode *vp)
227 {
228 struct ecoff_aouthdr *eap = &execp->a;
229
230 epp->ep_taddr = ECOFF_SEGMENT_ALIGN(execp, eap->text_start);
231 epp->ep_tsize = eap->tsize;
232 epp->ep_daddr = ECOFF_SEGMENT_ALIGN(execp, eap->data_start);
233 epp->ep_dsize = eap->dsize + eap->bsize;
234 epp->ep_entry = eap->entry;
235
236 /*
237 * check if vnode is in open for writing, because we want to
238 * demand-page out of it. if it is, don't do it, for various
239 * reasons
240 */
241 if ((eap->tsize != 0 || eap->dsize != 0) &&
242 vp->v_writecount != 0) {
243 #ifdef DIAGNOSTIC
244 if (vp->v_flag & VTEXT)
245 panic("exec: a VTEXT vnode has writecount != 0\n");
246 #endif
247 return ETXTBSY;
248 }
249 vn_marktext(vp);
250
251 /* set up command for text segment */
252 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, eap->tsize,
253 epp->ep_taddr, vp, ECOFF_TXTOFF(execp),
254 VM_PROT_READ|VM_PROT_EXECUTE);
255
256 /* set up command for data segment */
257 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, eap->dsize,
258 epp->ep_daddr, vp, ECOFF_DATOFF(execp),
259 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
260
261 /* set up command for bss segment */
262 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, eap->bsize,
263 ECOFF_SEGMENT_ALIGN(execp, eap->bss_start), NULLVP, 0,
264 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
265
266 return 0;
267 }
268