home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / vol07 / 08 / paging / protmode.c < prev    next >
C/C++ Source or Header  |  1992-12-01  |  5KB  |  215 lines

  1. /* 
  2. PROTMODE.C
  3. from December 1992 Microsoft Systems Journal
  4. Andrew Schulman
  5. */
  6.  
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <dos.h>
  10. #ifdef DPMI_APP
  11. #include "dpmishel.h"
  12. #else
  13. #include "windows.h"
  14. #endif
  15. #include "protmode.h"
  16.  
  17. /* Get entry point for the VxD API using Int 2Fh AX=1684h */
  18. api_entry get_vxd_api(WORD vxd_id)
  19. {
  20.     _asm push di
  21.     _asm push es
  22.     _asm mov ax, 1684h
  23.     _asm mov bx, vxd_id
  24.     _asm xor di, di
  25.     _asm mov es, di
  26.     _asm int 2fh
  27.     _asm mov ax, di
  28.     _asm mov dx, es
  29.     _asm pop es
  30.     _asm pop di
  31. }
  32.  
  33. DWORD get_cr3(void)
  34. {
  35.     static api_entry api = NULL;
  36.     if (! api) 
  37.         api = get_vxd_api(VCR3D);
  38.     if (! api) 
  39.         fail("This program requires device=cr3.386 in SYSTEM.INI");
  40.     _asm mov ax, 1      
  41.     _asm xor dx, dx
  42.     (*api)();
  43.     // return CR3 in DX:AX
  44. }
  45.  
  46. // not valid for phys_addr under one megabyte?
  47. // note that free call (31/0801) not supported in DPMI 0.9!!
  48. DWORD dpmi_phys_to_lin(DWORD phys_addr, DWORD num_bytes)
  49. {
  50.     _asm push si
  51.     _asm push di
  52.     _asm mov ax, 0800h
  53.     _asm mov bx, word ptr [phys_addr+2]
  54.     _asm mov cx, word ptr [phys_addr]
  55.     _asm mov si, word ptr [num_bytes+2]
  56.     _asm mov di, word ptr [num_bytes]
  57.     _asm int 31h
  58.     _asm jc error
  59.     _asm mov dx, bx
  60.     _asm mov ax, cx
  61.     _asm jmp short done
  62. error:
  63.     _asm xor ax, ax
  64.     _asm xor dx, dx
  65. done:
  66.     _asm pop di
  67.     _asm pop si
  68.     // return value in DX:AX
  69. }
  70.  
  71. void far *map_linear(DWORD lin_addr, DWORD num_bytes)
  72. {
  73.     WORD sel;
  74.     
  75.     /* allocate a selector similar to our current DS 
  76.        (i.e., a data selector) */
  77.     _asm mov sel, ds
  78.     if ((sel = AllocSelector(sel)) == 0)
  79.         fail("Can't allocate a selector!");
  80.     
  81.     /* set the base and limit of the new selector */
  82.     SetSelectorBase(sel, lin_addr);
  83.     SetSelectorLimit(sel, num_bytes - 1);   
  84.     
  85.     /* turn into a far pointer */
  86.     return MK_FP(sel, 0);
  87. }
  88.  
  89. void free_mapped_linear(void far *fp)
  90. {
  91.     FreeSelector(FP_SEG(fp));
  92. }
  93.  
  94. // would be nice to have free_mapped_physical, but 31/0801
  95. // is not available under DPMI 0.9!!!
  96.  
  97. DWORD pagedir_phys=0, pagedir_lin=0;
  98.  
  99. // when done, free with free_mapped_linear
  100. DWORD far *get_pagedir(void)
  101. {
  102.     DWORD far *pagedir;
  103.     
  104.     if (! (pagedir_phys = get_cr3()))
  105.         fail("Can't get CR3 (physical address of page directory)");
  106.     
  107.     if (! (pagedir_lin = dpmi_phys_to_lin(pagedir_phys, 4096)))
  108.         fail("Can't get linear address of page directory");
  109.     
  110.     if (! (pagedir = (DWORD far *) map_linear(pagedir_lin, 4096)))
  111.         fail("Can't map page directory into program's address space");
  112.     
  113.     /* page directory now mapped into program's address space */
  114.  
  115.     return pagedir;
  116. }
  117.  
  118. DWORD far *get_pagetab(DWORD far *pagedir, int pagetab_num)
  119. {
  120.     DWORD pagetab_phys;
  121.     DWORD pagetab_lin;
  122.     DWORD far *pagetab;
  123.     
  124.     pagetab_phys = pagedir[pagetab_num] & 0xFFFFF000L;
  125.     
  126.     if (! (pagetab_lin = dpmi_phys_to_lin(pagetab_phys, 4096)))
  127.         fail("Can't get linear address of page table");
  128.     
  129.     if (! (pagetab = (DWORD far *) map_linear(pagetab_lin, 4096)))
  130.         fail("Can't map page table into program's address space");
  131.     
  132.     return pagetab;
  133. }
  134.  
  135. /* C wrapper for the Intel SGDT instruction; must compile with
  136.    286 instructions (-G2 in Microsoft C; -2 in Borland C++). 
  137.    Places the Global Descriptor Table (GDT) base and limit into
  138.    the six-byte (FWORD PTR) structure pointed to by pgdtr.  In
  139.    Borland, compile via TASM with -B (built-in assembler doesn't
  140.    like FWORD) */
  141. void sgdt(GDTR far *pgdtr)
  142. {
  143.     _asm les bx, pgdtr
  144.     _asm sgdt fword ptr es:[bx]
  145. }
  146.  
  147. DESCRIPTOR far *gdt = 0;
  148.  
  149. /* note how simple this is with right set of primitives */
  150. DESCRIPTOR far *get_gdt(void)
  151. {
  152.     GDTR gdtr;
  153.     WORD sel;
  154.     
  155.     if (! gdt)  // one-time initialization
  156.     {
  157.         /* get the linear base address and size (limit) of the Global
  158.            Descriptor Table (GDT), using the Intel SGDT instruction */
  159.         sgdt(&gdtr);
  160.  
  161.         gdt = (DESCRIPTOR far *) map_linear(gdtr.base, gdtr.limit + 1);
  162.  
  163.         // printf("GDT @ %08lXh, fp=%Fp\n", gdtr.base, gdt);
  164.     }
  165.     
  166.     return gdt;
  167. }
  168.  
  169. BOOL is_system_seg(DESCRIPTOR far *desc)
  170. {
  171.     return (desc->rts_lo & 0x10);
  172. }
  173.  
  174. // get_base and get_limit not valid for some SYSTEM descriptors
  175.  
  176. DWORD get_base(DESCRIPTOR far *desc)
  177. {
  178.     return ((DWORD) desc->base_xhi << 24L) + ((DWORD) desc->base_hi << 16L) +
  179.        desc->base_lo;
  180. }
  181.  
  182. DWORD get_limit(DESCRIPTOR far *desc)
  183. {
  184.     DWORD limit = ((DWORD) (desc->limitrts_hi & 0x0F) << 16L) + 
  185.         (DWORD) desc->limit_lo;
  186.     if (desc->limitrts_hi & 0x80)   // page granularity
  187.         limit *= 4096;
  188.     return limit;
  189. }
  190.  
  191. WORD sldt(void)
  192. {
  193.     _asm sldt ax
  194. }
  195.  
  196. // again, note how simple with right primitives
  197. DESCRIPTOR far *get_ldt(void)
  198. {
  199.     WORD ldt_sel;
  200.     DESCRIPTOR far *ldt_desc;
  201.     DESCRIPTOR far *ldt;
  202.     DWORD base, limit;
  203.     
  204.     ldt_sel = sldt();
  205.     if (! gdt) get_gdt();
  206.     ldt_desc = &gdt[ldt_sel >> 3];  // know that LDT descr. is in GDT
  207.     base = get_base(ldt_desc);
  208.     limit = get_limit(ldt_desc);
  209.     // printf("LDT @ %04Xh base=%08lXh limit=%08lX\n", ldt_sel, base, limit);
  210.     ldt = (DESCRIPTOR far *) map_linear(base, limit + 1);
  211.     return ldt;
  212. }
  213.  
  214.  
  215.