home *** CD-ROM | disk | FTP | other *** search
- /*
- 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");
- }
-