diff options
author | dyson <dyson@FreeBSD.org> | 1997-08-09 01:43:15 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1997-08-09 01:43:15 +0000 |
commit | 305573cb2990c5d329d149cef5a3b5533b1e8fd9 (patch) | |
tree | df06304b637358dbe8a006fdb7a6ea5955fee179 /usr.bin/doscmd/exe.c | |
parent | dede28832bba6a9de7a428ff58df92439bddbc9c (diff) | |
download | FreeBSD-src-305573cb2990c5d329d149cef5a3b5533b1e8fd9.zip FreeBSD-src-305573cb2990c5d329d149cef5a3b5533b1e8fd9.tar.gz |
Add our doscmd to the tree. This is a result of work from BSDI, and
a group of dos emulator developers.
Submitted by: Jonathan Lemon <jlemon@americantv.com>
Obtained from: BSDI
Diffstat (limited to 'usr.bin/doscmd/exe.c')
-rw-r--r-- | usr.bin/doscmd/exe.c | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/usr.bin/doscmd/exe.c b/usr.bin/doscmd/exe.c new file mode 100644 index 0000000..0314a62 --- /dev/null +++ b/usr.bin/doscmd/exe.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1992, 1993, 1996 + * Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Berkeley Software + * Design, Inc. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI exe.c,v 2.2 1996/04/08 19:32:34 bostic Exp + * $Id: exe.c,v 1.3 1996/09/22 06:26:01 miff Exp $ + */ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <ctype.h> +#include "doscmd.h" + +/* exports */ +int pspseg; +int curpsp = 0; + +/* locals */ +static int psp_s[10] = { 0 }; +static int env_s[10]; +static regcontext_t frames[10]; +static char *env_block; + +static int +make_environment (char *cmdname, char **env) +{ + int i; + int total; + int len; + int envseg; + char *p; + char *env_block; + + total = 0; + for (i = 0; env[i]; i++) { + debug (D_EXEC,"env: %s\n", env[i]); + len = strlen (env[i]); + if (total + len >= 32 * 1024) + break; + total += len + 1; + } + + total++; /* terminating null */ + total += 2; /* word count */ + total += strlen (cmdname) + 1; + total += 4; /* some more zeros, just in case */ + + if ((envseg = mem_alloc(total/16 + 1, 1, NULL)) == 0) + fatal("out of memory for env\n"); + + env_block = (char *)MAKEPTR(envseg, 0); + memset (env_block, 0, total); + + p = env_block; + total = 0; + for (i = 0; env[i]; i++) { + len = strlen (env[i]); + if (total + len >= 32 * 1024) + break; + total += len + 1; + strcpy (p, env[i]); + p += strlen (p) + 1; + } + *p++ = 0; + *(short *)p = strlen(cmdname); + p += 2; + strcpy (p, cmdname); + while(*p) { + if (*p == '/') + *p = '\\'; + else if (islower(*p)) + *p = toupper(*p); + p++; + } + *p = '\0'; + return(envseg); +} + +static void +load_com(int fd, int start_segment) +{ + char *start_addr; + int i; + + start_addr = (char *)MAKEPTR(start_segment, 0); + + lseek (fd, 0, 0); + i = read (fd, start_addr, 0xff00); + + debug(D_EXEC, "Read %05x into %04x\n", + i, start_segment); +} + +static void +load_exe(int fd, int start_segment, int reloc_segment, struct exehdr *hdr, int text_size) +{ + char *start_addr; + int reloc_size; + struct reloc_entry *reloc_tbl, *rp; + u_short *segp; + int i; + + start_addr = (char *)MAKEPTR(start_segment, 0); + + lseek (fd, hdr->hdr_size * 16, 0); + if (read (fd, start_addr, text_size) != text_size) + fatal ("error reading program text\n"); + debug(D_EXEC, "Read %05x into %04x\n", + text_size, start_segment); + + if (hdr->nreloc) { + reloc_size = hdr->nreloc * sizeof (struct reloc_entry); + + if ((reloc_tbl = (struct reloc_entry *)malloc (reloc_size)) == NULL) + fatal ("out of memory for program\n"); + + lseek (fd, hdr->reloc_offset, 0); + if (read (fd, reloc_tbl, reloc_size) != reloc_size) + fatal ("error reading reloc table\n"); + + for (i = 0, rp = reloc_tbl; i < hdr->nreloc; i++, rp++) { + segp = (u_short *)MAKEPTR(start_segment + rp->seg, rp->off); + *segp += start_segment; + } + free((char *)reloc_tbl); + } +} + +void +load_command(regcontext_t *REGS, int run, int fd, char *cmdname, + u_short *param, char **argv, char **envs) +{ + struct exehdr hdr; + int min_memory, max_memory; + int biggest; + int envseg; + char *psp; + int text_size; + int i; + int start_segment; + int exe_file; + char *p; + int used, n; + char *fcb; + int newpsp; + u_short init_cs, init_ip, init_ss, init_sp, init_ds, init_es; + + if (envs) + envseg = make_environment(cmdname, envs); + else + envseg = env_s[curpsp]; + + /* read exe header */ + if (read (fd, &hdr, sizeof hdr) != sizeof hdr) + fatal ("can't read header\n"); + + /* proper header ? */ + if (hdr.magic == 0x5a4d) { + exe_file = 1; + text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page + - hdr.hdr_size * 16; + min_memory = hdr.min_memory + (text_size + 15)/16; + max_memory = hdr.max_memory + (text_size + 15)/16; + } else { + exe_file = 0; + min_memory = 64 * (1024/16); + max_memory = 0xffff; + } + + /* alloc mem block */ + pspseg = mem_alloc(max_memory, 1, &biggest); + if (pspseg == 0) { + if (biggest < min_memory || + (pspseg = mem_alloc(biggest, 1, NULL)) == 0) + fatal("not enough memory: needed %d have %d\n", + min_memory, biggest); + + max_memory = biggest; + } + + mem_change_owner(pspseg, pspseg); + mem_change_owner(envseg, pspseg); + + /* create psp */ + newpsp = curpsp + 1; + psp_s[newpsp] = pspseg; + env_s[newpsp] = envseg; + + psp = (char *)MAKEPTR(pspseg, 0); + memset(psp, 0, 256); + + psp[0] = 0xcd; + psp[1] = 0x20; + + *(u_short *)&psp[2] = pspseg + max_memory; + + /* + * this is supposed to be a long call to dos ... try to fake it + */ + psp[5] = 0xcd; + psp[6] = 0x99; + psp[7] = 0xc3; + + *(u_short *)&psp[0x16] = psp_s[curpsp]; + psp[0x18] = 1; + psp[0x19] = 1; + psp[0x1a] = 1; + psp[0x1b] = 0; + psp[0x1c] = 2; + memset(psp + 0x1d, 0xff, 15); + + *(u_short *)&psp[0x2c] = envseg; + + *(u_short *)&psp[0x32] = 20; + *(u_long *)&psp[0x34] = MAKEVEC(pspseg, 0x18); + *(u_long *)&psp[0x38] = 0xffffffff; + + psp[0x50] = 0xcd; + psp[0x51] = 0x98; + psp[0x52] = 0xc3; + + p = psp + 0x81; + *p = 0; + used = 0; + for (i = 0; argv[i]; i++) { + n = strlen(argv[i]); + if (used + 1 + n > 0x7d) + break; + *p++ = ' '; + memcpy(p, argv[i], n); + p += n; + used += n; + } + + psp[0x80] = strlen(psp + 0x81); + psp[0x81 + psp[0x80]] = 0x0d; + psp[0x82 + psp[0x80]] = 0; + + p = psp + 0x81; + parse_filename(0x00, p, psp + 0x5c, &n); + p += n; + parse_filename(0x00, p, psp + 0x6c, &n); + + if (param[4]) { + fcb = (char *)MAKEPTR(param[4], param[3]); + memcpy(psp + 0x5c, fcb, 16); + } + if (param[6]) { + fcb = (char *)MAKEPTR(param[6], param[5]); + memcpy(psp + 0x6c, fcb, 16); + } + +#if 0 + printf("005c:"); + for (n = 0; n < 16; n++) + printf(" %02x", psp[0x5c + n]); + printf("\n"); + printf("006c:"); + for (n = 0; n < 16; n++) + printf(" %02x", psp[0x6c + n]); + printf("\n"); +#endif + + disk_transfer_addr = MAKEVEC(pspseg, 0x80); + + start_segment = pspseg + 0x10; + + if (!exe_file) { + load_com(fd, start_segment); + + init_cs = pspseg; + init_ip = 0x100; + init_ss = init_cs; + init_sp = 0xfffe; + init_ds = init_cs; + init_es = init_cs; + } else { + load_exe(fd, start_segment, start_segment, &hdr, text_size); + + init_cs = hdr.init_cs + start_segment; + init_ip = hdr.init_ip; + init_ss = hdr.init_ss + start_segment; + init_sp = hdr.init_sp; + init_ds = pspseg; + init_es = init_ds; + } + + debug(D_EXEC, "cs:ip = %04x:%04x, ss:sp = %04x:%04x, " + "ds = %04x, es = %04x\n", + init_cs, init_ip, init_ss, init_sp, init_ds, init_es); + + if (run) { + frames[newpsp] = *REGS; + curpsp = newpsp; + + R_EFLAGS = 0x20202; + R_CS = init_cs; + R_IP = init_ip; + R_SS = init_ss; + R_SP = init_sp; + R_DS = init_ds; + R_ES = init_es; + + R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0; + + } else { + param[7] = init_sp; + param[8] = init_ss; + param[9] = init_ip; + param[10] = init_cs; + } +} + +void +load_overlay(int fd, int start_segment, int reloc_segment) +{ + struct exehdr hdr; + int text_size; + int exe_file; + + /* read exe header */ + if (read (fd, &hdr, sizeof hdr) != sizeof hdr) + fatal ("can't read header\n"); + + /* proper header ? */ + if (hdr.magic == 0x5a4d) { + exe_file = 1; + text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page + - hdr.hdr_size * 16; + } else { + exe_file = 0; + } + + if (!exe_file) + load_com(fd, start_segment); + else + load_exe(fd, start_segment, reloc_segment, &hdr, text_size); +} + +static int +get_psp(void) +{ + return(psp_s[curpsp]); +} + +int +get_env(void) +{ + return(env_s[curpsp]); +} + +void +exec_command(regcontext_t *REGS, int run, + int fd, char *cmdname, u_short *param) +{ + char *arg; + char *env; + char *argv[2]; + char *envs[100]; + + env = (char *)MAKEPTR(param[0], 0); + arg = (char *)MAKEPTR(param[2], param[1]); + + if (arg) { + int nbytes = *arg++; + arg[nbytes] = 0; + if (!*arg) + arg = NULL; + } + argv[0] = arg; + argv[1] = NULL; + + debug (D_EXEC, "exec_command: cmdname = %s\n" + "env = 0x0%x, arg = %04x:%04x(%s)\n", + cmdname, param[0], param[2], param[1], arg); + + if (env) { + int i; + for ( i=0; i < 99 && *env; ++i ) { + envs[i] = env; + env += strlen(env)+1; + } + envs[i] = NULL; + load_command(REGS, run, fd, cmdname, param, argv, envs); + } else + load_command(REGS, run, fd, cmdname, param, argv, NULL); +} + +void +exec_return(regcontext_t *REGS, int code) +{ + debug(D_EXEC, "Returning from exec\n"); + mem_free_owner(psp_s[curpsp]); + *REGS = frames[curpsp--]; + R_AX = code; + R_FLAGS &= ~PSL_C; /* It must have worked */ +} |