/* This is file EXPHDLR.C */ /* ** Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954 ** ** This file is distributed under the terms listed in the document ** "copying.dj", available from DJ Delorie at the address above. ** A copy of "copying.dj" should accompany this file; if not, a copy ** should be available from where this file was obtained. This file ** may not be distributed without a verbatim copy of "copying.dj". ** ** This file is distributed WITHOUT ANY WARRANTY; without even the implied ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* History:66,55 */ #include #include #include #include #include #include #include #include "build.h" #include "types.h" #include "gdt.h" #include "idt.h" #include "tss.h" #include "utils.h" #include "paging.h" #include "npx.h" #include "mono.h" #define SEGFAULT(p) { \ printf("Segmentation violation in pointer 0x%08lx\n", (p)); \ return 1; \ } extern int was_user_int; char transfer_buffer[4096]; /* must be near ptr for small model */ word32 user_dta; static struct REGPACK r; static word32 flmerge(word32 rf, word32 tf) { return (rf & 0xcff) | (tf & 0xfffff300L); } static set_controller(v) { disable(); outportb(0x20, 0x11); outportb(0x21, v); outportb(0x21, 4); outportb(0x21, 1); enable(); } init_controllers() { movedata(0, 0x08*4, 0, 0x78*4, 0x08*4); set_controller(0x78); } uninit_controllers() { set_controller(0x08); } extern int ctrl_c_flag; exception_handler() { int i; #if TOPLINEINFO char buf[20]; sprintf(buf, "0x%08lx", tss_ptr->tss_eip); for (i=0; buf[i]; i++) poke(screen_seg, i*2+80, buf[i] | 0x0600); #endif i = tss_ptr->tss_irqn; /* printf("i=%#02x, a0=%02x\n", i, inportb(0xa0)); */ if ((i>=0x70) && (i<0x7f) && (i != 0x75)) { if (i<0x78) intr(i, &r); else intr(i-0x70, &r); if (i == 0x79) { r.r_ax = 0x0100; intr(0x16, &r); if (!(r.r_flags & 0x40) && (r.r_ax == 0x2e03)) { _AH = 0; geninterrupt(0x16); ctrl_c_flag = 1; } } if (ctrl_c_flag) { ctrl_c_flag = 0; return 1; } return 0; } switch (i) { case 8: printf("double fault!\n"); exit(1); case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 9: case 10: case 11: case 12: case 13: case 15: return 1; case 0x75: return 1; case 7: printf("Fatal! Application attempted to use not-present 80387!\n"); printf("Floating point opcode at virtual address 0x%08lx\n", tss_ptr->tss_eip); return 1; case 14: return page_in(); case 0x10: return i_10(); case 0x11: case 0x12: case 0x14: case 0x16: case 0x17: case 0x1a: return generic_handler(); case 0x21: return i_21(); case 0x33: return i_33(); default: return 1; } } #if DEBUGGER static char flset[] = "VMRF NT OFDNIETFMIZR AC PE CY"; static char floff[] = " UPID PLNZ PO NC"; static char fluse[] = {1,1,0,1,0,0,1,1,1,1,1,1,0,1,0,1,0,1}; tssprint(TSS *t) { int i; printf("eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n", t->tss_eax, t->tss_ebx, t->tss_ecx, t->tss_edx); printf("esi=%08lx edi=%08lx ebp=%08lx ", t->tss_esi, t->tss_edi, t->tss_ebp); for (i=0; i<18; i++) if (fluse[i]) if (t->tss_eflags & (1<<(17-i))) printf(" %2.2s", flset+i*2); else printf(" %2.2s", floff+i*2); printf("\nds=%04x es=%04x fs=%04x gs=%04x ss:esp=%04x:%08lx cs=%04x\n", t->tss_ds, t->tss_es, t->tss_fs, t->tss_gs, t->tss_ss, t->tss_esp, t->tss_cs); } #endif /* DEBUGGER */ int retrieve_string(word32 v, char *transfer_buffer, char tchar) { int i; char c; for (i=0; i<4096; i++) { c = peek8(v); v++; transfer_buffer[i] = c; if (c == tchar) break; } return i+1; /* number of characters placed in buffer */ } static int old_text_mode = -1; generic_handler() { tss2reg(&r); intr(tss_ptr->tss_irqn, &r); reg2tss(&r); return 0; } i_10() { if ((tss_ptr->tss_eax & 0xFF00) == 0xFF00) { graphics_mode(tss_ptr->tss_eax & 0xff); return 0; } tss2reg(&r); intr(0x10, &r); reg2tss(&r); tss_ptr->tss_ebp = r.r_es * 16L + r.r_bp + 0xe0000000L; return 0; } i_33() { if (*((unsigned far *)0x000000CEL) == 0) return 0; r.r_ax = tss_ptr->tss_eax; r.r_bx = tss_ptr->tss_ebx; r.r_cx = tss_ptr->tss_ecx; r.r_dx = tss_ptr->tss_edx; intr(0x33, &r); tss_ptr->tss_eax = r.r_ax; tss_ptr->tss_ebx = r.r_bx; tss_ptr->tss_ecx = r.r_cx; tss_ptr->tss_edx = r.r_dx; return 0; } TSS last_tss; i_21() { word32 v, trans_total, countleft; int i, c, ah, tchar, trans_count; char *cp; memcpy(&last_tss, tss_ptr, sizeof(TSS)); tss2reg(&r); ah = (tss_ptr->tss_eax >> 8) & 0xff; #if 0 printf("int 21h ax=0x%04x bx=0x%04x cx=0x%04x dx=0x%04x\n", (int)(tss_ptr->tss_eax), (int)(tss_ptr->tss_ebx), (int)(tss_ptr->tss_ecx), (int)(tss_ptr->tss_edx) ); #endif switch (ah) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 0x0b: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x33: case 0x42: case 0x45: case 0x46: case 0x57: case 0x68: intr(0x21, &r); reg2tss(&r); return 0; case 0x3e: #if DEBUGGER if (r.r_bx <= 2) return 0; #endif intr(0x21, &r); reg2tss(&r); return 0; case 9: case 0x39: case 0x3a: case 0x3b: case 0x41: case 0x43: if (ah == 9) tchar = '$'; else tchar = 0; v = tss_ptr->tss_edx + ARENA; if (!page_is_valid(v)) { printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx); return 1; } retrieve_string(v, transfer_buffer, tchar); r.r_dx = FP_OFF(transfer_buffer); r.r_ds = _DS; intr(0x21, &r); reg2tss(&r); return 0; case 0x3c: v = tss_ptr->tss_edx + ARENA; if (!page_is_valid(v)) { printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx); return 1; } retrieve_string(v, transfer_buffer, 0); i = _creat(transfer_buffer, (int)(tss_ptr->tss_ecx)); if (i < 0) { tss_ptr->tss_eax = errno; tss_ptr->tss_eflags |= 1; } else { tss_ptr->tss_eax = i; tss_ptr->tss_eflags &= ~1; } return 0; case 0x3d: v = tss_ptr->tss_edx + ARENA; if (!page_is_valid(v)) { printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx); return 1; } retrieve_string(v, transfer_buffer, 0); i = tss_ptr->tss_eax & 0xf0; if (tss_ptr->tss_eax & O_WRONLY) i &= 1; if (tss_ptr->tss_eax & O_RDWR) i &= 2; i = _open(transfer_buffer, i); if (i < 0) { tss_ptr->tss_eax = errno; tss_ptr->tss_eflags |= 1; } else { tss_ptr->tss_eax = i; tss_ptr->tss_eflags &= ~1; } return 0; case 0x1a: user_dta = tss_ptr->tss_edx; setdta((char far *)transfer_buffer); return 0; case 0x2f: tss_ptr->tss_ebx = user_dta; return 0; case 0x30: intr(0x21, &r); reg2tss(&r); return 0; case 0x56: v = tss_ptr->tss_edx + ARENA; if (!page_is_valid(v)) { printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx); return 1; } i = retrieve_string(v, transfer_buffer, 0); r.r_dx = FP_OFF(transfer_buffer); r.r_ds = _DS; v = tss_ptr->tss_edi + ARENA; retrieve_string(v, transfer_buffer+i, 0); r.r_di = FP_OFF(transfer_buffer)+i; r.r_es = _DS; intr(0x21, &r); tss_ptr->tss_eax = r.r_ax; tss_ptr->tss_eflags = flmerge(r.r_flags, tss_ptr->tss_eflags); return 0; case 0x3f: trans_total = 0; countleft = tss_ptr->tss_ecx; v = tss_ptr->tss_edx; if (!page_is_valid(v+ARENA)) { printf("Segmentation violation in pointer 0x%08lx\n", tss_ptr->tss_edx); return 1; } while (countleft > 0) { trans_count = (countleft <= 4096) ? countleft : 4096; i = read(r.r_bx, transfer_buffer, trans_count); if (i < 0) { tss_ptr->tss_eflags |= 1; /* carry */ tss_ptr->tss_eax = _doserrno; return 0; } memput(v+ARENA, transfer_buffer, i); trans_total += i; v += i; countleft -= i; if (isatty(r.r_bx) && (itss_eax = trans_total; tss_ptr->tss_eflags &= ~1; return 0; case 0x40: trans_total = 0; countleft = tss_ptr->tss_ecx; if (countleft == 0) { r.r_ax = 0x4000; r.r_cx = 0; intr(0x21,&r); tss_ptr->tss_eax = 0; tss_ptr->tss_eflags &= ~1; return 0; } v = tss_ptr->tss_edx; if (!page_is_valid(v+ARENA)) SEGFAULT(v); r.r_dx = (int)transfer_buffer; while (countleft > 0) { trans_count = (countleft <= 4096) ? countleft : 4096; memget(v+ARENA, transfer_buffer, trans_count); i = write(r.r_bx, transfer_buffer, trans_count); if (i<0) /* carry */ { tss_ptr->tss_eflags |= 1; /* carry */ tss_ptr->tss_eax = _doserrno; return 0; } trans_total += i; v += i; countleft -= i; if (i < trans_count) break; } tss_ptr->tss_eax = trans_total; tss_ptr->tss_eflags &= ~1; return 0; case 0x44: return i_21_44(); case 0x4e: if (!page_is_valid(user_dta+ARENA)) SEGFAULT(user_dta); v = tss_ptr->tss_edx + ARENA; if (!page_is_valid(v)) SEGFAULT(v); retrieve_string(v, transfer_buffer+43, 0); r.r_dx = FP_OFF(transfer_buffer+43); r.r_ds = _DS; intr(0x21, &r); reg2tss(&r); for (i=20; i>=0; i--) transfer_buffer[i+28] = transfer_buffer[i+26]; transfer_buffer[32+13] = 0; /* asciiz termination */ memput(user_dta+ARENA, transfer_buffer, 48); return 0; case 0x4f: if (!page_is_valid(user_dta+ARENA)) SEGFAULT(user_dta); memget(user_dta+ARENA, transfer_buffer, 48); for (i=0; i<=20; i++) transfer_buffer[i+26] = transfer_buffer[i+28]; intr(0x21, &r); reg2tss(&r); for (i=20; i>=0; i--) transfer_buffer[i+28] = transfer_buffer[i+26]; transfer_buffer[32+13] = 0; /* asciiz termination */ memput(user_dta+ARENA, transfer_buffer, 48); return 0; case 0x47: getcurdir((int)(tss_ptr->tss_edx & 0xff), transfer_buffer); for (cp=transfer_buffer; *cp; cp++) { if (*cp == '\\') *cp = '/'; *cp = tolower(*cp); } memput(tss_ptr->tss_esi+ARENA, transfer_buffer, strlen(transfer_buffer)); tss_ptr->tss_eax = (unsigned)r.r_ax; tss_ptr->tss_eflags &= ~1; return 0; case 0x4a: if (tss_ptr->tss_eax & 0xff) tss_ptr->tss_eax = paging_sbrk(tss_ptr->tss_ebx); else tss_ptr->tss_eax = paging_brk(tss_ptr->tss_ebx); return 0; case 0x4c: #if DEBUGGER printf("Program exited normally, return code %d (0x%x)\n", (int)(tss_ptr->tss_eax & 0xff), (int)(tss_ptr->tss_eax & 0xff)); return 1; #else exit(tss_ptr->tss_eax & 0xff); #endif case 0xff: return turbo_assist(); default: return 1; } } struct time32 { word32 secs; word32 usecs; }; struct tz32 { word32 offset; word32 dst; }; struct stat32 { short st_dev; short st_ino; short st_mode; short st_nlink; short st_uid; short st_gid; short st_rdev; short st_align_for_word32; long st_size; long st_atime; long st_mtime; long st_ctime; long st_blksize; }; static int dev_count=1; turbo_assist() { word32 p1, p2, p3, r; struct time32 time32; struct tz32 tz32; struct stat32 statbuf32; struct stat statbuf; int i; char buf[128]; p1 = tss_ptr->tss_ebx; p2 = tss_ptr->tss_ecx; p3 = tss_ptr->tss_edx; switch (tss_ptr->tss_eax & 0xff) { case 1: retrieve_string(p1+ARENA, buf, 0); r = creat(buf, S_IREAD | S_IWRITE); break; case 2: retrieve_string(p1+ARENA, buf, 0); r = open(buf, (int)p2, S_IREAD | S_IWRITE); break; case 3: memset(&statbuf, 0, sizeof(statbuf)); r = fstat((int)p1, &statbuf); statbuf32.st_dev = dev_count++; statbuf32.st_ino = statbuf.st_ino; statbuf32.st_mode = statbuf.st_mode; statbuf32.st_nlink = statbuf.st_nlink; statbuf32.st_uid = statbuf.st_uid; statbuf32.st_gid = statbuf.st_gid; statbuf32.st_rdev = statbuf.st_rdev; statbuf32.st_size = statbuf.st_size; statbuf32.st_atime = statbuf.st_atime; statbuf32.st_mtime = statbuf.st_mtime; statbuf32.st_ctime = statbuf.st_ctime; statbuf32.st_blksize = 512; memput(p2+ARENA, &statbuf32, sizeof(statbuf32)); break; case 4: if (p2) { if (!page_is_valid(p2+ARENA)) SEGFAULT(p2); tz32.offset = timezone; tz32.dst = daylight; memput(p2+ARENA, &tz32, sizeof(tz32)); } if (p1) { if (!page_is_valid(p1+ARENA)) SEGFAULT(p1); time(&(time32.secs)); _AH = 0x2c; geninterrupt(0x21); time32.usecs = _DL * 10000L; memput(p1+ARENA, &time32, sizeof(time32)); } r = 0; break; case 5: if (p2) { if (!page_is_valid(p2+ARENA)) SEGFAULT(p2); memget(p2+ARENA, &tz32, sizeof(tz32)); timezone = tz32.offset; daylight = tz32.dst; } if (p1) { if (!page_is_valid(p1+ARENA)) SEGFAULT(p1); memget(p1+ARENA, &time32, sizeof(time32)); stime(&(time32.secs)); } r = 0; break; case 6: memset(&statbuf, 0, sizeof(statbuf)); retrieve_string(p1+ARENA, transfer_buffer, 0); r = stat(transfer_buffer, &statbuf); statbuf32.st_dev = dev_count++; statbuf32.st_ino = statbuf.st_ino; statbuf32.st_mode = statbuf.st_mode; statbuf32.st_nlink = statbuf.st_nlink; statbuf32.st_uid = statbuf.st_uid; statbuf32.st_gid = statbuf.st_gid; statbuf32.st_rdev = statbuf.st_rdev; statbuf32.st_size = statbuf.st_size; statbuf32.st_atime = statbuf.st_atime; statbuf32.st_mtime = statbuf.st_mtime; statbuf32.st_ctime = statbuf.st_ctime; statbuf32.st_blksize = 512; memput(p2+ARENA, &statbuf32, sizeof(statbuf32)); break; case 7: retrieve_string(p1+ARENA, transfer_buffer, 0); page_out_everything(); uninit_controllers(); sscanf(transfer_buffer, "%s%n", buf, &i); if (strpbrk(transfer_buffer, "<>|") == NULL) r = spawnlp(P_WAIT, buf, buf, transfer_buffer+i, 0); else r = -1; if (r & 0x80000000L) r = system(transfer_buffer); init_controllers(); page_in_everything(); break; case 8: r = setmode((int)p1, (int)p2); break; default: return 1; } tss_ptr->tss_eflags &= ~1; if (r == -1) { tss_ptr->tss_eflags |= 1; tss_ptr->tss_eax = errno; return 0; } tss_ptr->tss_eax = r; return 0; } i_21_44() { switch (tss_ptr->tss_eax & 0xff) { case 0x00: case 0x01: case 0x06: case 0x07: intr(0x21, &r); tss_ptr->tss_edx = r.r_dx; tss_ptr->tss_eax = r.r_ax; tss_ptr->tss_eflags = flmerge(r.r_flags, tss_ptr->tss_eflags); return 0; default: return 1; } } tss2reg(struct REGPACK *r) { r->r_ax = tss_ptr->tss_eax; r->r_bx = tss_ptr->tss_ebx; r->r_cx = tss_ptr->tss_ecx; r->r_dx = tss_ptr->tss_edx; r->r_si = tss_ptr->tss_esi; r->r_di = tss_ptr->tss_edi; r->r_flags = tss_ptr->tss_eflags; r->r_ds = r->r_es = _DS; } reg2tss(struct REGPACK *r) { tss_ptr->tss_eax = r->r_ax; tss_ptr->tss_ebx = r->r_bx; tss_ptr->tss_ecx = r->r_cx; tss_ptr->tss_edx = r->r_dx; tss_ptr->tss_esi = r->r_si; tss_ptr->tss_edi = r->r_di; tss_ptr->tss_eflags = flmerge(r->r_flags, tss_ptr->tss_eflags); }