Merge branch 'vendor/AWK'
[dragonfly.git] / usr.bin / doscmd / exe.c
1 /*
2  * Copyright (c) 1992, 1993, 1996
3  *      Berkeley Software Design, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Berkeley Software
16  *      Design, Inc.
17  *
18  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *      BSDI exe.c,v 2.2 1996/04/08 19:32:34 bostic Exp
31  *
32  * $FreeBSD: src/usr.bin/doscmd/exe.c,v 1.2.2.1 2002/04/25 11:04:51 tg Exp $
33  * $DragonFly: src/usr.bin/doscmd/exe.c,v 1.2 2003/06/17 04:29:26 dillon Exp $
34  */
35
36 #include <sys/types.h>
37 #include <sys/uio.h>
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 #include "doscmd.h"
44
45 /* exports */
46 int     pspseg;
47 int     curpsp = 0;
48
49 /* locals */
50 static int              psp_s[10] = { 0 };
51 static int              env_s[10];
52 static regcontext_t     frames[10];
53
54 static int
55 make_environment(char *cmd_name, char **env)
56 {
57     int i;
58     int total;
59     int len;
60     int envseg;
61     char *p;
62     char *env_block;
63
64     total = 0;
65     for (i = 0; env[i]; i++) {
66         debug (D_EXEC,"env: %s\n", env[i]);
67         len = strlen(env[i]);
68         if (total + len >= 32 * 1024)
69             break;
70         total += len + 1;
71     }
72
73     total++; /* terminating null */
74     total += 2; /* word count */
75     total += strlen(cmd_name) + 1;
76     total += 4; /* some more zeros, just in case */
77
78     if ((envseg = mem_alloc(total/16 + 1, 1, NULL)) == 0)
79         fatal("out of memory for env\n");
80
81     env_block = (char *)MAKEPTR(envseg, 0);
82     memset (env_block, 0, total);
83
84     p = env_block;
85     total = 0;
86     for (i = 0; env[i]; i++) {
87         len = strlen(env[i]);
88         if (total + len >= 32 * 1024)
89             break;
90         total += len + 1;
91         strcpy (p, env[i]);
92         p += strlen(p) + 1;
93     }   
94     *p++ = 0;
95     *(short *)p = strlen(cmd_name);
96     p += 2;
97     strcpy (p, cmd_name);
98     while(*p) {
99         if (*p == '/')
100             *p = '\\';
101         else if (islower(*p))
102             *p = toupper(*p);
103         p++;
104     }
105     *p = '\0';
106     return(envseg);
107 }
108
109 static void
110 load_com(int fd, int start_segment)
111 {
112     char *start_addr;
113     int i;
114
115     start_addr = (char *)MAKEPTR(start_segment, 0);
116
117     lseek (fd, 0, 0);
118     i = read (fd, start_addr, 0xff00);
119
120     debug(D_EXEC, "Read %05x into %04x\n",
121           i, start_segment);
122 }
123
124 static void
125 load_exe(int fd, int start_segment, int reloc_segment __unused, struct exehdr *hdr, int text_size)
126 {
127     char *start_addr;
128     int reloc_size;
129     struct reloc_entry *reloc_tbl, *rp;
130     u_short *segp;
131     int i;
132
133     start_addr = (char *)MAKEPTR(start_segment, 0);
134
135     lseek (fd, hdr->hdr_size * 16, 0);
136     if (read (fd, start_addr, text_size) != text_size)
137         fatal ("error reading program text\n");
138     debug(D_EXEC, "Read %05x into %04x\n",
139           text_size, start_segment);
140
141     if (hdr->nreloc) {
142         reloc_size = hdr->nreloc * sizeof (struct reloc_entry);
143
144         if ((reloc_tbl = (struct reloc_entry *)malloc (reloc_size)) == NULL)
145             fatal ("out of memory for program\n");
146
147         lseek (fd, hdr->reloc_offset, 0);
148         if (read (fd, reloc_tbl, reloc_size) != reloc_size)
149             fatal ("error reading reloc table\n");
150
151         for (i = 0, rp = reloc_tbl; i < hdr->nreloc; i++, rp++) {
152             segp = (u_short *)MAKEPTR(start_segment + rp->seg, rp->off);
153             *segp += start_segment;
154         }
155         free((char *)reloc_tbl);
156     }
157 }
158
159 void
160 load_command(regcontext_t *REGS, int run, int fd, char *cmd_name, 
161              u_short *param, char **argv, char **envs)
162 {
163     struct exehdr hdr;
164     int min_memory, max_memory;
165     int biggest;
166     int envseg;
167     char *psp;
168     int text_size = 0;
169     int i;
170     int start_segment;
171     int exe_file;
172     char *p;
173     int used, n;
174     char *fcb;
175     int newpsp;
176     u_short init_cs, init_ip, init_ss, init_sp, init_ds, init_es;
177
178     if (envs)
179         envseg = make_environment(cmd_name, envs);
180     else
181         envseg = env_s[curpsp];
182
183     /* read exe header */
184     if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
185         fatal ("can't read header\n");
186     
187     /* proper header ? */
188     if (hdr.magic == 0x5a4d) {
189         exe_file = 1;
190         text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
191             - hdr.hdr_size * 16;
192         min_memory = hdr.min_memory + (text_size + 15)/16;
193         max_memory = hdr.max_memory + (text_size + 15)/16;
194     } else {
195         exe_file = 0;
196         min_memory = 64 * (1024/16);
197         max_memory = 0xffff;
198     }
199     
200     /* alloc mem block */
201     pspseg = mem_alloc(max_memory, 1, &biggest);
202     if (pspseg == 0) {
203         if (biggest < min_memory ||
204             (pspseg = mem_alloc(biggest, 1, NULL)) == 0)
205             fatal("not enough memory: needed %d have %d\n",
206                   min_memory, biggest);
207         
208         max_memory = biggest;
209     }
210     
211     mem_change_owner(pspseg, pspseg);
212     mem_change_owner(envseg, pspseg);
213     
214     /* create psp */
215     newpsp = curpsp + 1;
216     psp_s[newpsp] = pspseg;
217     env_s[newpsp] = envseg;
218     
219     psp = (char *)MAKEPTR(pspseg, 0);
220     memset(psp, 0, 256);
221     
222     psp[0] = 0xcd;
223     psp[1] = 0x20;
224
225     *(u_short *)&psp[2] = pspseg + max_memory;
226     
227     /*
228      * this is supposed to be a long call to dos ... try to fake it
229      */
230     psp[5] = 0xcd;
231     psp[6] = 0x99;
232     psp[7] = 0xc3;
233     
234     *(u_short *)&psp[0x16] = psp_s[curpsp];
235     psp[0x18] = 1;
236     psp[0x19] = 1;
237     psp[0x1a] = 1;
238     psp[0x1b] = 0;
239     psp[0x1c] = 2;
240     memset(psp + 0x1d, 0xff, 15);
241     
242     *(u_short *)&psp[0x2c] = envseg;
243     
244     *(u_short *)&psp[0x32] = 20;
245     *(u_long *)&psp[0x34] = MAKEVEC(pspseg, 0x18);
246     *(u_long *)&psp[0x38] = 0xffffffff;
247     
248     psp[0x50] = 0xcd;
249     psp[0x51] = 0x98;
250     psp[0x52] = 0xc3;
251     
252     p = psp + 0x81;
253     *p = 0;
254     used = 0;
255     for (i = 0; argv[i]; i++) {
256         n = strlen(argv[i]);
257         if (used + 1 + n > 0x7d)
258             break;
259         *p++ = ' ';
260         memcpy(p, argv[i], n);
261         p += n;
262         used += n;
263     }
264
265     psp[0x80] = strlen(psp + 0x81);
266     psp[0x81 + psp[0x80]] = 0x0d;
267     psp[0x82 + psp[0x80]] = 0;
268     
269     p = psp + 0x81;
270     parse_filename(0x00, p, psp + 0x5c, &n);
271     p += n;
272     parse_filename(0x00, p, psp + 0x6c, &n);
273     
274     if (param[4]) {
275         fcb = (char *)MAKEPTR(param[4], param[3]);
276         memcpy(psp + 0x5c, fcb, 16);
277     }
278     if (param[6]) {
279         fcb = (char *)MAKEPTR(param[6], param[5]);
280         memcpy(psp + 0x6c, fcb, 16);
281     }
282
283 #if 0
284     printf("005c:");
285     for (n = 0; n < 16; n++)
286         printf(" %02x", psp[0x5c + n]);
287     printf("\n");
288     printf("006c:");
289     for (n = 0; n < 16; n++)
290         printf(" %02x", psp[0x6c + n]);
291     printf("\n");
292 #endif
293
294     disk_transfer_addr = MAKEVEC(pspseg, 0x80);
295     
296     start_segment = pspseg + 0x10;
297     
298     if (!exe_file) {
299         load_com(fd, start_segment);
300
301         init_cs = pspseg;
302         init_ip = 0x100;
303         init_ss = init_cs;
304         init_sp = 0xfffe;
305         init_ds = init_cs;
306         init_es = init_cs;
307     } else {
308         load_exe(fd, start_segment, start_segment, &hdr, text_size);
309         
310         init_cs = hdr.init_cs + start_segment;
311         init_ip = hdr.init_ip;
312         init_ss = hdr.init_ss + start_segment;
313         init_sp = hdr.init_sp;
314         init_ds = pspseg;
315         init_es = init_ds;
316     }
317
318     debug(D_EXEC, "cs:ip = %04x:%04x, ss:sp = %04x:%04x, "
319           "ds = %04x, es = %04x\n",
320           init_cs, init_ip, init_ss, init_sp, init_ds, init_es);
321     
322     if (run) {
323         frames[newpsp] = *REGS;
324         curpsp = newpsp;
325         
326         R_EFLAGS = 0x20202;
327         R_CS = init_cs;
328         R_IP = init_ip;
329         R_SS = init_ss;
330         R_SP = init_sp;
331         R_DS = init_ds;
332         R_ES = init_es;
333
334         R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0;
335
336     } else {
337         param[7] = init_sp;
338         param[8] = init_ss;
339         param[9] = init_ip;
340         param[10] = init_cs;
341     }
342 }
343
344 void
345 load_overlay(int fd, int start_segment, int reloc_segment)
346 {
347     struct exehdr hdr;
348     int text_size;
349     int exe_file;
350
351     /* read exe header */
352     if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
353         fatal ("can't read header\n");
354     
355     /* proper header ? */
356     if (hdr.magic == 0x5a4d) {
357         exe_file = 1;
358         text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
359             - hdr.hdr_size * 16;
360     } else {
361         exe_file = 0;
362     }
363
364     if (!exe_file)
365         load_com(fd, start_segment);
366     else
367         load_exe(fd, start_segment, reloc_segment, &hdr, text_size);
368 }
369
370 int
371 get_env(void)
372 {
373     return(env_s[curpsp]);
374 }
375
376 void
377 exec_command(regcontext_t *REGS, int run,
378              int fd, char *cmd_name, u_short *param)
379 {
380     char *arg;
381     char *env;
382     char *argv[2];
383     char *envs[100];
384
385     env = (char *)MAKEPTR(param[0], 0);
386     arg = (char *)MAKEPTR(param[2], param[1]);
387
388     if (arg) {
389         int nbytes = *arg++;
390         arg[nbytes] = 0;
391         if (!*arg)
392             arg = NULL;
393     }
394     argv[0] = arg;
395     argv[1] = NULL;
396
397     debug (D_EXEC, "exec_command: cmd_name = %s\n"
398                    "env = 0x0%x, arg = %04x:%04x(%s)\n",
399         cmd_name, param[0], param[2], param[1], arg);
400
401     if (env) {
402         int i;
403         for ( i=0; i < 99 && *env; ++i ) {
404             envs[i] = env;
405             env += strlen(env)+1;
406         }
407         envs[i] = NULL;
408         load_command(REGS, run, fd, cmd_name, param, argv, envs);
409     } else
410         load_command(REGS, run, fd, cmd_name, param, argv, NULL);
411 }
412
413 void
414 exec_return(regcontext_t *REGS, int code)
415 {
416     debug(D_EXEC, "Returning from exec\n");
417     mem_free_owner(psp_s[curpsp]);
418     *REGS = frames[curpsp--];
419     R_AX = code;
420     R_FLAGS &= ~PSL_C;          /* It must have worked */
421 }