home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / c / library / dos / tvision / dpmi / dpmirun / dpmirun.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-29  |  18.4 KB  |  678 lines

  1. //=====================================================================
  2. //
  3. //  dpmirun.cpp
  4. //
  5. //  This is the loader for protected mode dos applications.
  6. //
  7. //  This is very dependant on Borland C++.
  8. //  It must be compiled in small model.
  9. //
  10. //  It requires DPMI to work.
  11. //
  12. //  Copyright (c) 1994, Kevin Morgan, All rights reserved.
  13. //
  14. //=====================================================================
  15.  
  16. #define GLOBALS
  17. #include "dpmirun.h"
  18.  
  19. DpmiApplication Dpmi;
  20.  
  21. #define CONTINUE(n)  do {  \
  22.     pGpfRegs  = (GpfRegs far *) MK_FP(_SS, _BP); \
  23.     if (setjmp(int21buf)==0) longjmp(trapbuf,n); } while (0)
  24.  
  25. #define SWITCHBACK(x)  longjmp(int21buf,x)
  26.  
  27. #ifndef DEBUG
  28. #define PRINTME(n)
  29. #else
  30. #define PRINTME(n)  CONTINUE(n)
  31. #endif
  32. //=====================================================================
  33. //
  34. //  GpfRegs
  35. //
  36. //  This is what our stack looks like after we have entered our
  37. //  exception handler.
  38. //
  39. //  This is heavily dependant on order that Borland C pushes
  40. //  registers onto the stack.
  41. //
  42. //=====================================================================
  43. struct GpfRegs {
  44.     WORD Rbp;
  45.     WORD Rdi;
  46.     WORD Rsi;
  47.     WORD Rds;
  48.     WORD Res;
  49.     WORD Rdx;
  50.     WORD Rcx;
  51.     WORD Rbx;
  52.     WORD Rax;
  53.     WORD Rip;
  54.     WORD Rcs;
  55.     WORD Rfl;
  56.     WORD faultip;
  57.     WORD faultcs;
  58.     WORD flags;
  59.     WORD sp;
  60.     WORD ss;
  61. };
  62.  
  63.  
  64. //=====================================================================
  65. //
  66. //  global variables
  67. //
  68. //=====================================================================
  69. unsigned realDs;        // real mode segment for our DS
  70.  
  71. unsigned realCs;        // real mode segment for our CS
  72.  
  73. unsigned protDsAlias;   // CS alias for our DS
  74.  
  75. jmp_buf trapbuf;        // for a long jump to our exception handler
  76.  
  77. jmp_buf int21buf;       // for a long jump to coroutine to handle int 21h
  78.  
  79. GpfRegs gpfRegs;        // copy of registers at the time of the exception
  80.  
  81. GpfRegs far * pGpfRegs; // points to original registers at int/fault
  82.  
  83. DpmiInterruptVector oldInt21, oldInt61, oldCtrlC;
  84.  
  85. ModuleLoader *module;   // represents the .EXE we're trying to run
  86.  
  87. //=====================================================================
  88. //
  89. //  printDpmiException
  90. //
  91. //  print out our machine state, and attempt to do a traceback
  92. //
  93. //=====================================================================
  94. void printDpmiException(ModuleLoader *module)
  95. {
  96.     int i;
  97.     GpfRegs * pGpfRegs  = &gpfRegs;
  98.  
  99.     kprintf("\nProcessor Exception:\n");
  100.     kprintf("CS=%04x, DS=%04x  SS:SP=%04x:%04x\n",  _CS, _DS, _SS, _SP);
  101.  
  102.     kprintf("bp=%04x, di=%04x, si=%04x ds=%04x\n",
  103.         pGpfRegs->Rbp,
  104.         pGpfRegs->Rdi,
  105.         pGpfRegs->Rsi,
  106.         pGpfRegs->Rds);
  107.     kprintf("es=%04x, dx=%04x, cx=%04x bx=%04x\n",
  108.         pGpfRegs->Res,
  109.         pGpfRegs->Rdx,
  110.         pGpfRegs->Rcx,
  111.         pGpfRegs->Rbx);
  112.     kprintf("ax=%04x, ip=%04x, cs=%04x fl=%04x\n",
  113.         pGpfRegs->Rax,
  114.         pGpfRegs->Rip,
  115.         pGpfRegs->Rcs,
  116.         pGpfRegs->Rfl);
  117.  
  118.     kprintf("Fault CS:IP = %04x:%04x Flags=%04x\n",
  119.         pGpfRegs->faultcs,
  120.         pGpfRegs->faultip,
  121.         pGpfRegs->flags);
  122.  
  123.     kprintf("ss:sp = %04x:%04x\n",
  124.         pGpfRegs->ss,
  125.         pGpfRegs->sp);
  126.  
  127.     static jmp_buf savetrap;
  128.     memcpy(savetrap, trapbuf, sizeof(jmp_buf));
  129.  
  130.     if (setjmp(trapbuf)==0) {   // a fault here is ok
  131.         printf("\nStack traceback follows:\n");
  132.         {
  133.             char *faultDescr = module->describeFaultPc(
  134.                                     pGpfRegs->faultcs,
  135.                                     pGpfRegs->faultcs,
  136.                                     pGpfRegs->faultip);
  137.             kprintf("Fault at  %s\n", faultDescr);
  138.         }
  139.         unsigned bp = pGpfRegs->Rbp;
  140.         unsigned nearCs = pGpfRegs->faultcs;
  141.         for (i=0;i<20;i++) {
  142.             unsigned far *p = (unsigned far *) MK_FP(pGpfRegs->ss, bp);
  143.             char *faultDescr = module->describeFaultPc(
  144.                                     nearCs, p[2], p[1]);
  145.             kprintf("call from %s\n", faultDescr);
  146.             if (p[0]<=bp) break;
  147.             if (p[0]==0xffff) break;
  148.             bp = p[0];
  149.         }
  150.     }
  151.     memcpy(trapbuf, savetrap, sizeof(jmp_buf));
  152. }
  153.  
  154.  
  155. //=====================================================================
  156. //
  157. //  patchExceptionHandler
  158. //
  159. //  Before we can install a protected mode interrupt handler, we
  160. //  need to modify the interrupt procedure's prolog, because of
  161. //  the way BorlandC generates code...
  162. //
  163. //  This is very specific to this implementation
  164. //  and very easy to break!
  165. //
  166. //  In the prolog for Borland C interrupt procedures contains
  167. //  code to push the registers, and load DS with DGROUP.
  168. //
  169. //          ...
  170. //          MOV AX, DGROUP
  171. //          MOV DS, AX
  172. //          ...
  173. // 
  174. //  The problem is that this is compiled in with the
  175. //  DGROUP value of our real mode data segment.
  176. //
  177. //  Since this is a protected mode interrupt handler,
  178. //  we need that to be the protected mode selector
  179. //  for our data segment (not known till run time).
  180. //
  181. //  So we actually modify our code at run time to
  182. //  have the right value.
  183. //
  184. //  To accomplish this, we create a writeable alias selector,
  185. //  modify the code, and get rid of the alias.
  186. //
  187. //=====================================================================
  188. void patchExceptionHandler(DpmiInterruptVector v)
  189. {
  190.     unsigned WriteableCS;
  191.     unsigned far *p = (unsigned far *) v;
  192.  
  193.     if (Dpmi.createAlias(_CS, WriteableCS)!=DPMI_OK) {
  194.         printf("patchExceptionHandler: cannot create CS alias\n");
  195.         return;
  196.     }
  197.  
  198.     FP_SEG(p) = WriteableCS;
  199.     p[5] = _DS;
  200.     Dpmi.freeSelector(WriteableCS);
  201. }
  202.  
  203. //=====================================================================
  204. //
  205. //  installExceptionHandler
  206. //
  207. //  Install an exception handler to handle all protected mode processor
  208. //  exceptions.
  209. //
  210. //=====================================================================
  211. void installExceptionHandler(DpmiInterruptVector v)
  212. {
  213.     memset(&gpfRegs, 0, sizeof(gpfRegs));
  214.     FP_SEG(v) = _CS;
  215.     int i;
  216.     patchExceptionHandler( v );
  217. //    for (i=0;i<32;i++)
  218. //        Dpmi.setExceptionHandler(i, v);
  219.  
  220.     Dpmi.setExceptionHandler( 0, v);
  221.     Dpmi.setExceptionHandler( 6, v);
  222.     Dpmi.setExceptionHandler( 7, v);
  223.     Dpmi.setExceptionHandler( 9, v);
  224.     Dpmi.setExceptionHandler(12, v);
  225.     Dpmi.setExceptionHandler(13, v);
  226.  
  227. //    kprintf("exception handler traps set\n");
  228. }
  229.  
  230. //=====================================================================
  231. //
  232. //  installIntHandler
  233. //
  234. //  Install an exception handler to handle all protected mode processor
  235. //  exceptions.
  236. //
  237. //=====================================================================
  238. DpmiInterruptVector installIntHandler(int intno, DpmiInterruptVector v)
  239. {
  240.     DpmiInterruptVector oldVect;
  241.     FP_SEG(v) = _CS;
  242.     patchExceptionHandler( v );
  243.     oldVect = Dpmi.getProtVect(intno);
  244.     Dpmi.setProtVect(intno, v); 
  245.     return oldVect;
  246. }
  247.  
  248. //=====================================================================
  249. //
  250. //  copyArgs
  251. //
  252. //  copy the argv and envp arrays. Mainly needed because we need to
  253. //  convert from an array of near pointers to an array of far pointers.
  254. //
  255. //=====================================================================
  256. char far * far * copyArgs(int num, char **argv)
  257. {
  258.     if (num==0) {
  259.         char **p = argv;
  260.         while (*p++) num++;
  261.     }
  262.     char far * far * table = new char far * [num+1];
  263.     int i;
  264.     for (i=0;i<num;i++)
  265.         table[i] = argv[i];
  266.     table[num] = 0;
  267.     return table;
  268. }
  269.  
  270. //=====================================================================
  271. //
  272. //  ctrl_c
  273. //
  274. //  This is a routine to catch Control-C interrupts
  275. //  
  276. //
  277. //=====================================================================
  278. void far interrupt ctrl_c(...)
  279. {
  280.     pGpfRegs  = (GpfRegs far *) MK_FP(_SS, _BP);
  281.     longjmp(trapbuf,2);
  282. }
  283.  
  284. //=====================================================================
  285. //
  286. //  ReflectedRegs
  287. //
  288. //  an instance for each interrupt we reflect from real mode
  289. //  to protected mode.
  290. //
  291. //=====================================================================
  292. class ReflectedRegs {
  293.     public:
  294.         DPMI_Regs dregs;
  295.  
  296.         DpmiInterruptVector func;
  297.  
  298.         struct {            // this is actually a bit of code to
  299.             char opCall;    // call our protected mode reflector
  300.             unsigned off;
  301.             unsigned seg;
  302.             char iRet;
  303.         } isr;
  304.         unsigned long counter;
  305.         DpmiInterruptVector oldVect;
  306.         DpmiInterruptVector oldPVect;
  307.         int intNr;
  308.         unsigned magic;
  309. };
  310.  
  311.  
  312. //=====================================================================
  313. //
  314. //  reflectToProtMode
  315. //
  316. //  reflect a real mode interrupt to our protected mode handler
  317. //  (gets called in protected mode mode)
  318. //=====================================================================
  319. #pragma argsused
  320. void far interrupt reflectToProtMode(unsigned bp, unsigned di,
  321.     unsigned si, unsigned ds, unsigned es)
  322. {
  323.     ReflectedRegs far *caller = 
  324.             (ReflectedRegs far *) MK_FP(es, di);
  325.     unsigned far * stack = 
  326.             (unsigned far *) MK_FP(ds, si);
  327.     (*caller->func)();  // reflect the interrupt in protected mode
  328.     caller->counter++;
  329.     caller->dregs.cs = stack[1];
  330.     caller->dregs.ip = stack[0];
  331.     caller->dregs.sp += 4;
  332. }
  333.  
  334. //=====================================================================
  335. //
  336. //  installIntHandler
  337. //
  338. //  install reflecting real mode interrupt handler
  339. //
  340. //=====================================================================
  341. int installIntHandler(GpfRegs far *pGpfRegs)
  342. {
  343.     int intNr = pGpfRegs->Rbx;
  344.     DpmiInterruptVector func;
  345.     ReflectedRegs *iregp;
  346.     func = ( DpmiInterruptVector ) MK_FP(pGpfRegs->Rcx, pGpfRegs->Rdx);
  347.     iregp = (ReflectedRegs *) new ReflectedRegs;
  348.  
  349.     DpmiInterruptVector callback;
  350.  
  351.     {
  352.         DpmiInterruptVector h = (DpmiInterruptVector) reflectToProtMode;
  353.         patchExceptionHandler(h);
  354.         FP_SEG(h) = _CS;
  355.         if (Dpmi.allocateRealCallback(h, &iregp->dregs, callback)!=DPMI_OK) {
  356.             return DPMI_ERR;
  357.         }
  358.     }
  359.     iregp->magic      = 0x7079;
  360.     iregp->isr.opCall = 0x9a;   // call instruction
  361.     iregp->isr.seg    = FP_SEG(callback);
  362.     iregp->isr.off    = FP_OFF(callback);
  363.     iregp->isr.iRet   = 0xcf;   // iret
  364.     iregp->func       = func;
  365.     iregp->counter    = 0;
  366.     iregp->intNr      = intNr;
  367.     iregp->oldVect    = Dpmi.getRealVect(intNr);
  368.     iregp->oldPVect   = Dpmi.getProtVect(intNr);
  369.  
  370.     unsigned char far *pIsr = (unsigned char far *) &iregp->isr;   // compiler fills in a protected mode selector
  371.     FP_SEG(pIsr) = realDs;
  372.  
  373.     Dpmi.setRealVect(intNr, (DpmiInterruptVector) pIsr);
  374.     Dpmi.setProtVect(intNr, func);
  375.     pGpfRegs->Rbx = (unsigned) iregp;
  376.  
  377.     return DPMI_OK;
  378. }
  379.  
  380. //=====================================================================
  381. //
  382. //  removeIntHandler
  383. //
  384. //  remove real mode interrupt handler
  385. //
  386. //=====================================================================
  387. void removeIntHandler(GpfRegs far *pGpfRegs)
  388. {
  389.     ReflectedRegs *iregp = (ReflectedRegs *) pGpfRegs->Rbx;
  390.     if (iregp->magic  != 0x7079) {
  391.         pGpfRegs->Rax = 1;
  392.         return;
  393.     }
  394.     Dpmi.setRealVect(iregp->intNr, iregp->oldVect);
  395.     Dpmi.setProtVect(iregp->intNr, iregp->oldPVect);
  396.     iregp->magic = 0;
  397.     delete iregp;
  398.     pGpfRegs->Rax = 0;
  399. }
  400.  
  401. //=====================================================================
  402. //
  403. //  processInt61
  404. //
  405. //  coroutine to process int61 calls
  406. //
  407. //=====================================================================
  408. void processInt61(ModuleLoader *)
  409. {
  410.     // this is where we put processing for any calls that have to
  411.     // run in our stack space.
  412.     // we swap stacks by doing a setjmp/longjmp which takes us to here.
  413.     // When we're done, we switch back by doing a mirror setjmp/longjmp
  414.     // Of course this means that this code is not re-entrant, so it's
  415.     // best to avoid it altogether.
  416.     //
  417.     switch (pGpfRegs->Rax) {
  418.         case EXAPI_INSTALL:  // install reflector
  419.             {
  420.                 installIntHandler(pGpfRegs);
  421.             }
  422.             break;
  423.  
  424.         case EXAPI_REMOVE:
  425.             {
  426.                 removeIntHandler(pGpfRegs);
  427.             }
  428.             break;
  429.         case EXAPI_INITCOMM:
  430.             {
  431.                 initComm(pGpfRegs->Rbx, pGpfRegs->Rcx, pGpfRegs->Rdx);
  432.                 pGpfRegs->Rax = 0;
  433.             }
  434.             break;
  435.         case EXAPI_TERMCOMM:
  436.             {
  437.                 termComm(pGpfRegs->Rbx);
  438.                 pGpfRegs->Rax = 0;
  439.             }
  440.             break;
  441.         default:
  442.             {
  443.                 char *faultDescr = module->describeFaultPc(
  444.                                         pGpfRegs->Rcs,
  445.                                         pGpfRegs->Rcs, pGpfRegs->Rip);
  446.                 printf("dosX interrupt at  %s\n", faultDescr);
  447.                 fflush(stdout);
  448.             }
  449.     }
  450.     SWITCHBACK(1);
  451. }
  452.  
  453. //=====================================================================
  454. //
  455. //  int61
  456. //
  457. //  This is a routine to catch int61 calls
  458. //  (my internal debug stuff)
  459. //
  460. //  Be careful here, since _SS != _DS since this is the interface to
  461. //  the user program
  462. //=====================================================================
  463. void far interrupt int61(...)
  464. {
  465.     pGpfRegs  = (GpfRegs far *) MK_FP(_SS, _BP);
  466.     switch (pGpfRegs->Rax) {
  467.         case EXAPI_READCOMM:
  468.             {
  469.                 CommRequest far * req = (CommRequest far *)
  470.                         MK_FP(pGpfRegs->Rcx, pGpfRegs->Rdx);
  471.                 readComm(pGpfRegs->Rbx, req);
  472.                 pGpfRegs->Rax = 0;
  473.             }
  474.             break;
  475.         case EXAPI_WRITECOMM:
  476.             {
  477.                 CommRequest far * req = (CommRequest far *)
  478.                         MK_FP(pGpfRegs->Rcx, pGpfRegs->Rdx);
  479.                 writeComm(pGpfRegs->Rbx, req);
  480.                 pGpfRegs->Rax = 0;
  481.             }
  482.             break;
  483.         default:
  484.             CONTINUE(5);
  485.     }
  486. }
  487.  
  488. //=====================================================================
  489. //
  490. //  dpmiException
  491. //
  492. //  This is a routine to catch protected mode processor exceptions.
  493. //  
  494. //
  495. //=====================================================================
  496. void far interrupt dpmiException(...)
  497. {
  498.     GpfRegs far * pGpfRegs  = (GpfRegs far *) MK_FP(_SS, _BP);
  499.     _fmemcpy( &gpfRegs, pGpfRegs, sizeof(gpfRegs) );
  500.     longjmp(trapbuf,1);
  501. }
  502.  
  503. //=====================================================================
  504. //
  505. //  callMain
  506. //
  507. //  Start executing the program we just loaded.
  508. //
  509. //  We allocate a protected mode stack for the new program,
  510. //  copy argument and environment variables, switch to the
  511. //  new stack, and call the program's entrypoint passing
  512. //  argc, argv, and envp.
  513. //
  514. //=====================================================================
  515. void callMain(ModuleLoader *module, void far *startCsIp, int argc, char **argv, char **envp)
  516. {
  517.     const int StackSize = 4096;
  518.     static char far *stk = (char far *) module->getStack(StackSize);
  519.     if (!stk) {
  520.         Dpmi.fail("cannot allocate protected mode stack\n");
  521.         return;
  522.     }
  523.  
  524.     stk += (StackSize-32);
  525.  
  526.     static int (_far *mainline)(int, char far * far *, char far * far *);
  527.     mainline = ( int (_far *)(int, char far * far *, char far * far *) ) startCsIp;
  528.  
  529.  
  530.     // strip off the loader's name
  531.     argc--;
  532.     argv++;
  533.  
  534.     static char far* far* newargv = copyArgs(argc, argv);
  535.  
  536.     static char far* far* newenvp = copyArgs(0, envp);
  537.  
  538.     static int newargc = argc;
  539.  
  540.     switch (setjmp(trapbuf)) {
  541.         case 0:
  542.             // switch stacks 
  543.             flushall();
  544.             asm {
  545.                 mov ax, word ptr stk
  546.                 mov bx, word ptr stk+2
  547.                 mov ss,bx
  548.                 mov sp,ax
  549.                 push ds
  550.             }
  551.  
  552.             (*mainline)(newargc,newargv,newenvp);
  553.  
  554.             asm {
  555.                 pop ds
  556.             }
  557.             longjmp(trapbuf,3);
  558.             break;
  559.         case 1:
  560.             if (setjmp(trapbuf)==0) {
  561.                 printDpmiException(module);
  562.             }
  563.             Dpmi.fail("Processor Exception encountered\n");
  564.             break;
  565.         case 2:
  566.             {
  567.                 Dpmi.fail("Control-C intercepted\n");
  568.             }
  569.             break;
  570.         case 3:
  571.             break;
  572.         case 5:
  573.             processInt61(module);
  574.             break;
  575.         default:
  576.             ;
  577.     }
  578. }
  579.  
  580.  
  581. //=====================================================================
  582. //
  583. //  protectedMain
  584. //
  585. //  This is the protected mode mainline.
  586. //  We set up exception handler, load the program and run it.
  587. //=====================================================================
  588. int protectedMain(int argc, char *argv[], char *envp[])
  589. {
  590.     if (argc<2) {
  591.         printf("usage: dpmirun filename ...\n");
  592.         Dpmi.dosExit(1);
  593.     }
  594.  
  595.     module = newModuleLoader();
  596.  
  597.     static char *where;
  598.  
  599.     where = "before execution\n";
  600.     if (setjmp(trapbuf)!=0) {
  601.         puts(where);
  602.         Dpmi.fail("Exception encountered before execution\n");
  603.     }
  604.  
  605.     where = "setup exception handler";
  606.     installExceptionHandler(dpmiException);
  607.  
  608.     Dpmi.createAlias(_DS, protDsAlias); // for making thunks!
  609.  
  610. #ifdef DEBUG21
  611.     oldInt21 = installIntHandler(0x21, int21);
  612. #endif
  613.  
  614.     oldCtrlC = installIntHandler(0x23, ctrl_c);
  615.     oldInt61 = installIntHandler(EXTENDER_VECT, int61);
  616.  
  617.     where = "error loading executable";
  618.     module->loadExecutable(argv[1]);
  619.  
  620.     where = "error adjusting selectors";
  621.     module->adjustSelectors();
  622.  
  623.     where = "error getting entry point";
  624.     void _far *entryPoint = module->entryPoint();
  625.  
  626.     where = "error check loadErrors";
  627.     if (module->loadErrors()) {
  628.         printf("cannot execute because of load errors\n");
  629.         return 0;
  630.     }
  631.  
  632.     where = "reset traps";
  633.     callMain(module, entryPoint, argc, argv, envp);
  634.  
  635.     Dpmi.setProtVect(0x23, oldCtrlC);
  636.  
  637.     Dpmi.setProtVect(EXTENDER_VECT, oldInt61);
  638.  
  639. #ifdef DEBUG21
  640.     Dpmi.setProtVect(0x21, oldInt21);
  641. #endif
  642.  
  643.     return 0;
  644. }
  645.  
  646.  
  647. //=====================================================================
  648. //
  649. //  main
  650. //
  651. //  We switch to protected mode, and call the protected mode mainline
  652. //
  653. //=====================================================================
  654. int main(int argc, char *argv[], char *envp[])
  655. {
  656.     int ret;
  657.     
  658.     flushall();     // flush all buffers before switch into protected mode, 
  659.                     // so I/O redirection works properly
  660.     realDs = _DS;
  661.     realCs = _CS;
  662.  
  663.     if (!Dpmi.present())
  664.       if (!Dpmi.init())
  665.         Dpmi.fail("This program requires DPMI");
  666.  
  667.     // now in protected mode: segment registers have changed
  668.  
  669.  
  670.     ret = protectedMain(argc, argv, envp);
  671.  
  672.     flushall();
  673.  
  674.     Dpmi.dosExit(ret);
  675.  
  676.     return 0;
  677. }
  678.