Category : Files from Magazines
Archive   : DDJ-9008.ZIP
Filename : DUDLEY.LST

 
Output of file : DUDLEY.LST contained in archive : DDJ-9008.ZIP
_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
#include
#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
#include
#include
#include

#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
#include
#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 ;





  3 Responses to “Category : Files from Magazines
Archive   : DDJ-9008.ZIP
Filename : DUDLEY.LST

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/