home *** CD-ROM | disk | FTP | other *** search
/ For Beginners & Professional Hackers / cd.iso / docum / dos-ref.doc / examples / chap2.arj / LDDPMI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-25  |  7.2 KB  |  273 lines

  1. /*
  2. LDDPMI.C -- undocumented DOS call from DPMI
  3.  
  4. sample output:
  5.     in protected mode
  6.     Real mode DOS List Of Lists = 028E:0026
  7.     Protected DOS List Of Lists = 00AD:0026
  8.     LASTDRIVE=E
  9.         
  10. cl -AS lddpmi.c     
  11. */
  12.  
  13. #ifndef M_I86SM
  14. #error Requires Microsoft C small model
  15. #endif
  16.  
  17. #include <stdlib.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <dos.h>
  21.  
  22. #define ABSADDR(seg, ofs) \
  23.     ((((unsigned long) seg) << 4) + ((ofs) & 0xFFFF))
  24.  
  25. #pragma pack(1)
  26.  
  27. typedef struct {
  28.     unsigned long edi, esi, ebp, reserved, ebx, edx, ecx, eax;
  29.     unsigned flags, es, ds, fs, gs, ip, cs, sp, ss;
  30.     } RMODE_CALL;
  31.     
  32. typedef struct {
  33.     unsigned accessed   : 1;
  34.     unsigned read_write : 1;
  35.     unsigned conf_exp   : 1;
  36.     unsigned code       : 1;
  37.     unsigned xsystem    : 1;
  38.     unsigned dpl        : 2;
  39.     unsigned present    : 1;
  40.     } ACCESS;
  41.     
  42. typedef struct {
  43.     unsigned        limit;
  44.     unsigned        addr_lo;
  45.     unsigned char   addr_hi; 
  46.     ACCESS          access;
  47.     unsigned        reserved;
  48.     } DESCRIPTOR;   
  49.  
  50. typedef enum { FALSE, TRUE } BOOL;
  51.  
  52. BOOL dpmi_rmode_intr(unsigned intno, unsigned flags, 
  53.     unsigned copywords, RMODE_CALL far *rmode_call);
  54.  
  55. void dos_exit(unsigned err)
  56.     _asm mov al, err
  57.     _asm mov ah, 04ch
  58.     _asm int 21h
  59. }
  60.  
  61. void pmode_putchar(int c)
  62. {
  63.     static RMODE_CALL r;
  64.     static RMODE_CALL *pr = (void *) 0;
  65.     if (! pr)
  66.     {
  67.         pr = &r;
  68.         memset(pr, 0, sizeof(RMODE_CALL));
  69.         r.eax = 0x0200;
  70.     }
  71.     r.edx = c;
  72.     dpmi_rmode_intr(0x21, 0, 0, pr);
  73. }
  74.  
  75. void pmode_puts(char *s)
  76. {
  77.     while (*s)
  78.     {
  79.         pmode_putchar(*s);
  80.         s++;
  81.     }
  82.     pmode_putchar(0x0d);
  83.     pmode_putchar(0x0a);
  84. }
  85.  
  86. void cdecl pmode_printf(const char *fmt, ...)
  87. {
  88.     char buf[128], *s=buf;
  89.     va_list marker;
  90.     va_start(marker, fmt);
  91.     vsprintf(buf, fmt, marker); 
  92.     va_end(marker);
  93.     while (*s) 
  94.         pmode_putchar(*s++);
  95. }
  96.  
  97. void fail(char *s)       { puts(s); exit(1); }
  98. void pmode_fail(char *s) { pmode_puts(s); dos_exit(1); }
  99.  
  100. /* Determines if DPMI is present and, if so, switches into
  101.    protected mode */
  102. BOOL dpmi_init(void)
  103. {
  104.     void (far *dpmi)();
  105.     unsigned hostdata_seg, hostdata_para, dpmi_flags;
  106.     _asm {
  107.         mov ax, 1687h           ; test for DPMI presence
  108.         int 2Fh
  109.         and ax, ax
  110.         jnz nodpmi              ; if (AX == 0) DPMI is present
  111.         mov dpmi_flags, bx
  112.         mov hostdata_para, si   ; paras for DPMI host private data
  113.         mov dpmi, di
  114.         mov dpmi+2, es          ; DPMI protected-mode switch entry point
  115.         jmp short gotdpmi
  116.         }
  117. nodpmi:
  118.     return FALSE;
  119. gotdpmi:
  120.     if (_dos_allocmem(hostdata_para, &hostdata_seg) != 0)
  121.         pmode_fail("can't allocate memory");
  122.     
  123.     /* enter protected mode */
  124.     _asm {
  125.         mov ax, hostdata_seg
  126.         mov es, ax
  127.         mov ax, dpmi_flags
  128.         }
  129.     (*dpmi)();
  130.         
  131.     return TRUE;
  132. }
  133.  
  134. /* Performs a real-mode interrupt from protected mode */
  135. BOOL dpmi_rmode_intr(unsigned intno, unsigned flags, 
  136.     unsigned copywords, RMODE_CALL far *rmode_call)
  137. {
  138.     if (flags) intno |= 0x100;
  139.     _asm {
  140.         push di
  141.         push bx
  142.         push cx
  143.         mov ax, 0300h       ; simulate real-mode interrupt
  144.         mov bx, intno       ; interrupt number, flags
  145.         mov cx, copywords;  ; words to copy from pmode to rmode stack
  146.         les di, rmode_call  ; ES:DI = address of rmode call struct
  147.         int 31h             ; call DPMI
  148.         jc error
  149.         mov ax, 1           ; return TRUE
  150.         jmp short done
  151. error:  mov ax, 0           ; return FALSE
  152. done:   pop cx
  153.         pop bx
  154.         pop di
  155.         }
  156. }
  157.  
  158. /* Allocates a single protected-mode LDT selector */
  159. unsigned dpmi_sel(void)
  160. {
  161.     _asm {
  162.         mov ax, 0           ; Allocate LDT Descriptors
  163.         mov cx, 1           ; allocate just one
  164.         int 31h             ; call DPMI
  165.         jc err
  166.         jmp short done      ; AX holds new LDT selector
  167. err:    mov ax, 0           ; failed
  168. done:   }
  169. }
  170.  
  171. BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  172. {
  173.     _asm {
  174.         push di
  175.         push bx
  176.         mov ax, 000ch       ; Set Descriptor
  177.         mov bx, pmodesel    ; protected mode selector
  178.         les di, d           ; descriptor
  179.         int 31h             ; call DPMI
  180.         jc error
  181.         mov ax, 1           ; return TRUE
  182.         jmp short done
  183. error:  mov ax, 0           ; return FALSE
  184. done:   pop di
  185.         pop bx
  186.         }
  187. }
  188.  
  189. BOOL dpmi_sel_free(unsigned pmodesel)
  190. {
  191.     _asm {
  192.         mov ax, 0001h       ; Free LDT Descriptor
  193.         mov bx, pmodesel    ; selector to free
  194.         int 31h             ; call DPMI
  195.         jc error
  196.         mov ax, 1           ; return TRUE
  197.         jmp short done
  198. error:  mov ax, 0           ; return FALSE
  199. done:   }
  200. }
  201.  
  202. main(int argc, char *argv[])
  203. {
  204.     DESCRIPTOR d;
  205.     RMODE_CALL r;
  206.     void far *fp;
  207.     char far *doslist = (char far *) 0;
  208.     unsigned long addr;
  209.     unsigned pmodesel;
  210.     unsigned offset, lastdrv_ofs, lastdrv;
  211.     
  212.     /*
  213.         Determine if DPMI present and, if so, switch
  214.         to protected mode
  215.     */  
  216.     if (dpmi_init())
  217.         pmode_puts("now in protected mode");
  218.     else
  219.         fail("DPMI not present");   
  220.  
  221.     /*
  222.         Call INT 21h AH=52h (Get DOS List Of Lists)
  223.     */
  224.     memset(&r, 0, sizeof(RMODE_CALL));
  225.     r.eax = 0x5200;
  226.     if (! dpmi_rmode_intr(0x21, 0, 0, &r))
  227.         pmode_fail("DPMI rmode intr failed");
  228.     FP_SEG(doslist) = r.es;
  229.     FP_OFF(doslist) = r.ebx;
  230.     pmode_printf("Real mode DOS List Of Lists = %Fp\r\n", doslist);
  231.  
  232.     /* doslist now holds a real-mode address: in order to address it
  233.        in protected mode, allocate an LDT descriptor and set its 
  234.        contents; when done, deallocate the LDT descriptor
  235.     */
  236.     if (! (pmodesel = dpmi_sel()))
  237.         pmode_fail("DPMI can't alloc pmode selector");
  238.     d.limit = 0xFFFF;
  239.     addr = ABSADDR(r.es, 0);
  240.     d.addr_lo = addr & 0xFFFF;
  241.     d.addr_hi = addr >> 16;
  242.     d.access.accessed = 0;      /* never been used */
  243.     d.access.read_write = 1;    /* read-write */
  244.     d.access.conf_exp = 0;      /* not a stack */
  245.     d.access.code = 0;          /* data */
  246.     d.access.xsystem = 1;       /* not system descriptor */
  247.     fp = (void far *) main;
  248.     d.access.dpl = FP_SEG(fp) & 3;  /* protection level */
  249.     d.access.present = 1;       /* it's present in memory */
  250.     d.reserved = 0;
  251.     if (! dpmi_set_descriptor(pmodesel, &d))
  252.         pmode_fail("DPMI can't set descriptor");
  253.     
  254.     FP_SEG(doslist) = pmodesel; /* convert to protected-mode address */
  255.     FP_OFF(doslist) = r.ebx;
  256.     pmode_printf("Protected mode DOS List Of Lists = %Fp\r\n", doslist);
  257.  
  258.     /* now have protected-mode selector to DOS List of Lists */
  259.     /* Get LASTDRIVE number, print LASTDRIVE letter */
  260.     lastdrv = doslist[_osmajor==3 && _osminor==0 ? 0x1b : 0x21];
  261.     pmode_printf("LASTDRIVE=%c\r\n", 'A' - 1 + lastdrv);
  262.  
  263.     if (! dpmi_sel_free(pmodesel))
  264.         pmode_fail("DPMI can't free selector");
  265.     
  266.     /* in protected mode, flush output and quit */
  267.     dos_exit(0);
  268.  
  269. dpmifail:
  270.     pmode_fail("DPMI failure");
  271. }
  272.