1*1d577fe3Spgoyette /* $NetBSD: m68k4k_exec.c,v 1.25 2019/11/20 19:37:53 pgoyette Exp $ */
2c9bf6a7eSthorpej
3c9bf6a7eSthorpej /*
4c9bf6a7eSthorpej * Copyright (c) 1993, 1994 Christopher G. Demetriou
5c9bf6a7eSthorpej * All rights reserved.
6c9bf6a7eSthorpej *
7c9bf6a7eSthorpej * Redistribution and use in source and binary forms, with or without
8c9bf6a7eSthorpej * modification, are permitted provided that the following conditions
9c9bf6a7eSthorpej * are met:
10c9bf6a7eSthorpej * 1. Redistributions of source code must retain the above copyright
11c9bf6a7eSthorpej * notice, this list of conditions and the following disclaimer.
12c9bf6a7eSthorpej * 2. Redistributions in binary form must reproduce the above copyright
13c9bf6a7eSthorpej * notice, this list of conditions and the following disclaimer in the
14c9bf6a7eSthorpej * documentation and/or other materials provided with the distribution.
15c9bf6a7eSthorpej * 3. All advertising materials mentioning features or use of this software
16c9bf6a7eSthorpej * must display the following acknowledgement:
17c9bf6a7eSthorpej * This product includes software developed by Christopher G. Demetriou.
18c9bf6a7eSthorpej * 4. The name of the author may not be used to endorse or promote products
19c9bf6a7eSthorpej * derived from this software without specific prior written permission
20c9bf6a7eSthorpej *
21c9bf6a7eSthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22c9bf6a7eSthorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23c9bf6a7eSthorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24c9bf6a7eSthorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25c9bf6a7eSthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26c9bf6a7eSthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27c9bf6a7eSthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28c9bf6a7eSthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29c9bf6a7eSthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30c9bf6a7eSthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31c9bf6a7eSthorpej */
32c9bf6a7eSthorpej
33c9bf6a7eSthorpej /*
34c9bf6a7eSthorpej * Exec glue to provide compatibility with older NetBSD m68k4k exectuables.
35c9bf6a7eSthorpej *
36c9bf6a7eSthorpej * Taken directly from kern/exec_aout.c and frobbed to map text and
37c9bf6a7eSthorpej * data as m68k4k executables expect.
38c9bf6a7eSthorpej *
39f4a068d5Sthorpej * This module only works on machines with PAGE_SIZE == 4096. It's not clear
40c9bf6a7eSthorpej * that making it work on other machines is worth the trouble.
41c9bf6a7eSthorpej */
42c9bf6a7eSthorpej
43dab6ef8bSlukem #include <sys/cdefs.h>
44*1d577fe3Spgoyette __KERNEL_RCSID(0, "$NetBSD: m68k4k_exec.c,v 1.25 2019/11/20 19:37:53 pgoyette Exp $");
45dab6ef8bSlukem
46c9bf6a7eSthorpej #if !defined(__m68k__)
47c9bf6a7eSthorpej #error YOU GOTTA BE KIDDING!
48c9bf6a7eSthorpej #endif
49c9bf6a7eSthorpej
50c9bf6a7eSthorpej #include <sys/param.h>
51c9bf6a7eSthorpej #include <sys/systm.h>
52c9bf6a7eSthorpej #include <sys/proc.h>
53c9bf6a7eSthorpej #include <sys/malloc.h>
542df25715She #include <sys/module.h>
55c9bf6a7eSthorpej #include <sys/vnode.h>
56c9bf6a7eSthorpej #include <sys/exec.h>
57ea28690bScegger #include <sys/exec_aout.h>
58c9bf6a7eSthorpej #include <sys/resourcevar.h>
59c9bf6a7eSthorpej
60c9bf6a7eSthorpej #include <compat/m68k4k/m68k4k_exec.h>
61c9bf6a7eSthorpej
62*1d577fe3Spgoyette MODULE(MODULE_CLASS_EXEC, exec_m68k4k, NULL);
6392ce8c6aSad
6454b7adb1Schristos static struct execsw exec_m68k4k_execsw = {
6554b7adb1Schristos .es_hdrsz = sizeof(struct exec),
6654b7adb1Schristos .es_makecmds = exec_m68k4k_makecmds,
6754b7adb1Schristos .u = {
6854b7adb1Schristos .elf_probe_func = NULL,
6954b7adb1Schristos },
7054b7adb1Schristos .es_emul = &emul_netbsd,
7154b7adb1Schristos .es_prio = EXECSW_PRIO_ANY,
7254b7adb1Schristos .es_arglen = 0,
7354b7adb1Schristos .es_copyargs = copyargs,
7454b7adb1Schristos .es_setregs = NULL,
7554b7adb1Schristos .es_coredump = coredump_netbsd,
7654b7adb1Schristos .es_setup_stack = exec_setup_stack,
7792ce8c6aSad };
7892ce8c6aSad
7992ce8c6aSad static int
exec_m68k4k_modcmd(modcmd_t cmd,void * arg)8092ce8c6aSad exec_m68k4k_modcmd(modcmd_t cmd, void *arg)
8192ce8c6aSad {
8292ce8c6aSad
8392ce8c6aSad switch (cmd) {
8492ce8c6aSad case MODULE_CMD_INIT:
8554b7adb1Schristos return exec_add(&exec_m68k4k_execsw, 1);
8692ce8c6aSad
8792ce8c6aSad case MODULE_CMD_FINI:
8854b7adb1Schristos return exec_remove(&exec_m68k4k_execsw, 1);
8992ce8c6aSad
9092ce8c6aSad default:
9192ce8c6aSad return ENOTTY;
9292ce8c6aSad }
9392ce8c6aSad }
9492ce8c6aSad
95f2af9174Sdsl int exec_m68k4k_prep_zmagic(struct lwp *, struct exec_package *);
96f2af9174Sdsl int exec_m68k4k_prep_nmagic(struct lwp *, struct exec_package *);
97f2af9174Sdsl int exec_m68k4k_prep_omagic(struct lwp *, struct exec_package *);
98c9bf6a7eSthorpej
99c9bf6a7eSthorpej /*
100c9bf6a7eSthorpej * exec_m68k4k_makecmds(): Check if it's an a.out-format executable
101c9bf6a7eSthorpej * with an m68k4k magic number.
102c9bf6a7eSthorpej *
103c9bf6a7eSthorpej * Given a proc pointer and an exec package pointer, see if the referent
104c9bf6a7eSthorpej * of the epp is in a.out format. Just check 'standard' magic numbers for
105c9bf6a7eSthorpej * this architecture.
106c9bf6a7eSthorpej *
107c9bf6a7eSthorpej * This function, in the former case, or the hook, in the latter, is
108c9bf6a7eSthorpej * responsible for creating a set of vmcmds which can be used to build
109c9bf6a7eSthorpej * the process's vm space and inserting them into the exec package.
110c9bf6a7eSthorpej */
111c9bf6a7eSthorpej
112c9bf6a7eSthorpej int
exec_m68k4k_makecmds(struct lwp * l,struct exec_package * epp)11328bae79bSdsl exec_m68k4k_makecmds(struct lwp *l, struct exec_package *epp)
114c9bf6a7eSthorpej {
115c9bf6a7eSthorpej u_long midmag, magic;
116c9bf6a7eSthorpej u_short mid;
117c9bf6a7eSthorpej int error;
118c9bf6a7eSthorpej struct exec *execp = epp->ep_hdr;
119c9bf6a7eSthorpej
120c9bf6a7eSthorpej /* See note above... */
121f4a068d5Sthorpej if (M68K4K_LDPGSZ != PAGE_SIZE)
122c9bf6a7eSthorpej return ENOEXEC;
123c9bf6a7eSthorpej
124c9bf6a7eSthorpej if (epp->ep_hdrvalid < sizeof(struct exec))
125c9bf6a7eSthorpej return ENOEXEC;
126c9bf6a7eSthorpej
127c9bf6a7eSthorpej midmag = ntohl(execp->a_midmag);
128c9bf6a7eSthorpej mid = (midmag >> 16) & 0x3ff;
129c9bf6a7eSthorpej magic = midmag & 0xffff;
130c9bf6a7eSthorpej
131c9bf6a7eSthorpej midmag = mid << 16 | magic;
132c9bf6a7eSthorpej
133c9bf6a7eSthorpej switch (midmag) {
134c9bf6a7eSthorpej case (MID_M68K4K << 16) | ZMAGIC:
13595e1ffb1Schristos error = exec_m68k4k_prep_zmagic(l, epp);
136c9bf6a7eSthorpej break;
137c9bf6a7eSthorpej case (MID_M68K4K << 16) | NMAGIC:
13895e1ffb1Schristos error = exec_m68k4k_prep_nmagic(l, epp);
139c9bf6a7eSthorpej break;
140c9bf6a7eSthorpej case (MID_M68K4K << 16) | OMAGIC:
14195e1ffb1Schristos error = exec_m68k4k_prep_omagic(l, epp);
142c9bf6a7eSthorpej break;
143c9bf6a7eSthorpej default:
144c9bf6a7eSthorpej error = ENOEXEC;
145c9bf6a7eSthorpej }
146c9bf6a7eSthorpej
147c9bf6a7eSthorpej if (error)
148c9bf6a7eSthorpej kill_vmcmds(&epp->ep_vmcmds);
149c9bf6a7eSthorpej
150c9bf6a7eSthorpej return error;
151c9bf6a7eSthorpej }
152c9bf6a7eSthorpej
153c9bf6a7eSthorpej /*
154c9bf6a7eSthorpej * exec_m68k4k_prep_zmagic(): Prepare an m68k4k ZMAGIC binary's exec package
155c9bf6a7eSthorpej *
156c9bf6a7eSthorpej * First, set of the various offsets/lengths in the exec package.
157c9bf6a7eSthorpej *
158c9bf6a7eSthorpej * Then, mark the text image busy (so it can be demand paged) or error
159c9bf6a7eSthorpej * out if this is not possible. Finally, set up vmcmds for the
160c9bf6a7eSthorpej * text, data, bss, and stack segments.
161c9bf6a7eSthorpej */
162c9bf6a7eSthorpej
163c9bf6a7eSthorpej int
exec_m68k4k_prep_zmagic(struct lwp * l,struct exec_package * epp)16428bae79bSdsl exec_m68k4k_prep_zmagic(struct lwp *l, struct exec_package *epp)
165c9bf6a7eSthorpej {
166c9bf6a7eSthorpej struct exec *execp = epp->ep_hdr;
167993948e9Schs int error;
168c9bf6a7eSthorpej
169c9bf6a7eSthorpej epp->ep_taddr = M68K4K_USRTEXT;
170c9bf6a7eSthorpej epp->ep_tsize = execp->a_text;
171c9bf6a7eSthorpej epp->ep_daddr = epp->ep_taddr + execp->a_text;
172c9bf6a7eSthorpej epp->ep_dsize = execp->a_data + execp->a_bss;
173c9bf6a7eSthorpej epp->ep_entry = execp->a_entry;
174c9bf6a7eSthorpej
175993948e9Schs error = vn_marktext(epp->ep_vp);
176993948e9Schs if (error)
177993948e9Schs return (error);
178c9bf6a7eSthorpej
179c9bf6a7eSthorpej /* set up command for text segment */
180c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_text,
181c9bf6a7eSthorpej epp->ep_taddr, epp->ep_vp, 0, VM_PROT_READ|VM_PROT_EXECUTE);
182c9bf6a7eSthorpej
183c9bf6a7eSthorpej /* set up command for data segment */
184c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, execp->a_data,
185c9bf6a7eSthorpej epp->ep_daddr, epp->ep_vp, execp->a_text,
186c9bf6a7eSthorpej VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
187c9bf6a7eSthorpej
188c9bf6a7eSthorpej /* set up command for bss segment */
1890b71a2d5Schristos if (execp->a_bss)
190c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, execp->a_bss,
191c9bf6a7eSthorpej epp->ep_daddr + execp->a_data, NULLVP, 0,
192c9bf6a7eSthorpej VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
193c9bf6a7eSthorpej
19495e1ffb1Schristos return (*epp->ep_esch->es_setup_stack)(l, epp);
195c9bf6a7eSthorpej }
196c9bf6a7eSthorpej
197c9bf6a7eSthorpej /*
198c9bf6a7eSthorpej * exec_m68k4k_prep_nmagic(): Prepare a m68k4k NMAGIC binary's exec package
199c9bf6a7eSthorpej */
200c9bf6a7eSthorpej
201c9bf6a7eSthorpej int
exec_m68k4k_prep_nmagic(struct lwp * l,struct exec_package * epp)20228bae79bSdsl exec_m68k4k_prep_nmagic(struct lwp *l, struct exec_package *epp)
203c9bf6a7eSthorpej {
204c9bf6a7eSthorpej struct exec *execp = epp->ep_hdr;
205c9bf6a7eSthorpej long bsize, baddr;
206c9bf6a7eSthorpej
207c9bf6a7eSthorpej epp->ep_taddr = M68K4K_USRTEXT;
208c9bf6a7eSthorpej epp->ep_tsize = execp->a_text;
209c9bf6a7eSthorpej epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text,
210c9bf6a7eSthorpej M68K4K_LDPGSZ);
211c9bf6a7eSthorpej epp->ep_dsize = execp->a_data + execp->a_bss;
212c9bf6a7eSthorpej epp->ep_entry = execp->a_entry;
213c9bf6a7eSthorpej
214c9bf6a7eSthorpej /* set up command for text segment */
215c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_text,
216c9bf6a7eSthorpej epp->ep_taddr, epp->ep_vp, sizeof(struct exec),
217c9bf6a7eSthorpej VM_PROT_READ|VM_PROT_EXECUTE);
218c9bf6a7eSthorpej
219c9bf6a7eSthorpej /* set up command for data segment */
220c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, execp->a_data,
221c9bf6a7eSthorpej epp->ep_daddr, epp->ep_vp, execp->a_text + sizeof(struct exec),
222c9bf6a7eSthorpej VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
223c9bf6a7eSthorpej
224c9bf6a7eSthorpej /* set up command for bss segment */
225f4a068d5Sthorpej baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
226c9bf6a7eSthorpej bsize = epp->ep_daddr + epp->ep_dsize - baddr;
227c9bf6a7eSthorpej if (bsize > 0)
228c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
229c9bf6a7eSthorpej NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
230c9bf6a7eSthorpej
23195e1ffb1Schristos return (*epp->ep_esch->es_setup_stack)(l, epp);
232c9bf6a7eSthorpej }
233c9bf6a7eSthorpej
234c9bf6a7eSthorpej /*
235c9bf6a7eSthorpej * exec_m68k4k_prep_omagic(): Prepare a m68k4k OMAGIC binary's exec package
236c9bf6a7eSthorpej */
237c9bf6a7eSthorpej
238c9bf6a7eSthorpej int
exec_m68k4k_prep_omagic(struct lwp * l,struct exec_package * epp)23928bae79bSdsl exec_m68k4k_prep_omagic(struct lwp *l, struct exec_package *epp)
240c9bf6a7eSthorpej {
241c9bf6a7eSthorpej struct exec *execp = epp->ep_hdr;
242c9bf6a7eSthorpej long dsize, bsize, baddr;
243c9bf6a7eSthorpej
244c9bf6a7eSthorpej epp->ep_taddr = M68K4K_USRTEXT;
245c9bf6a7eSthorpej epp->ep_tsize = execp->a_text;
246c9bf6a7eSthorpej epp->ep_daddr = epp->ep_taddr + execp->a_text;
247c9bf6a7eSthorpej epp->ep_dsize = execp->a_data + execp->a_bss;
248c9bf6a7eSthorpej epp->ep_entry = execp->a_entry;
249c9bf6a7eSthorpej
250c9bf6a7eSthorpej /* set up command for text and data segments */
251c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn,
252c9bf6a7eSthorpej execp->a_text + execp->a_data, epp->ep_taddr, epp->ep_vp,
253c9bf6a7eSthorpej sizeof(struct exec), VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
254c9bf6a7eSthorpej
255c9bf6a7eSthorpej /* set up command for bss segment */
256f4a068d5Sthorpej baddr = roundup(epp->ep_daddr + execp->a_data, PAGE_SIZE);
257c9bf6a7eSthorpej bsize = epp->ep_daddr + epp->ep_dsize - baddr;
258c9bf6a7eSthorpej if (bsize > 0)
259c9bf6a7eSthorpej NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, bsize, baddr,
260c9bf6a7eSthorpej NULLVP, 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
261c9bf6a7eSthorpej
262c9bf6a7eSthorpej /*
263c9bf6a7eSthorpej * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
264c9bf6a7eSthorpej * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
265c9bf6a7eSthorpej * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
266c9bf6a7eSthorpej * respectively to page boundaries.
267c9bf6a7eSthorpej * Compensate `ep_dsize' for the amount of data covered by the last
268c9bf6a7eSthorpej * text page.
269c9bf6a7eSthorpej */
270f4a068d5Sthorpej dsize = epp->ep_dsize + execp->a_text - roundup(execp->a_text,
271f4a068d5Sthorpej PAGE_SIZE);
272c9bf6a7eSthorpej epp->ep_dsize = (dsize > 0) ? dsize : 0;
27395e1ffb1Schristos return (*epp->ep_esch->es_setup_stack)(l, epp);
274c9bf6a7eSthorpej }
275