home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l440 / 2.ddi / CHAP2 / LDDPMI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-14  |  8.4 KB  |  303 lines

  1. /*
  2. LDDPMI.C -- undocumented DOS call from DPMI
  3.  
  4. Revised substantially from the version in UNDOCUMENTED DOS, pp. 74-80
  5.  
  6. This is a DOS program that starts out in real mode, and uses DPMI
  7. to switch into protected mode.  In addition to using DPMI, it also
  8. uses the protected-mode INT 21h services of the Windows 3.0 Enhanced
  9. mode DOS extender (that's why calls to printf, etc. work below,
  10. even after we've switched into protected mode).
  11.  
  12. For information on using DPMI in a Windows program, see the article
  13. "The Programming Challenge of Windows Protected Mode" by Andrew
  14. Schulman, _PC Magazine_, 25 June 1991.
  15.  
  16. Works with Microsoft C 6.0 (or higher) and Borland C++ 2.0 (or higher)
  17. (Some of the _asm convolutions were needed for Borland C++)
  18.  
  19. sample output:
  20.     in protected mode
  21.     Real mode DOS List Of Lists = 028E:0026
  22.     Protected DOS List Of Lists = 00AD:0026
  23.     LASTDRIVE=E
  24.         
  25. Microsoft C 6.0 (or higher): cl -AS lddpmi.c     
  26. Borland C++ 2.0 (or higher): bcc -ms lddpmi.c
  27. */
  28.  
  29. #include <stdlib.h>
  30. #include <stdarg.h>
  31. #include <stdio.h>
  32. #include <assert.h>
  33. #include <dos.h>
  34.  
  35. #ifdef __TURBOC__
  36. #pragma inline
  37. #define _dos_allocmem(x,y)      (allocmem(x, y) != -1)
  38. #endif
  39.  
  40. #define ABSADDR(seg, ofs) \
  41.     ((((unsigned long) seg) << 4) + ((ofs) & 0xFFFF))
  42.  
  43. #pragma pack(1)
  44.  
  45. typedef struct {
  46.     unsigned long edi, esi, ebp, reserved, ebx, edx, ecx, eax;
  47.     unsigned flags, es, ds, fs, gs, ip, cs, sp, ss;
  48.     } RMODE_CALL;
  49.     
  50. typedef struct {
  51.     unsigned char accessed   : 1;
  52.     unsigned char read_write : 1;
  53.     unsigned char conf_exp   : 1;
  54.     unsigned char code       : 1;
  55.     unsigned char xsystem    : 1;
  56.     unsigned char dpl        : 2;
  57.     unsigned char present    : 1;
  58.     } ACCESS;
  59.     
  60. /* structure of a protected-mode descriptor */  
  61. typedef struct {
  62.     unsigned limit, addr_lo;
  63.     unsigned char addr_hi;
  64.     ACCESS access;
  65.     unsigned char reserved, addr_xhi;
  66.     } DESCRIPTOR;   
  67.     
  68. typedef enum { FALSE, TRUE } BOOL;
  69.  
  70. BOOL dpmi_rmode_intr(unsigned intno, unsigned flags, 
  71.     unsigned copywords, RMODE_CALL far *rmode_call);
  72.  
  73. void dos_exit(unsigned char err)
  74.     _asm mov al, err
  75.     _asm mov ah, 04ch
  76.     _asm int 21h
  77. }
  78.  
  79. void fail(char *s)       { puts(s); dos_exit(1); }
  80.  
  81. /* Determines if DPMI is present and, if so, switches into
  82.    protected mode */
  83. BOOL dpmi_init(void)
  84. {
  85.     void (far *dpmi)();
  86.     unsigned hostdata_seg, hostdata_para, dpmi_flags;
  87.     
  88.     _asm {
  89.         mov ax, 1687h           // test for DPMI presence
  90.         int 2Fh
  91.         and ax, ax
  92.         jnz nodpmi              // if (AX == 0) DPMI is present
  93.         mov dpmi_flags, bx
  94.         mov hostdata_para, si   // paras for DPMI host private data
  95.         mov dpmi, di
  96.         mov dpmi+2, es          // DPMI protected-mode switch entry point
  97.         jmp short gotdpmi
  98.         }
  99. nodpmi:
  100.     return FALSE;
  101. gotdpmi:
  102.     if (_dos_allocmem(hostdata_para, &hostdata_seg) != 0)
  103.         fail("can't allocate memory");
  104.     
  105.     /* enter protected mode */
  106.     _asm {
  107.         mov ax, hostdata_seg
  108.         mov es, ax
  109.         mov ax, dpmi_flags
  110.         }
  111.     (*dpmi)();
  112.         
  113.     return TRUE;
  114. }
  115.  
  116. /* Performs a real-mode interrupt from protected mode */
  117. BOOL dpmi_rmode_intr(unsigned intno, unsigned flags, 
  118.     unsigned copywords, RMODE_CALL far *rmode_call)
  119. {
  120.     if (flags) intno |= 0x100;
  121.     _asm {
  122.         push di
  123.         push bx
  124.         push cx
  125.         mov ax, 0300h       // simulate real-mode interrupt
  126.         mov bx, intno       // interrupt number, flags
  127.         mov cx, copywords;  // words to copy from pmode to rmode stack
  128.         les di, rmode_call  // ES:DI = address of rmode call struct
  129.         int 31h             // call DPMI
  130.         jc error
  131.         mov ax, 1           // return TRUE
  132.         jmp short done
  133.         }
  134. error:  
  135.         _asm mov ax, 0           // return FALSE
  136. done:   
  137.         _asm pop cx
  138.         _asm pop bx
  139.         _asm pop di
  140. }
  141.  
  142. /* Allocates a single protected-mode LDT selector */
  143. unsigned dpmi_sel(void)
  144. {
  145.     _asm {
  146.         mov ax, 0           // Allocate LDT Descriptors
  147.         mov cx, 1           // allocate just one
  148.         int 31h             // call DPMI
  149.         jc err
  150.         jmp short done      // AX holds new LDT selector
  151.         }
  152. err:    
  153.         _asm mov ax, 0      // failed
  154. done:;   
  155. }
  156.  
  157. BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  158. {
  159.     _asm {
  160.         push di
  161.         push bx
  162.         mov ax, 000ch       // Set Descriptor
  163.         mov bx, pmodesel    // protected mode selector
  164.         les di, d           // descriptor
  165.         int 31h             // call DPMI
  166.         jc error
  167.         mov ax, 1           // return TRUE
  168.         jmp short done
  169.         }
  170. error:  
  171.         _asm mov ax, 0      // return FALSE
  172. done:   
  173.         _asm pop di
  174.         _asm pop bx
  175. }
  176.  
  177. BOOL dpmi_get_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  178. {
  179.     _asm {
  180.         push di
  181.         mov ax, 000bh       // Get Descriptor
  182.         mov bx, word ptr pmodesel    // protected mode selector
  183.         les di, dword ptr d // descriptor
  184.         int 31h             // call DPMI
  185.         jc error
  186.         mov ax, 1           // return TRUE
  187.         jmp short done
  188.         }
  189. error:  
  190.         _asm xor ax, ax     // return FALSE
  191. done:
  192.         _asm pop di
  193. }
  194.  
  195. BOOL dpmi_sel_free(unsigned pmodesel)
  196. {
  197.     _asm {
  198.         mov ax, 0001h       // Free LDT Descriptor
  199.         mov bx, pmodesel    // selector to free
  200.         int 31h             // call DPMI
  201.         jc error
  202.         mov ax, 1           // return TRUE
  203.         jmp short done
  204.         }
  205. error:  
  206.         _asm mov ax, 0           // return FALSE
  207. done:;
  208. }
  209.  
  210. void far *get_doslist(void)
  211. {
  212.     _asm {
  213.         xor bx, bx
  214.         mov es, bx
  215.         mov ah, 52h
  216.         int 21h
  217.         mov dx, es
  218.         mov ax, bx
  219.         }
  220. }
  221.  
  222. main()
  223. {
  224.     DESCRIPTOR d;
  225.     RMODE_CALL r;
  226.     void far *fp;
  227.     char far *doslist = (char far *) 0;
  228.     unsigned long addr;
  229.     unsigned pmodesel;
  230.     unsigned offset, lastdrv_ofs, lastdrv;
  231.  
  232.     /* program requires small model! */
  233.     assert((sizeof(void*) == 2) && (sizeof(void (*)()) == 2));
  234.     
  235.     assert(sizeof(ACCESS) == 1);
  236.     assert(sizeof(DESCRIPTOR) == 8);
  237.     
  238.     /* Determine if DPMI present and, if so, switch to protected mode */  
  239.     if (dpmi_init())
  240.         puts("now in protected mode");
  241.     else
  242.         fail("DPMI not present");   
  243.     
  244.     /* Call INT 21h AH=52h (Get DOS List Of Lists) */
  245.     memset(&r, 0, sizeof(RMODE_CALL));
  246.     r.eax = 0x5200;
  247.     if (! dpmi_rmode_intr(0x21, 0, 0, &r))
  248.         fail("DPMI rmode intr failed");
  249.     FP_SEG(doslist) = r.es;
  250.     FP_OFF(doslist) = r.ebx;
  251.     printf("Real mode DOS List Of Lists = %Fp\r\n", doslist);
  252.     
  253.     /* doslist now holds a real-mode address: in order to address it
  254.        in protected mode, allocate an LDT descriptor and set its 
  255.        contents; when done, deallocate the LDT descriptor
  256.     */
  257.     if (! (pmodesel = dpmi_sel()))
  258.         fail("DPMI can't alloc pmode selector");
  259.     
  260.     /* set size of segment */
  261.     d.limit = 0xFFFF;
  262.     
  263.     /* set base address of segment */
  264.     addr = ABSADDR(r.es, 0);
  265.     d.addr_lo = addr & 0xFFFF;
  266.     d.addr_hi = addr >> 16;
  267.     d.addr_xhi = 0;             /* IMPORTANT! */
  268.     
  269.     /* set access-rights of segment */
  270.     d.access.accessed = 0;      /* never been used */
  271.     d.access.read_write = 1;    /* read-write */
  272.     d.access.conf_exp = 0;      /* not a stack */
  273.     d.access.code = 0;          /* data */
  274.     d.access.xsystem = 1;       /* not system descriptor */
  275.     fp = (void far *) main;
  276.     d.access.dpl = FP_SEG(fp) & 3;  /* protection level */
  277.     d.access.present = 1;       /* it's present in memory */
  278.     d.reserved = 0;
  279.  
  280.     if (! dpmi_set_descriptor(pmodesel, &d))
  281.         fail("DPMI can't set descriptor");
  282.     
  283.     FP_SEG(doslist) = pmodesel; /* convert to protected-mode address */
  284.     FP_OFF(doslist) = r.ebx;
  285.     printf("Protected mode DOS List Of Lists = %Fp\r\n", doslist);
  286.     
  287.     /* now have protected-mode selector to DOS List of Lists */
  288.     /* Get LASTDRIVE number, print LASTDRIVE letter */
  289.     lastdrv = doslist[_osmajor==3 && _osminor==0 ? 0x1b : 0x21];
  290.     printf("LASTDRIVE=%c\r\n", 'A' - 1 + lastdrv);
  291.     
  292.     if (! dpmi_sel_free(pmodesel))
  293.         fail("DPMI can't free selector");
  294.     
  295.     /* in protected mode, flush output and quit */
  296.     fflush(stdout);
  297.     dos_exit(0);
  298.  
  299. dpmifail:
  300.     fail("DPMI failure");
  301. }
  302.