xref: /netbsd-src/sys/compat/m68k4k/m68k4k_exec.c (revision 1d577fe3790e662ec592913bd86905a501cfc612)
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