home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
msysjour
/
vol07
/
08
/
paging
/
protmode.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-01
|
5KB
|
215 lines
/*
PROTMODE.C
from December 1992 Microsoft Systems Journal
Andrew Schulman
*/
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#ifdef DPMI_APP
#include "dpmishel.h"
#else
#include "windows.h"
#endif
#include "protmode.h"
/* Get entry point for the VxD API using Int 2Fh AX=1684h */
api_entry get_vxd_api(WORD vxd_id)
{
_asm push di
_asm push es
_asm mov ax, 1684h
_asm mov bx, vxd_id
_asm xor di, di
_asm mov es, di
_asm int 2fh
_asm mov ax, di
_asm mov dx, es
_asm pop es
_asm pop di
}
DWORD get_cr3(void)
{
static api_entry api = NULL;
if (! api)
api = get_vxd_api(VCR3D);
if (! api)
fail("This program requires device=cr3.386 in SYSTEM.INI");
_asm mov ax, 1
_asm xor dx, dx
(*api)();
// return CR3 in DX:AX
}
// not valid for phys_addr under one megabyte?
// note that free call (31/0801) not supported in DPMI 0.9!!
DWORD dpmi_phys_to_lin(DWORD phys_addr, DWORD num_bytes)
{
_asm push si
_asm push di
_asm mov ax, 0800h
_asm mov bx, word ptr [phys_addr+2]
_asm mov cx, word ptr [phys_addr]
_asm mov si, word ptr [num_bytes+2]
_asm mov di, word ptr [num_bytes]
_asm int 31h
_asm jc error
_asm mov dx, bx
_asm mov ax, cx
_asm jmp short done
error:
_asm xor ax, ax
_asm xor dx, dx
done:
_asm pop di
_asm pop si
// return value in DX:AX
}
void far *map_linear(DWORD lin_addr, DWORD num_bytes)
{
WORD sel;
/* allocate a selector similar to our current DS
(i.e., a data selector) */
_asm mov sel, ds
if ((sel = AllocSelector(sel)) == 0)
fail("Can't allocate a selector!");
/* set the base and limit of the new selector */
SetSelectorBase(sel, lin_addr);
SetSelectorLimit(sel, num_bytes - 1);
/* turn into a far pointer */
return MK_FP(sel, 0);
}
void free_mapped_linear(void far *fp)
{
FreeSelector(FP_SEG(fp));
}
// would be nice to have free_mapped_physical, but 31/0801
// is not available under DPMI 0.9!!!
DWORD pagedir_phys=0, pagedir_lin=0;
// when done, free with free_mapped_linear
DWORD far *get_pagedir(void)
{
DWORD far *pagedir;
if (! (pagedir_phys = get_cr3()))
fail("Can't get CR3 (physical address of page directory)");
if (! (pagedir_lin = dpmi_phys_to_lin(pagedir_phys, 4096)))
fail("Can't get linear address of page directory");
if (! (pagedir = (DWORD far *) map_linear(pagedir_lin, 4096)))
fail("Can't map page directory into program's address space");
/* page directory now mapped into program's address space */
return pagedir;
}
DWORD far *get_pagetab(DWORD far *pagedir, int pagetab_num)
{
DWORD pagetab_phys;
DWORD pagetab_lin;
DWORD far *pagetab;
pagetab_phys = pagedir[pagetab_num] & 0xFFFFF000L;
if (! (pagetab_lin = dpmi_phys_to_lin(pagetab_phys, 4096)))
fail("Can't get linear address of page table");
if (! (pagetab = (DWORD far *) map_linear(pagetab_lin, 4096)))
fail("Can't map page table into program's address space");
return pagetab;
}
/* C wrapper for the Intel SGDT instruction; must compile with
286 instructions (-G2 in Microsoft C; -2 in Borland C++).
Places the Global Descriptor Table (GDT) base and limit into
the six-byte (FWORD PTR) structure pointed to by pgdtr. In
Borland, compile via TASM with -B (built-in assembler doesn't
like FWORD) */
void sgdt(GDTR far *pgdtr)
{
_asm les bx, pgdtr
_asm sgdt fword ptr es:[bx]
}
DESCRIPTOR far *gdt = 0;
/* note how simple this is with right set of primitives */
DESCRIPTOR far *get_gdt(void)
{
GDTR gdtr;
WORD sel;
if (! gdt) // one-time initialization
{
/* get the linear base address and size (limit) of the Global
Descriptor Table (GDT), using the Intel SGDT instruction */
sgdt(&gdtr);
gdt = (DESCRIPTOR far *) map_linear(gdtr.base, gdtr.limit + 1);
// printf("GDT @ %08lXh, fp=%Fp\n", gdtr.base, gdt);
}
return gdt;
}
BOOL is_system_seg(DESCRIPTOR far *desc)
{
return (desc->rts_lo & 0x10);
}
// get_base and get_limit not valid for some SYSTEM descriptors
DWORD get_base(DESCRIPTOR far *desc)
{
return ((DWORD) desc->base_xhi << 24L) + ((DWORD) desc->base_hi << 16L) +
desc->base_lo;
}
DWORD get_limit(DESCRIPTOR far *desc)
{
DWORD limit = ((DWORD) (desc->limitrts_hi & 0x0F) << 16L) +
(DWORD) desc->limit_lo;
if (desc->limitrts_hi & 0x80) // page granularity
limit *= 4096;
return limit;
}
WORD sldt(void)
{
_asm sldt ax
}
// again, note how simple with right primitives
DESCRIPTOR far *get_ldt(void)
{
WORD ldt_sel;
DESCRIPTOR far *ldt_desc;
DESCRIPTOR far *ldt;
DWORD base, limit;
ldt_sel = sldt();
if (! gdt) get_gdt();
ldt_desc = &gdt[ldt_sel >> 3]; // know that LDT descr. is in GDT
base = get_base(ldt_desc);
limit = get_limit(ldt_desc);
// printf("LDT @ %04Xh base=%08lXh limit=%08lX\n", ldt_sel, base, limit);
ldt = (DESCRIPTOR far *) map_linear(base, limit + 1);
return ldt;
}