📄 lddpmi.c
字号:
/*
LDDPMI.C -- undocumented DOS call from DPMI
Revised substantially from the version in UNDOCUMENTED DOS, pp. 74-80
This is a DOS program that starts out in real mode, and uses DPMI
to switch into protected mode. In addition to using DPMI, it also
uses the protected-mode INT 21h services of the Windows 3.0 Enhanced
mode DOS extender (that's why calls to printf, etc. work below,
even after we've switched into protected mode).
For information on using DPMI in a Windows program, see the article
"The Programming Challenge of Windows Protected Mode" by Andrew
Schulman, _PC Magazine_, 25 June 1991.
Works with Microsoft C 6.0 (or higher) and Borland C++ 2.0 (or higher)
(Some of the _asm convolutions were needed for Borland C++)
sample output:
in protected mode
Real mode DOS List Of Lists = 028E:0026
Protected DOS List Of Lists = 00AD:0026
LASTDRIVE=E
Microsoft C 6.0 (or higher): cl -AS lddpmi.c
Borland C++ 2.0 (or higher): bcc -ms lddpmi.c
*/
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <dos.h>
#ifdef __TURBOC__
#pragma inline
#define _dos_allocmem(x,y) (allocmem(x, y) != -1)
#endif
#define ABSADDR(seg, ofs) \
((((unsigned long) seg) << 4) + ((ofs) & 0xFFFF))
#pragma pack(1)
typedef struct {
unsigned long edi, esi, ebp, reserved, ebx, edx, ecx, eax;
unsigned flags, es, ds, fs, gs, ip, cs, sp, ss;
} RMODE_CALL;
typedef struct {
unsigned char accessed : 1;
unsigned char read_write : 1;
unsigned char conf_exp : 1;
unsigned char code : 1;
unsigned char xsystem : 1;
unsigned char dpl : 2;
unsigned char present : 1;
} ACCESS;
/* structure of a protected-mode descriptor */
typedef struct {
unsigned limit, addr_lo;
unsigned char addr_hi;
ACCESS access;
unsigned char reserved, addr_xhi;
} DESCRIPTOR;
typedef enum { FALSE, TRUE } BOOL;
BOOL dpmi_rmode_intr(unsigned intno, unsigned flags,
unsigned copywords, RMODE_CALL far *rmode_call);
void dos_exit(unsigned char err)
{
_asm mov al, err
_asm mov ah, 04ch
_asm int 21h
}
void fail(char *s) { puts(s); dos_exit(1); }
/* Determines if DPMI is present and, if so, switches into
protected mode */
BOOL dpmi_init(void)
{
void (far *dpmi)();
unsigned hostdata_seg, hostdata_para, dpmi_flags;
_asm {
mov ax, 1687h // test for DPMI presence
int 2Fh
and ax, ax
jnz nodpmi // if (AX == 0) DPMI is present
mov dpmi_flags, bx
mov hostdata_para, si // paras for DPMI host private data
mov dpmi, di
mov dpmi+2, es // DPMI protected-mode switch entry point
jmp short gotdpmi
}
nodpmi:
return FALSE;
gotdpmi:
if (_dos_allocmem(hostdata_para, &hostdata_seg) != 0)
fail("can't allocate memory");
/* enter protected mode */
_asm {
mov ax, hostdata_seg
mov es, ax
mov ax, dpmi_flags
}
(*dpmi)();
return TRUE;
}
/* Performs a real-mode interrupt from protected mode */
BOOL dpmi_rmode_intr(unsigned intno, unsigned flags,
unsigned copywords, RMODE_CALL far *rmode_call)
{
if (flags) intno |= 0x100;
_asm {
push di
push bx
push cx
mov ax, 0300h // simulate real-mode interrupt
mov bx, intno // interrupt number, flags
mov cx, copywords; // words to copy from pmode to rmode stack
les di, rmode_call // ES:DI = address of rmode call struct
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm mov ax, 0 // return FALSE
done:
_asm pop cx
_asm pop bx
_asm pop di
}
/* Allocates a single protected-mode LDT selector */
unsigned dpmi_sel(void)
{
_asm {
mov ax, 0 // Allocate LDT Descriptors
mov cx, 1 // allocate just one
int 31h // call DPMI
jc err
jmp short done // AX holds new LDT selector
}
err:
_asm mov ax, 0 // failed
done:;
}
BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
{
_asm {
push di
push bx
mov ax, 000ch // Set Descriptor
mov bx, pmodesel // protected mode selector
les di, d // descriptor
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm mov ax, 0 // return FALSE
done:
_asm pop di
_asm pop bx
}
BOOL dpmi_get_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
{
_asm {
push di
mov ax, 000bh // Get Descriptor
mov bx, word ptr pmodesel // protected mode selector
les di, dword ptr d // descriptor
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm xor ax, ax // return FALSE
done:
_asm pop di
}
BOOL dpmi_sel_free(unsigned pmodesel)
{
_asm {
mov ax, 0001h // Free LDT Descriptor
mov bx, pmodesel // selector to free
int 31h // call DPMI
jc error
mov ax, 1 // return TRUE
jmp short done
}
error:
_asm mov ax, 0 // return FALSE
done:;
}
void far *get_doslist(void)
{
_asm {
xor bx, bx
mov es, bx
mov ah, 52h
int 21h
mov dx, es
mov ax, bx
}
}
main()
{
DESCRIPTOR d;
RMODE_CALL r;
void far *fp;
char far *doslist = (char far *) 0;
unsigned long addr;
unsigned pmodesel;
unsigned offset, lastdrv_ofs, lastdrv;
/* program requires small model! */
assert((sizeof(void*) == 2) && (sizeof(void (*)()) == 2));
assert(sizeof(ACCESS) == 1);
assert(sizeof(DESCRIPTOR) == 8);
/* Determine if DPMI present and, if so, switch to protected mode */
if (dpmi_init())
puts("now in protected mode");
else
fail("DPMI not present");
/* Call INT 21h AH=52h (Get DOS List Of Lists) */
memset(&r, 0, sizeof(RMODE_CALL));
r.eax = 0x5200;
if (! dpmi_rmode_intr(0x21, 0, 0, &r))
fail("DPMI rmode intr failed");
FP_SEG(doslist) = r.es;
FP_OFF(doslist) = r.ebx;
printf("Real mode DOS List Of Lists = %Fp\r\n", doslist);
/* doslist now holds a real-mode address: in order to address it
in protected mode, allocate an LDT descriptor and set its
contents; when done, deallocate the LDT descriptor
*/
if (! (pmodesel = dpmi_sel()))
fail("DPMI can't alloc pmode selector");
/* set size of segment */
d.limit = 0xFFFF;
/* set base address of segment */
addr = ABSADDR(r.es, 0);
d.addr_lo = addr & 0xFFFF;
d.addr_hi = addr >> 16;
d.addr_xhi = 0; /* IMPORTANT! */
/* set access-rights of segment */
d.access.accessed = 0; /* never been used */
d.access.read_write = 1; /* read-write */
d.access.conf_exp = 0; /* not a stack */
d.access.code = 0; /* data */
d.access.xsystem = 1; /* not system descriptor */
fp = (void far *) main;
d.access.dpl = FP_SEG(fp) & 3; /* protection level */
d.access.present = 1; /* it's present in memory */
d.reserved = 0;
if (! dpmi_set_descriptor(pmodesel, &d))
fail("DPMI can't set descriptor");
FP_SEG(doslist) = pmodesel; /* convert to protected-mode address */
FP_OFF(doslist) = r.ebx;
printf("Protected mode DOS List Of Lists = %Fp\r\n", doslist);
/* now have protected-mode selector to DOS List of Lists */
/* Get LASTDRIVE number, print LASTDRIVE letter */
lastdrv = doslist[_osmajor==3 && _osminor==0 ? 0x1b : 0x21];
printf("LASTDRIVE=%c\r\n", 'A' - 1 + lastdrv);
if (! dpmi_sel_free(pmodesel))
fail("DPMI can't free selector");
/* in protected mode, flush output and quit */
fflush(stdout);
dos_exit(0);
dpmifail:
fail("DPMI failure");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -