home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1990 / 08 / dudley.lst < prev    next >
File List  |  1990-06-20  |  15KB  |  564 lines

  1. _PORTING C PROGRAMS TO 80386 PROTECTED MODE_
  2. by William F. Dudley, Jr.
  3.  
  4. [LISTING ONE]
  5.  
  6. ; William F. Dudley, Jr.
  7. ; real mode module callable from protected mode, passes string in
  8. ; buffer in code segment.
  9. ss_text         SEGMENT BYTE PUBLIC 'CODE' use16
  10.                 ASSUME  CS:ss_text , DS:NOTHING , ES:NOTHING
  11. ; The string is pointed to by DS:SI with the length in CX.
  12. ; encryption value of string returned in AX.
  13.         public    QUERY_FAR
  14.  
  15. QUERY_FAR    PROC    FAR
  16.         CALL    QUERY
  17.         RET
  18. QUERY_FAR    ENDP
  19.  
  20. QUERY        PROC    NEAR
  21. ;
  22. ; here lives the real mode dongle communications code
  23. QUERY        ENDP
  24.         
  25.         public    _test_string
  26. _test_string    db    256 dup (?)
  27.  
  28.         public    _end_real
  29. _end_real label    byte
  30.  
  31. ss_text         ENDS
  32.                 END
  33.  
  34.  
  35. [LISTING TWO]
  36.  
  37. /* William F. Dudley Jr.
  38.  * module to connect real mode assembly code to prot mode C
  39.  */
  40. #include <stdio.h>
  41. #include <dos.h>
  42. #include "list5.h"
  43.  
  44. int real_addr;            /* real address of start of real mode code */
  45. int real_seg, real_off;        /* segment and offset of real_addr */
  46.  
  47. #pragma aux QUERY_FAR "*";    /* tell Watcom C that no '_' is used */
  48.  
  49. extern char test_string;    /* string buffer in real mode module */
  50. extern char end_real;        /* end of real mode code */
  51. extern char QUERY_FAR;    /* actually a function, but we just want address */
  52.  
  53. short COMPUTE(char *str);    /* this is the subroutine that does the work */
  54. int pr2real(void);        /* initialize value of real_addr, etc. */
  55.  
  56. void real_setup(void) {
  57.     real_addr = pr2real();
  58.     real_seg = (real_addr >> 16) & 0xffff ;
  59.     real_off = real_addr & 0xffff ;
  60. }
  61.  
  62. int pr2real(void) {
  63. union REGS r;
  64. struct SREGS sr;
  65.  
  66.   r.x.ax = 0x250f;    /* convert prot addr to real addr */
  67.   r.d.ebx = 0;        /* start of program */
  68.   r.d.ecx = (int)&end_real;    /* length of real mode stuff */
  69.   sr.fs = 0x3c;
  70.   sr.es = Ds();
  71.   sr.ds = sr.ss = sr.gs = 0x14;
  72.   sr.cs = 0x0c;
  73.   int386x(0x21, &r, &r, &sr);
  74.   if(r.d.cflag) {
  75.       fprintf(stderr, "Error in PR2REAL(), can't map address.\n");
  76.       fflush(stderr);
  77.       exit(1);
  78.   }
  79.   return(r.d.ecx);
  80. }
  81.  
  82. short COMPUTE(char *str) {
  83. union REGS r;
  84. struct phregs pr;
  85. unsigned short i;
  86. unsigned j;
  87.   r.x.ax = 0x2510;        /* call function */
  88.   r.d.ebx = real_addr;        /* get segment of real mode stuff */
  89.   r.x.bx = (int)&QUERY_FAR;    /* EBX is address of QUERY_FAR subroutine */
  90.   r.d.ecx = 0;            /* 0 words on stack */
  91.   r.d.edx = (int)≺        /* DS:EDX is address of register struct */
  92.   pr.ECX = strlen(str);        /* CX is length of string */
  93.   i = real_off + (int)&test_string;
  94.   j = i + (real_seg<<4);          /* calculate address in selector 0x34 */
  95.   blk_mv_pr(str, 0x34, j, pr.ECX);    /* copy string to buffer in real CS */
  96.   r.x.si = i;            /* DS:SI points to string */
  97.   pr.ES = pr.DS = real_seg;
  98.   int386(0x21, &r, &r);
  99.   return(r.x.ax);
  100. }
  101.  
  102.  
  103.  
  104. [LISTING THREE]
  105.  
  106. ; William F. Dudley Jr.
  107. ; copy from real to protected or vice-versa
  108. ; void blk_mov_pr(char *bufadr, unsigned reg_seg, unsigned reg_off, unsigned count);
  109. ; type    variable    is in:
  110. ; char    *bufadr        EAX
  111. ; uint    reg_off        EBX
  112. ; uint    count        ECX
  113. ; uint    reg_seg        EDX
  114. ; Transfers COUNT bytes from the buffer (in the current data seg) bufadr
  115. ; to address in protected memory at reg_seg:reg_off.
  116.  
  117.     NAME    blk_mov
  118.     EXTRN    __STK:WORD
  119. _TEXT    SEGMENT    PUBLIC BYTE USE32 'CODE'
  120.     ASSUME    CS:_TEXT
  121.     PUBLIC    blk_mov_pr_
  122.     PUBLIC    blk_mov_rp_
  123.  
  124. ; protected to real
  125. blk_mov_pr_    proc    near
  126.     pushf
  127.     push    EDI
  128.     push    ESI
  129.     push    ES
  130.     jecxz    non1
  131.     cld
  132.     ; count is in ECX already
  133.     mov    ESI, EAX    ;bufadr is source
  134.     mov    ES, DX        ;reg_seg is dest (ES:EDI)
  135.     mov    EDI, EBX    ;reg_off is dest
  136.     rep    movsb
  137. non1:    pop    ES
  138.     pop    ESI
  139.     pop    EDI
  140.     popf
  141.     ret
  142. blk_mov_pr_    endp
  143.  
  144. ; real to protected
  145. blk_mov_rp_    proc    near
  146.     pushf
  147.     push    EDI
  148.     push    ESI
  149.     push    ES
  150.     push    DS
  151.     jecxz    non2
  152.     cld
  153.     push    DS
  154.     pop    ES
  155.     ;count is in ECX
  156.     mov    EDI,EAX        ;bufadr    is dest (ES:EDI)
  157.     mov    DS,DX        ;reg_seg is source (DS:ESI)
  158.     mov    ESI,EBX        ;reg_off is source
  159.     repe    movsb 
  160. non2:    pop    DS
  161.     pop    ES
  162.     pop    ESI
  163.     pop    EDI
  164.     popf
  165.     ret
  166. blk_mov_rp_    endp
  167.  
  168. _TEXT    ENDS
  169.     END
  170.  
  171.  
  172.  
  173.  
  174. [LISTING FOUR]
  175.  
  176. /* William F. Dudley Jr. */
  177.  
  178. #include <stdio.h>
  179. #include <dos.h>
  180. #include <process.h>
  181. #include <io.h>
  182.  
  183. #include "list5.h"        /* dud's driver interface constants */
  184.  
  185. /* map of real mode link (call buffer) memory:
  186.  * rel address    name        comment
  187.  * 0        rcolortable    pointer to 128 bytes for color table storage
  188.  * 128        qpixel        pointer to MAXB (8500) bytes for pixel storage
  189.  */
  190. #define MAXB 8500
  191.  
  192. int mblocks;            /* no of save/restore blocks    */
  193. static int ddi_allocated = 0;    /* true if initialization has been performed */
  194. static int rcolortable;    /* real mode address of colortable (intermode buf) */
  195.  
  196. static int qpixel;        /* real mode address of line storage space */
  197. int nsegment, noffset;        /* line storage segment & offset */
  198. static short psegment;        /* protected address of pixel buffer */
  199. static int poffset;        /* protected address of pixel buffer */
  200.  
  201. extern int vectnum;        /* ddi interrupt vector (usually 0x7A) */
  202. extern void pdintinit(void);    /* setup for pdinterp() */
  203.  
  204. static int blocksizes[100];    /* array of saved blocks for save/rstr scrn */
  205.  
  206. /* sets video mode and initializes the video parameters */
  207. void setvmode(void)
  208. {
  209.   union REGS r;
  210.   struct SREGS sr;
  211.   int i;
  212.   char paltbl[64];    /* driver will dump palette here. */
  213.  
  214.     if(!ddi_allocated) {
  215.     r.x.ax = 0x250d;    /* get real mode link information */
  216.     /* segment regs must all have legal values in them.
  217.      * These values are documented in the Phar-Lap Extender manual
  218.      */
  219.     sr.fs = 0x3c;
  220.     sr.ds = sr.ss = sr.es = sr.gs = 0x14;    /* the data "segment" */
  221.     sr.cs = 0x0c;                /* the code "segment" */
  222.     int386x(0x21, &r, &r, &sr);
  223.     /* es:edx = protected address of call buffer */
  224.     rcolortable = r.d.ebx;    /* ebx = real address of call buffer */
  225.     poffset = r.d.edx;    /* save protected offset to table start */
  226.     psegment = sr.es;    /* psegment = 0x60 in Phar-World */
  227.     qpixel = rcolortable + 128;
  228.     reset_lines();
  229.     if(r.d.ecx < (MAXB + MAXCOLORS)) {    /* ecx = size of buffer */
  230.         fprintf(stderr,"real mode buffer isn't big enough: %d\n", r.d.ecx);
  231.         abort();
  232.     }
  233.     }
  234.     r.h.ah = KINIT1;
  235.     r.x.bx = (rcolortable >> 16) & 0xffff;    /* segment of real mode buf */
  236.     r.x.cx = rcolortable & 0xffff;        /* offset of real mode buf */
  237.     r.x.si = r.x.di = 0;    /* clear so we can tell if they are set */
  238.     int86(vectnum, &r, &r);
  239.     /* The registers have various video constants in them.  The code that
  240.      * uses them is not shown for clarity.
  241.      */
  242.     if(!r.x.si && !r.x.di) {    /* if driver does not return its address */
  243.     fprintf(stderr, "old driver installed, you need current version!\n");
  244.     exit(1);
  245.     }
  246.     prot.vidfn.addr[1] = r.x.si;    /* real mode address of video entry */
  247.     prot.vidfn.addr[0] = r.x.di;
  248.     pdintinit();
  249.     listinit();
  250.     color_mask = (int)r.h.al - 1;
  251.     if(!ddi_allocated) {
  252.     /* copy from real to prot bufr */
  253.     blk_mv_rp(paltbl, psegment, poffset, 64);
  254.     /* copy array of chars to array of ints */
  255.     for(i=0 ; i <= color_mask ; i++ ) colortable[i] = (int)paltbl[i];
  256.     }
  257.  
  258.     r.h.ah = KINIT2;
  259.     r.h.al = 0;            /* don't switch modes */
  260.     int86 (vectnum, &r, &r);
  261.     /* The registers have various video constants in them.  The code that
  262.      * uses them is not shown for clarity.
  263.      */
  264.     mblocks = r.h.dl;        /* number of blocks to save screen */
  265.     ddi_allocated = TRUE;
  266. }
  267.  
  268. void reset_lines ()
  269. {
  270.     nsegment = (qpixel >> 16) & 0xffff;
  271.     noffset = qpixel & 0xffff;
  272.     return;
  273. }
  274.  
  275. /* Restore Video Buffer, returns status */
  276. int rstr_vbuf(void)
  277. {
  278. union REGS r;
  279. int i, l;
  280. int rtncode = 0;
  281. char bbuf[8200];
  282. char *lbuf;
  283. lbuf = (char *)bbuf;
  284.  
  285.     if (vbfnum!=NULL) rtncode=lseek(vbfnum,0L,0);    /* beg of file */
  286.     else return(OKAY);
  287.  
  288.     r.h.ah = INITDMP;        /* init driver */
  289.     r.h.al = SWRITE;
  290. #ifdef __386__
  291.     r.x.bx = nsegment;
  292.     r.x.cx = noffset;
  293. #else
  294.     r.x.bx = FP_SEG(lbuf);
  295.     r.x.cx = FP_OFF(lbuf);
  296. #endif
  297.     int86(vectnum, &r, &r);
  298.     /* now restore screen */
  299.     for(i = 0 ; i < mblocks ; i++ ) {
  300.     rtncode=read(vbfnum, lbuf, blocksizes[i]);
  301.     if(rtncode<= 0) return(ERROR);
  302.     r.h.ah = KDUMP;
  303. #ifdef __386__
  304.     l = (blocksizes[i] < 8192) ? blocksizes[i] : 8192 ;
  305.     blk_mv_pr(bbuf, psegment, poffset+128, l); /* copy from prot to real */
  306. #endif
  307.     int86(vectnum, &r, &r);
  308.     }
  309.     return(OKAY);
  310. }
  311.  
  312. /* clear the draw list */
  313. void listinit(void) {
  314.     prot.list[0][0] = 0;
  315.     prot.lp = 0;
  316.     list_p = prot.list[0];
  317. }
  318.  
  319.  
  320.  
  321.  
  322. [LISTING FIVE]
  323.  
  324. /* William F. Dudley, Jr.
  325.  * macros for getting to the driver from an application
  326.  */
  327.  
  328. extern int vectnum;
  329.  
  330. int Ds(void);            /* what is value of DS register */
  331. #pragma aux Ds = \
  332.     0x8c 0xd8    /* mov ax, ds */ \
  333.     modify [AH AL];
  334.  
  335. /* register arrangement for Phar-Lap function 0x2510 */
  336. struct phregs {
  337.         unsigned short DS;
  338.         unsigned short ES;
  339.         unsigned short FS;
  340.         unsigned short GS;
  341.     int EAX;
  342.     int EBX;
  343.     int ECX;
  344.     int EDX;
  345.     } ;
  346.  
  347. #define LLEN 100    /* assembly language module must agree with this */
  348. #ifndef PDINTERP
  349. extern
  350. #endif
  351.     struct {
  352.     union {
  353.         int (* p)(); /* this is for human info only, we never call it */
  354.         short int addr[2];    /* [0]seg and [1]off of driver entry point */
  355.     } vidfn ;
  356.     short int lp;
  357.     short int list[LLEN][6];
  358.     } prot ;
  359. #ifndef PDINTERP
  360. extern
  361. #endif
  362.     short int *list_p;
  363. void listinit(void);
  364. void pdinterp(void);
  365.  
  366. void kdidraw(short int,short int,short int,short int,short int,short int);
  367. /* tell Watcom C how to use registers for arguments */
  368. #pragma aux kdidraw parm [EAX] [EBX] [ECX] [EDX] [ESI] [EDI];
  369.  
  370. /* move to x1,y1, route/line width will be w */
  371. #define M(x1,y1,w) kdidraw((KMOVE<<8), x1, y1, w, 0, 0)
  372. /* put dot at x1, y, color c, atrib at */
  373. #define DOT(x1,y1,c,at) kdidraw(at+(KWDOT<<8), x1, y1, c, 0, 0)
  374. /* draw line from M point to x1,y1, color c, atrib at */
  375. #define D(x1,y1,c,at) kdidraw(at+(KDRAW<<8), x1, y1, c, 0, 0)
  376.  
  377.  
  378.  
  379.  
  380. [LISTING SIX]
  381.  
  382. ; William F. Dudley, Jr.
  383. ; "porting a large application to 386 protected mode"
  384. ; This is the protected mode function that stuffs draw commands
  385. ; in the draw list.  If the list fills up, it automatically calls
  386. ; pdinterp() to empty it.
  387. ;
  388.         NAME    storlist
  389.         EXTRN   pdinterp_:WORD
  390.         EXTRN   _prot:WORD
  391.         EXTRN   _list_p:WORD
  392. LLEN    EQU    100        ; size of draw list, must agree with C version.
  393. DGROUP        GROUP   CONST,_DATA,_BSS
  394. _TEXT        SEGMENT PUBLIC BYTE USE32 'CODE'
  395.         ASSUME  CS:_TEXT,DS:DGROUP
  396.         PUBLIC  kdidraw_
  397.         ; args in ax,bx,cx,dx,si,di
  398.         ; global list pointer in _list_p is incremented by 12
  399. kdidraw_:
  400.         push    esi                ;save si
  401.         mov     si,ax            ;save ax
  402.         mov     eax,dword ptr _list_p
  403.         mov     word ptr [eax],si
  404.         mov     word ptr [eax+2],bx
  405.         mov     word ptr [eax+4],cx
  406.         mov     word ptr [eax+6],dx
  407.         pop        esi                ; get back si
  408.         mov     word ptr [eax+8],si
  409.         mov     word ptr [eax+10],di
  410.         add     eax, 12
  411.         mov     dword ptr _list_p,eax
  412.  
  413.         inc     word ptr _prot+4H
  414.         cmp     word ptr _prot+4H,LLEN-3
  415.         jle     L1
  416.         call    near ptr pdinterp_
  417.         jmp     short L2
  418. L1:        mov     word ptr [eax],0000H
  419. L2:        ret
  420. _TEXT       ENDS
  421.  
  422. CONST       SEGMENT PUBLIC WORD USE32 'DATA'
  423. CONST       ENDS
  424. _DATA       SEGMENT PUBLIC WORD USE32 'DATA'
  425. _DATA       ENDS
  426. _BSS        SEGMENT PUBLIC WORD USE32 'BSS'
  427. _BSS        ENDS
  428.         END
  429.  
  430.  
  431.  
  432. [LISTING SEVEN]
  433.  
  434. /* pdinterp.c -- William F. Dudley, Jr.
  435.  * protected dinterp() for Phar-Lap environment.
  436.  * this is the protected half of the draw list kdi processor
  437.  */
  438. #include <stdio.h>
  439. #include <dos.h>
  440. #define PDINTERP 1
  441. #include "list5.h"
  442.  
  443. extern int real_addr;        /* real address of start of real mode code */
  444. extern int real_seg, real_off;        /* segment and offset of real_addr */
  445. extern char real;        /* real copy of vidfnp, lp, draw list */
  446. extern char end_real;
  447. extern char dinterp;    /* actually a function, but we just want address */
  448. void pdinterp(void);
  449. int pr2real(void);
  450.  
  451. static union REGS pregs;
  452. static struct phregs pr;
  453. static unsigned short real_o;
  454. static unsigned abs_adr;
  455. static int pdinitted=0;
  456.  
  457. void pdinterp() {
  458. union REGS r;
  459.   if(!prot.lp) return;
  460.   if(!pdinitted) pdintinit();
  461.   /* copy list to buffer in real code seg */
  462.   blk_mov_pr(&prot, 0x34, abs_adr, sizeof(prot));
  463.   int386(0x21, &pregs, &r);
  464.   prot.list[prot.lp = 0][0] = 0;
  465.   list_p = prot.list[0];
  466. }
  467.  
  468. void pdintinit(void) {
  469.   pregs.x.ax = 0x2510;        /* call function */
  470.   pregs.d.ebx = real_addr;    /* get segment of real mode stuff */
  471.   pregs.x.bx = (short int)&dinterp; /* EBX is address of dinterp subroutine */
  472.   pregs.d.ecx = 0;        /* 0 words on stack */
  473.   pregs.d.edx = (int)≺    /* DS:EDX is address of register struct */
  474.   real_o = real_off + (short int)ℜ
  475.   abs_adr = real_o + (real_seg<<4);   /* calculate address in selector 0x34 */
  476.   pregs.x.si = real_o+6;          /* DS:SI points to list */
  477.   pr.ES = pr.DS = real_seg;
  478.   pdinitted = 1;
  479. }
  480.  
  481. #if IN_C
  482. /* this is a C version of the kdidraw() function in list6.asm */
  483. void kdidraw(short int Ax,short int Bx,short int Cx,short int Dx, short int Si,short int Di) {
  484. register short int *pi_;
  485.     pi_=prot.list[prot.lp];
  486.     *pi_++ = (short)(Ax);
  487.     *pi_++ = (short)(Bx);
  488.     *pi_++ = (short)(Cx);
  489.     *pi_++ = (short)(Dx);
  490.     *pi_++ = (short)(Si);
  491.     *pi_++ = (short)(Di);
  492.     if(++prot.lp > LLEN-3) pdinterp();
  493.     else *pi_ = 0;
  494. }
  495. #endif
  496.  
  497.  
  498.  
  499.  
  500. [LISTING EIGHT]
  501.  
  502. ; William F. Dudley, Jr.
  503. ; "Porting a large application to 386 protected mode"
  504. ; This is the real mode draw list interpreter.
  505. ;
  506. d_text    SEGMENT BYTE PUBLIC 'CODE' use16
  507.     ASSUME  CS:d_text , DS:NOTHING , ES:NOTHING
  508.  
  509. LLEN    EQU    100        ; size of draw list
  510.  
  511.     public    _dinterp
  512.     public    _real
  513. _real    label    word
  514.     db    (12*LLEN+6) dup (?)
  515.  
  516. _dinterp proc    far
  517.     call    dint
  518.     ret
  519. _dinterp endp
  520.  
  521. ; ds:si points to real array at entry
  522. dint    proc    near
  523. floop:    push    word ptr [si+10]    ; di
  524.     push    word ptr [si+8]        ; si
  525.     push    word ptr [si+6]        ; dx
  526.     push    word ptr [si+4]        ; cx
  527.     push    word ptr [si+2]        ; bx
  528.     push    word ptr [si+0]        ; ax
  529.     add    si,12 
  530.     call    dword ptr cs:[_real]
  531.     add    sp,12
  532. iftest:    cmp    word ptr [si+0] ,0
  533.     jne    floop
  534.     ret    
  535. dint    endp
  536.  
  537. d_text    ends
  538.     end
  539.  
  540.  
  541.  
  542. [Example 1: Three locations in the real mode code are directly accessed
  543. from protected mode]
  544.  
  545. extern char test_string;  /* string buffer in real mode module */
  546. extern char end_real;     /* end of real mode code */
  547. extern char QUERY_FAR;   /* actually a function, but we just want address */
  548.  
  549.  
  550. [Example 2: Protected-mode structure] 
  551.  
  552.  
  553. struct {
  554.   union {
  555.    int (* p)();
  556.      short int addr[2];  /* [0]segment and [1]offset of driver entry point */
  557.     } vidfn ;
  558.    short int lp;
  559.  short int list[LLEN][6];
  560. } prot ;
  561.  
  562.  
  563.  
  564.