📄 pgdos32q.gml
字号:
This can be done with DPMI call 100h. This program
will call DOS int 21, function 39h, "Create
Directory".
Compile & Link: wcl386 -l=dos4g simulate
*/
#include <i86.h>
#include <dos.h>
#include <stdio.h>
#include <string.h>
.code break
static struct rminfo {
long EDI;
long ESI;
long EBP;
long reserved_by_system;
long EBX;
long EDX;
long ECX;
long EAX;
short flags;
short ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;
.code break
void main()
{
union REGS regs;
struct SREGS sregs;
int interrupt_no=0x31;
short selector;
short segment;
char far *str;
/* DPMI call 100h allocates DOS memory */
memset(&sregs,0,sizeof(sregs));
regs.w.ax=0x0100;
regs.w.bx=0x0001;
int386x( interrupt_no, ®s, ®s, &sregs);
segment=regs.w.ax;
selector=regs.w.dx;
.code break
/* Move string to DOS real-mode memory */
str=MK_FP(selector,0);
_fstrcpy( str, "myjunk" );
/* Set up real-mode call structure */
memset(&RMI,0,sizeof(RMI));
RMI.EAX=0x00003900; /* call service 39h ah=0x39 */
RMI.DS=segment; /* put DOS seg:off into DS:DX*/
RMI.EDX=0; /* DOS ignores EDX high word */
.code break
/* Use DPMI call 300h to issue the DOS interrupt */
regs.w.ax = 0x0300;
regs.h.bl = 0x21;
regs.h.bh = 0;
regs.w.cx = 0;
sregs.es = FP_SEG(&RMI);
regs.x.edi = FP_OFF(&RMI);
int386x( interrupt_no, ®s, ®s, &sregs );
}
.code end
.*
.section How do you install a bi-modal interrupt handler using DOS/4GW?
.*
.np
.ix 'DOS/4GW' 'bi-modal interrupt'
.ix 'bi-modal interrupt'
Due to the nature of the protected-mode/real-mode interface, it is often
difficult to handle high speed communications with hardware interrupt
handlers.
For example, if you install your communications interrupt handler in
protected mode, you may find that some data is lost when transmitting
data from a remote machine at the rate of 9600 baud.
This occurs because the data arrived at the communication port while the
machine was in the process of transferring the previous interrupt up to
protected mode.
Data will also be lost if you install the interrupt handler in real mode
since your program, running in protected mode, will have to switch down
into real mode to handle the interrupt.
The reason for this is that the data arrived at the communication port
while the DOS extender was switching between real mode and protected
mode, and the machine was not available to process the interrupt.
.np
To avoid the delay caused by switching between real-mode and protected
mode to handle hardware interrupts, install interrupt handlers in both
real-mode and protected-mode.
During the execution of a protected-mode program, the system often
switches down into real-mode for DOS system calls.
If a communications interrupt occurs while the machine is in real-mode,
then the real-mode interrupt handler will be used.
If the interrupt occurs when the machine is executing in protected-mode,
then the protected-mode interrupt handler will be used.
This enables the machine to process the hardware interrupts faster and
avoid the loss of data caused by context switching.
.np
Installing the interrupt handlers in both protected-mode and real-mode
is called bi-modal interrupt handling.
The following program is an example of how to install both handlers for
Interrupt 0x0C (also known as COM1 or IRQ4).
The program writes either a 'P' to absolute address 0xB8002 or an 'R' to
absolute address 0xB8000.
These locations are the first two character positions in screen memory
for a color display.
As the program runs, you can determine which interrupt is handling the
COM1 port by the letter that is displayed.
A mouse attached to COM1 makes a suitable demo.
Type on the keyboard as you move the mouse around.
The ESC key can be used to terminate the program.
Transmitted data from a remote machine at 9600 baud can also be used to
test the COM1 handling.
.code begin
/*
BIMODAL.C - The following program demonstrates how
to set up a bi-modal interrupt handler for DOS/4GW
Compile and link: wcl386 -l=dos4g bimodal bimo.obj
*/
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#define D32RealSeg(P) ((((DWORD) (P)) >> 4) & 0xFFFF)
#define D32RealOff(P) (((DWORD) (P)) & 0xF)
typedef unsigned int WORD;
typedef unsigned long DWORD;
extern void com1_init (void);
extern void __interrupt pmhandler (void);
extern void __interrupt __far rmhandler (void);
.code break
void *D32DosMemAlloc (DWORD size)
{
union REGS r;
r.x.eax = 0x0100; /* DPMI allocate DOS memory */
r.x.ebx = (size + 15) >> 4; /* Number of paragraphs requested */
int386 (0x31, &r, &r);
if( r.x.cflag ) /* Failed */
return ((DWORD) 0);
return (void *) ((r.x.eax & 0xFFFF) << 4);
}
.code break
void main (void)
{
union REGS r;
struct SREGS sr;
void *lowp;
void far *fh;
WORD orig_pm_sel;
DWORD orig_pm_off;
WORD orig_rm_seg;
WORD orig_rm_off;
int c;
/* Save the starting protected-mode handler address */
r.x.eax = 0x350C; /* DOS get vector (INT 0Ch) */
sr.ds = sr.es = 0;
int386x (0x21, &r, &r, &sr);
orig_pm_sel = (WORD) sr.es;
orig_pm_off = r.x.ebx;
.code break
/*
Save the starting real-mode handler address using DPMI
(INT 31h).
*/
r.x.eax = 0x0200; /* DPMI get real mode vector */
r.h.bl = 0x0C;
int386 (0x31, &r, &r);
orig_rm_seg = (WORD) r.x.ecx;
orig_rm_off = (WORD) r.x.edx;
.code break
/*
Allocate 128 bytes of DOS memory for the real-mode
handler, which must of course be less than 128 bytes
long. Then copy the real-mode handler into that
segment.
*/
if(! ( lowp = D32DosMemAlloc(128) ) ) {
printf ("Couldn't get low memory!\n");
exit (1);
}
memcpy (lowp, (void *) rmhandler, 128);
.code break
/*
Install the new protected-mode vector. Because INT 0Ch
is in the auto-passup range, its normal "passdown"
behavior will change as soon as we install a
protected-mode handler. After this next call, when a
real mode INT 0Ch is generated, it will be resignalled
in protected mode and handled by pmhandler.
*/
r.x.eax = 0x250C; /* DOS set vector (INT 0Ch) */
fh = (void far *) pmhandler;
r.x.edx = FP_OFF (fh);
/* DS:EDX == &handler */
sr.ds = FP_SEG (fh);
sr.es = 0;
int386x (0x21, &r, &r, &sr);
.code break
/*
Install the new real-mode vector. We do this after
installing the protected-mode vector in order to
override the "passup" behavior. After the next call,
interrupts will be directed to the appropriate handler,
regardless of which mode we are in when they are
generated.
*/
r.x.eax = 0x0201;
r.h.bl = 0x0C;
/* CX:DX == real mode &handler */
r.x.ecx = D32RealSeg(lowp);
r.x.edx = D32RealOff(lowp);
int386 (0x31, &r, &r);
.code break
/*
Initialize COM1.
*/
com1_init ();
puts( "Move mouse, transmit data; ESC to quit\n" );
while( 1 ) {
if( kbhit() ) {
if( ( (c = getch ()) & 0xff ) == 27 )
break;
putch (c);
}
delay( 1 );
}
.code break
/*
Clean up.
*/
r.x.eax = 0x250C; /* DOS set vector (INT 0Ch) */
r.x.edx = orig_pm_off;
sr.ds = orig_pm_sel; /* DS:EDX == &handler */
sr.es = 0;
int386x (0x21, &r, &r, &sr);
r.x.eax = 0x0201; /* DPMI set real mode vector */
r.h.bl = 0x0C;
/* CX:DX == real mode &handler */
r.x.ecx = (DWORD) orig_rm_seg;
r.x.edx = (DWORD) orig_rm_off;
int386 (0x31, &r, &r);
}
.code end
.np
You will also need to create the following assembler code module.
The first part provides the interrupt handling routine for the
real-mode interrupt handler.
The second provides the protected-mode version of the interrupt
handler.
.code begin
;**
;** bimo.asm:
;** Assembler code for real-mode and protected-mode
;** INT 0xC interrupt handlers to support the INT 0xC
;** interrupt in both modes
;**
.li .386
;**
;** The real-mode interrupt handler is in a 16-bit code
;** segment so that the assembler will generate the right
;** code. We will copy this code down to a 16-bit segment
;** in low memory rather than executing it in place.
;**
_TEXT16 SEGMENT BYTE PUBLIC USE16 'CODE'
ASSUME cs:_TEXT16
PUBLIC rmhandler_
rmhandler_:
push es
push bx
mov bx,0B800h
mov es,bx ; ES = 0xB800
sub bx,bx ; BX = 0
mov WORD PTR es:[bx],0720h ; Clear 2 char cells
mov WORD PTR es:[bx+2],0720h
mov BYTE PTR es:[bx],'R' ; Write R to memory
pop bx
pop es
push ax
push dx
mov dx,03FAh
in al,dx ; Read ports so
mov dx,03F8h ; interrupts can
in al,dx ; continue to be
mov dx,020h ; generated
mov al,dl
out dx,al ; Send EOI
pop dx
pop ax
iret
_TEXT16 ENDS
.code break
;**
;** The protected-mode interrupt handler is in a 32-bit code
;** segment. Even so, we have to be sure to force an IRETD
;** at the end of the handler, because MASM doesn't generate
;** one. This handler will be called on a 32-bit stack by
;** DOS/4GW.
;**
;** _DATA is the flat model data segment, which we load into
;** ES so we can write to absolute address 0xB8000. (In the
;** flat model, DS is based at 0.)
;**
_DATA SEGMENT BYTE PUBLIC USE32 'DATA'
_DATA ENDS
.code break
DGROUP GROUP _DATA
_TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
ASSUME cs:_TEXT
PUBLIC com1_init_
com1_init_:
mov ax,0F3h ; 9600,n,8,1
mov dx,0 ; com1
int 14h ; Initialize COM1
mov bx,03F8h ; COM1 port space
lea dx,[bx+5] ; line status reg
in al,dx
lea dx,[bx+4] ; modem control reg
in al,dx
or al,8 ; enable OUT2 int
out dx,al
lea dx,[bx+2] ; int id register
in al,dx
mov dx,bx ; data receive reg
in al,dx
in al,21h ; interrupt mask reg
and al,0EFh ; force IRQ4 unmask
out 21h,al
lea dx,[bx+1] ; int enable reg
mov al,1
out dx,al ; enable received int
ret
.code break
PUBLIC pmhandler_
pmhandler_:
push es
push bx
mov bx,DGROUP
mov es,bx
mov ebx,0B8000h ; ES:EBX=flat:0B8000h
mov DWORD PTR es:[ebx],07200720h ; Clear cells
mov BYTE PTR es:[ebx+2],'P' ; Write P to memory
pop bx
pop es
push ax
push dx
mov dx,03FAh
in al,dx ; Read ports so
mov dx,03F8h ; interrupts can
in al,dx ; continue to be
mov dx,020h ; generated
mov al,dl
out dx,al ; Send EOI
pop dx
pop ax
iretd
_TEXT ENDS
END
.code end
.*
.do end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -