home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1990
/
08
/
dudley.lst
< prev
next >
Wrap
File List
|
1990-06-20
|
15KB
|
564 lines
_PORTING C PROGRAMS TO 80386 PROTECTED MODE_
by William F. Dudley, Jr.
[LISTING ONE]
; William F. Dudley, Jr.
; real mode module callable from protected mode, passes string in
; buffer in code segment.
ss_text SEGMENT BYTE PUBLIC 'CODE' use16
ASSUME CS:ss_text , DS:NOTHING , ES:NOTHING
; The string is pointed to by DS:SI with the length in CX.
; encryption value of string returned in AX.
public QUERY_FAR
QUERY_FAR PROC FAR
CALL QUERY
RET
QUERY_FAR ENDP
QUERY PROC NEAR
;
; here lives the real mode dongle communications code
QUERY ENDP
public _test_string
_test_string db 256 dup (?)
public _end_real
_end_real label byte
ss_text ENDS
END
[LISTING TWO]
/* William F. Dudley Jr.
* module to connect real mode assembly code to prot mode C
*/
#include <stdio.h>
#include <dos.h>
#include "list5.h"
int real_addr; /* real address of start of real mode code */
int real_seg, real_off; /* segment and offset of real_addr */
#pragma aux QUERY_FAR "*"; /* tell Watcom C that no '_' is used */
extern char test_string; /* string buffer in real mode module */
extern char end_real; /* end of real mode code */
extern char QUERY_FAR; /* actually a function, but we just want address */
short COMPUTE(char *str); /* this is the subroutine that does the work */
int pr2real(void); /* initialize value of real_addr, etc. */
void real_setup(void) {
real_addr = pr2real();
real_seg = (real_addr >> 16) & 0xffff ;
real_off = real_addr & 0xffff ;
}
int pr2real(void) {
union REGS r;
struct SREGS sr;
r.x.ax = 0x250f; /* convert prot addr to real addr */
r.d.ebx = 0; /* start of program */
r.d.ecx = (int)&end_real; /* length of real mode stuff */
sr.fs = 0x3c;
sr.es = Ds();
sr.ds = sr.ss = sr.gs = 0x14;
sr.cs = 0x0c;
int386x(0x21, &r, &r, &sr);
if(r.d.cflag) {
fprintf(stderr, "Error in PR2REAL(), can't map address.\n");
fflush(stderr);
exit(1);
}
return(r.d.ecx);
}
short COMPUTE(char *str) {
union REGS r;
struct phregs pr;
unsigned short i;
unsigned j;
r.x.ax = 0x2510; /* call function */
r.d.ebx = real_addr; /* get segment of real mode stuff */
r.x.bx = (int)&QUERY_FAR; /* EBX is address of QUERY_FAR subroutine */
r.d.ecx = 0; /* 0 words on stack */
r.d.edx = (int)≺ /* DS:EDX is address of register struct */
pr.ECX = strlen(str); /* CX is length of string */
i = real_off + (int)&test_string;
j = i + (real_seg<<4); /* calculate address in selector 0x34 */
blk_mv_pr(str, 0x34, j, pr.ECX); /* copy string to buffer in real CS */
r.x.si = i; /* DS:SI points to string */
pr.ES = pr.DS = real_seg;
int386(0x21, &r, &r);
return(r.x.ax);
}
[LISTING THREE]
; William F. Dudley Jr.
; copy from real to protected or vice-versa
; void blk_mov_pr(char *bufadr, unsigned reg_seg, unsigned reg_off, unsigned count);
; type variable is in:
; char *bufadr EAX
; uint reg_off EBX
; uint count ECX
; uint reg_seg EDX
; Transfers COUNT bytes from the buffer (in the current data seg) bufadr
; to address in protected memory at reg_seg:reg_off.
NAME blk_mov
EXTRN __STK:WORD
_TEXT SEGMENT PUBLIC BYTE USE32 'CODE'
ASSUME CS:_TEXT
PUBLIC blk_mov_pr_
PUBLIC blk_mov_rp_
; protected to real
blk_mov_pr_ proc near
pushf
push EDI
push ESI
push ES
jecxz non1
cld
; count is in ECX already
mov ESI, EAX ;bufadr is source
mov ES, DX ;reg_seg is dest (ES:EDI)
mov EDI, EBX ;reg_off is dest
rep movsb
non1: pop ES
pop ESI
pop EDI
popf
ret
blk_mov_pr_ endp
; real to protected
blk_mov_rp_ proc near
pushf
push EDI
push ESI
push ES
push DS
jecxz non2
cld
push DS
pop ES
;count is in ECX
mov EDI,EAX ;bufadr is dest (ES:EDI)
mov DS,DX ;reg_seg is source (DS:ESI)
mov ESI,EBX ;reg_off is source
repe movsb
non2: pop DS
pop ES
pop ESI
pop EDI
popf
ret
blk_mov_rp_ endp
_TEXT ENDS
END
[LISTING FOUR]
/* William F. Dudley Jr. */
#include <stdio.h>
#include <dos.h>
#include <process.h>
#include <io.h>
#include "list5.h" /* dud's driver interface constants */
/* map of real mode link (call buffer) memory:
* rel address name comment
* 0 rcolortable pointer to 128 bytes for color table storage
* 128 qpixel pointer to MAXB (8500) bytes for pixel storage
*/
#define MAXB 8500
int mblocks; /* no of save/restore blocks */
static int ddi_allocated = 0; /* true if initialization has been performed */
static int rcolortable; /* real mode address of colortable (intermode buf) */
static int qpixel; /* real mode address of line storage space */
int nsegment, noffset; /* line storage segment & offset */
static short psegment; /* protected address of pixel buffer */
static int poffset; /* protected address of pixel buffer */
extern int vectnum; /* ddi interrupt vector (usually 0x7A) */
extern void pdintinit(void); /* setup for pdinterp() */
static int blocksizes[100]; /* array of saved blocks for save/rstr scrn */
/* sets video mode and initializes the video parameters */
void setvmode(void)
{
union REGS r;
struct SREGS sr;
int i;
char paltbl[64]; /* driver will dump palette here. */
if(!ddi_allocated) {
r.x.ax = 0x250d; /* get real mode link information */
/* segment regs must all have legal values in them.
* These values are documented in the Phar-Lap Extender manual
*/
sr.fs = 0x3c;
sr.ds = sr.ss = sr.es = sr.gs = 0x14; /* the data "segment" */
sr.cs = 0x0c; /* the code "segment" */
int386x(0x21, &r, &r, &sr);
/* es:edx = protected address of call buffer */
rcolortable = r.d.ebx; /* ebx = real address of call buffer */
poffset = r.d.edx; /* save protected offset to table start */
psegment = sr.es; /* psegment = 0x60 in Phar-World */
qpixel = rcolortable + 128;
reset_lines();
if(r.d.ecx < (MAXB + MAXCOLORS)) { /* ecx = size of buffer */
fprintf(stderr,"real mode buffer isn't big enough: %d\n", r.d.ecx);
abort();
}
}
r.h.ah = KINIT1;
r.x.bx = (rcolortable >> 16) & 0xffff; /* segment of real mode buf */
r.x.cx = rcolortable & 0xffff; /* offset of real mode buf */
r.x.si = r.x.di = 0; /* clear so we can tell if they are set */
int86(vectnum, &r, &r);
/* The registers have various video constants in them. The code that
* uses them is not shown for clarity.
*/
if(!r.x.si && !r.x.di) { /* if driver does not return its address */
fprintf(stderr, "old driver installed, you need current version!\n");
exit(1);
}
prot.vidfn.addr[1] = r.x.si; /* real mode address of video entry */
prot.vidfn.addr[0] = r.x.di;
pdintinit();
listinit();
color_mask = (int)r.h.al - 1;
if(!ddi_allocated) {
/* copy from real to prot bufr */
blk_mv_rp(paltbl, psegment, poffset, 64);
/* copy array of chars to array of ints */
for(i=0 ; i <= color_mask ; i++ ) colortable[i] = (int)paltbl[i];
}
r.h.ah = KINIT2;
r.h.al = 0; /* don't switch modes */
int86 (vectnum, &r, &r);
/* The registers have various video constants in them. The code that
* uses them is not shown for clarity.
*/
mblocks = r.h.dl; /* number of blocks to save screen */
ddi_allocated = TRUE;
}
void reset_lines ()
{
nsegment = (qpixel >> 16) & 0xffff;
noffset = qpixel & 0xffff;
return;
}
/* Restore Video Buffer, returns status */
int rstr_vbuf(void)
{
union REGS r;
int i, l;
int rtncode = 0;
char bbuf[8200];
char *lbuf;
lbuf = (char *)bbuf;
if (vbfnum!=NULL) rtncode=lseek(vbfnum,0L,0); /* beg of file */
else return(OKAY);
r.h.ah = INITDMP; /* init driver */
r.h.al = SWRITE;
#ifdef __386__
r.x.bx = nsegment;
r.x.cx = noffset;
#else
r.x.bx = FP_SEG(lbuf);
r.x.cx = FP_OFF(lbuf);
#endif
int86(vectnum, &r, &r);
/* now restore screen */
for(i = 0 ; i < mblocks ; i++ ) {
rtncode=read(vbfnum, lbuf, blocksizes[i]);
if(rtncode<= 0) return(ERROR);
r.h.ah = KDUMP;
#ifdef __386__
l = (blocksizes[i] < 8192) ? blocksizes[i] : 8192 ;
blk_mv_pr(bbuf, psegment, poffset+128, l); /* copy from prot to real */
#endif
int86(vectnum, &r, &r);
}
return(OKAY);
}
/* clear the draw list */
void listinit(void) {
prot.list[0][0] = 0;
prot.lp = 0;
list_p = prot.list[0];
}
[LISTING FIVE]
/* William F. Dudley, Jr.
* macros for getting to the driver from an application
*/
extern int vectnum;
int Ds(void); /* what is value of DS register */
#pragma aux Ds = \
0x8c 0xd8 /* mov ax, ds */ \
modify [AH AL];
/* register arrangement for Phar-Lap function 0x2510 */
struct phregs {
unsigned short DS;
unsigned short ES;
unsigned short FS;
unsigned short GS;
int EAX;
int EBX;
int ECX;
int EDX;
} ;
#define LLEN 100 /* assembly language module must agree with this */
#ifndef PDINTERP
extern
#endif
struct {
union {
int (* p)(); /* this is for human info only, we never call it */
short int addr[2]; /* [0]seg and [1]off of driver entry point */
} vidfn ;
short int lp;
short int list[LLEN][6];
} prot ;
#ifndef PDINTERP
extern
#endif
short int *list_p;
void listinit(void);
void pdinterp(void);
void kdidraw(short int,short int,short int,short int,short int,short int);
/* tell Watcom C how to use registers for arguments */
#pragma aux kdidraw parm [EAX] [EBX] [ECX] [EDX] [ESI] [EDI];
/* move to x1,y1, route/line width will be w */
#define M(x1,y1,w) kdidraw((KMOVE<<8), x1, y1, w, 0, 0)
/* put dot at x1, y, color c, atrib at */
#define DOT(x1,y1,c,at) kdidraw(at+(KWDOT<<8), x1, y1, c, 0, 0)
/* draw line from M point to x1,y1, color c, atrib at */
#define D(x1,y1,c,at) kdidraw(at+(KDRAW<<8), x1, y1, c, 0, 0)
[LISTING SIX]
; William F. Dudley, Jr.
; "porting a large application to 386 protected mode"
; This is the protected mode function that stuffs draw commands
; in the draw list. If the list fills up, it automatically calls
; pdinterp() to empty it.
;
NAME storlist
EXTRN pdinterp_:WORD
EXTRN _prot:WORD
EXTRN _list_p:WORD
LLEN EQU 100 ; size of draw list, must agree with C version.
DGROUP GROUP CONST,_DATA,_BSS
_TEXT SEGMENT PUBLIC BYTE USE32 'CODE'
ASSUME CS:_TEXT,DS:DGROUP
PUBLIC kdidraw_
; args in ax,bx,cx,dx,si,di
; global list pointer in _list_p is incremented by 12
kdidraw_:
push esi ;save si
mov si,ax ;save ax
mov eax,dword ptr _list_p
mov word ptr [eax],si
mov word ptr [eax+2],bx
mov word ptr [eax+4],cx
mov word ptr [eax+6],dx
pop esi ; get back si
mov word ptr [eax+8],si
mov word ptr [eax+10],di
add eax, 12
mov dword ptr _list_p,eax
inc word ptr _prot+4H
cmp word ptr _prot+4H,LLEN-3
jle L1
call near ptr pdinterp_
jmp short L2
L1: mov word ptr [eax],0000H
L2: ret
_TEXT ENDS
CONST SEGMENT PUBLIC WORD USE32 'DATA'
CONST ENDS
_DATA SEGMENT PUBLIC WORD USE32 'DATA'
_DATA ENDS
_BSS SEGMENT PUBLIC WORD USE32 'BSS'
_BSS ENDS
END
[LISTING SEVEN]
/* pdinterp.c -- William F. Dudley, Jr.
* protected dinterp() for Phar-Lap environment.
* this is the protected half of the draw list kdi processor
*/
#include <stdio.h>
#include <dos.h>
#define PDINTERP 1
#include "list5.h"
extern int real_addr; /* real address of start of real mode code */
extern int real_seg, real_off; /* segment and offset of real_addr */
extern char real; /* real copy of vidfnp, lp, draw list */
extern char end_real;
extern char dinterp; /* actually a function, but we just want address */
void pdinterp(void);
int pr2real(void);
static union REGS pregs;
static struct phregs pr;
static unsigned short real_o;
static unsigned abs_adr;
static int pdinitted=0;
void pdinterp() {
union REGS r;
if(!prot.lp) return;
if(!pdinitted) pdintinit();
/* copy list to buffer in real code seg */
blk_mov_pr(&prot, 0x34, abs_adr, sizeof(prot));
int386(0x21, &pregs, &r);
prot.list[prot.lp = 0][0] = 0;
list_p = prot.list[0];
}
void pdintinit(void) {
pregs.x.ax = 0x2510; /* call function */
pregs.d.ebx = real_addr; /* get segment of real mode stuff */
pregs.x.bx = (short int)&dinterp; /* EBX is address of dinterp subroutine */
pregs.d.ecx = 0; /* 0 words on stack */
pregs.d.edx = (int)≺ /* DS:EDX is address of register struct */
real_o = real_off + (short int)ℜ
abs_adr = real_o + (real_seg<<4); /* calculate address in selector 0x34 */
pregs.x.si = real_o+6; /* DS:SI points to list */
pr.ES = pr.DS = real_seg;
pdinitted = 1;
}
#if IN_C
/* this is a C version of the kdidraw() function in list6.asm */
void kdidraw(short int Ax,short int Bx,short int Cx,short int Dx, short int Si,short int Di) {
register short int *pi_;
pi_=prot.list[prot.lp];
*pi_++ = (short)(Ax);
*pi_++ = (short)(Bx);
*pi_++ = (short)(Cx);
*pi_++ = (short)(Dx);
*pi_++ = (short)(Si);
*pi_++ = (short)(Di);
if(++prot.lp > LLEN-3) pdinterp();
else *pi_ = 0;
}
#endif
[LISTING EIGHT]
; William F. Dudley, Jr.
; "Porting a large application to 386 protected mode"
; This is the real mode draw list interpreter.
;
d_text SEGMENT BYTE PUBLIC 'CODE' use16
ASSUME CS:d_text , DS:NOTHING , ES:NOTHING
LLEN EQU 100 ; size of draw list
public _dinterp
public _real
_real label word
db (12*LLEN+6) dup (?)
_dinterp proc far
call dint
ret
_dinterp endp
; ds:si points to real array at entry
dint proc near
floop: push word ptr [si+10] ; di
push word ptr [si+8] ; si
push word ptr [si+6] ; dx
push word ptr [si+4] ; cx
push word ptr [si+2] ; bx
push word ptr [si+0] ; ax
add si,12
call dword ptr cs:[_real]
add sp,12
iftest: cmp word ptr [si+0] ,0
jne floop
ret
dint endp
d_text ends
end
[Example 1: Three locations in the real mode code are directly accessed
from protected mode]
extern char test_string; /* string buffer in real mode module */
extern char end_real; /* end of real mode code */
extern char QUERY_FAR; /* actually a function, but we just want address */
[Example 2: Protected-mode structure]
struct {
union {
int (* p)();
short int addr[2]; /* [0]segment and [1]offset of driver entry point */
} vidfn ;
short int lp;
short int list[LLEN][6];
} prot ;