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