xref: /minix3/minix/servers/rs/exec.c (revision 0b98e8aad89f2bd4ba80b523d73cf29e9dd82ce1)
1 #include "inc.h"
2 #include <assert.h>
3 #include <sys/exec.h>
4 #include <libexec.h>
5 #include <minix/param.h>
6 #include <machine/vmparam.h>
7 
8 static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
9 	char *frame, int frame_len, vir_bytes ps_str);
10 static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str);
11 static int read_seg(struct exec_info *execi, off_t off,
12         vir_bytes seg_addr, size_t seg_bytes);
13 
14 /* Array of loaders for different object formats */
15 static struct exec_loaders {
16 	libexec_exec_loadfunc_t load_object;
17 } const exec_loaders[] = {
18 	{ libexec_load_elf },
19 	{ NULL }
20 };
21 
22 extern struct minix_kerninfo *_minix_kerninfo;
23 
24 int srv_execve(int proc_e, char *exec, size_t exec_len, char **argv,
25 	char **envp)
26 {
27 	size_t frame_size = 0;	/* Size of the new initial stack. */
28 	int argc = 0;		/* Argument count. */
29 	int envc = 0;		/* Environment count */
30 	char overflow = 0;	/* No overflow yet. */
31 	char *frame;
32 	struct ps_strings *psp;
33 	int vsp = 0;	/* (virtual) Stack pointer in new address space. */
34 
35 	char *progname;
36 	int r;
37 
38 	minix_stack_params(argv[0], argv, envp, &frame_size, &overflow,
39 		&argc, &envc);
40 
41 	/* The party is off if there is an overflow. */
42 	if (overflow) {
43 		errno = E2BIG;
44 		return -1;
45 	}
46 
47 	/* Allocate space for the stack frame. */
48 	if ((frame = (char *) sbrk(frame_size)) == (char *) -1) {
49 		errno = E2BIG;
50 		return -1;
51 	}
52 
53 	minix_stack_fill(argv[0], argc, argv, envc, envp, frame_size, frame,
54 		&vsp, &psp);
55 
56 	(progname=strrchr(argv[0], '/')) ? progname++ : (progname=argv[0]);
57 
58 	r = do_exec(proc_e, exec, exec_len, progname, frame, frame_size,
59 		vsp + ((char *)psp - frame));
60 
61 	/* Failure, return the memory used for the frame and exit. */
62 	(void) sbrk(-frame_size);
63 
64 	return r;
65 }
66 
67 
68 static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
69 	char *frame, int frame_len, vir_bytes ps_str)
70 {
71 	int r;
72 	vir_bytes vsp;
73 	struct exec_info execi;
74 	int i;
75 
76 	memset(&execi, 0, sizeof(execi));
77 
78 	execi.stack_high = _minix_kerninfo->kinfo->user_sp;
79 	execi.stack_size = DEFAULT_STACK_LIMIT;
80 	execi.proc_e = proc_e;
81 	execi.hdr = exec;
82 	execi.filesize = execi.hdr_len = exec_len;
83 	strncpy(execi.progname, progname, PROC_NAME_LEN-1);
84 	execi.progname[PROC_NAME_LEN-1] = '\0';
85 	execi.frame_len = frame_len;
86 
87 	/* callback functions and data */
88 	execi.copymem = read_seg;
89 	execi.clearproc = libexec_clearproc_vm_procctl;
90 	execi.clearmem = libexec_clear_sys_memset;
91 	execi.allocmem_prealloc_cleared = libexec_alloc_mmap_prealloc_cleared;
92 	execi.allocmem_prealloc_junk = libexec_alloc_mmap_prealloc_junk;
93 	execi.allocmem_ondemand = libexec_alloc_mmap_ondemand;
94 
95 	for(i = 0; exec_loaders[i].load_object != NULL; i++) {
96 	    r = (*exec_loaders[i].load_object)(&execi);
97 	    /* Loaded successfully, so no need to try other loaders */
98 	    if (r == OK) break;
99 	}
100 
101 	/* No exec loader could load the object */
102 	if (r != OK) {
103 	    printf("RS: do_exec: loading error %d\n", r);
104 	    return r;
105 	}
106 
107 	/* Inform PM */
108         if((r = libexec_pm_newexec(execi.proc_e, &execi)) != OK)
109 		return r;
110 
111 	/* Patch up stack and copy it from RS to new core image. */
112 	vsp = execi.stack_high - frame_len;
113 	r = sys_datacopy(SELF, (vir_bytes) frame,
114 		proc_e, (vir_bytes) vsp, (phys_bytes)frame_len);
115 	if (r != OK) {
116 		printf("do_exec: copying out new stack failed: %d\n", r);
117 		exec_restart(proc_e, r, execi.pc, ps_str);
118 		return r;
119 	}
120 
121 	return exec_restart(proc_e, OK, execi.pc, ps_str);
122 }
123 
124 /*===========================================================================*
125  *				exec_restart				     *
126  *===========================================================================*/
127 static int exec_restart(int proc_e, int result, vir_bytes pc, vir_bytes ps_str)
128 {
129 	int r;
130 	message m;
131 
132 	memset(&m, 0, sizeof(m));
133 	m.m_type = PM_EXEC_RESTART;
134 	m.m_rs_pm_exec_restart.endpt = proc_e;
135 	m.m_rs_pm_exec_restart.result = result;
136 	m.m_rs_pm_exec_restart.pc = pc;
137 	m.m_rs_pm_exec_restart.ps_str = ps_str;
138 
139 	r = ipc_sendrec(PM_PROC_NR, &m);
140 	if (r != OK)
141 		return r;
142 
143 	return m.m_type;
144 }
145 
146 /*===========================================================================*
147  *                             read_seg                                     *
148  *===========================================================================*/
149 static int read_seg(
150 struct exec_info *execi,       /* various data needed for exec */
151 off_t off,                     /* offset in file */
152 vir_bytes seg_addr,            /* address to load segment */
153 size_t seg_bytes           /* how much is to be transferred? */
154 )
155 {
156 /*
157  * The byte count on read is usually smaller than the segment count, because
158  * a segment is padded out to a click multiple, and the data segment is only
159  * partially initialized.
160  */
161 
162   int r;
163 
164   if (off+seg_bytes > execi->hdr_len) return ENOEXEC;
165   if((r= sys_datacopy(SELF, ((vir_bytes)execi->hdr)+off,
166   	execi->proc_e, seg_addr, seg_bytes)) != OK) {
167 	printf("RS: exec read_seg: copy 0x%x bytes into %i at 0x%08lx failed: %i\n",
168 		(int) seg_bytes, execi->proc_e, seg_addr, r);
169   }
170   return r;
171 }
172