]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/doscmd/exe.c
This commit was generated by cvs2svn to compensate for changes in r76866,
[FreeBSD/FreeBSD.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  * $FreeBSD$
32  */
33
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #include <ctype.h>
38 #include "doscmd.h"
39
40 /* exports */
41 int     pspseg;
42 int     curpsp = 0;
43
44 /* locals */
45 static int              psp_s[10] = { 0 };
46 static int              env_s[10];
47 static regcontext_t     frames[10];
48 static char             *env_block;
49
50 static int
51 make_environment (char *cmdname, char **env)
52 {
53     int i;
54     int total;
55     int len;
56     int envseg;
57     char *p;
58     char *env_block;
59
60     total = 0;
61     for (i = 0; env[i]; i++) {
62         debug (D_EXEC,"env: %s\n", env[i]);
63         len = strlen (env[i]);
64         if (total + len >= 32 * 1024)
65             break;
66         total += len + 1;
67     }
68
69     total++; /* terminating null */
70     total += 2; /* word count */
71     total += strlen (cmdname) + 1;
72     total += 4; /* some more zeros, just in case */
73
74     if ((envseg = mem_alloc(total/16 + 1, 1, NULL)) == 0)
75         fatal("out of memory for env\n");
76
77     env_block = (char *)MAKEPTR(envseg, 0);
78     memset (env_block, 0, total);
79
80     p = env_block;
81     total = 0;
82     for (i = 0; env[i]; i++) {
83         len = strlen (env[i]);
84         if (total + len >= 32 * 1024)
85             break;
86         total += len + 1;
87         strcpy (p, env[i]);
88         p += strlen (p) + 1;
89     }   
90     *p++ = 0;
91     *(short *)p = strlen(cmdname);
92     p += 2;
93     strcpy (p, cmdname);
94     while(*p) {
95         if (*p == '/')
96             *p = '\\';
97         else if (islower(*p))
98             *p = toupper(*p);
99         p++;
100     }
101     *p = '\0';
102     return(envseg);
103 }
104
105 static void
106 load_com(int fd, int start_segment)
107 {
108     char *start_addr;
109     int i;
110
111     start_addr = (char *)MAKEPTR(start_segment, 0);
112
113     lseek (fd, 0, 0);
114     i = read (fd, start_addr, 0xff00);
115
116     debug(D_EXEC, "Read %05x into %04x\n",
117           i, start_segment);
118 }
119
120 static void
121 load_exe(int fd, int start_segment, int reloc_segment, struct exehdr *hdr, int text_size)
122 {
123     char *start_addr;
124     int reloc_size;
125     struct reloc_entry *reloc_tbl, *rp;
126     u_short *segp;
127     int i;
128
129     start_addr = (char *)MAKEPTR(start_segment, 0);
130
131     lseek (fd, hdr->hdr_size * 16, 0);
132     if (read (fd, start_addr, text_size) != text_size)
133         fatal ("error reading program text\n");
134     debug(D_EXEC, "Read %05x into %04x\n",
135           text_size, start_segment);
136
137     if (hdr->nreloc) {
138         reloc_size = hdr->nreloc * sizeof (struct reloc_entry);
139
140         if ((reloc_tbl = (struct reloc_entry *)malloc (reloc_size)) == NULL)
141             fatal ("out of memory for program\n");
142
143         lseek (fd, hdr->reloc_offset, 0);
144         if (read (fd, reloc_tbl, reloc_size) != reloc_size)
145             fatal ("error reading reloc table\n");
146
147         for (i = 0, rp = reloc_tbl; i < hdr->nreloc; i++, rp++) {
148             segp = (u_short *)MAKEPTR(start_segment + rp->seg, rp->off);
149             *segp += start_segment;
150         }
151         free((char *)reloc_tbl);
152     }
153 }
154
155 void
156 load_command(regcontext_t *REGS, int run, int fd, char *cmdname, 
157              u_short *param, char **argv, char **envs)
158 {
159     struct exehdr hdr;
160     int min_memory, max_memory;
161     int biggest;
162     int envseg;
163     char *psp;
164     int text_size;
165     int i;
166     int start_segment;
167     int exe_file;
168     char *p;
169     int used, n;
170     char *fcb;
171     int newpsp;
172     u_short init_cs, init_ip, init_ss, init_sp, init_ds, init_es;
173
174     if (envs)
175         envseg = make_environment(cmdname, envs);
176     else
177         envseg = env_s[curpsp];
178
179     /* read exe header */
180     if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
181         fatal ("can't read header\n");
182     
183     /* proper header ? */
184     if (hdr.magic == 0x5a4d) {
185         exe_file = 1;
186         text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
187             - hdr.hdr_size * 16;
188         min_memory = hdr.min_memory + (text_size + 15)/16;
189         max_memory = hdr.max_memory + (text_size + 15)/16;
190     } else {
191         exe_file = 0;
192         min_memory = 64 * (1024/16);
193         max_memory = 0xffff;
194     }
195     
196     /* alloc mem block */
197     pspseg = mem_alloc(max_memory, 1, &biggest);
198     if (pspseg == 0) {
199         if (biggest < min_memory ||
200             (pspseg = mem_alloc(biggest, 1, NULL)) == 0)
201             fatal("not enough memory: needed %d have %d\n",
202                   min_memory, biggest);
203         
204         max_memory = biggest;
205     }
206     
207     mem_change_owner(pspseg, pspseg);
208     mem_change_owner(envseg, pspseg);
209     
210     /* create psp */
211     newpsp = curpsp + 1;
212     psp_s[newpsp] = pspseg;
213     env_s[newpsp] = envseg;
214     
215     psp = (char *)MAKEPTR(pspseg, 0);
216     memset(psp, 0, 256);
217     
218     psp[0] = 0xcd;
219     psp[1] = 0x20;
220
221     *(u_short *)&psp[2] = pspseg + max_memory;
222     
223     /*
224      * this is supposed to be a long call to dos ... try to fake it
225      */
226     psp[5] = 0xcd;
227     psp[6] = 0x99;
228     psp[7] = 0xc3;
229     
230     *(u_short *)&psp[0x16] = psp_s[curpsp];
231     psp[0x18] = 1;
232     psp[0x19] = 1;
233     psp[0x1a] = 1;
234     psp[0x1b] = 0;
235     psp[0x1c] = 2;
236     memset(psp + 0x1d, 0xff, 15);
237     
238     *(u_short *)&psp[0x2c] = envseg;
239     
240     *(u_short *)&psp[0x32] = 20;
241     *(u_long *)&psp[0x34] = MAKEVEC(pspseg, 0x18);
242     *(u_long *)&psp[0x38] = 0xffffffff;
243     
244     psp[0x50] = 0xcd;
245     psp[0x51] = 0x98;
246     psp[0x52] = 0xc3;
247     
248     p = psp + 0x81;
249     *p = 0;
250     used = 0;
251     for (i = 0; argv[i]; i++) {
252         n = strlen(argv[i]);
253         if (used + 1 + n > 0x7d)
254             break;
255         *p++ = ' ';
256         memcpy(p, argv[i], n);
257         p += n;
258         used += n;
259     }
260
261     psp[0x80] = strlen(psp + 0x81);
262     psp[0x81 + psp[0x80]] = 0x0d;
263     psp[0x82 + psp[0x80]] = 0;
264     
265     p = psp + 0x81;
266     parse_filename(0x00, p, psp + 0x5c, &n);
267     p += n;
268     parse_filename(0x00, p, psp + 0x6c, &n);
269     
270     if (param[4]) {
271         fcb = (char *)MAKEPTR(param[4], param[3]);
272         memcpy(psp + 0x5c, fcb, 16);
273     }
274     if (param[6]) {
275         fcb = (char *)MAKEPTR(param[6], param[5]);
276         memcpy(psp + 0x6c, fcb, 16);
277     }
278
279 #if 0
280     printf("005c:");
281     for (n = 0; n < 16; n++)
282         printf(" %02x", psp[0x5c + n]);
283     printf("\n");
284     printf("006c:");
285     for (n = 0; n < 16; n++)
286         printf(" %02x", psp[0x6c + n]);
287     printf("\n");
288 #endif
289
290     disk_transfer_addr = MAKEVEC(pspseg, 0x80);
291     
292     start_segment = pspseg + 0x10;
293     
294     if (!exe_file) {
295         load_com(fd, start_segment);
296
297         init_cs = pspseg;
298         init_ip = 0x100;
299         init_ss = init_cs;
300         init_sp = 0xfffe;
301         init_ds = init_cs;
302         init_es = init_cs;
303     } else {
304         load_exe(fd, start_segment, start_segment, &hdr, text_size);
305         
306         init_cs = hdr.init_cs + start_segment;
307         init_ip = hdr.init_ip;
308         init_ss = hdr.init_ss + start_segment;
309         init_sp = hdr.init_sp;
310         init_ds = pspseg;
311         init_es = init_ds;
312     }
313
314     debug(D_EXEC, "cs:ip = %04x:%04x, ss:sp = %04x:%04x, "
315           "ds = %04x, es = %04x\n",
316           init_cs, init_ip, init_ss, init_sp, init_ds, init_es);
317     
318     if (run) {
319         frames[newpsp] = *REGS;
320         curpsp = newpsp;
321         
322         R_EFLAGS = 0x20202;
323         R_CS = init_cs;
324         R_IP = init_ip;
325         R_SS = init_ss;
326         R_SP = init_sp;
327         R_DS = init_ds;
328         R_ES = init_es;
329
330         R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0;
331
332     } else {
333         param[7] = init_sp;
334         param[8] = init_ss;
335         param[9] = init_ip;
336         param[10] = init_cs;
337     }
338 }
339
340 void
341 load_overlay(int fd, int start_segment, int reloc_segment)
342 {
343     struct exehdr hdr;
344     int text_size;
345     int exe_file;
346
347     /* read exe header */
348     if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
349         fatal ("can't read header\n");
350     
351     /* proper header ? */
352     if (hdr.magic == 0x5a4d) {
353         exe_file = 1;
354         text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
355             - hdr.hdr_size * 16;
356     } else {
357         exe_file = 0;
358     }
359
360     if (!exe_file)
361         load_com(fd, start_segment);
362     else
363         load_exe(fd, start_segment, reloc_segment, &hdr, text_size);
364 }
365
366 static int
367 get_psp(void)
368 {
369     return(psp_s[curpsp]);
370 }
371
372 int
373 get_env(void)
374 {
375     return(env_s[curpsp]);
376 }
377
378 void
379 exec_command(regcontext_t *REGS, int run,
380              int fd, char *cmdname, u_short *param)
381 {
382     char *arg;
383     char *env;
384     char *argv[2];
385     char *envs[100];
386
387     env = (char *)MAKEPTR(param[0], 0);
388     arg = (char *)MAKEPTR(param[2], param[1]);
389
390     if (arg) {
391         int nbytes = *arg++;
392         arg[nbytes] = 0;
393         if (!*arg)
394             arg = NULL;
395     }
396     argv[0] = arg;
397     argv[1] = NULL;
398
399     debug (D_EXEC, "exec_command: cmdname = %s\n"
400                    "env = 0x0%x, arg = %04x:%04x(%s)\n",
401         cmdname, param[0], param[2], param[1], arg);
402
403     if (env) {
404         int i;
405         for ( i=0; i < 99 && *env; ++i ) {
406             envs[i] = env;
407             env += strlen(env)+1;
408         }
409         envs[i] = NULL;
410         load_command(REGS, run, fd, cmdname, param, argv, envs);
411     } else
412         load_command(REGS, run, fd, cmdname, param, argv, NULL);
413 }
414
415 void
416 exec_return(regcontext_t *REGS, int code)
417 {
418     debug(D_EXEC, "Returning from exec\n");
419     mem_free_owner(psp_s[curpsp]);
420     *REGS = frames[curpsp--];
421     R_AX = code;
422     R_FLAGS &= ~PSL_C;          /* It must have worked */
423 }