From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/MEMM/EMM/EMM.H | 223 +++ v4.0/src/MEMM/EMM/EMM40.C | 571 ++++++++ v4.0/src/MEMM/EMM/EMMDATA.ASM | 467 +++++++ v4.0/src/MEMM/EMM/EMMDEF.INC | 331 +++++ v4.0/src/MEMM/EMM/EMMDISP.ASM | 234 ++++ v4.0/src/MEMM/EMM/EMMFUNCT.C | 660 +++++++++ v4.0/src/MEMM/EMM/EMMINC.ASM | 55 + v4.0/src/MEMM/EMM/EMMP.ASM | 2978 +++++++++++++++++++++++++++++++++++++++++ v4.0/src/MEMM/EMM/EMMSUP.ASM | 652 +++++++++ v4.0/src/MEMM/EMM/MAKEFILE | 95 ++ 10 files changed, 6266 insertions(+) create mode 100644 v4.0/src/MEMM/EMM/EMM.H create mode 100644 v4.0/src/MEMM/EMM/EMM40.C create mode 100644 v4.0/src/MEMM/EMM/EMMDATA.ASM create mode 100644 v4.0/src/MEMM/EMM/EMMDEF.INC create mode 100644 v4.0/src/MEMM/EMM/EMMDISP.ASM create mode 100644 v4.0/src/MEMM/EMM/EMMFUNCT.C create mode 100644 v4.0/src/MEMM/EMM/EMMINC.ASM create mode 100644 v4.0/src/MEMM/EMM/EMMP.ASM create mode 100644 v4.0/src/MEMM/EMM/EMMSUP.ASM create mode 100644 v4.0/src/MEMM/EMM/MAKEFILE (limited to 'v4.0/src/MEMM/EMM') diff --git a/v4.0/src/MEMM/EMM/EMM.H b/v4.0/src/MEMM/EMM/EMM.H new file mode 100644 index 0000000..24c0974 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMM.H @@ -0,0 +1,223 @@ +/******************************************************************************* + * + * (C) Copyright Microsoft Corp. 1986 + * + * TITLE: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver + * EMMLIB.LIB - Expanded Memory Manager Library + * + * MODULE: EMM.H - EMM includes for "C" code + * + * VERSION: 0.04 + * + * DATE: June 14,1986 + * + ******************************************************************************* + * CHANGE LOG + * Date Version Description + * -------- -------- ------------------------------------------------------- + * 06/14/86 Original + * 06/14/86 0.00 Changed stack frame structure to match new emmdisp.asm + * and allow byte regs access (SBP). + * 06/28/86 0.02 Name change from CEMM386 to CEMM (SBP). + * 07/06/86 0.04 Changed save area structure (SBP). + * + ******************************************************************************/ + +#define OK 0 +#define EMM_SW_MALFUNCTION 0x80 +#define EMM_HW_MALFUNCTION 0x81 +#define INVALID_HANDLE 0x83 +#define INVALID_FUNCTION 0x84 +#define NO_MORE_HANDLES 0x85 +#define SAVED_PAGE_DEALLOC 0x86 +#define NOT_ENOUGH_EXT_MEM 0x87 +#define NOT_ENOUGH_FREE_MEM 0x88 +#define ZERO_PAGES 0x89 +#define LOG_PAGE_RANGE 0x8A +#define PHYS_PAGE_RANGE 0x8B +#define SAVE_AREA_FULL 0x8C +#define MAP_PREV_SAVED 0x8D +#define NO_MAP_SAVED 0x8E +#define INVALID_SUBFUNCTION 0x8F +#define FEATURE_NOT_SUPPORTED 0x91 +#define NAMED_HANDLE_NOT_FOUND 0xA0 +#define DUPLICATE_HANDLE_NAMES 0xA1 +#define ACCESS_DENIED 0xA4 + +/* + * various usefull defines + */ +#define PAGE_SIZE 0x1000 +#define NULL_HANDLE (struct handle_ptr *)0x0FFF +#define NULL_PAGE 0xFFFF +#define NULL_SAVE (struct save_map *)0 + +#define GET 0x00 /* get/set page map sub codes */ +#define SET 0x01 +#define GETSET 0x02 +#define SIZE 0x03 + +#define EMM_VERSION 0x40 +#define Handle_Name_Len 8 + +/* + * defines for INTERNAL vs EXTERNAL current_map save + */ +#define INTERNAL_SAVE (unsigned)1 +#define EXTERNAL_SAVE (unsigned)0 + +/* + * page table structure + */ +struct pt { /* page table structure, HW defined */ + long pt_entry[1024]; + }; + +/* + * Page frame table. + * Size is dynamic, based on number of pages + * available. Allocated at intialization time. Each entry + * references 4 80386 pages. + * Note that the lower 12 bits of the page address are used + * as a link field + */ +union pft386{ + unsigned long address; + struct{ + unsigned short p_handle; + unsigned short high; + } words; +}; + +/* + * save_map + * This is an array of structures that save the + * current mapping state. Size is dynamically determined. + */ +struct save_map{ + unsigned short s_handle; + unsigned short window[4]; + }; +/* + * handle_table + * This is an array of handle pointers. It + * is dynamically sized based on the amount of memory being + * managed. + * pft_index of NULL_PAGE means free + */ +struct handle_ptr{ + unsigned short page_index; /* index of list header in emm_page */ + unsigned short page_count; /* size of list in EMM pages */ + }; + +/* + * Handle_Name + * This is an 8 character handle name. + */ +typedef char Handle_Name[Handle_Name_Len]; + +/* + * Handle_Dir_Entry + * + */ +struct Handle_Dir_Entry { + unsigned short Handle_Value; + Handle_Name Dir_Handle_Name; + }; + + +/* + * register frame on stack + * + * This is the stack frame on entry to the in67 dispatcher + */ +struct reg_frame { + unsigned short rdi; /* int 67 entry registers */ + unsigned short pad0; + unsigned short rsi; + unsigned short pad1; + unsigned short rbp; + unsigned short pad2; + unsigned short rsp; + unsigned short pad3; + union { + struct { + unsigned short rbx; + unsigned short pad4; + unsigned short rdx; + unsigned short pad5; + unsigned short rcx; + unsigned short pad6; + unsigned short rax; + unsigned short pad7; + } x; + struct { + unsigned char rbl; + unsigned char rbh; + unsigned short pad8; + unsigned char rdl; + unsigned char rdh; + unsigned short pad9; + unsigned char rcl; + unsigned char rch; + unsigned short padA; + unsigned char ral; + unsigned char rah; + unsigned short padB; + } h; + } hregs; + unsigned short ret_addr; /* return addr */ + unsigned short rcs; /* CS segment */ + unsigned short PFlag; /* protected mode flag */ + unsigned short rds; /* int 67 entry DS segment */ + unsigned short res; /* int 67 entry ES segment */ + unsigned short rgs; /* int 67 entry GS segment */ + unsigned short rfs; /* int 67 entry FS segment */ + }; + +extern struct reg_frame far *regp; +/* + * macros to set the value of a given register + * on the stack + */ +#define setAH(xx) regp->hregs.h.rah = xx +#define setAX(xx) regp->hregs.x.rax = xx +#define setBX(xx) regp->hregs.x.rbx = xx +#define setCX(xx) regp->hregs.x.rcx = xx +#define setDX(xx) regp->hregs.x.rdx = xx + + + +/* + * 4.0 EXTRAS + */ + +/* + * Number of Physical Pages: + * + * LIM 3.2: Page Frame ==> 4 x 16k pages + * LIM 4.0: 256k to 640k ==> 24 x 16k pages plus 3.2 page frame + */ +#define EMM32_PHYS_PAGES 4 +#define EMM40_PHYS_PAGES (24 + EMM32_PHYS_PAGES) + +/* + * structure of mappable physical page + */ +struct mappable_page { + unsigned short page_seg; /* segment of physical page */ + unsigned short physical_page; /* physical page number */ +}; + +/* OS/E Enable/Disable defines */ +#define OS_IDLE 0 +#define OS_ENABLED 1 +#define OS_DISABLED 2 + +/* + * structure of page map `register' bank + */ +struct PageBankMap { + unsigned short pbm_window; + unsigned char pbm_map[64]; + }; diff --git a/v4.0/src/MEMM/EMM/EMM40.C b/v4.0/src/MEMM/EMM/EMM40.C new file mode 100644 index 0000000..cce3a64 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMM40.C @@ -0,0 +1,571 @@ +/******************************************************************************* + * + * (C) Copyright Microsoft Corp. 1986 + * + * TITLE: VDMM + * + * MODULE: EMM40.C - EMM 4.0 functions code. + * + * VERSION: 0.00 + * + * DATE: Feb 25, 1987 + * + ******************************************************************************* + * CHANGE LOG + * Date Version Description + * -------- -------- ------------------------------------------------------- + * 02/25/87 0.00 Orignal + * + ******************************************************************************* + * FUNCTIONAL DESCRIPTION + * + * Paged EMM Driver for the iAPX 386. + * Extra functions defined in the 4.0 spec required by Windows. + * + ******************************************************************************/ + +/****************************************************************************** + INCLUDE FILES + ******************************************************************************/ +#include "emm.h" +/*#include "mem_mgr.h"*/ + + +/****************************************************************************** + EXTERNAL DATA STRUCTURES + ******************************************************************************/ +/* + * handle_table + * This is an array of handle pointers. + * page_index of zero means free + */ +extern struct handle_ptr handle_table[]; +extern Handle_Name Handle_Name_Table[]; /* Handle names */ +extern unsigned short handle_table_size; /* number of entries */ +extern unsigned short handle_count; /* active handle count */ + +/* + * EMM Page table + * this array contains lists of indexes into the 386 + * Page Table. Each list is pointed to by a handle + * table entry and is sequential/contiguous. This is + * so that maphandlepage doesn't have to scan a list + * for the specified entry. + */ +extern unsigned short *emm_page; /* _emm_page array */ +extern int free_count; /* current free count */ +extern int total_pages; /* number being managed */ +extern unsigned emmpt_start; /* next free entry in table */ + +/* + * EMM free table + * this array is a stack of available page table entries. + * each entry is an index into the pseudo page table + */ +/*extern unsigned free_stack_count; /* number of entries */ + +/* + * Current status of `HW'. The way this is handled is that + * when returning status to caller, normal status is reported + * via EMMstatus being moved into AX. Persistant errors + * (such as internal datastructure inconsistancies, etc) are + * placed in `EMMstatus' as HW failures. All other errors are + * transient in nature (out of memory, handles, ...) and are + * thus reported by directly setting AX. The EMMstatus variable + * is provided for expansion and is not currently being + * set to any other value. + */ +extern unsigned short EMMstatus; + +/* + * 4.0 EXTRAS + */ + +extern unsigned short emm40_info[5]; /* hardware information */ +extern struct mappable_page mappable_pages[]; /* mappable segments + and corresponding pages */ +extern short mappable_page_count; /* number of entries in above */ +extern short page_frame_pages; /* pages in the page frame */ +extern short physical_page_count; /* number of physical pages */ +/*extern char VM1_cntxt_pages; /* pages in a VM1 context */ +/*extern char VMn_cntxt_pages; /* pages in a VM context */ +/*extern char VM1_cntxt_bytes; /* bytes in a VM1 context */ +/*extern char VMn_cntxt_bytes; /* bytes in a VM context */ +extern char cntxt_pages; /* pages in context */ +extern char cntxt_bytes; /* bytes in context */ +extern unsigned short PF_Base; +extern unsigned short VM1_EMM_Pages; +/*extern unsigned short VM1_EMM_Offset;*/ +extern long page_frame_base[]; +extern char EMM_MPindex[]; +extern long OSEnabled; /* OS/E function flag */ +extern long OSKey; /* Key for OS/E function */ + +/****************************************************************************** + EXTERNAL FUNCTIONS + ******************************************************************************/ +extern struct handle_ptr *valid_handle(); /* validate handle */ +extern unsigned far *source_addr(); /* get DS:SI far ptr */ +extern unsigned far *dest_addr(); /* get ES:DI far ptr */ +extern unsigned wcopyb(); +extern unsigned copyout(); +extern unsigned short Avail_Pages(); + + +/****************************************************************************** + ROUTINES + ******************************************************************************/ + +/* + * Reallocate Pages + * parameters: + * bx -- new number of pages + * dx -- handle + * returns: + * bx -- new number of pages + * + * Change the number of pages allocated to a handle. + * + * ISP 5/23/88 Updated for MEMM + */ +ReallocatePages() +{ +#define handle ((unsigned short)regp->hregs.x.rdx) + + register struct handle_ptr *hp; + struct handle_ptr *hp_save; + unsigned new_size; + register unsigned n_pages; + register unsigned next; + + if ( (hp = valid_handle(handle)) == NULL_HANDLE ) + return; /* (error code already set) */ + + setAH((unsigned char)EMMstatus); /* Assume success */ + new_size = regp->hregs.x.rbx; + if ( new_size == hp->page_count ) + return; /* do nothing... */ + + if ( new_size > hp->page_count ) { + if ( new_size > total_pages ) { + setAH(NOT_ENOUGH_EXT_MEM); + return; + } + n_pages = new_size - hp->page_count; + if ( n_pages > Avail_Pages() ) { + setAH(NOT_ENOUGH_FREE_MEM); + return; + } + if ( hp->page_count == 0 ) + next = hp->page_index = emmpt_start; + else + next = hp->page_index + hp->page_count; + hp->page_count = new_size; + if ( next != emmpt_start ) { + /* + * Must shuffle emm_page array to make room + * for the extra pages. wcopyb correctly + * handles this case where the destination + * overlaps the source. + */ + wcopyb(emm_page+next, emm_page+next+n_pages, + emmpt_start - next); + /* Now tell other handles where their pages went */ + hp_save = hp; + for ( hp = handle_table; + hp < &handle_table[handle_table_size]; hp++ ) + if ( hp->page_index != NULL_PAGE && + hp->page_index >= next ) + hp->page_index += n_pages; + hp = hp_save; + } + emmpt_start += n_pages; + if ( get_pages(n_pages, next) == NULL_PAGE) { /* strange failure */ + setAH(NOT_ENOUGH_FREE_MEM); + new_size = hp->page_count - n_pages; /* as it was! */ + setBX(new_size); + goto shrink; /* and undo damage */ + } + } else { + /* Shrinking - make handle point to unwanted pages */ + shrink: + hp->page_count -= new_size; + hp->page_index += new_size; + free_pages(hp); /* free space in emm_page array */ + /* Undo damage to handle, the index was not changed */ + hp->page_count = new_size; + hp->page_index -= new_size; + } + +#undef handle +} + +/* + * UndefinedFunction + * + * An undefined or unsupported function. + * + * 05/10/88 ISP No update needed + */ +UndefinedFunction() +{ + setAH(INVALID_FUNCTION); +} + +/* + * Get Mappable Physical Address Array + * parameters: + * al == 0 + * es:di -- destination + * returns: + * cx -- number of mappable pages + * + * parameters: + * al == 1 + * returns: + * cx -- number of mappable pages + * + * Get the number of mappable pages and the segment address for each + * physical page. + * + * ISP 5/23/88 Updated for MEMM. u_ptr made into a far pointer. + */ +GetMappablePAddrArray() +{ + unsigned far *u_ptr; + int n_pages; + int i; + struct mappable_page *mp = mappable_pages; + + n_pages = mappable_page_count; + + if ( regp->hregs.h.ral == 0 ) { + if ( n_pages > 0 ) { + u_ptr = dest_addr(); /* ES:DI */ + for (i=0 ; i < 48 ; i++) + if (EMM_MPindex[i] != -1) + copyout(((struct mappable_page far *)u_ptr)++, + mp + EMM_MPindex[i], + sizeof(struct mappable_page) ); + } + } else if ( regp->hregs.h.ral != 1 ) { + setAH(INVALID_SUBFUNCTION); + return; + } + setCX(n_pages); + setAH((unsigned char)EMMstatus); +} + +/* + * Get Expanded Memory Hardware Information + * parameters: + * al == 0 + * es:di -- user array + * returns: + * es:di[0] = raw page size in paragraphs + * es:di[2] = number of EXTRA fast register sets + * es:di[4] = number of bytes needed to save a context + * es:di[6] = number of settable DMA channels + * + * parameters: + * al == 1 + * returns: + * bx = number of free raw pages + * dx = total number of raw pages + * + * ISP 5/23/88 Updated for MEMM. Made u_ptr into far ptr. + */ +GetInformation() +{ + unsigned far *u_ptr; + unsigned pages; + + if ( OSEnabled >= OS_DISABLED ) { + setAH(ACCESS_DENIED); /* Denied by operating system */ + return; + } + + if ( regp->hregs.h.ral == 0 ) { + u_ptr = dest_addr(); /* ES:DI */ + emm40_info[2] = (short)cntxt_bytes; /* update size */ + copyout(u_ptr, emm40_info, sizeof(emm40_info)); + setAH((unsigned char)EMMstatus); + } else if ( regp->hregs.h.ral == 1 ) { + GetUnallocatedPageCount(); /* Use existing code */ + } else + setAH(INVALID_SUBFUNCTION); +} + +/* + * GetSetHandleAttribute + * + * parameters: + * al == 0 + * returns: + * al == 0 -- volatile handles + * + * parameters: + * al == 1 + * returns: + * ah = 91h -- Feature not supported + * + * parameters: + * al == 2 + * returns: + * al == 0 -- Supports ONLY volatile handles + * + * 05/09/88 ISP No update needed + */ +GetSetHandleAttribute() +{ +#define handle ((unsigned short)regp->hregs.x.rdx) + + if ( regp->hregs.h.ral == 0 ) { + if (valid_handle(handle) == NULL_HANDLE) + return; /* (error code already set) */ + setAX(EMMstatus << 8); /* AL = 0 [volatile attribute] */ + } else if ( regp->hregs.h.ral == 1 ) { + setAH(FEATURE_NOT_SUPPORTED); + } else if ( regp->hregs.h.ral == 2 ) { + setAX(EMMstatus << 8); /* AL = 0 [volatile attribute] */ + } else + setAH(INVALID_SUBFUNCTION); + +#undef handle +} + + + + +/* + * GetSetHandleName + * + * Subfunction 0 Gets the name of a given handle + * Subfunction 1 Sets a new name for handle + * + * parameters: + * al == 0 + * es:di == Data area to copy handle name to + * dx -- handle + * returns: + * [es:di] == Name of DX handle + * + * parameters: + * al == 1 + * ds:si == new handle name + * dx -- handle + * returns: + * ah = Status + * + * ISP 5/23/88 Updated for MEMM. Name made into far *. Copyin routine used + * to copy name in into handle name table. + */ +GetSetHandleName() +{ + register unsigned short handle = ((unsigned short)regp->hregs.x.rdx); + register char far *Name; + + /* Validate subfunction */ + if ( (regp->hregs.h.ral != 0) && (regp->hregs.h.ral != 1) ) { + setAH(INVALID_SUBFUNCTION); + return; + } + + /* Validate handle */ + + if ( valid_handle(handle) == NULL_HANDLE ) + return; /* (error code already set) */ + + /* Implement subfunctions 0 and 1 */ + if ( regp->hregs.h.ral == 0 ) { + Name = (char far *)dest_addr(); /* ES:DI */ + copyout(Name, Handle_Name_Table[handle & 0xFF], Handle_Name_Len); + setAH((unsigned char)EMMstatus); + } else if ( regp->hregs.h.ral == 1 ) { + GetHandleDirectory(); /* See if already there */ + switch ( regp->hregs.h.rah ) { + case NAMED_HANDLE_NOT_FOUND: + break; + case DUPLICATE_HANDLE_NAMES: + return; + default: + if ( handle == regp->hregs.x.rdx ) + break; /* same handle, OK */ + regp->hregs.x.rdx = handle; + setAH(DUPLICATE_HANDLE_NAMES); + return; + } + Name = (char far *)source_addr(); + copyin(Handle_Name_Table[handle & 0xFF], Name, Handle_Name_Len); + setAH((unsigned char)EMMstatus); + } else + setAH(INVALID_SUBFUNCTION); + +} + + + + +/* + * GetHandleDirectory + * + * Subfunction 0 Returns a directory of handles and handle names + * Subfunction 1 Returns the handle specified by the name at [ds:si] + * + * parameters: + * al == 0 + * es:di == Data area to copy handle name to + * returns: + * al == Number of entries in the handle_dir array + * [es:di] == Handle_Dir array + * + * parameters: + * al == 1 + * [ds:si] == Handle name to locate + * returns: + * ah == Status + * + * parameters: + * al == 2 + * returns: + * bx == Total handles in system + * + * ISP 5/23/88 Updated for MEMM. nameaddress and dir_entry made into far * + * copyin routine used to copy name into local area for search. + */ +GetHandleDirectory() +{ + char far *NameAddress; + register struct handle_ptr *hp; + struct Handle_Dir_Entry far *Dir_Entry; + unsigned short Handle_Num, Found; +/* + * since all local variables are allocated on stack (SS seg) + * and DS and SS has grown apart (ie DS != SS), + * we need variables in DS seg (ie static variables) to pass + * to copyout(),copyin() and Names_Match() which expects those + * parameters that are near pointers to be in DS + * + * PC 08/03/88 + */ + static Handle_Name Name; + static unsigned short Real_Handle; + + if ( regp->hregs.h.ral == 0 ) { + Dir_Entry = (struct Handle_Dir_Entry far *)dest_addr(); + hp = handle_table; + for (Handle_Num = 0; Handle_Num < handle_table_size; Handle_Num++) { + if ( hp->page_index != NULL_PAGE) { + Real_Handle = Handle_Num; + copyout(Dir_Entry, &Real_Handle, sizeof(short)); + copyout(Dir_Entry->Dir_Handle_Name, Handle_Name_Table[Handle_Num], Handle_Name_Len); + Dir_Entry++; + } hp++; + } setAX((EMMstatus << 8) + handle_count); + } else if ( regp->hregs.h.ral == 1 ) { + NameAddress = (char far *)source_addr(); + copyin(Name, NameAddress, Handle_Name_Len); + hp = handle_table; + Found = 0; + Handle_Num = 0; + while ((Handle_Num < handle_table_size) && (Found < 2)) { + if ( hp->page_index != NULL_PAGE ) { + if (Names_Match(Name, Handle_Name_Table[Handle_Num])) { + Found++; + Real_Handle = Handle_Num; + } + } hp++; + Handle_Num++; + } + switch (Found) { + case 0: + setAH((unsigned char)NAMED_HANDLE_NOT_FOUND); + break; + case 1: + setDX(Real_Handle); + setAH((unsigned char)EMMstatus); + break; + default: + setAH((unsigned char)DUPLICATE_HANDLE_NAMES); + } + + } else if ( regp->hregs.h.ral == 2 ) { + setBX(handle_table_size); + setAH((unsigned char)EMMstatus); + } else + setAH(INVALID_SUBFUNCTION); + +#undef handle +} + +/* + * Prepare For Warm Boot + * + * Always ready to reboot the system so just return status = OK + * + * parameters: + * None + * returns: + * AH = EMMstatus + * + * 05/09/88 ISP No update needed. + * + */ +PrepareForWarmBoot() +{ + setAH((unsigned char)EMMstatus); +} + +/* + * Enable/Disable OS/E Function Set Functions + * + * Enable/Disable access to functions 26, 28 and 30 + * + * parameters: + * AL = 0 Enable Functions + * AL = 1 Disable Functions + * AL = 2 Return Access Key + * BX, CX Access Key + * returns: + * AH = EMMstatus + * BX, CX Access Key if successful + * + * 05/09/88 ISP Updated for MEMM. Removed check for pCurVMID + * + */ +OSDisable() +{ + unsigned char function = regp->hregs.h.ral; + + if ( function > 2 ) { + setAH(INVALID_SUBFUNCTION); + return; + } + + if ( OSEnabled == OS_IDLE ) { /* First invocation */ + if ( function == 2 ) { + setAH(ACCESS_DENIED); + return; + } + OSKey = Get_Key_Val(); /* Suitably random number */ + regp->hregs.x.rbx = (short)OSKey; + regp->hregs.x.rcx = (short)(OSKey >> 16); + } else { /* Check Key */ + if ( (short)OSKey != regp->hregs.x.rbx + || (short)(OSKey >> 16) != regp->hregs.x.rcx ) { + setAH(ACCESS_DENIED); + return; + } + } + if ( function == 0 ) /* enable */ + OSEnabled = 1; + else if ( function == 1 ) /* disable */ + OSEnabled = 2; + else if ( function == 2 ) /* return key */ + OSEnabled = 0; + + setAH((unsigned char)EMMstatus); +} + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/EMM/EMMDATA.ASM b/v4.0/src/MEMM/EMM/EMMDATA.ASM new file mode 100644 index 0000000..dce5928 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMDATA.ASM @@ -0,0 +1,467 @@ +page 58,132 +;****************************************************************************** + title EMMDATA - EMM data structures definitions +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver +; EMMLIB.LIB - Expanded Memory Manager Functions Library +; +; Module: EMMDAT +; +; Version: 0.04 +; +; Date: June 14,1986 +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/14/86 Added MapSize (SBP) +; 06/27/86 0.02 Reordered tables to place size dependent ones at end. +; 06/28/86 0.02 Name change from CEMM386 to CEMM (SBP). +; 07/06/86 0.04 Made _emm_page,_emm_free, and _pft386 pointers instead +; of labels to allow sizing of these arrays based on the +; number of pages in the system. Also added _emm_brk. +; ? 0.05 Modified for WIN386 +; 05/06/88 0.06 Modified back for MEMM. +; +;****************************************************************************** +; +; Functional Description: +; data definitions for emm/lim +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p +; include protseg.inc + include vdmseg.inc + include vdmsel.inc + include page.inc + include emmdef.inc + +_DATA SEGMENT + + public EMM_PAGE_CNT + public HANDLE_CNT + + PUBLIC _total_pages + PUBLIC _EMMstatus + PUBLIC _emm40_info + PUBLIC _page_frame_base + PUBLIC _mappable_pages + PUBLIC _mappable_page_count + PUBLIC _physical_page_count + PUBLIC _page_frame_pages + PUBLIC EMM_MPindex + PUBLIC _EMM_MPindex + PUBLIC _save_map + PUBLIC _handle_table + PUBLIC _Handle_Name_Table + PUBLIC _handle_table_size + PUBLIC _handle_count + PUBLIC _emmpt_start + PUBLIC _free_top + PUBLIC _free_count + PUBLIC _emm_page + PUBLIC _emm_free + PUBLIC _pft386 + PUBLIC _emm_brk + PUBLIC EMM_dynamic_data_area + PUBLIC EMM_data_end + PUBLIC _regp + PUBLIC EMM_savES + PUBLIC EMM_savDI + PUBLIC CurRegSet + PUBLIC _CurRegSet + PUBLIC CurRegSetn + PUBLIC FRS_array + PUBLIC FRS_free + PUBLIC PF_Base + PUBLIC _PF_Base + PUBLIC _OSEnabled + PUBLIC _OSKey + PUBLIC _VM1_EMM_Pages + PUBLIC _cntxt_pages + PUBLIC _cntxt_bytes + + + +;****************************************************************************** +; DATA STRUCTURES FOR MEMM +; +; The data structures are documented below. Only a description of how +; emm interfaces with the page table memory mananger is appropriate here +; +; During initialisation the pages in the physical address space to be devoted +; to emm are indicated in the _pft386 array. This array translates the emm +; page number to a pte in the system page table. +; +; The emm pages currently free are copied to the emm_free stack and the +; free_stack pointer points to the top of this stack. +; +; When pages are allocated to a handle the pages are allocated from the stack +; and copied to the emm_page array. The place where a handles pages are +; copied to in this array is recorded in the handle table. The emm_page array +; should be kept compacted all the time. Thus if a handle is deallocated, the +; pages allocated to the handle are copied to the emm_free stack and the hole +; left behind in the emm_page array is compacted by shifting all the entries +; below upwards updating the indexes stored in the handle table if needed. +; +; given map_handle_page(phys_page, log_page, handle) +; +; a. determine pte offset in system page table corresponding to phys_page +; from the _page_frame_base table. +; +; b. access handle table for the handle and determine the start of the +; emm pages allocated to the handle in the emm_page array. +; +; c. add log_page to this start offset in the emm_page array and access +; the entry in this array. This entry is an offset into the _pft386 +; array for the emm page under consideration. +; +; d. use this index into _pft386 to access the pte for the log page under +; consideration. +; +; e. store this pte in the pte offset corresponding to the phys_page as +; determined in a. +;****************************************************************************** + + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;00. EMM Status +; Current status of `HW'. The way this is handled is that +; when returning status to caller, normal status is reported +; via EMMstatus being moved into AX. Persistant errors +; (such as internal datastructure inconsistancies, etc) are +; placed in `EMMstatus' as HW failures. All other errors are +; transient in nature (out of memory, handles, ...) and are +; thus reported by directly setting AX. The EMMstatus variable +; is provided for expansion and is not currently being +; set to any other value. +; +; set to OK for now. when integrated, the value should be +; set to EMM_HW_MALFUNCTION (81H) initially, then set to +; OK (00H) when the `EMM ON' function is invoke +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_EMMstatus LABEL WORD + DW 00H + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;01. Register Block Pointer +; points to the the vm86 regs on the +; stack +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_regp LABEL WORD + DW 0 + DW 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;02. TOTAL_PAGES +; total # of EMM pages in system +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_total_pages LABEL WORD + DW 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;03. LIM 3.2 PAGE FRAME +; A suitable lim 3.2 page frame found +; by scanning for free area +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +PF_Base label word +_PF_Base label word + dw 0FFFFh ; Undefined initially + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;04. PAGE FRAME BASE +; this is the map of linear addr. +; of the n 16kb physical pages used to +; access the EMM pages. The contents +; far pointers into the system page +; table. If a lim 3.2 page frame is +; available it gets the entries at the +; beginning +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_page_frame_base LABEL DWORD + DW MAX_PHYS_PAGES dup (0, PAGET_GSEL) ; PTE offsets of physical pages + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;05. MAPPABLE PAGE ARRAY +; this is the segment, physical page +; correspondence array +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +_mappable_pages LABEL WORD + REPT MAX_PHYS_PAGES + Mappable_Page <0, 0> + ENDM + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;06. MAPPABLE PAGE INDEX ARRAY +; the pages in system memory are numbered +; 4000h onwards whereas the physical page +; numbers are arbitrarily numbered. this +; array indexes into the mappable page +; array. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +EMM_MPindex LABEL byte ; table of indexes into above +_EMM_MPindex LABEL byte + db 48 dup (-1) ; 4000h to 10000h + +_mappable_page_count dw MAX_PHYS_PAGES ; number of entries in above +_physical_page_count dw 0 ; number of physical pages + + +_page_frame_pages dw 4 ; pages in the page frame +ifdef CGA +_VM1_EMM_Pages dw 30 ; 4000h to B800h for now +else +_VM1_EMM_Pages dw 24 ; 4000h to A000h for now +endif + +; don't need it (used only in _set_40windows) +; +;_VM1_EMM_Offset dw 0 ; Offset of these in context +; +; combined into _cntxt_pages and _cntxt_bytes +; +;_VM1_cntxt_pages db 0 ; Pages in context +;_VM1_cntxt_bytes db 0 ; Bytes in context +;_VMn_cntxt_pages db 0 +;_VMn_cntxt_bytes db 0 + +_cntxt_pages db 0 ; Pages in context +_cntxt_bytes db 0 ; Bytes in context + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;07. HARDWARE INFORMATION +; Hardware information returned by Get +; Information call +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_emm40_info LABEL WORD + dw 0400h ; raw page size in paragraphs (16k) + dw FRS_COUNT-1 ; number of fast register sets + dw size FRS_window+2 ; max. number of bytes to save a context + ; ( FRS_window size + 2 ) + dw 0 ; settable DMA channels + dw 0 ; DMA_channel_operation + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;08. FRS MAPPING STATE ARRAY +; Used to emulate FRS. FRS 0..FRS_COUNT-1. FRS 0 +; is the normal mapping set. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +FRS_array LABEL WORD ; Array of Fast Register Set structures + REPT FRS_COUNT +FRS_struc <> + ENDM + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;09. Variables to support FRS Implementation +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +FRS_free db 0 ; How many of the above are free +CurRegSetn db 0 ; Number of Current Register Set +_CurRegSet LABEL WORD +CurRegSet dw 0 ; Pointer to Current Register Set Area + ; in FRS_array + +; initialized to 0:0 for initial buffer inquiry +; +EMM_savES dw 0 ; store for buffer address provided +EMM_savDI dw 0 ; by user on frs function + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;10. Variable to support OS access functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_OSEnabled dd 0 ; Security feature +_OSKey dd ? ; Key for security functions + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;11. Mysterious variable right now +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +VEMMD_SSbase dd 0 ; Linear base of Stack Segment + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;12. save_map +; This is an array of structures that save +; the current mapping state. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_save_map LABEL BYTE + REPT HANDLE_CNT ; one save area per handle +SaveMap_struc <> ; save area + ENDM + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;13. handle_table +; This is an array of handle pointers. +; In addition to the handle number a ptr +; to the start of the ems pages allocated +; to the handle in emm_page array is given +; emm_page index of NULL_PAGE means free +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_handle_table LABEL WORD + REPT HANDLE_CNT ; one table per handle +HandleTable_struc <> ; initialized handle table + ENDM + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;14. handle name table +; Under LIM 4.0 each allocated handle can +; be given a 8 byte name. this array keeps +; track of the handle names +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_Handle_Name_Table LABEL QWORD + DQ HANDLE_CNT dup (0) ; 8 0 bytes for every handle name + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;15. book-keeping variables for handle table +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_handle_table_size LABEL WORD + DW HANDLE_CNT + +_handle_count LABEL WORD + DW 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;16. EMMPT_START +; emmpt_start is the index of the next +; free entry in emm_page +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_emmpt_start LABEL WORD + DW 0 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;17. FREE pointers +; free_top is the index for the top free +; page in the emm_free stack. +; free_count is the number of free +; pages in the emm_free stack +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_free_top LABEL WORD + DW EMM_PAGE_CNT ; none free initially + +_free_count LABEL WORD + DW 0 ; none free initially + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;18. POINTERS to the variable sized data structures +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_emm_page dw offset dgroup:EMM_dynamic_data_area +_emm_free dw 0 +_pft386 dw 0 +_emm_brk dw offset dgroup:EMM_data_end +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Espensive data structures are going to be +; to be assigned storage dynamically so that we +; don't end up wasting space. These data areas +; are referred to by pointers above. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +EMM_dynamic_data_area LABEL BYTE +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +ifndef NOHIMEM +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;19. EMM Page table +; this array contains lists of indexes into the pseudo +; Page Table. Each list is pointed to +; by a handle table entry and is sequential/contiguous. +; This is so that maphandlepage doesn't have to scan +; a list for the specified entry. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_def_emm_page LABEL WORD + DW EMM_PAGE_CNT DUP(0) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;20. EMM free table +; this array is a stack of available page table entries. +; each entry is an index into pft386[]. +; it is initialized to FFFF entries. this is +; a null page entry/ +; it is initialized to FFFF entries. this is +; a null page entry. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_def_emm_free LABEL WORD + DW EMM_PAGE_CNT DUP(NULL_PAGE) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;21. PAGE FRAME TABLE +; This array contains addresses of physical +; page frames for 386 pages. A page is +; referred to by an index into this array. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_def_pft386 LABEL DWORD + DD EMM_PAGE_CNT DUP(NULL_HANDLE AND 0fffh) + +endif + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +EMM_data_end label byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +_DATA ENDS + +ifndef NOHIMEM + +else + +VDATA SEGMENT + public vdata_begin +vdata_begin label byte +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;19. EMM Page table +; this array contains lists of indexes into the pseudo +; Page Table. Each list is pointed to +; by a handle table entry and is sequential/contiguous. +; This is so that maphandlepage doesn't have to scan +; a list for the specified entry. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_def_emm_pagev LABEL WORD + DW EMM_PAGE_CNT DUP(0) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;20. EMM free table +; this array is a stack of available page table entries. +; each entry is an index into pft386[]. +; it is initialized to FFFF entries. this is +; a null page entry/ +; it is initialized to FFFF entries. this is +; a null page entry. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_def_emm_freev LABEL WORD + DW EMM_PAGE_CNT DUP(NULL_PAGE) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;21. PAGE FRAME TABLE +; This array contains addresses of physical +; page frames for 386 pages. A page is +; referred to by an index into this array. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +_def_pft386v LABEL DWORD + DD EMM_PAGE_CNT DUP(NULL_HANDLE AND 0fffh) + +VDATA ENDS + + + +endif + + + END + + diff --git a/v4.0/src/MEMM/EMM/EMMDEF.INC b/v4.0/src/MEMM/EMM/EMMDEF.INC new file mode 100644 index 0000000..ffe0630 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMDEF.INC @@ -0,0 +1,331 @@ +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver +; EMMLIB.LIB - Expanded Memory Manager Library +; +; Module: EMMDEF.INC - defines for EMM code. +; +; Version: 0.04 +; +; Date: June 21, 1986 +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 06/21/86 Original +; 06/25/86 0.02 Changed HANDLE_CNT to 255 to match LIM spec (SBP). +; 06/28/86 0.02 Name change from CEMM386 to CEMM (SBP). +; 07/06/86 0.04 Changed save area struct (SBP). +; 05/25/88 Changed to meet LIM 4.0 Spec (PC) +;****************************************************************************** +ifndef INC_LIST +.xlist +endif + +;****************************************************************************** +; G E N E R A L D E F I N E S +;****************************************************************************** +EMM_PAGE_CNT = 2048 ; maximum of 2048 EMM pages (32MB) +HANDLE_CNT = 255 ; maximum of 255 EMM handles +FRS_COUNT = 16 ; number of 'Fast Register Sets' + +EMM32_PHYS_PAGES = 4 ; page frame contains 4 pages +; +; The 0 to 1M contains 64 physical pages. Of these we are not mapping anything +; between E000 and FFFF, 0000 and 4000. So the Maximum physcial pages we can +; get for mapping is 40. + +TOT_PHYS_PAGES equ 64 +MAX_PHYS_PAGES equ 40 ; Life, the Universe + ; and Everything +PAGE_SIZE = 1000h +; +; Of the above mappable pages the regions C000h to Dfffh have to be searched +; for the mappable pages. +; +ABOVE_CONV_STRT_SEG equ 0C000h +ABOVE_CONV_STRT_PG equ ABOVE_CONV_STRT_SEG SHR 10 +; +ABOVE_CONV_END_SEG equ 0DC00h +ABOVE_CONV_END_PG equ ABOVE_CONV_END_SEG SHR 10 +; +MAX_ABOVE_CONV_PAGES EQU 8 +; +; Also the system memory mappable region starts at 4000h +; +CONV_STRT_SEG equ 4000h +CONV_STRT_PG equ CONV_STRT_SEG SHR 10 +; +NUM_CONV_PGS equ (0A000h -4000h) SHR 10 +; +; During init we keep track of mappable pages with an array of mappable_segs +; + +PAGE_MAPPABLE equ 0FFh ; +PAGE_NOT_MAPPABLE equ 0h ; + + +NULL_PAGE = 0FFFFh +NULL_HANDLE = 00FFFh + + +; +; Flags for memory move/xchg +; +Source_GT_Dest_Flag = 80h ; Source > Destination for copy / xchg +Overlap_Flag = 40h ; Copy overlapping memory +Backward_Copy_Flag = 20h ; copy is going to be backward +; +; Flags for PFlag use in Alter Map and Jump +; +PFLAG_VM = 0002h ; VM bit in High word of EFLAG +PFLAG_VIRTUAL = 0020h ; wheather it's call from virtual or proected mode +PFLAG_PATCH_CS_IP = 0008h ; Tell Protected mode dispatch to + ; patch new CS:IP onto it's return address +;****************************************************************************** +; S T A T U S D E F I N E S +;****************************************************************************** +OK = 0 +EMM_SW_MALFUNCTION = 80h +EMM_HW_MALFUNCTION = 81h +INVALID_HANDLE = 83h +INVALID_FUNCTION = 84h +NO_MORE_HANDLES = 85h +SAVED_PAGE_DEALLOC = 86h +NOT_ENOUGH_EXT_MEM = 87h +NOT_ENOUGH_FREE_MEM = 88h +ZERO_PAGES = 89h +LOG_PAGE_RANGE = 8Ah +PHYS_PAGE_RANGE = 8Bh +SAVE_AREA_FULL = 8Ch +MAP_PREV_SAVED = 8Dh +NO_MAP_SAVED = 8Eh +INVALID_SUBFUNCTION = 8Fh + +; LIM 4.0 extras + +VALID_OVERLAP = 92h +INSUFFICIENT_EMM_PAGES = 93h +CONVENTIONAL_EMM_OVERLAP= 94h +INVALID_OFFSET = 95h +INVALID_REGION_LENGTH = 96h +OVERLAPPING_EXCHANGE = 97h +INVALID_MEMORY_TYPE = 98h +FRSETS_UNSUPPORTED = 99h +INVALID_FRSET = 9Ah +NO_MORE_FRSETS = 9Bh +FRSET_NON_ZERO = 9Ch +FRSET_UNDEFINED = 9Dh +FRSET_NO_DMA = 9Eh +FRSET_INVALID_DMA = 9Fh +HANDLE_NAME_NOT_FOUND = 0A0h +DUPLICATE_HANDLE_NAME = 0A1h +INVALID_WRAPAROUND = 0A2h +SOURCE_CORRUPTED = 0A3h +ACCESS_DENIED = 0A4h + + +;****************************************************************************** +; GET/SET PAGE MAP SUBFUNCTION CODES +;****************************************************************************** +GSPM_GET equ 0 +GSPM_SET equ 1 +GSPM_GETSET equ 2 +GSPM_SIZE equ 3 + +; +; OSEnabled Values +; +OS_IDLE equ 0 +OS_ENABLED equ 1 +OS_DISABLED equ 2 + +;****************************************************************************** +; S T R U C T U R E S +;****************************************************************************** + +; +; stack frame after pushad on real/virtual mode entry +; +r67_Frame struc +rDI dd ? +rSI dd ? +rBP dd ? +rSP dd ? +rBX dd ? +rDX dd ? +rCX dd ? +rAX dd ? +retaddr dw ? +rCS dw ? +PFlag dw ? +rDS dw ? +rES dw ? +rGS dw ? +rFS dw ? +r67_Frame ends + + +; +; for _handle_table +; +HandleTable_struc struc +ht_index dw NULL_PAGE ; index into emm_page for handle's pgs +ht_count dw 0 ; number of emm_pages for this handle +HandleTable_struc ends + +; +; for _save_area +; +SaveMap_struc struc +s_handle dw NULL_HANDLE ; owning handle +s_map dw EMM32_PHYS_PAGES dup (NULL_PAGE) ; EMM page #s +SaveMap_struc ends + +; +; structure linking segment with physical page number +; +Mappable_Page struc +mappable_seg dw ? +mappable_pg dw ? +Mappable_Page ends + +; +; Get Partial Page Map +; +gppm_struc struc +gppm_count dw ? +gppm_segs dw ? +gppm_struc ends + +; +; Structures used as arguments to Map Handle Array function +; + +; For subfunction 0: +mha_array0 struc +mha0_log_pg dw ? +mha0_phys_pg dw ? +mha_array0 ends + +; For subfunction 1: +mha_array1 struc +mha1_log_pg dw ? +mha1_seg dw ? +mha_array1 ends + +; Used by Map and Jump and Map and Call -- Identical to mha_array0 and 1 +log_phys_map_struct struc +log_page_number dw ? +phys_page_number_seg dw ? +log_phys_map_struct ends + +; Map and Jump structure +maj_struct struc +maj_target_address dd ? +maj_log_phys_map_len db ? +maj_map_address dd ? +maj_struct ends + +; Map and Call structure +mac_struct struc +mac_target_address dd ? +mac_new_page_map_len db ? +mac_new_map_address dd ? +mac_old_page_map_len db ? +mac_old_map_address dd ? +mac_reserved dw 4 dup (?) +mac_struct ends + +; Move / Exchange memory structure +mem_memory_descriptor_struct struc +mem_memory_type db ? +mem_handle dw ? +mem_initial_offset dw ? +mem_initial_seg_page dw ? +mem_memory_descriptor_struct ends + + +mem_struct struc +mem_region_length dd ? +mem_source db (SIZE mem_memory_descriptor_struct) dup (?) +mem_dest db (SIZE mem_memory_descriptor_struct) dup (?) +mem_struct ends + +; +; Fast Register Set Description +; +FRS_struc struc +FRS_Window dw MAX_PHYS_PAGES dup (NULL_PAGE) ; emm page numbers +FRS_alloc dw 0 ; Is this set allocated +FRS_struc ends + + page +;**************************************************************************** +; +; Dword_Align -- Aligns code to dword boundry by inserting nops +; +;**************************************************************************** + +Dword_Align MACRO Seg_Name +IF (($ - OFFSET Seg_Name:0) MOD 4) + db 90h ;; Nop in code / else byte of 90h in data + Dword_Align Seg_Name +ENDIF + ENDM + + page +;*********************************************** +; +; Validate_Handle - check the handle in DX +; +; ENTRY: Handle as per LIM4.0 spec. in DX +; +; EXIT: If the handle is invalid jump To Death_Label, otherwise, +; EDX points to the _handle_table entry for the handle +; +; USES: EDX +; +;*********************************************** +Validate_Handle MACRO Death_Label + + cmp dx, [_handle_table_size] ;Q: handle in range ? + jae Death_Label ; N: go to error label + shl dx, 2 ; Y: convert handle to + add dx, offset _handle_table ; pointer + xchg bx, dx + cmp [bx.ht_index], NULL_PAGE ;Q: is this handle active ? + xchg bx, dx + je Death_Label ; N: return error + + ENDM + +;*********************************************** +; +; Handle2HandlePtr - convert the handle in DX to +; points into handle_table +; +; ENTRY: Handle as per LIM4.0 spec. in DX +; +; EXIT: EDX points to the _handle_table entry for the handle +; +; USES: EDX +; +;*********************************************** +Handle2HandlePtr MACRO + + shl dx, 2 ; Y: convert handle to + add dx, offset _handle_table ; pointer + + ENDM + +.list ; end of EMMDEF.INC + + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/EMM/EMMDISP.ASM b/v4.0/src/MEMM/EMM/EMMDISP.ASM new file mode 100644 index 0000000..f7ec55c --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMDISP.ASM @@ -0,0 +1,234 @@ +page 58,132 +;****************************************************************************** + title EMMDISP - EMM dispatcher +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver +; EMMLIB.LIB - Expanded Memory Manager Functions Library +; +; Module: EMM Dispatcher +; +; Version: 0.04 +; +; Date: May 17, 1986 +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 5/17/86 0 initial code +; 6/14/86 modified registers on stack for exit and removed call +; to _emm_init (SBP). +; 6/28/86 0.02 Name change from CEMM386 to CEMM (SBP). +; 7/06/86 0.04 Changed data assumes to DGROUP (SBP). +; 5/25/88 Changed function range check to cover LIM 4.0 (PC) +;****************************************************************************** +; +; Functional Description: +; This module serves to trap Int 67h, place +; arguments on the stack and call the associated +; function +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + +;****************************************************************************** +; P U B L I C S +;****************************************************************************** + public int67_Entry + public dispatch_vector + +;****************************************************************************** +; I N C L U D E S +;****************************************************************************** + include vdmseg.inc + include vdmsel.inc + include emmdef.inc +; +;****************************************************************************** +; D E F I N E S +;****************************************************************************** +; +FALSE equ 0 +TRUE equ not FALSE +CR equ 0dh +LF equ 0ah + +mkvect MACRO name + extrn _&name:near + dw offset _TEXT:_&name +endm + +;****************************************************************************** +; E X T E R N A L S +;****************************************************************************** + +_DATA SEGMENT +extrn _EMMstatus:word +extrn Active_Status:byte +extrn Auto_Mode:byte +extrn _regp:word +_DATA ENDS + + +;****************************************************************************** +; local data +;****************************************************************************** +; +; remove duplicated variables (defined in emmdata.asm) +; +;_DATA SEGMENT +; +;_regp label word +; dw 0 +; dw 0 +; +;_DATA ENDS + +_TEXT SEGMENT +assume cs:_text,ds:DGROUP,ss:DGROUP,es:DGROUP +; + db 'PxB' +; + +dispatch_vector label word + mkvect GetStatus + mkvect GetPageFrameAddress + mkvect GetUnallocatedPageCount + mkvect AllocatePages + mkvect MapHandlePage + mkvect DeallocatePages + mkvect GetEMMVersion + mkvect SavePageMap + mkvect RestorePageMap + mkvect GetPageMappingRegisterIOArray + mkvect GetLogicalToPhysicalPageTrans + mkvect GetEMMHandleCount + mkvect GetEMMHandlePages + mkvect GetAllEMMHandlePages + mkvect GetSetPageMap + mkvect GetSetPartial ; AH = 4Fh + ; 4.0 Functions... + mkvect MapHandleArray ; AH = 50h + mkvect ReallocatePages + mkvect GetSetHandleAttribute + mkvect GetSetHandleName + mkvect GetHandleDirectory + mkvect AlterMapAndJump + mkvect AlterMapAndCall + mkvect MoveExchangeMemory + mkvect GetMappablePAddrArray + mkvect GetInformation + mkvect AllocateRawPages + mkvect AlternateMapRegisterSet + mkvect PrepareForWarmBoot + mkvect OSDisable + +;************************************* +; int67_Entry(PFlag,DS,ES) - entry point for int 67 (EMM functions) +; +; unsigned PFlag; /* non-zero = protected mode, else */ +; /* virtual or real mode */ +; unsigned DS; /* DS segment value on entry to int67 */ +; unsigned ES; /* ES segment value on entry to int67 */ +; +; ENTRY: +; REAL or VIRTUAL mode +; DS = DGROUP segment +; PROTECTED mode +; DS = VDMD_GSEL +; +; At the point of the indirect call, +; The stack looks as follows: +; +; +; +-------+ +; | FS | +2CH <--- entry FS segment +; +-------+ +; | GS | +2AH <--- entry GS segment +; +-------+ +; | ES | +28H <--- entry ES segment +; +-------+ +; | DS | +26h <--- entry DS segment +; +-------+ +; | PFlag | +24h <--- protected mode flag +; +-------+ +; | CS | +22h <--- from FAR call to int67_handler +; +-------+ +; | ret | +20h <--- CS:ret +; +-------+ +; | EAX | +1C <-+- from PUSH ALL +; +-------+ | +; | ECX | +18 V +; +-------+ +; | EDX | +14 +; +-------+ +; | EBX | +10 +; +-------+ +; | ESP | +C +; +-------+ +; | EBP | +8 +; +-------+ +; | ESI | +4 +; +-------+ +; | EDI | <--- regp +; +-------+ +; +;************************************* +int67_Entry proc far + pushad ; save all regs + mov bp,sp ; SS:[BP] points to stack frame +; + mov [_regp],sp ; regp points to regs on stack + mov [_regp+2],ss ; regp now has a far ptr to regs + + ; + ; validate function code + ; + sub ah,40h ; check if entry code too small + jb i67_inv_exit ; if so, error exit + cmp ah,(5Dh-40h) ; check if entry code too big + ja i67_inv_exit ; if so, error exit + + ; + ; check for VDM off + ; + cmp [Auto_Mode],0 ;Q: Auto mode on ? + jne i67_jump ; Y: go ahead + cmp [Active_Status],0 ; N:Q: are we ON ? + je i67_off_err ; N: exit with error code + + ; + ; call through the jump table + ; +i67_jump: + xchg ah,al ; AL = function code + mov si,ax + xchg ah,al ; AH = function code again + and si,00FFh ; SI = function # + shl si,1 ; SI = table offset + call CS:dispatch_vector[si] ; call function + +ok_exit: + popad ; restore all regs + ret ; bye! + +i67_off_err: ; set h/w error + mov byte ptr [bp.rAX+1],EMM_HW_MALFUNCTION + jmp ok_exit + +i67_inv_exit: ; set invalid function code error + mov byte ptr [bp.rAX+1],INVALID_FUNCTION + jmp ok_exit + +int67_entry endp + +_TEXT ENDS +END + \ No newline at end of file diff --git a/v4.0/src/MEMM/EMM/EMMFUNCT.C b/v4.0/src/MEMM/EMM/EMMFUNCT.C new file mode 100644 index 0000000..7547536 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMFUNCT.C @@ -0,0 +1,660 @@ +/******************************************************************************* + * + * (C) Copyright Microsoft Corp. 1986 + * + * TITLE: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver + * EMMLIB.LIB - Expanded Memory Manager Library + * + * MODULE: EMMFUNCT.C - EMM functions code. + * + * VERSION: 0.10 + * + * DATE: June 14,1986 + * + ******************************************************************************* + * CHANGE LOG + * Date Version Description + * -------- -------- ------------------------------------------------------- + * 06/14/86 Changed status return to return only AH. And added + * PFlag to decide on selector versus segment on long + * address generation (SBP). + * 06/14/86 Moved save_current_map and restore_map to ASM (SBP). + * 06/15/86 Changed NULL_HANDLE to 0x0FFF (see emm.h) (SBP). + * 06/21/86 Moved MapHandlePage to ASM (SBP). + * Handle # passed to client has high byte = NOT (low byte) + * as in the Above Board (SBP). + * Valid_Handle -> ASM (SBP). + * 06/23/86 Make_Addr removed. source_addr and dest_addr added(SBP). + * 06/25/86 0.02 Dealloc checks for save area in use (SBP). + * 06/28/86 0.02 Name change from CEMM386 to CEMM (SBP). + * 06/29/86 0.02 Return after NOT_ENOUGH_FREE_MEM error in Allocate(SBP). + * 07/06/86 0.04 Changed _emm_page,_emm_free, & _pft386 to ptrs (SBP). + * 07/06/86 0.04 moved SavePageMap and RestorePageMap to .ASM (SBP). + * 07/08/86 0.04 moved GetSetPageMap to .ASM (SBP). + * 07/09/86 0.04 removed code which places handle # in _pft386 + * entry (SBP). + * 07/09/86 0.05 fixed bug in deallocate (SBP). + * 05/09/88 0.10 modified for MEMM, modifications are indicated in + * individual routines (ISP). + * + ******************************************************************************* + * FUNCTIONAL DESCRIPTION + * + * Paged EMM Driver for the iAPX 386. + * + * The basic concept is to use the 386's page tables to emulate + * the functions of an EMM board. There are several constraints + * that are a result of poor planning on the LIM specifiers part. + * - maximum of 64K instantaneously mapped. this will + * be faithfully emulated in this design + * - maximum of 8Mb of extended memory can be used. + * The actual reason for this is because each board + * can only support 128 16Kb pages and the limit of + * 4 Aboveboards implies 512 pages maximum. This will + * not be adhered to since the limit in unnecessary. + * + * The memory managed by this scheme can be discontiguous but + * a 16Kb EMM page can not be composed of discontiguous pieces. + * This is not necessary but does simplify the job of managing + * the memory. + * + * The LIM specification implies the existence of a partitioning + * of extended memory into `boards'. While this concept is not + * meaningfull in the 386 environment, a page to logical board + * mapping is provided to support some of the LIM specified + * functions: + * pages 0 to 127 map to board 0 + * pages 128 to 255 map to board 1 + * ... + * The pages in this case are logical pages and pages on the + * same logical board may actually reside on different physical + * boards. (In fact, if contiguous memory, a page could actually + * be split across 2 different boards.) + * + * A brief note on parameters: + * all parameters to EMM functions are passed in registers. + * on entry to the EMM dispatch code, the registers are pushed + * onto the stack. In order to access them, they are pointed + * to by a global variable (regp). Defines are used to name + * these parameters and make the code more readable. + * + * Definitions: + * Handle: + * 16 bit value that references a block of + * allocated memory. Internally, it is an index into a handle + * table. Externally, the high byte is the NOT of the low byte + * for compatibility with the Above Board EMM driver. + * + * EMM page: + * a 16Kb contiguous portion of memory, aligned on a + * 16Kb boundary in 8086 address space. In physical + * address space it can be aligned on a 4Kb boundary. + * + * page + * 386 page. 4Kb in size and 4Kb aligned in physical + * address space. + * + * far86 * + * An iAPX 86 style 32 bit pointer. It consists of + * a 16 bit offset in the low word and a base + * address in the high word. + * + * Logical page + * an EMM page allocated to a handle via allocatepages + * function. each such page has a logical page number. + * + * physical page frame + * the location in physical 8086 space that an EMM page + * gets mapped to. there are 4 such locations. they are + * contiguous starting at page_frame_base + * + * 386 page frame + * this is the physical page in 80386 physical + * address space. the address of a 386 page frame + * is the value placed in a 80386 page table entry's + * high 20 bits. + ******************************************************************************/ + +/****************************************************************************** + INCLUDE FILES + ******************************************************************************/ +#include "emm.h" + + +/****************************************************************************** + EXTERNAL DATA STRUCTURES + ******************************************************************************/ +/* + * I/O Map + * map_size + * this is an array of port addresses, 4 ports per + * emulated board. Each emulated board has up to + * 128 16Kb EMM pages assigned. The size of the table, + * the number of ports used, is map_size + * map_size = (/(128*4))*4 + */ +/*extern unsigned short iomap[]; */ +/*extern char map_size;*/ + +/* + * map_known + * This flags is set whenever the user is given the I/O map + */ +/*extern char map_known; */ + +/* + * page frame base + * this is a map of the linear addresses of the + * 4 16Kb EMM `physical' windows that the user + * accesses the EMM pages through. The entries + * of this array are far pointers into the page table. + * Thus, the address defined by page_frame_base[0] + * is the address of the long word that is the page + * table entry for the first EMM window. The reason for + * this obscurity is in speed of mapping -- it is used + * to directly obtain access to the entry to be programmed + */ +extern unsigned long page_frame_base[]; + +/* + * save_map + * This is an array of structures that save the + * current mapping state. Size is dynamically determined. + */ +extern struct save_map save_map[]; + +/* + * handle_table + * This is an array of handle pointers. + * page_index of zero means free + */ +extern struct handle_ptr handle_table[]; +extern Handle_Name Handle_Name_Table[]; +extern unsigned short handle_table_size; /* number of entries */ +extern unsigned short handle_count; /* active handle count */ + +/* + * EMM Page table + * this array contains lists of indexes into the 386 + * Page Frame Addresses (pft386). Each list is pointed to + * by a handle table entry and is sequential/contiguous. + * This is so that maphandlepage doesn't have to scan + * a list for the specified entry. + */ +extern unsigned short *emm_page; /* ptr to _emm_page array */ +extern unsigned short free_count; /* current free count */ +extern unsigned short total_pages; /* number being managed */ +extern unsigned short emmpt_start; /* next free entry in table */ + +/* + * EMM free table + * this array is a stack of available page table entries. + * each entry is an index into pft386[]. + */ +extern unsigned short *emm_free; /* ptr to _emm_free array */ +extern unsigned short free_top; + +/* + * Page frame table + * This array contains addresses of physical page frames + * for 386 pages. A page is refered to by an index into + * this array + */ +extern union pft386 *pft386; /* ptr to page frame table array */ + + +/* + * Current status of `HW'. The way this is handled is that + * when returning status to caller, normal status is reported + * via EMMstatus being moved into AX. Persistant errors + * (such as internal datastructure inconsistancies, etc) are + * placed in `EMMstatus' as HW failures. All other errors are + * transient in nature (out of memory, handles, ...) and are + * thus reported by directly setting AX. The EMMstatus variable + * is provided for expansion and is not currently being + * set to any other value. + */ +extern unsigned short EMMstatus; + +/* + * debug & such + */ +/*unsigned null_count = 0; /* number of attempts to map null pages */ + + +/****************************************************************************** + EXTERNAL FUNCTIONS + ******************************************************************************/ +extern struct handle_ptr *valid_handle(); /* validate handle */ +extern unsigned far *source_addr(); /* get DS:SI far ptr */ +extern unsigned far *dest_addr(); /* get ES:DI far ptr */ +/*extern unsigned AutoUpdate(); /* update auto mode */ +extern unsigned wcopy(); +extern unsigned copyout(); +extern void reallocate(); + + +/****************************************************************************** + ROUTINES + ******************************************************************************/ + +/* + * Avail_Pages() + * returns: number of available emm pages + * + * 06/09/88 PC added the function + */ +unsigned short +Avail_Pages() +{ + return(free_count) ; +} + +/* + * get_pages(num,pto) + * num --- number of pages desired + * pto --- offset into emm_page array where the pages got are to be copied + * return value: + * emm_page[] index (pointer to list of allocated pages) + * NULL_PAGE means failure. + * + * 05/06/88 ISP Updated for MEMM removed handle as a parameter + */ +unsigned +get_pages(num,pto) +register unsigned num; +register unsigned pto; +{ + register unsigned pg; + unsigned f_page; + + if(free_count < num) + return(NULL_PAGE); /* not enough memory */ + free_count -= num; /* adjust free count */ + f_page = pg = pto; +/* emmpt_start += num; */ /* new offset of avail area */ + + /* + * copy num elements from the emm_free array + * to the emm_page table array and update the + * corresponding page frame table entry (with a + * handle back pointer) + */ + wcopy(emm_free+free_top, emm_page+pg, num); + free_top += num; + return(f_page); +} + + +/* + * free_pages(hp) + * hp --- handle whose pages should be deallocated + * + * Free the pages associated with the handle, but don't free the handle + * + * 05/09/88 ISP Pulled out from the deallocate page routine + */ +void +free_pages(hp) +register struct handle_ptr *hp; +{ + register unsigned next; + unsigned new_start; + unsigned h_size; + + if (hp->page_count == 0) return ; + /* + * copy freed pages to top of free stack + */ + free_top -= hp->page_count; /* free_top points to new top */ + free_count += hp->page_count; /* bookkeeping */ + wcopy(emm_page+hp->page_index, /* addr of first of list */ + emm_free+free_top, /* addr of free space */ + hp->page_count); /* # of pages to be freed */ + + /* + * now, the hard part. squeeze the newly created hole + * out of the emm_page array. this also requires updating the + * handle_table entry via the backlink in the pft386 array. + * + * do this in two phases: + * - copy the lower portion up to squeeze the hole out + * - readjust the handle table to point to the new + * location of the head element + */ + + next = hp->page_index + hp->page_count; + if(next == emmpt_start ) /* any lists below? */ + { + /* no, all done */ + emmpt_start -= hp->page_count; + return; + } + + new_start = emmpt_start - hp->page_count; + wcopy(emm_page+next, /* 1st of rest of list */ + emm_page+hp->page_index,/* addr of freed area */ + emmpt_start-next); /* size of block of pages */ + + /* + * loop through the handle table entries, fixing up + * their page index fields + */ + h_size = hp->page_count; + hp->page_count = 0; /* not really necessary */ + for(hp=handle_table;hp < &handle_table[handle_table_size];hp++) + if((hp->page_index != NULL_PAGE) && + (hp->page_index >= next) ) + hp->page_index -= h_size; + emmpt_start = new_start; /* fix emmpt_start */ +} + +/* + * get status + * no parameters + * + * return current status of EMM subsystem + * (which, due to superior design is always just fine) + * + * 05/06/88 ISP No Update needed for MEMM + */ +GetStatus() +{ + setAH((unsigned char)EMMstatus); /* if we got here, we're OK */ +} + + +/* + * get page frame address + * no parameters + * + * return the address of where the pages get mapped + * in user space + * + * 05/06/88 ISP Updated this routine from WIN386 sources. + */ +GetPageFrameAddress() +{ + extern unsigned short PF_Base; + extern unsigned short page_frame_pages; + + /* + * return the 8086 style base address of + * the page frame base. + */ + if ( page_frame_pages < 4 ) { + setAH(EMM_HW_MALFUNCTION); /* GET LOST!!! */ + if ( PF_Base == 0xFFFF ) + setBX(0xB000); /* In case error is ignored */ + else + setBX(PF_Base); /* stunted page frame */ + return; + } + setBX(PF_Base); + setAH((unsigned char)EMMstatus); /* OK return */ +} + + +/* + * get unallocated page count + * no parameters + * + * returns: + * bx -- count of free pages + * dx -- total number of pages (free and allocated) + * + * 05/06/88 ISP No update needed for MEMM + */ +GetUnallocatedPageCount() +{ + setBX(free_count); + setDX(total_pages); + setAH((unsigned char)EMMstatus); +} + +/* + * allocate pages + * parameters: + * n_pages (bx) -- allocation size request + * + * allocates the requested number of pages, creates + * a handle table entry and returns a handle to the + * allocated pages. + * calls AllocateRawPages + * + * 05/09/88 ISP updated for MEMM. Only handle value returned, not handle + * value with high byte as not of handle value. call to get + * pages also updated to remove handle parameter. + */ +AllocatePages() +{ +#define n_pages ((unsigned)regp->hregs.x.rbx) + if(handle_count == handle_table_size){ /* no more handles? */ + setAH(NO_MORE_HANDLES); /* nope */ + return; + } + + if(n_pages == 0) { + setAH(ZERO_PAGES); + return; + } + + AllocateRawPages() ; +} +#undef n_pages + +/* + * allocate raw pages + * parameters: + * n_pages (bx) -- allocation size request + * + * allocates the requested number of raw pages, + * allocating 0 page is Okay + * calls allocated pages if non-zero. + * + * CREATED : 08/08/88 PLC + */ +AllocateRawPages() +{ +#define n_pages ((unsigned)regp->hregs.x.rbx) + register unsigned handle; /* handle table index */ + register struct handle_ptr *hp; + + if(handle_count == handle_table_size){ /* no more handles? */ + setAH(NO_MORE_HANDLES); /* nope */ + return; + } + + if(n_pages > total_pages) { + setAH(NOT_ENOUGH_EXT_MEM); + return; + } + + /* + * loop through table to + * find available handle (page_index = NULL_PAGE) + */ + hp = (struct handle_ptr *)handle_table; + for(handle=0;handlepage_index == NULL_PAGE) + break; /* found a free one */ + /* + * try and allocate pages + */ + if((hp->page_index=get_pages(n_pages,emmpt_start)) != NULL_PAGE) { + emmpt_start += n_pages; + setAH((unsigned char)EMMstatus); /* got them! */ + } + else { + setAH(NOT_ENOUGH_FREE_MEM); /* out of pages */ + return; + } + + hp->page_count=n_pages; /* set count */ + handle_count++; + setDX(handle); + +/* AutoUpdate(); /* update status of Auto mode */ + +} +#undef n_pages + +/* + * deallocate pages + * parameters: + * dx -- handle + * + * free up the pages and handle table entry associated + * with this handle + * + * 05/09/88 ISP Updated for MEMM. Pulled out free_page routine and + * added support for handle name blanking. + */ +DeallocatePages() +{ +#define handle ((unsigned)regp->hregs.x.rdx) + register struct handle_ptr *hp; + struct save_map *smp; /* save map table ptr */ + long *Name ; /* points to handle name entry to clear */ + + if ( handle == 0 ) { /* Special handle, don't release */ + int savbx = regp->hregs.x.rbx; + regp->hregs.x.rbx = 0; + ReallocatePages(); + regp->hregs.x.rbx = savbx; + return; + } + + if((hp=valid_handle(handle)) == NULL_HANDLE) + return; /* invalid handle, error code set */ + /* + * check for save area in use for this handle + */ + if( save_map[ (handle & 0x00FF) ].s_handle != (unsigned)NULL_HANDLE ) + { + setAH(SAVED_PAGE_DEALLOC); + return; + } + + free_pages(hp); /*free the pages associated with handle*/ + hp->page_index = NULL_PAGE; /*and then free the handle*/ + hp->page_count = 0; /*bookkeeping*/ + Name = (long *)Handle_Name_Table[handle & 0xFF]; + *(Name+1) = *(Name) = 0L; /* zero the eight byte name */ + handle_count--; /* one less active handle */ + +/* AutoUpdate(); /* update status of Auto mode */ + setAH((unsigned char)EMMstatus); /* done */ +} +#undef handle + + +/* + * get emm version + * no parameters + * + * returns the version number of the emm driver + * + * 05/06/88 ISP No update needed for MEMM + */ +GetEMMVersion() +{ + setAX( (EMMstatus<<8) | EMM_VERSION ); +} + +/* + * Get EMM handle count + * no parameters + * + * return the number of active EMM handles + * + * 05/06/88 ISP No update needed for MEMM + */ +GetEMMHandleCount() +{ + setBX(handle_count); + setAH((unsigned char)EMMstatus); +} + +/* + * Get EMM handle pages + * parameters: + * dx -- handle + * + * return the number of pages allocated to specified handle in BX + * + * 05/09/88 ISP No update needed for MEMM + */ +GetEMMHandlePages() +{ +#define handle ((unsigned)regp->hregs.x.rdx) + register struct handle_ptr *hp; + + if((hp=valid_handle(handle))==NULL_HANDLE) /*valid handle? */ + return; /* no */ + setBX(hp->page_count); + setAH((unsigned char)EMMstatus); +} + +/* + * Get All EMM Handle Pages + * parameters: + * es:di -- userptr + * + * fill out array of handle/size pairs + * + * 05/09/88 ISP Updated for MEMM (just removed upper byte of handle) + */ +GetAllEMMHandlePages() +{ + unsigned far *u_ptr; + register struct handle_ptr *hp; + register unsigned h_index; + + /* + * scan handle table and for each valid entry, + * copy handle and size to user array + */ + u_ptr = dest_addr(); + + hp=handle_table; + for(h_index=0;h_indexpage_index != NULL_PAGE) /* valid entry? */ + { + *u_ptr++ = h_index; /* handle */ + *u_ptr++ = hp->page_count; /*# of pgs for handle*/ + } + hp++; /* next entry */ + } + setBX(handle_count); /* bx <-- handle count */ + setAH((unsigned char)EMMstatus); +} + +/* + * Get Page Mapping Register I/O Port Array + * parameters: + es:di -- user array + * + * 05/09/88 ISP Function not supported + */ +GetPageMappingRegisterIOArray() +{ + + setAH(INVALID_FUNCTION); +} + +/* + * Get Logical to Physical Page Translation Array + * parameters: + * es:di -- pointer to user array + * dx ----- EMM handle + * + * 05/09/88 ISP Function not supported + */ +GetLogicalToPhysicalPageTrans() +{ + setAH(INVALID_FUNCTION); +} + \ No newline at end of file diff --git a/v4.0/src/MEMM/EMM/EMMINC.ASM b/v4.0/src/MEMM/EMM/EMMINC.ASM new file mode 100644 index 0000000..0074f54 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMINC.ASM @@ -0,0 +1,55 @@ + page 58,132 +;****************************************************************************** + title EMMINC.ASM - lists all EMMLIB.LIB include files +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver +; EMMLIB.LIB - Expanded Memory Manager Functions Library +; +; Module: EMMINC.ASM - lists all EMMLIB.LIB include files +; +; Version: 0.02 +; +; Date: June 14, 1986 +; +;****************************************************************************** +; +; Change Log: +; +; DATE REVISION Description +; -------- -------- -------------------------------------------- +; 06/25/86 original +; 06/28/86 0.02 Name change from CEMM386 to CEMM (SBP). +; +;****************************************************************************** +; Functional Description: +; This module includes all CEMM include files used by EMMLIB +; and will provide a listing of all when assembled to produce a listing file. +; +;****************************************************************************** +.lfcond +.386p + +;****************************************************************************** +; I N C L U D E S +;****************************************************************************** +INC_LIST EQU 1 ; list include files + + page + include DESC.INC + page + include EMMDEF.INC + page +; include INSTR386.INC +; page + include OEMDEP.INC + page + include PAGE.INC + page + include VDMSEG.INC + page + include VDMSEL.INC + + end diff --git a/v4.0/src/MEMM/EMM/EMMP.ASM b/v4.0/src/MEMM/EMM/EMMP.ASM new file mode 100644 index 0000000..a60b46e --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMP.ASM @@ -0,0 +1,2978 @@ +page 58,132 +;****************************************************************************** + title EMMP - EMM protected mode functions +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986, 1987 +; +; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver +; EMMLIB.LIB - Expanded Memory Manager Functions Library +; +; Module: EMMP - WIN386 EMM functions +; +; Version: 0.04 +; +; Date: July 7,1986 +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 07/07/86 0.04 Moved here from version 0.04 EMMSUP.ASM +; 07/08/86 0.04 Added Get/Set Page Map (SBP). +; 05/13/88 Change to LIM 4.0 functionality (PC) +; +;****************************************************************************** +; +; Functional Description: +; This file contains the EMM functions which require greatest efficiency. +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + +; include protseg.inc + include vdmseg.inc + include page.inc +; include vdmm.inc + include vm386.inc + include vdmsel.inc + include emmdef.inc + include desc.inc +; include vmdm.inc +; include vpicd.inc +; include vdmmmac.inc + +;****************************************************************************** +; P U B L I C S +;****************************************************************************** +_TEXT segment + public _MapHandlePage + public _SavePageMap + public _RestorePageMap + public _GetSetPageMap + public _GetSetPartial + public _MapHandleArray + public _AlterMapAndJump + public _AlterMapAndCall +; public TS_VEMMD_MC_Ret + public _MoveExchangeMemory + public _AlternateMapRegisterSet +; public VEMMD_Set_Map_Region +; public VEMMD_Unset_Map_Region +; public _VMpte_to_EMMpte +; public _Remap_EMM + public _Get_Key_Val +_TEXT ends + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** + +_TEXT segment + +extrn _source_addr:near +extrn _dest_addr:near + +extrn SetDescInfoResident:near +extrn SegOffTo24Resident:near + +extrn ErrHndlr:near + +_TEXT ends + +_DATA SEGMENT + +;extrn _regp:dword ; pointer to entry stack frame +;extrn VEMMD_pt:dword +;extrn Cur_VM_Handle:dword +;extrn Cur_VMID:dword +;extrn _VM_List:dword +;extrn _MaxEMMSize:dword +;extrn _VEMMD_PgFrame:word +;extrn _VEMMD_Last_Offset:word +extrn PF_Base:word +extrn _OSEnabled:dword +;extrn NullAvailPTE:dword +;extrn NullUnavailPTE:dword + +extrn _total_pages:word ; total # of EMM pages in system + +; +; table of offsets into in to the first page table +; for user logical emm page map +; +extrn _page_frame_base:dword + +extrn _pft386:word + +extrn _mappable_pages:word ; table of mappable pages +extrn _mappable_page_count:word ; how many in the table +extrn _page_frame_pages:word ; how many in the page frame +extrn _physical_page_count:word ; number of physical pages +extrn _VM1_EMM_Pages:word ; pages not in the page frame +;extrn _VM1_EMM_Offset:word ; offset of these in a context +extrn _cntxt_pages:byte ; number of pages in a context +extrn _cntxt_bytes:byte ; number of bytes in a context + + +; +; table of indexes into the above - maps segment to physical page +; +extrn EMM_MPindex:byte + +; +; ptr to table of emm page # for each handle's logical pages. +; +extrn _emm_page:word + +; +; handle data structure +; +extrn _handle_table:word +extrn _handle_table_size:word + +; +; save area for handles +; +extrn _save_map:byte + +; +; Save area and misc variables for 4.0 function 27 +; +extrn EMM_savES:word +extrn EMM_savDI:word + +extrn CurRegSetn:byte +extrn FRS_free:byte +extrn CurRegSet:dword +extrn FRS_array:word + +extrn _regp:word +_DATA ENDS + + page +;****************************************************************************** +; C O D E +;****************************************************************************** +_TEXT SEGMENT +assume cs:_TEXT, ds:DGROUP, ss:DGROUP + + page +;*********************************************** +; +; normalize +; +; ENTRY: Sel,Off - Selector:offset to be normalize +; protected mode only +; +; EXIT: Sel:Off normalized +; +; USES: Sel,Off +; NOTE: Sel and Off should not be BX,DX,AX +; +;*********************************************** +normalize MACRO Sel,Off + + push dx + push ax + push bx + push es + + push Sel ; save for later reload + mov bx, Sel ; get Selector into BX + + push GDTD_GSEL ; ES -> GDT + pop es + + and bl,SEL_LOW_MASK ; mask off mode bits + mov dx,es:[bx+2] ; AL:DX <-- base address + mov al,es:[bx+4] + add dx,Off ; adjust base address + adc al,0 + mov es:[bx+2],dx ; store it back + mov es:[bx+4],al + xor Off, Off ; new Offset + + pop Sel ; reload Selector (flush cache) + + pop es + pop bx + pop ax + pop dx + + ENDM + +;*********************************************** +; +; get_space_from_stack +; +; ENTRY: Len - amount of space requested +; +; EXIT: Len space allocated on ES:DI (client's stack) +; ES:DI - points to First element on top of stack +; +; USES: DI +; +;*********************************************** +Get_space_from_stack MACRO Len + + sub di, Len + ENDM + +;*********************************************** +; +; release_space_to_stack +; +; ENTRY: Len - amount of space to be release +; +; EXIT: Len space released from client's stack (DS:SI) +; +; USES: SI +; +;*********************************************** +release_space_to_stack MACRO Len + + add si, Len + ENDM + +;*********************************************** +; +; Set_EMM_GDT - set GDT entry of selector with some fix infos +; like access and limit +; +; ENTRY: Handle - selector of GDT to modify +; +; EXIT: GDT entry set +; bx - selector +; +; USES: ax,bx,cx,dx,es +; +;*********************************************** +Set_EMM_GDT MACRO handle + + mov bx, handle ; GDT selector + call SegOffTo24Resident ; AL:DX <-- 24 bit base address + mov cx, 0ffffh ; Limit + mov ah, D_DATA0 ; Acess right + push GDTD_GSEL + pop es ; ES:0 <-- GDT + call SetDescInfoResident ; set GDT entry + ENDM + +;*********************************************** +; +; Set_Byte_Gran - set granularity of GDT entry to byte +; +; ENTRY: Handle - selector of GDT to modify +; +; EXIT: Granularity bit clear in GDT +; bx - Selector +; +; USES: bx,es +; +;*********************************************** +Set_Byte_Gran MACRO handle + + mov bx, handle ; GDT selector + push GDTD_GSEL + pop es ; ES:0 <-- GDT + and byte ptr es:[bx+6],NOT R_GRAN ; clear gran bit + ENDM + +;*********************************************** +; +; Set_Page_Gran - set granularity of GDT entry to page +; +; ENTRY: Handle - selector of GDT to modify +; +; EXIT: Granularity bit set in GDT +; bx - Selector +; +; USES: bx,es +; +;*********************************************** +Set_Page_Gran MACRO handle + + mov bx, handle ; GDT selector + push GDTD_GSEL + pop es ; ES:0 <-- GDT + or byte ptr es:[bx+6], R_GRAN ; set gran bit + ENDM + +;*********************************************** +; +; Get_FRS_window - get pointer to Fast Register Set window +; +; ENTRY: Reg - points to an FRS_struc +; +; EXIT: Reg - points to FRS_window entry in the structure +; +; USES: Reg +; +;*********************************************** +Get_FRS_window MACRO Reg + + mov Reg, word ptr [CurRegSet] ; just offset (assume dgroup) + add Reg, FRS_window ; points to FRS window entries + ENDM + + page +;********************************************************************** +; +; map_EMM_page - set page table entries for a page frame +; +; ENTRY: AX - physical page number to be mapped +; BX - EMM page number to map +; EXIT: page table set up for EMM page # in this page frame +; DESTROY:EAX,BX +; +;*********************************************** +map_EMM_page proc near + cmp ax,[_physical_page_count] ;Q: valid physical page# ? + jae short mEp_inv_page ; N: invalid page number + ; Y: continue with it + cmp bx,[_total_pages] ;Q: valid EMM page# ? + jae short mEp_inv_page ; N: invalid page number + ; Y: continue with it + push es ; preserve es + push cx ; preserve cx + push di ; preserve di + push ax ; save ax (phys page#) + + ; + ; construct pointer to physical address of the first + ; 386 page and move it into eax + ; + mov cx,bx ; emm page# in cx to save in FRS later + shl bx,2 ; bx <-- pft index * 4 + + ; + ; continue calulation of pte + ; + add bx,[_pft386] ; BX = points into _pft386 + mov eax,[bx] ; EAX = physical address of EMM page # + and ax,0F000H ; clear the low 12 bits + or ax,P_AVAIL ; page ctl bits <-- user,present,write + + pop bx ; bx <-- physical page index + + ; + ; save mapping (offset into _pft386 struct) into + ; current FRS's physical page entry + ; + + Get_FRS_Window DI ; di <-- address of current FRS + add di,bx ; di <-- address of physical page + add di,bx ; entry in FRS + mov [di],cx ; save mapping (emm page#) into FRS + ; + ; construct pointer to physical address of + ; page frame + ; + + shl bx,2 ; bx <-- index * 4 + add bx,offset DGROUP:_page_frame_base ; bx = offset for entry in _page_frame_base + les di,[bx] ; es:di <-- page frame address + + ; + ; now, + ; es:di points to the 1st entry in the page table + ; for this page frame + ; eax contains the new value of the PTE + ; set up 4 entries + ; + + pushf ; preserve direction flag + cld ; forward + + stosd ; store 1st page table entry + add eax,P_SIZE ; eax <-- next address + + stosd ; store 2nd page table entry + add eax,P_SIZE ; eax <-- next address + + stosd ; store 3rd page table entry + add eax,P_SIZE ; eax <-- next address + + stosd ; store 4th page table entry + + popf ; restore direction flag + pop di ; get DI back + pop cx ; get CX back + pop es ; get ES back + clc + ret + +mEp_inv_page: + stc + ret + +map_EMM_page endp + + page +;********************************************************************** +; +; unmap_page - unmap a physical page +; +; ENTRY: AX - physical page number to be unmapped +; DESTROY:EAX +; +;********************************************************************** +unmap_page proc near + ; + ; find FRS entry for the physical page and + ; update it as unmapped + ; + push es + push di + push bx + push cx + Get_FRS_Window DI ; di <-- address of current FRS + add di, ax ; di <-- address of physical page + add di, ax ; entry in FRS + mov [di], NULL_PAGE ; unmap the entry + + ; + ; find out the segment of the physical page + ; + mov cx, [_physical_page_count] + mov di, offset DGROUP:_mappable_pages +unmap_page_loop: + cmp ax, [di].mappable_pg + je unmap_page_found + add di, size Mappable_Page + loop unmap_page_loop + + jmp short unmap_page_exit ; non-found : just return + +unmap_page_found: + mov bx, [di].mappable_seg ; get segment into bx first + + ; + ; construct pointer to physical address of + ; page frame + ; + xchg ax,bx + shl bx,2 ; bx <-- index * 4 + add bx,offset DGROUP:_page_frame_base ; bx <-- points to PTE address of phys page# + les di,[bx] ; es:di <-- points to PTE of page frame + xchg ax,bx + + ; + ; construct PTE + ; + movzx eax, bx ; EAX <-- segment of physical page + shl eax, 4 + and ax,0F000H ; clear the low 12 bits + or ax,P_AVAIL ; page ctl bits <-- user,present,write + + cmp eax, 0A0000h ; Q:above 640K ? + jge unmap_page_ok ; Y: go ahead, unmap it + mov eax, 0 ; N: shouldn't unmap below 640K - make page NotPresent + +unmap_page_ok: + pushf + cld + stosd ; unmap pte of page frame + add eax,P_SIZE + stosd + add eax,P_SIZE + stosd + add eax,P_SIZE + stosd + popf + +unmap_page_exit: + pop cx + pop bx + pop di + pop es + ret +unmap_page endp + + page +;********************************************************************** +; +; map_page - map a logical page to a phyical page +; +; ENTRY: AX - physical page number to be mapped +; BX - logical page number to map +; DX - handle pointer (do not destroy) +; DESTROY:EAX,BX +; +;********************************************************************** +map_page proc near + cmp ax,[_physical_page_count] ;Q: valid physical page# ? + jae short mp_inv_phy ; N: invalid page number + ; Y: continue with it + cmp bx,0FFFFh ;Q: unmap ? + je short mp_unmap_page ; Y: go ahead + + xchg bx, dx + cmp dx,[bx.ht_count] ;Q: valid logical page# ? + xchg bx, dx + jae short mp_inv_log ; N: invalid page number + ; Y: continue with it + + xchg bx, dx + add dx,[bx.ht_index] ; dx <-- index into _emm_page + xchg bx, dx + shl bx,1 ; bx <-- index * 2 + add bx,[_emm_page] + mov bx,[bx] ; bx <-- emm page# + call map_EMM_page + jc short mp_inv_emm_page ; emm page range error + ret + +mp_unmap_page: + call unmap_page + clc + ret + +mp_inv_emm_page: + mov byte ptr [bp.rAX+1],SOURCE_CORRUPTED + stc + ret + +mp_inv_phy: + mov byte ptr [bp.rAX+1],PHYS_PAGE_RANGE + stc + ret + +mp_inv_log: + mov byte ptr [bp.rAX+1],LOG_PAGE_RANGE + stc + ret +map_page endp + + + page +;*********************************************** +; +; _MapHandlePage - map a handle's page +; +; This routine maps 4 386 pages into the address +; space. +; +; ENTRY: PROTECTED MODE ONLY +; AH = 44h = map handle page function # +; AL = window # (physical page #) +; BX = logical page # +; DX = EMM handle +; REGS on STACK: SI = not used by this function +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: page table entries set up +; AH = status of this function +; = EMM_HW_MALFUNCTION if entry in real/virtual mode. +; +; USED: EAX, EBX, EDX, EDI +; +;*********************************************** + +Dword_Align _TEXT +_MapHandlePage proc near + + Validate_Handle + + mov byte ptr [bp.rAX+1],OK ; Assume success! + movzx eax, al ; Physical page + movzx ebx, bx ; Logical page + + push eax + mov eax, cr3 + mov cr3, eax ; Flush old mapping now + pop eax + + jmp map_page ; Common page mapping code + +mhp_inv_handle: + mov byte ptr [bp.rAX+1], INVALID_HANDLE + ret + +_MapHandlePage endp + + page +;*********************************************** +; +; _SavePageMap - save current page mapping +; +; This routine save the current page mapping context for a handle. +; +; ENTRY: PROTECTED MODE +; AH = 07h = save page map function # +; DX = EMM handle +; REGS on STACK: SI = not used by this function +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: current state saved +; AH = status of this function +; +; USED: AX,BX,CX,DX,SI,DI +; +;*********************************************** + +Dword_Align _TEXT +_SavePageMap proc near + cmp [_page_frame_pages], 4 + jb short srpm_nopf ; no page frame + + mov ax, dx ; Save for later + Validate_Handle + ; check state of handle's page area + imul bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for + ; this handle's save area + lea di,_save_map[bx] ; DS:DI points to handle's save area + cmp [di].s_handle,NULL_HANDLE + ;Q: save area in use ? + jne short spm_prev_saved ; Y: return error + ; N: use it now + cld + push ds + pop es + stosw ; store handle # in s_handle + Get_FRS_window SI ; Current FRS page mappings + movsd ; move to save area + movsd ; Lim 3.2 has only 4 page frames + + mov byte ptr [bp.rAX+1],OK ; ok return + ret + +spm_prev_saved: + mov byte ptr [bp.rAX+1],MAP_PREV_SAVED + ret + +srpm_inv_handle: ; Shared error returns + mov byte ptr [bp.rAX+1],INVALID_HANDLE + ret + +srpm_nopf: + mov byte ptr [bp.rAX+1], EMM_HW_MALFUNCTION ; No page frame!!! + ret + +_SavePageMap endp + + page +;*********************************************** +; +; _RestorePageMap - restore handle's saved page mapping +; +; This routine restores the current page mapping context +; from a handle's save area. +; +; ENTRY: PROTECTED MODE ONLY +; AH = 08h = restore page map function # +; DX = EMM handle +; REGS on STACK: SI = not used by this function +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: current state restored +; AH = status of this function +; +; USED: AX,BX,CX,DX,SI,DI +; +;*********************************************** + +Dword_Align _TEXT +_RestorePageMap proc near + cmp [_page_frame_pages], 4 + jb short srpm_nopf ; no page frame + + mov ax, dx ; Save for later + Validate_Handle srpm_inv_handle + ; check state of handle's page area + imul bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for + ; this handle's save area + lea si,_save_map[bx] ; DS:SI points to handle's save area + cmp [si].s_handle,NULL_HANDLE + ;Q: save area in use ? + je short rpm_no_map_saved ; N: return error + ; Y: restore it + + mov byte ptr [bp.rAX+1],OK ; Assume success + mov [si].s_handle,NULL_HANDLE ; null handle's save area + + lea si,[si].s_map ; SI -> handle's save area + Get_FRS_window DI ; Get pointer to current window + push ds + pop es ; ES <-- DGROUP + cld + movsd ; restore 4 words + movsd ; Lim 3.2 has only 4 page frames + jmp _set_windows ; Restore mapping + +rpm_no_map_saved: + mov byte ptr [bp.rAX+1],NO_MAP_SAVED + ret + +_RestorePageMap endp + + page +;*********************************************** +; +; _GetSetPageMap - get/set page map to/from external save area +; +; This routine stores the current page mapping context (Intel +; compatible form for now) to an external save area and/or restores +; the current page mapping context from an external save area. +; +; ENTRY: PROTECTED MODE ONLY +; AH = 4Eh = Get/Set page map function number +; or AH = 5Ch = Get/Set large page map function number +; AL = SUBFUNCTION CODE +; AL = 0 => Get page map +; AL = 1 => Set page map +; AL = 2 => Get and Set page map +; AL = 3 => return size of page map +; REGS on STACK: SI = not used by this function +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: current state saved / restored +; AH = status of this function +; +; USED: BX,CX,DX,SI,DI +; +;*********************************************** +Dword_Align _TEXT +_GetSetPageMap proc near + + cmp al,GSPM_GET ;Q: get page map subfunction ? + je short _get_map ; Y: get it + + cmp al,GSPM_SET ;Q: set page map subfunction ? + je _set_map ; Y: set it + + cmp al,GSPM_GETSET ;Q: get & set page map subfunction ? + jne short gspm_chk_size ; N: check for size function + call _get_map ; Y: get current map first + jmp short _set_map ; set new one + +gspm_chk_size: + cmp al, GSPM_SIZE ;Q: return map size subfunction ? + jne short gspm_inv_subfun ; N: return invalid subfunction + + mov al, [_cntxt_bytes] ; size of map + mov ah, OK ; ok return + mov word ptr [bp.rAX], ax + ret + +gspm_inv_subfun: + mov byte ptr [bp.rAX+1],INVALID_SUBFUNCTION + ret + +gspm_inv_fun: + mov byte ptr [bp.rAX+1],INVALID_FUNCTION + ret + +_GetSetPageMap endp + + page +;*********************************************** +; +; _get_map - save current mapping register state to external area +; +; ENTRY: on stack +; clients ES:DI -> client's buffer for state +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: state stored in client's buffer +; return code set on stack +; +; USED: AX,BX,CX,DX,SI,DI,ES +; +; DESCRIPTION: This function saves the current mapping +; into the save area specified. +; +;*********************************************** +Dword_Align _TEXT +_get_map proc + + cld + call _dest_addr ; DX:AX ptr for client's buff + mov es,dx + mov di,ax ; ES:DI pts to clients buffer + + Get_FRS_window SI ; Get pointer to current window + movzx ecx, [_cntxt_pages] + mov ax, cx + stosw ; save # pages + shr cx, 1 ; now dwords + rep movsd ; mov bytes to current map area + mov byte ptr [bp.rAX+1],OK ; ok return + ret + +_get_map endp + + page +;*********************************************** +; +; _set_map - restore mapping register state +; +; ENTRY: on stack +; clients DS:SI -> client's buffer containing state to restore +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: state restored from client's buffer +; return code set on stack +; CLC => no errors +; STC => error occurred +; +; USED: EAX,BX,CX,DX,SI,DI,ES +; +; +; DESCRIPTION: This function restores the mapping from the state info input. +; The mapping is assumed to be the same as in the +; save_current_map function. The count in the saved +; state is verified. +; +;*********************************************** +Dword_Align _TEXT +_set_map proc near + + mov byte ptr [bp.rAX+1],OK ; Assume success + Get_FRS_window DI ; Get pointer to current window + ; before DS gets trashed + push ds + pop es ; use ES to address data + push dx + mov si, ax + call _source_addr ; DX:AX ptr for client's buff + mov ds,dx + xchg si,ax ; DS:SI pts to clients buffer + pop dx + + cld + movzx ecx, es:[_cntxt_pages] ; number of words in mapping + lodsw ; saved size + cmp ax, cx ; should be this + jne short sm_inv_source ; Wrong, saved data corrupted + shr cx, 1 ; now a word count + rep movsd + push es + pop ds ; DS <-- DGROUP + jmp _set_windows ; make it effective + +sm_inv_source: + mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED + ret + +sm_exit: + ret + +_set_map endp + + page +;*********************************************** +; +; _set_windows - re-map all mapped physical pages +; +; This routine maps all mapped 386 pages of the EMM page frame into the +; linear address space for the page frame. +; +; ENTRY: PROTECTED MODE ONLY +; DS = DGROUP +; SS:[BP] -> regp stack frame +; +; EXIT: page tables changed to map these pages. +; _current_map contents initialized. +; +; uses: +; FLAGS, EAX, EBX, ECX, ESI, EDI +; +;*********************************************** +; +_set_windows proc near +; + xor ax, ax ; start from PHYS page 0 + Get_FRS_Window SI ; SI <-- current FRS map +sw_loop: + mov bx, word ptr [si] ; BX <-- emm page # + add si, 2 ; prepare for next PHYS page + cmp bx, 0FFFFh ; not mapped ? + je sw_unmap_page ; Y: unmap it + cmp bx, [_total_pages] ; emm page out of range ? + ja sw_corrupt ; Y: error + mov di, bx + shl di, 2 ; SI <-- _pft386 offset of emm page + add di, [_pft386] + cmp dword ptr [di], 0 ; pte not mapped ? + je sw_corrupt ; Y: error + push eax + call map_EMM_page ; map a page + pop eax +sw_done_page: + inc ax + cmp ax, [_physical_page_count] + jb sw_loop ; next page + + mov eax, cr3 + mov cr3, eax ; flush TLB + ret + +sw_unmap_page: + push eax + call unmap_Page + pop eax + jmp short sw_done_page + +sw_corrupt: + mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED + pop dx + ret + +_set_windows endp + + page +;******************************************************************************* +; +; LIM 4.0 EXTRAS for Windows +; +;******************************************************************************* + +;*********************************************** +; +; _GetSetPartial - get/set partial page map to/from external save area +; +; This routine stores the current page mapping context +; to an external save area and/or restores the current page +; mapping context from an external save area. +; +; ENTRY: PROTECTED MODE ONLY +; AH = 4Fh = Get/Set page map function number +; AL = SUBFUNCTION CODE +; AL = 0 => Get page map +; AL = 1 => Set page map +; AL = 2 => return size of page map +; REGS on STACK: SI = not used by this function +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: current state saved / restored +; AH = status of this function +; +; USED: BX,CX,DX,SI,DI +; +;*********************************************** +_GetSetPartial proc near + cmp al, 0 ; Get...? + jne gsppm_not0 + + call _source_addr ; uses AX, DX + mov fs, dx + mov si, ax + call _dest_addr ; uses AX, DX + mov es, dx + mov di, ax + cld + lods word ptr fs:[si] + stosw ; Save count in save area + or ax, ax + jz gsppm_ok ; nothing to do + movzx ecx, ax + + mov dx, [_mappable_page_count] + cmp cx, dx + ja gsppm_inv_phys +gsppm_get_loop: + lods word ptr fs:[si] ; Get segment + shr ax, 10 ; 16k page number + sub ax, CONV_STRT_PG ; first page in emm_mpindex arr + jb gsppm_inv_seg ; only pages above 256k + mov bx, ax + mov al, EMM_MPindex[bx] ; convert to physical page + cmp al, -1 ; does it exist + je gsppm_inv_seg + mov bx, ax + shl bx, 2 + lea ax, _mappable_pages[bx] + mov bx, ax + mov bx, [bx.mappable_seg] ; segment for this page + cmp bx, fs:[si-2] + jne gsppm_inv_seg ; must match exactly + mov bx, ax + movzx ebx, [bx.mappable_pg] ; the physical page + cmp bx, dx + ja gsppm_inv_seg + mov ax, bx + stosw ; Save physical page + Get_FRS_window BX ; Get pointer to current window + add bx, ax ; get ptr to emm page# in FRS + add bx, ax + mov ax, [bx] + stosw ; and current mapping + loop gsppm_get_loop + +gsppm_ok: + mov byte ptr [bp.rAX+1], OK + ret + +gsppm_not0: + cmp al, 1 ; Set...? + jne gsppm_not1 + ; Set Partial Page Map + call _source_addr ; uses AX, DX + mov fs, dx + mov si, ax + movzx ecx, word ptr fs:[si] ; Get count from save area + add si, 2 + jecxz gsppm_ok ; Zero count, do nothing + + Get_FRS_window DX ; Get pointer to current window + cmp cx, [_mappable_page_count] + ja short gsppm_corrupt ; can't be more than phys pages +gsppm_set_loop: + push esi + movzx eax, word ptr fs:[si] ; Get Physical page + cmp ax, [_mappable_page_count] + jae gsppm_sl_bad + + movzx esi, word ptr fs:[si+2] ; Get mapping (emm page#) + mov di,dx + add di,ax + add di,ax ; di <-- current FRS phy page + mov [di], si ; Save new mapping + + cmp si, 0FFFFh ; Unmapped? + je short gsppm_unmap ; yes, go unmap it + cmp si, [_total_pages] ; valid page? + jae short gsppm_sl_bad ; no, fail + + mov bx, si ; bx <-- emm page# + ; ax <-- phys page# + call map_EMM_page + +gsppm_set_done: + pop esi + add esi, 4 ; Next page to map + loop gsppm_set_loop + mov eax, cr3 ; Flush TLB + mov cr3, eax + jmp gsppm_ok + +gsppm_unmap: + call unmap_page ; with ax <-- phys page# + jmp gsppm_set_done ; On to next page + +gsppm_sl_bad: + pop esi +gsppm_corrupt: + mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED + ret + +gsppm_not1: + cmp al, 2 ; Size? + jne gspm_inv_subfun + cmp bx, [_mappable_page_count] ; # of page frames + ja short gsppm_inv_phys + shl bx, 2 ; Size = pages * 4 + 2 + add bx, 2 + mov byte ptr [bp.rAX], bl + jmp gsppm_ok + +gsppm_inv_subfun: + mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION + ret + +gsppm_inv_phys: +gsppm_inv_seg: + mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE + ret + +_GetSetPartial endp + + page +;*********************************************** +; +; _MapHandleArray - map an array of a handle's pages +; +; This routine maps the physical pages according to +; an array of mappings. +; +; ENTRY: PROTECTED MODE ONLY +; AH = 50h = map handle page function # +; AL = Subfunction: 0) Physical pages described by their number +; 1) Physical pages described by segment +; CX = number of pages to be mapped +; DX = EMM handle +; REGS on STACK DS:SI = array of mappings +; SS:[BP] -> regp stack frame +; DS = DGROUP +; NOTE: +; There is a second entry point for this procedure at the label +; MapHandleArray_Entry_2. The entry conditions for this are identical +; to those specified above except that ESI points to the mapping array-- +; the DS:SI on the stack are ignored. Also, the value in AH is undefined. +; This entry point is used by the AlterMapAndJump and AlterMapAndCall +; functions. +; +; EXIT: context block ve_window set up +; page table entries set up +; AH = status of this function +; = EMM_HW_MALFUNCTION if entry in real/virtual mode. +; +; USED: AX,BX,DX,SI,DI,FS +; +;*********************************************** +Dword_Align _TEXT +_MapHandleArray proc near + mov si, ax + push dx + call _source_addr ; DX:AX <-- mapping array + xchg si, ax + mov fs, dx + pop dx ; FS:SI <-- mapping array + +MapHandleArray_Entry_2: + cmp al, 1 ; Q: Is subfunction 0 or 1? + ja mha_inv_sub ; N: Invalid subfunction + + Validate_Handle + + mov byte ptr [bp.rAX+1], OK ; Assume success + movzx ecx, cx + jecxz short mha_exit ; none to do, just return + + or al, al ; which subfunction? + jnz short mha_sub1 ; subfunction 1? + + ; + ; Subfunction 0: array contains logical and physical + ; page numbers. + ; +mha_sub0: + movzx eax, fs:[si.mha0_phys_pg] ; physical page number + movzx ebx, fs:[si.mha0_log_pg] ; logical page number + call map_page ; map it if possible + jc short mha_exit ; Error code already set + add si, size mha_array0 + loop mha_sub0 + jmp short mha_exit + + ; + ; Subfunction 1: array contains logical page number and + ; segment numbers corresponding to the + ; desired physical pages. + ; +mha_sub1: + mov di, fs:[si.mha1_seg] ; segment to map + mov ax, di ; save for later + shr di, 10 ; 16k page number + sub di, CONV_STRT_PG ; first page in emm_mpindex arr + jb short mha_inv_seg ; only pages above 256k + movsx edi, EMM_MPindex[di] ; convert to physical page + cmp edi, -1 ; does it exist + je short mha_inv_seg + shl di, 2 ; index * 4 + lea di, _mappable_pages[di] + cmp ax, [di.mappable_seg] ; segment for this page + jne short mha_inv_seg ; must match exactly + movzx eax, [di.mappable_pg] ; the physical page + movzx ebx, fs:[si.mha1_log_pg] ; the logical page + call map_page ; try to map it + jc short mha_exit ; error code already set + add si, size mha_array1 + loop mha_sub1 ; back for next segment to map + +mha_exit: + mov eax, cr3 ; Always clear TLB, we may have + mov cr3, eax ; mapped pages before an error + ret + ; ERRORS... +mha_inv_handle: + mov byte ptr [bp.rAX+1], INVALID_HANDLE + ret +mha_inv_sub: + mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION + ret +mha_inv_seg: + mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE + jmp mha_exit + +_MapHandleArray endp + + + + page +;*********************************************** +; +; _AlterMapAndJump - map an array of a handle's pages and Jump to a +; a specified address +; +; This routine maps pages using the MapHandleArray procedure and jumps +; to the specified address +; +; ENTRY: PROTECTED MODE ONLY +; AL = Mapping method -- 0 = Physical pages, 1 = Segments +; DX = EMM handle +; REGS on STACK +; REGS on STACK -- DS:SI -> Map and Jump structure +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: context block ve_window set up +; page table entries set up +; AH = status of this function +; = EMM_HW_MALFUNCTION if entry in real/virtual mode. +; Address specified in Map and Jump structure will be new return address +; +; USED: AX,BX,CX,SI,DI,FS,GS +; +;********************************************** + +_AlterMapAndJump PROC NEAR + + push dx + mov si, ax + call _source_addr ; DX:AX <-- map & jump struct + mov gs, dx + xchg si, ax ; GS:SI <-- map & jump struct + pop dx + push si + push ax + push dx ; save EMM handle + mov dx, WORD PTR gs:[si.maj_map_address] ; AX:DX <-- map array + mov ax, WORD PTR gs:[si.maj_map_address+2] + Set_EMM_GDT EMM2_GSEL + mov fs, bx ; FS:0 <-- map array + pop dx ; restore handle + pop ax ; restore subfunction + movzx ecx, byte ptr gs:[si.maj_log_phys_map_len] ; Length of map + xor si, si ; FS:SI <-- map array + call MapHandleArray_Entry_2 ; Map the array + pop si + + mov ah, byte ptr [bp.rAX+1] + or ah, ah + jnz SHORT AMJ_Error + mov eax, dword ptr gs:[si.maj_target_address] + mov word ptr [bp.retaddr], ax ; Put jump address in place of + shr eax, 16 ; old IRET return address + mov word ptr [bp.rCS], ax + ; + ; now, pop 5 words from client's stack because we are not + ; going to go back. (See AlterMapAndCall for client's + ; Stack frame structure) + ; + mov edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP] ; clients's ESP + add edi, 5 * 2 ; "pop" 5 words + mov dword ptr [bp.rFS+2+VTFO.VMTF_ESP], edi ; save it + ; + ; tell EMMpEntry to patch CS:IP onto its' iretd stack frame + ; + or word ptr [bp.PFlag], PFLAG_PATCH_CS_IP +AMJ_Error: ; Do the jump + ret + +_AlterMapAndJump ENDP + + + page +;*********************************************** +; +; _AlterMapAndCall - map an array of a handle's pages and call a procedure +; at a specified address (similar to a FAR call) +; This function pushes the return address on the +; client's stack and Jumps to the specified procedure. +; The "Called" procedure will return to AMC_return_address +; +; ENTRY: PROTECTED MODE ONLY +; AL = Subfunction -- 0 = Map phys pages, 1 = Map segs, 2 = Frame size +; DX = EMM handle +; REGS on STACK DS:SI = Map and Call structure +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: context block ve_window set up +; page table entries set up +; Transfer Space pushed on client's stack +; Return address CS and IP will point to called procedure +; AH = status of this function +; = EMM_HW_MALFUNCTION if entry in real/virtual mode. +; +; USED: AX,BX,CX,DX,SI,DI +; +;*********************************************** + +_AlterMapAndCall PROC NEAR + + cmp al, 2 ; Q: Which subfuction ? + ja AMC_inv_sub ; >2: invalid subfunction + je AMC_Stack_Fram_Size ; =2: Stack frame size subfuncion + ; <2: map and call + push dx + mov si, ax + call _source_addr ; DX:AX <-- map & call structure + mov gs, dx + xchg si, ax ; GS:SI <-- map & call structure + pop dx + ; + ; check new and old map's length + ; + xor ch, ch + mov cl, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map + cmp cx, [_physical_page_count] + jae AMC_inv_phys_pages + mov cl, byte ptr gs:[si.mac_new_page_map_len] ; CX = Length of new map + cmp cx, [_physical_page_count] + jae AMC_inv_phys_pages + ; + ; get client's SS:ESP so we can push stuffs on it + ; + push ax + push dx + + mov edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP] ; clients's ESP + mov ax, word ptr [bp.rFS+2+VTFO.VMTF_SS] ; client's SS + xor dx, dx ; AX:DX <-- Seg:Off of Client's Stack + + push ax ; client's Stack Segment + Set_EMM_GDT EMM2_GSEL + push bx ; client's Stack Selector + ; + ; get CS's Base to "push" on stack for later retf from client + ; + push GDTD_GSEL + pop es ; ES:0 <-- GDT + mov bx, cs ; selector + and bl, SEL_LOW_MASK + mov dx, word ptr es:[bx + 2] ; get lower 16 bit of Base + mov al, byte ptr es:[bx + 4] ; get upper 8 bit of Base + shr dx, 4 + shl al, 4 + or dh, al ; get the segment value + mov bx, dx ; into BX + + pop es ; ES:DI <-- client's SS + pop cx ; CX <-- Client's stack Segment + + pop dx + pop ax + ; + ; save client's stack segment and target address on stack + ; cause they (CX and EMM1_GSEL) get destroy + ; + push cx + push word ptr gs:[si].mac_target_address+2 + push word ptr gs:[si].mac_target_address + ; + ; On the Client's stack : + ; + ; +-----------------+ + ; | client's Flag | + ; +-----------------+ + ; | client's CS | + ; +-----------------+ + ; | client's IP | + ; +-----------------+ + ; | EMM_rEntry's CS | + ; +-----------------+ + ; | EMM_rEntry's IP | <-- "SS:ESP" (ES:EDI) + ; +-----------------+ + ; + ; "pop" EMM_rEntry's CS:IP off the stack, save it on Ring0 stack + ; in case thereis an error and need to restore state of stack. + ; keep the rest (client's FLAG, CS and IP) + ; + push es:[di+2] ; EMM_rEntry's CS + push es:[di] ; EMM_rEntry's IP + add di, 2 * 2 ; "pop" + ; + ; save old map on stack + ; + movzx ecx, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map + shl cx, 2 ; CX * 4 (4 bytes each entry) + inc cx ; one more for length + get_space_from_stack CX ; ES:DI <-- space on stack + dec cx + shr cx, 2 ; CX back to length in bytes + + push ds + push di ; save postion of stack + push si + push ax + push bx + push dx + push cx ; save #pages + + cld + mov dx, word ptr gs:[si.mac_old_map_address] ; AX:DX <-- map array + mov ax, word ptr gs:[si.mac_old_map_address+2] + push es + Set_EMM_GDT USER1_GSEL + pop es + mov ds, bx ; DS:0 <-- map array + xor si, si + pop cx + mov ax, cx + stosb ; store length of map + + shl cx, 1 ; move word + rep movsw + + pop dx ; restore handle + pop bx ; restore Segment of client Stack + pop ax ; restore subfunction + pop si + pop di + pop ds + ; + ; save FRS context on stack + ; + movzx ecx, [_cntxt_bytes] + get_space_from_stack CX ; ES:DI <-- space on stack + + push si + push di + get_FRS_Window SI ; DS:SI <-- mapping context + shr ecx, 1 ; move words + rep movsw + + pop di + pop si + ; + ; map new mapping + ; + push bx + push ax + push dx + + push di ; save "stack pointer" + push si + push ax + push dx ; save EMM handle + mov dx, WORD PTR gs:[si.mac_new_map_address]; AX:DX <-- map array + mov ax, WORD PTR gs:[si.mac_new_map_address+2] + push es + Set_EMM_GDT USER1_GSEL + pop es + mov fs, bx ; FS:0 <-- map array + xor si, si + pop dx ; restore handle + pop ax ; restore subfunction + movzx ecx, byte ptr gs:[si.mac_new_page_map_len] + call MapHandleArray_Entry_2 ; Map the array + pop si ; Restore structure pointer + pop di ; restore "stack" pointer + pop dx + pop ax + mov bh, byte ptr [bp.rAX+1] + or bh, bh + pop bx + jnz AMC_map_Error + ; + ; save needed registers, return address and call address + ; on client's stack + ; + dec di + dec di ; "pre-decrement" stack + std ; store backward + stosw ; subfunction code + mov ax, dx ; EMM handle + stosw + mov ax, ds ; DGROUP + stosw + mov ax, bx ; CS for return from called code + stosw + mov ax, offset AMC_return_address ; IP for return from called code + mov es:[di], ax ; "push" without decrement "SP" + cld + ; + ; NOW build a iretd stack frame to go back to virtual mode + ; + pop ax ; no error : we can throw + pop ax ; away EMM-rEntry's CS:IP now + + pop ax ; target address + pop dx ; target address+2 + pop cx ; Stack Segment + + push 0 + push word ptr [bp].rGS + push 0 + push word ptr [bp].rFS + push 0 + push word ptr [bp].rDS + push 0 + push word ptr [bp].rES + push 0 + push cx ; client's SS + push edi ; client's ESP + push PFLAG_VM ; VM bit + mov bx, word ptr [bp].PFlag + and bx, not PFLAG_VIRTUAL ; clear fake bit + push bx + push 0 + push dx ; target address+2 + push 0 + push ax ; target address + ; + ; restore registers context from stack frame + ; + mov eax, dword ptr [bp].rAX + mov ebx, dword ptr [bp].rBX + mov ecx, dword ptr [bp].rCX + mov edx, dword ptr [bp].rDX + mov esi, dword ptr [bp].rSI + mov edi, dword ptr [bp].rDI + mov ebp, dword ptr [bp].rFS+2 ; clients's EBP + ; + ; return to virtual mode via iretd with calling address on stack + ; + iretd + +AMC_map_Error: + ; + ; mapping error occur : restore state and exit + ; + movzx ecx, [_cntxt_bytes] + push es + pop ds ; DS:SI <-- stack + xchg si, di + release_space_to_stack CX ; DS:SI <-- space on stack + ; + movzx ecx, byte ptr gs:[di.mac_old_page_map_len] ; CX = Length of old map + shl cx, 2 ; CX * 4 (4 bytes each entry) + inc cx ; one more for length + release_space_to_stack CX ; DS:SI <-- space on stack + ; + mov di, si + mov cx, 4 + get_space_from_stack CX ; ES:DI <-- space on stack + pop es:[di] ; restore EMM_rEntry's CS:IP + pop es:[di+2] + + pop ax ; discard target addr etc + pop ax + pop ax + + ret + +AMC_Stack_Fram_Size: + mov byte ptr [bp.rAX+1], OK ; No error + mov ax, [_mappable_page_count] ; assume ALL mappable pages + shl ax, 2 ; 4 bytes per page + add ax, 1 + (3+5)*2 ; map length + ; + 3 words already pushed by EMM_rEntry + ; + 5 registers pushed + add al, [_cntxt_bytes] ; FRS context + adc ah, 0 + mov word ptr [bp.rBX], ax + ret + +AMC_inv_phys_pages: + mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE + ret + +AMC_inv_sub: + mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION + ret + +_AlterMapAndCall ENDP + + +;****************************************************************************** +; +; AMC_return_address -- Return from procedure called through a Map & Call +; +; NOTE: MapHandleArray will only access AH on the stack and so the +; TSTF stack frame will work properly for this procedure. +; +; ENTRY: VTFOE frame,EBP,EBX,ESI are on the stack +; +;****************************************************************************** + +AMC_return_address proc far + +; +; This will causes an illegal instruction trap and goes into protected +; mode. The handler will return back to the point right after the +; 2 bytes ARPL instruction with ring0 stack having and IRETD stack frame +; + arpl ax, ax + ; + ; In Protected Mode Now + ; + pushad ; saves all regs + mov ax, sp ; saves stack frame address + mov [_regp], ax ; to _regp + + mov esi, dword ptr [bp.VTFOE.VMTF_ESP] ; clients's ESP + mov ax, word ptr [bp.VTFOE.VMTF_SS] ; client's SS + xor dx, dx ; AX:DX <-- Seg:Off of Client's Stack + + Set_EMM_GDT EMM2_GSEL + mov fs, bx ; FS:SI <-- client's Stack + + cld ; forward + ; + ; "pop" back registers on "stack" FS:SI + ; + push fs + pop ds + lodsw + mov es, ax ; DGROUP + lodsw + mov dx, ax ; EMM handle + lodsw ; subfunction code + ; + ; restore mapping context + ; + push ax + + push es + pop ds ; DGROUP + get_FRS_Window DI ; ES:DI <-- FRS mapping context regs + push fs + pop ds ; DS:SI <-- client's stack + xor ch, ch + mov cl, ES:[_cntxt_bytes] + shr cx, 1 ; move word + cld + rep movsw + ; + ; map old mapping + ; + lodsb + mov ah, 0 + mov cx, ax ; length + pop ax ; subfunction code + push si + push cx + push bp + mov bp, [_regp] ; setup pushad frame first + push es + pop ds ; DS <-- DGROUP + call MapHandleArray_Entry_2 ; map it + pop bp + pop cx + pop si + shl cx, 2 ; 4 bytes per mapping + release_space_to_stack CX + ; + ; saves CS:IP (BX:CX) on iretd stack frame + ; + push fs + pop ds ; DS <-- Client's Stack + push ax + lodsw + mov word ptr [bp.VTFOE+VMTF_EIP], ax + lodsw + mov word ptr [bp.VTFOE+VMTF_CS], ax + lodsw + mov word ptr [bp.VTFOE+VMTF_EFLAGS], ax + mov word ptr [bp.VTFOE+VMTF_EFLAGShi], PFLAG_VM + pop ax + ; + ; save client's new stack pointer + ; + mov dword ptr [bp.VTFOE.VMTF_ESP], esi + popad + pop esi + pop ebx + pop ebp + add esp, 4 ; discard "error" code + ; + ; set return status + ; + mov ah, OK + + iretd + +AMC_return_address endp + + page +;****************************************************************************** +; +; _MoveExchangeMemory +; +; This function (23) will copy or exchange memory between EMM and +; conventional memory or EMM to EMM. +; Subfunction 0 is memory copy. Subfunction 1 is exchange. +; The current mapping context is preserved since the EMM pages are +; mapped into high memory using VM1s page table. +; +; ENTRY: PROTECTED MODE ONLY +; AL = Subfunction -- 0 = Copy, 1 = Exchange +; DX = EMM handle +; REGS on STACK DS:SI = Move/Exchange structure +; SS:[BP] -> regp stack frame +; DS = DGROUP +; +; EXIT: AL = Status +; +; USES: AX, BX, CX, DX, SI, DI +; +;============================================================================== +; +; ALGORITHM: +; +; BEGIN +; check/validate source/dest and overlay,etc +; +; save mapping context of first physical page frame as source page frame +; save mapping context of second physical page frame as dest page frame +; +; /* +; * setup source and dest memory pointers +; */ +; if (source.type == conv.mem) +; DS:SI = source.initial.segment:source.initial.offset +; else +; if (backward.copy) +; calculate last source emm page and new offset +; map source.initial.page into source.page.frame +; DS:SI = segment.of.source.page.frame:source.initial.offset +; +; if (dest.type == conv.mem) +; ES:DI = dest.initial.segment:dest.initial.offset +; else +; if (backward.copy) +; calculate last dest emm page and new offset +; map dest.initial.page into dest.page.frame +; ES:DI = segment.of.dest.page.frame:dest.initial.offset +; +; /******** +; * +; * DS:SI - addresses source data area +; * ES:DI - addresses dest buffer area +; * +; */ +; +; for (total.byte.to.process != 0) { +; /* +; * find out how many bytes to process (least bytes to process) +; */ +; if (source.type == conv.mem) +; bytes.to.process = 0x4000 - dest.offset +; else +; if (dest.type == conv.mem) +; bytes.to.process = 0x4000 - source.offset +; else /* emm to emm */ +; if (backward.copy) +; bytes.to.process = min(source.offset, dest.offset) + 1 +; else +; bytes.to.process = 0x4000 - max(source.offset, dest.offset) +; +; /* +; * adjust the total +; */ +; if (bytes.to.process > totol.bytes.to.process) +; bytes.to.process = totol.bytes.to.process +; +; total.bytes.to.process -= bytes.to.process +; +; /* +; * do the processing +; */ +; move/exchange bytes.to.process bytes +; +; /* +; * adjust memory pointers and map in new pages if necessary +; * for the next iternation +; */ +; if (total.bytes.to.process != 0) +; if (source.type == emm) +; if (SI == 0x4000) +; /* +; * forward.copy's index expire +; */ +; map next emm source page into source.page.frame +; SI = 0 +; if (SI == 0xffff) +; /* +; * backward.copy's index expire +; */ +; map prev emm source page into source.page.frame +; SI = 0x3fff +; else +; normalize DS:SI +; +; if (dest.type == emm) +; if (DI == 0x4000) +; /* +; * forward.copy's index expire +; */ +; map next emm dest page into dest.page.frame +; DI = 0 +; if (DI == 0xffff) +; /* +; * backward.copy's index expire +; */ +; map prev emm dest page into dest.page.frame +; DI = 0x3fff +; else +; normalize ES:DI +; } +; +; restore first page frame's mapping context +; restore second page frame's mapping context +; END +; +;============================================================================== + + +_MoveExchangeMemory proc near + mov byte ptr [bp.rAX+1], OK ; Assume everything work OK + cld ; Assume forward direction + + cmp al, 1 ; Q: Valid subfunction? + ja mem_inv_sub ; N: Error + + push ds + pop fs ; fs <-- addresses MEMM's data group + + push dx + push cx + push bx + push ax + + push bp + mov bp,[_regp] + mov ax, word ptr [bp.rDS] ; DX:AX <-- move/xchg struct + mov dx, word ptr [bp.rSI] + Set_EMM_GDT USER1_GSEL ; use USER1_GSEL since both EMM1_GSEL + ; and EMM2_GSEL will be used + mov ds, bx + xor si, si ; DS:SI <-- Move/Exchange structure + pop bp + pop ax + pop bx + pop cx + pop dx + + mov ecx, [si.mem_region_length]; ECX = Length of memory region + or ecx, ecx ; Q: Move 0 bytes? + jz mem_no_error ; Y: Silly! -- Just return + cmp ecx, 0100000h ; Q: Move greater than 1 Meg? + ja mem_inv_region_len ; Y: Error + + mov bl, [si.mem_source.mem_memory_type]; Q: Is move Conventional + or bl, [si.mem_dest.mem_memory_type] ; to Conven? + jz mem_conv_to_conv ; Y: Go do it + + mov bl, [si.mem_source.mem_memory_type]; Q: Is move EMM + and bl, [si.mem_dest.mem_memory_type] ; to EMM + jz SHORT mem_no_overlap ; N: No overlap + mov bx, [si.mem_source.mem_handle] + cmp bx, [si.mem_dest.mem_handle] ; Q: Same handle? + jnz SHORT mem_no_overlap ; N: No overlap + movzx ebx, [si.mem_source.mem_initial_seg_page] + movzx edx, [si.mem_source.mem_initial_offset] + shl ebx, 14 ; * 4000h + add ebx, edx ; EBX = Source offset within EMM + push ebx ; Save it temporarily + movzx edx, [si.mem_dest.mem_initial_seg_page] + movzx ebx, [si.mem_dest.mem_initial_offset] + shl edx, 14 ; * 4000h + add edx, ebx ; EDX = Dest offset within EMM + pop ebx ; Source offset + sub edx, ebx ; EDX = Source - Destination + jg SHORT mem_dest_gt_source ; Don't negate if Dest > Source + or al, Source_GT_Dest_Flag ; Set flag to note Source > Dest + neg edx ; Absolute value of EDX +mem_dest_gt_source: + cmp edx, ecx ; Q: Is there an overlap? + jae SHORT mem_no_overlap ; N: Continue + test al, 1 ; Q: Is this an exchange? + jnz mem_inv_overlap ; Y: Error -- Cant overlap xchg + mov byte ptr [bp.rAX+1], VALID_OVERLAP ; Assume everything OK but overlap + or al, Overlap_Flag ; N: Note this for later + test al, Source_GT_Dest_Flag ; Q: Is it gonna be backward copy + jnz mem_no_overlap ; N: Continue + or al, Backward_Copy_Flag ; Y: Note for later + std ; Set backword direction + +mem_no_overlap: + ; + ; check validility of source + ; + lea di, [si.mem_source] + call validate_for_Move_or_Exchange + or ah, ah + jnz mem_error_exit + ; + ; check validility of dest + ; + lea di, [si.mem_dest] + call validate_for_Move_or_Exchange + or ah, ah + jnz mem_error_exit + + or edx, edx ; delayed test for exact move/xchg + je mem_valid_overlap ; WEIRD!!! -- Move to same place! +; +; initialize loop +; + push ds + pop gs + mov bx, si ; GS:BX <-- move/exchange structure + ; + ; save first 2 physical page frames' mapping and use those pages + ; as source and dest physical pages + ; + push fs + pop ds ; DS <-- DGROUP + get_FRS_Window SI + push word ptr [SI] ; save 1st pgae's mapping on stack + push word ptr [SI+2] ; save 2st page's mapping on stack + + ; + ; setup dest + ; +mem_set_dest: + cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ? + jnz mem_map_dest ; N: map in emm page + ; + ; conv memory : setup starting address of dest (always forward) + ; + mov cx, gs:[bx.mem_dest.mem_initial_seg_page] + mov dx, gs:[bx.mem_dest.mem_initial_offset] ; CX:DX <-- dest address + + push ax + push bx + mov ax, cx ; AX:DX <-- first byte + Set_EMM_GDT EMM2_GSEL + mov es, bx + xor di, di ; ES:DI <-- dest SelOff + pop bx + pop ax + push 0ffffh ; fake a logical page# + jmp mem_set_source + +mem_map_dest: + ; + ; emm memory : find out starting address of dest + ; + mov dx, gs:[bx.mem_dest.mem_initial_seg_page] ; initial logical page# + mov di, gs:[bx.mem_dest.mem_initial_offset] ; initial offset + + test al, Backward_Copy_Flag ; Q: Backward copy ? + jz SHORT mem_map_dest_forward ; N: forward + + ; + ; backward move : calculate last logical page# and offset + ; + mov ecx, gs:[bx.mem_region_length] + movzx edi, gs:[bx.mem_dest.mem_initial_offset] + dec edi + add ecx, edi + push ecx + and ecx, 00003fffh + mov edi, ecx ; new offset + pop ecx + shr ecx, 14 ; / 16K = # of pages + add dx, cx ; last emm page# + +mem_map_dest_forward: + push dx ; put current dest logical page# on stack + ; + ; prepare to map + ; + push ax + push bx + + push dx + mov dx, gs:[bx.mem_dest.mem_handle] + Handle2HandlePtr + pop bx + mov ax, 1 ; 2nd page frame + call map_page + jc mem_mapping_error_3_pop ; pop out dest seg_page + + ; contruct GDT entry for EMM2_GSEL for ES:0 + ; + mov ax, [PF_Base] + add ax, 0400h ; 2nd page frame segment + xor dx, dx ; offset 0 + Set_EMM_GDT EMM2_GSEL + mov es, bx ; ES:DI <-- dest address + + pop bx + pop ax + + ; + ; setup source + ; +mem_set_source: + cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ? + jnz mem_map_source ; N: map in emm page + ; + ; conv memory : setup starting address of source (always forward) + ; + mov cx, gs:[bx.mem_source.mem_initial_seg_page] + mov dx, gs:[bx.mem_source.mem_initial_offset] ; CX:DX <-- source address + + push ax + push bx + push es + mov ax, cx ; AX:DX <-- first byte + Set_EMM_GDT EMM1_GSEL + mov ds, bx + xor si, si + pop es + pop bx + pop ax + push 0ffffh ; fake a logical page# + jmp short mem_set_done + +mem_map_source: + ; + ; emm memory : find out starting address of dest + ; + mov dx, gs:[bx.mem_source.mem_initial_seg_page] ; initial logical page# + mov si, gs:[bx.mem_source.mem_initial_offset] ; inital offset + + test al, Backward_Copy_Flag ; Q: Backward copy ? + jz SHORT mem_map_source_forward ; N: forward + + ; + ; backward move : calculate last logical page# and offset + ; + mov ecx, gs:[bx.mem_region_length] + movzx esi, gs:[bx.mem_source.mem_initial_offset] + dec esi + add ecx, esi + push ecx + and ecx, 00003fffh + mov esi, ecx ; new offset + pop ecx + shr ecx, 14 ; / 16K = # of pages + add dx, cx ; last emm page# + +mem_map_source_forward: + push dx ; put current source logical page# on stack + ; + ; prepare to map + ; + push ax + push bx + + push dx + mov dx, gs:[bx.mem_source.mem_handle] + Handle2HandlePtr + pop bx + mov ax, 0 ; 1st page frame + call map_page + jc mem_mapping_error_4_pop ; pop out dest and source seg_page + + ; contruct GDT entry for EMM1_GSEL for DS:0 + ; + mov ax, [PF_Base] ; 1st page frame segment + xor dx, dx ; offset 0 + push es + Set_EMM_GDT EMM1_GSEL + pop es ; ES:0 <-- GDT + mov ds, bx ; ES:DI <-- dest address + + pop bx + pop ax + + ; DS:SI <-- source address + ; ES:DI <-- dest address + +mem_set_done: + mov edx, gs:[bx.mem_region_length] ; total length to move/xchg + +; +; main move/exchange loop +; +mem_loop: + mov ecx, cr3 + mov cr3, ecx ; flush TLB after each map loop + + mov ecx, 4000h ; maximum length to move/xchg + ; in one mapping (<16K) + cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ? + jnz mem_source_is_emm ; N: check dest + sub cx, di ; CX <-- length to move/xchg + jmp short mem_calculate_length +mem_source_is_emm: + cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ? + jnz mem_both_are_emm ; N: find out which + ; emm has less + ; to move/exchange + sub cx, si ; CX <-- length to move/xchg + jmp short mem_calculate_length +mem_both_are_emm: + test al, Backward_Copy_Flag ; Q:backward copy ? + jz SHORT mem_2_emm_forward ; N:forward + mov cx, si + inc cx + cmp si, di ; Q:sidi ? (max(si,di)) + ja mem_si_gt_di ; Y: use si + sub cx, di ; N: use di + jmp short mem_calculate_length +mem_si_gt_di: + sub cx, si ; si>di + +mem_calculate_length: + cmp ecx, edx ; Q: bytes in this batch > total + jbe mem_do_move_xchg ; N: go ahead to move/xchg + mov ecx, edx ; Y: use total instead + +; +; move/xchg loop +; +mem_do_move_xchg: + sub edx, ecx ; Adjust total first + + test al, 1 ; Q: Is this an exchange? + jnz SHORT mem_exchange ; Y: Do it + test al, Backward_Copy_Flag ; N: Q:Is this backward copy ? + jz SHORT mem_move_forward ; N: forward +; +; memory move backward +; + rep movsb + jmp mem_next_round +; +; memory move forward +; +mem_move_forward: + push eax + mov eax, ecx + shr ecx, 2 ; ECX = # DWORDS to copy + rep movsd ; Move the DWORDS + mov ecx, eax + and ecx, 00000003h ; ECX = # BYTES left to copy + rep movsb ; Move the BYTES + pop eax + jmp short mem_next_round +; +; momory exchange +; +mem_exchange: + push dx + push ax + push bx + push ecx ; Save total # bytes on stack + shr ecx, 2 ; ECX = # DWORDS to exchange + jecxz mem_xchg_bytes ; Exit if no DWORDS left + mov dx, 4 ; Size of DWORD +mem_xchg_dword_loop: + mov eax, [si] + mov ebx, es:[di] + mov es:[di], eax + mov [si], ebx + add si, dx + add di, dx + loop mem_xchg_dword_loop ; Loop until all DWORDS exchanged +mem_xchg_bytes: + pop ecx + and ecx, 00000003h ; ECX = # BYTES left to exchange + jecxz mem_xchg_done ; Exit if no DWORDS left +mem_xchg_byte_loop: + mov al, [si] + mov bl, es:[di] + mov es:[di], al + mov [si], bl + inc si + inc di + loop mem_xchg_byte_loop ; Loop until all BYTES exchanged +mem_xchg_done: + pop bx + pop ax + pop dx ; DONE!!!! + +; +; prepare for next iteration +; +mem_next_round: + ; + ; get source and dest's current mapped logical page + ; from stack + ; + pop cx ; source logical page# + shl ecx, 16 ; put in high word + pop cx ; dest logical page# + + or edx, edx ; Q: all done ? + jz mem_exit ; Y: restore context first + + ; fix dest addresses + ; + cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ? + jnz mem_map_next_dest ; N: map next page + normalize ES,DI + jmp mem_check_source + +mem_map_next_dest: + cmp di, 4000h ; Q: di expires (forward)? + je short mem_map_next_dest_forward ; Y: + cmp di, 0ffffh ; Q: di expires (backward) ? + jne short mem_check_source ; N: go check source + + mov di, 3fffh ; set di for next round + dec cx ; next logical page + jmp SHORT mem_map_next_dest_do_map + +mem_map_next_dest_forward: + xor di, di ; clear di for next round + inc cx ; next logical page + + ; + ; map in the next dest page + ; +mem_map_next_dest_do_map: + push dx + push ax + push bx + push ecx + push ds + push fs + pop ds + mov dx, gs:[bx.mem_dest.mem_handle] + Handle2HandlePtr + mov ax, 1 ; 2nd page frame + mov bx, cx + call map_page + pop ds + pop ecx + pop bx + pop ax + pop dx + jc mem_mapping_error + + ; + ; fix source addresses + ; +mem_check_source: + ror ecx, 16 ; get source log page in low word + cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ? + jnz mem_map_next_source ; N: map next page + normalize DS,SI + jmp mem_check_done + +mem_map_next_source: + cmp si, 4000h ; Q: si expires (forward)? + je short mem_map_next_source_forward ; Y: + cmp si, 0ffffh ; Q: si expires (backward) ? + jne short mem_check_done ; N: all done + + mov si, 3fffh ; set si for next round + dec cx ; next logical page + jmp SHORT mem_map_next_source_do_map + +mem_map_next_source_forward: + xor si, si ; clear si for next round + inc cx ; next logical page + + ; + ; map in the next source page + ; +mem_map_next_source_do_map: + push dx + push ax + push bx + push ecx + push ds + push fs + pop ds + mov dx, gs:[bx.mem_source.mem_handle] + Handle2HandlePtr + mov ax, 0 ; 1st page frame + mov bx, cx + call map_page + pop ds + pop ecx + pop bx + pop ax + pop dx + jc mem_mapping_error + ; + ; push back the logical pages on stack for + ; next iternation : dest first, then source + ; +mem_check_done: + ror ecx, 16 + push cx + ror ecx, 16 + push cx + jmp mem_loop + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; conv to conv +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +mem_conv_to_conv: + ; + ; check validility of source + ; + lea di, [si.mem_source] + call validate_for_Move_or_Exchange + or ah, ah + jnz mem_error_exit + ; + ; check validility of dest + ; + lea di, [si.mem_dest] + call validate_for_Move_or_Exchange + or ah, ah + jnz mem_error_exit + + push ax ; save subfunction + push [si.mem_region_length] ; save length + + movzx eax, [si.mem_dest.mem_initial_seg_page] + movzx edx, [si.mem_dest.mem_initial_offset] + mov edi, eax + shl edi, 4 + add edi, edx ; EDI <-- dest linear addr + Set_EMM_GDT EMM2_GSEL + Set_Page_Gran EMM2_GSEL + push bx ; save dest GDT selector + + movzx eax, [si.mem_source.mem_initial_seg_page] + movzx edx, [si.mem_source.mem_initial_offset] + mov esi, eax + shl esi, 4 + add esi, edx ; ESI <-- source linear addr + Set_EMM_GDT EMM1_GSEL + Set_Page_Gran EMM1_GSEL + mov ds, bx + + pop es ; recover dest GDT sel + pop ecx ; recover length + pop ax ; recover subfunction + ; + ; test for overlapping transfer + ; + mov byte ptr [bp.rAX+1], VALID_OVERLAP ; assume valid overlap + sub edi, esi ; EDI = Source - Destination + jg SHORT mem_dest_gt_source_2 ; Don't negate if Dest > Source + or al, Source_GT_Dest_Flag ; Set flag to note Source > Dest + neg edi ; Absolute value of EDI +mem_dest_gt_source_2: + mov ebx, edi ; Use EBX instead + cmp ebx, ecx ; Q: Is there an overlap? + jae SHORT mem_no_overlap_2 ; N: Continue + test al, 1 ; Q: Is this an exchange? + jnz mem_inv_overlap ; Y: Error -- Cant overlap xchg + or al, Overlap_Flag ; N: Note this for later + test al, Source_GT_Dest_Flag ; Q: Is it gonna be backward copy + jnz mem_no_overlap_2 ; N: Continue + or al, Backward_Copy_Flag ; Y: Note for later + + mov edx, (not 1)+1 ; increment value of -1 (2's compliment of 4) + mov esi, ecx ; Fix ESI and EDI for reverse copy + dec esi + mov edi, esi + jmp short mem_conv_copy + +mem_no_overlap_2: + mov byte ptr [ebp.rAX+1], OK ; Everything worked OK + mov edx, 1 ; increment value of 1 + xor esi, esi ; DS:ESI <-- source addr + xor edi, edi ; ES:EDI <-- dest addr + + test al, 1 ; Q:copy ? + jnz mem_conv_xchg ; N:go do exchange + +mem_conv_copy: + or ebx, ebx + je mem_valid_overlap ; WEIRD!!! -- Move to same place! + + jecxz mem_conv_done +mem_conv_copy_loop: + mov bl, [esi] + mov es:[edi], bl + add esi, edx + add edi, edx + dec ecx + jnz mem_conv_copy_loop + jmp mem_conv_done ; DONE!!!! + +mem_conv_xchg: + jecxz mem_conv_done +mem_conv_xchg_loop: + mov al, [esi] + mov bl, es:[edi] + mov es:[edi], al + mov [esi], bl + inc esi + inc edi + dec ecx + jnz mem_conv_xchg_loop ; Loop until all BYTES exchanged +mem_conv_done: + Set_Byte_Gran EMM1_GSEL ; make sure EMM1_GSEL and + Set_Byte_Gran EMM2_GSEL ; EMM2_GSEL are Byte Granulated + ret + +mem_error_exit: + cld + mov byte ptr [bp.rAX+1], ah ; error code already set in ah + ret +mem_valid_overlap: + mov byte ptr [bp.rAX+1], VALID_OVERLAP + ret +mem_no_error: + mov byte ptr [bp.rAX+1], OK + ret + +mem_inv_sub: + mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION + ret +mem_inv_region_len: + mov byte ptr [bp.rAX+1], INVALID_REGION_LENGTH + ret +mem_bad_memory_types: + mov byte ptr [bp.rAX+1], INVALID_MEMORY_TYPE + ret +mem_inv_overlap: + mov byte ptr [bp.rAX+1], OVERLAPPING_EXCHANGE + ret +; +; discard old ax,bx,source seg_page#,dest seg_page# +; +mem_mapping_error_4_pop: + pop bx +mem_mapping_error_3_pop: + pop bx + pop bx + pop bx +mem_mapping_error: + mov eax, cr3 ; Always clear TLB, we may have + mov cr3, eax ; mapped pages before an error +; +; all done, need to restore context of physical page frames +; +mem_exit: + push fs ; get DGROUP back into DS + pop ds + get_FRS_Window BX + pop word ptr [bx+2] + pop word ptr [bx] + cld ; string forward again + jmp _set_windows ; remap all pages + +_MoveExchangeMemory endp + + +;****************************************************************************** +; +; validate_for_Move_Or_Exchange +; +; This procedure is called by _MoveExchangeMemory to validate +; varies parameter on the memeory descriptor structure. +; It is called once for the source and once for the +; destination memory descriptor structures. +; +; ENTRY: +; CX = move length +; DS:DI = Move/Exchange memory descriptor data structure (source or dest) +; FS = MEMM's data segment +; EXIT: +; AH = Status (0 = No error) -- AL is preserved +; +; USES: +; DI, Flags +; AL and all other registers are preserved +; +;============================================================================== + +validate_for_Move_Or_Exchange PROC NEAR + + push edx ; Used as temporary variable + push eax + + mov dl, [di.mem_memory_type] + or dl, dl ; Q: Conventional memory? + jz ME_Map_Conventional ; Y: Nothing to map + cmp dl, 1 ; Q: Expanded memory? + jne ME_Map_Inv_Mem ; N: Invalid memory type + ; Y: EMM memory -- Must map it + mov dx, [di.mem_handle] ; Get the handle + + push ds ; validate_handle expect DS + push fs ; points to dgroup + pop ds + Validate_Handle ME_Map_Inv_Handle ; check it + pop ds + + xchg bx, dx + mov ax, fs:[bx.ht_count] ; EAX = # pages in handle + xchg bx, dx + cmp ax,[di.mem_initial_seg_page];Q: Is initial page in range + jbe ME_Map_Invalid_log_page ; N: Error + cmp [di.mem_initial_offset], 04000h; Q: Is offset unreasonable? + jae ME_Map_Invalid_Offset ; Y: Error + + movzx edx, [di.mem_initial_offset] + add edx, ecx + add edx, 16 * 1024 - 1 ; round up to nearest emm page boundary + shr edx, 14 ; / 16K = # of emm pages + add dx, [di.mem_initial_seg_page] ; last emm page of move/exchange + cmp dx, ax + ja ME_Map_Not_Enough_EMM ;Q: Is last page in range + jmp short ME_Map_OK ; N: error + +ME_Map_Conventional: + movzx edx, word ptr [di.mem_initial_seg_page] + shl edx, 4 + movzx edi, word ptr [di.mem_initial_offset] + add edx, edi ; EDX --> Conven mem to move/exch + mov edi, edx ; Use EDI for test + add edi, ecx ; EDI = Base + Move length + cmp edi, 100000h ; Q: Is there wraparound? + jae SHORT ME_Map_Inv_Wraparound ; Y: Error + cmp fs:[_page_frame_pages], 0 ; Is there a page frame? + je short No_EMM_Overlap ; no, no problem + cmp edi, 0E0000h ; Q: Is move ABOVE EMM area? + jae SHORT No_EMM_Overlap ; Y: That's not a problem + movzx eax, fs:[PF_Base] ; Where page frame starts + shl eax, 4 + cmp edi, eax ; Q: Does move run into EMM area? + ja SHORT ME_Map_Inv_Overlap ; Y: Error +No_EMM_Overlap: + ; N: Everything is okie dokie +ME_Map_OK: + pop eax + pop edx + mov ah, OK + ret + +ME_Map_Inv_Mem: + pop eax + pop edx + mov ah, INVALID_MEMORY_TYPE + ret + +ME_Map_Inv_Handle: + pop ds + pop eax + pop edx + mov ah, INVALID_HANDLE + ret + +ME_Map_Invalid_log_page: + pop eax + pop edx + mov ah, LOG_PAGE_RANGE + ret + +ME_Map_Invalid_Offset: + pop eax + pop edx + mov ah, INVALID_OFFSET + ret + +ME_Map_Not_Enough_EMM: + pop eax + pop edx + mov ah, INSUFFICIENT_EMM_PAGES + ret + +ME_Map_Inv_Overlap: + pop eax + pop edx + mov ah, CONVENTIONAL_EMM_OVERLAP + ret + +ME_Map_Inv_Wraparound: + pop eax + pop edx + mov ah, INVALID_WRAPAROUND + ret + +validate_for_Move_Or_Exchange ENDP + + + page +;*********************************************** +; +; _AlternateMapRegisterSet - handle alternative register sets +; +; This routine switches the current register set or stores +; the current page mapping context to an external save area and/or +; restores the current page mapping context from an external save area. +; +; ENTRY: PROTECTED MODE ONLY +; AH = 5Bh = Alternate Map Register Set function +; AL = SUBFUNCTION CODE +; AL = 0 => Get Alternate Map Register Set +; AL = 1 => Set Alternate Map Register Set +; AL = 2 => Get and Set Alternate Map Register Set +; AL = 3 => Get Alternate Map Save Array size +; AL = 4 => Allocate Alternate Map Register Set +; AL = 5 => Deallocate Alternate Map Register Set +; AL = 6 => Enable DMA on Alternate Map Register Set +; AL = 7 => Disable DMA on Alternate Map Register Set +; See sub-functions for individual ENTRY registers +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: from individual sub-function or error with +; AH = INVALID_SUBFUNCTION +; +; USED: EAX,ESI +; +;*********************************************** +Dword_Align _TEXT +_AlternateMapRegisterSet proc near + cmp [_OSEnabled], OS_DISABLED + jae short AMRS_NotAllowed ; Disabled by OS + cmp al, 08h ; Valid sub-function? + ja short AMRS_invalid + cld ; Done for all sub-functions + mov byte ptr [bp.rAX+1], OK ; Assume success! + movzx esi, al ; get offset to function dispatch + shl si, 1 + jmp CS:AMRS_map[si] ; go to relevant sub-function + ; Return directly or to AMRS_exit... +AMRS_exit: ; Exit with AH already set + ret + +AMRS_NotAllowed: + mov byte ptr [bp.rAX+1], ACCESS_DENIED + ret + +AMRS_invalid: + mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION + ret ; Error return! + +AMRS_bad_src: + mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED + ret ; Error return! + +AMRS_noDMA: + mov byte ptr [bp.rAX+1], FRSET_NO_DMA + ret ; Error return! + +Dword_Align _TEXT +AMRS_map dw _TEXT:AMRS_get + dw _TEXT:AMRS_set + dw _TEXT:AMRS_size + dw _TEXT:AMRS_allocate + dw _TEXT:AMRS_deallocate + ; For now... + dw _TEXT:AMRS_noDMA ; AMRS_DMAallocate + dw _TEXT:AMRS_noDMA ; AMRS_DMAassign + dw _TEXT:AMRS_noDMA ; AMRS_DMAdeassign + dw _TEXT:AMRS_noDMA ; AMRS_DMAfree + + page +;*********************************************** +; +; AMRS_get - get the current 'fast' register set +; +; ENTRY: on stack +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: on stack +; BL = register set number, +; state stored in client's buffer if BL == 0 +; ES:SI set to point to client's buffer +; return code set on stack +; +; USED: EAX, EBX +; +; DESCRIPTION: This function returns the current register set number. +; If it is zero, it returns the save area previously specified +; +;----------------------------------------------- +Dword_Align _TEXT +AMRS_get: + mov al, [CurRegSetn] ; Get current set number + mov byte ptr [bp.rBX], al ; to be picked up later + or al, al + jz short AMRS_get0 + ret ; non-zero - all done +AMRS_get0: ; Echo save area address + movzx eax, [EMM_savES] ; saved ES for reg set 0 + mov word ptr [bp.rES], ax + movzx edi, [EMM_savDI] ; saved DI for reg set 0 + mov word ptr [bp.rDI], di + or ax, ax + jnz short AMRS_get2 ; got dest addr + or di, di + jz short AMRS_get1 ; not specified yet +AMRS_get2: + xor dx, dx + Set_EMM_GDT EMM1_GSEL + mov es, bx ; ES:DI <-- temp store + Get_FRS_window SI ; Get pointer to current window + movzx eax, [_cntxt_pages] ; how many pages + stosw ; save size + mov ecx, eax + shr ecx, 1 ; convert to dwords + rep movsd ; save the map +AMRS_get1: + ret + + page +;*********************************************** +; +; AMRS_set - set the current 'fast' register set +; +; ENTRY: BL = register set number +; on stack +; if BL == 0 +; ES:DI -> buffer containing mappings for register set 0 +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: return code set on stack +; +; USED: EAX, EBX, ECX, EDX, ESI, EDI +; +; DESCRIPTION: This function sets the current register set number. +; If it is zero, it uses the save area specified in ES:DI. +; +;----------------------------------------------- +Dword_Align _TEXT +AMRS_set: + cmp bl, FRS_COUNT ; Validate new Reg Set + jae AMRS_inv_FRS + movzx eax, bl + imul eax, size FRS_struc + xchg ax, bx + lea bx, FRS_array[bx] ; Get pointer to the new Reg Set + cmp [bx.FRS_alloc], 0 ; Make sure it is allocated + xchg ax, bx + je AMRS_undef_FRS ; unallocated, go complain + + cmp bl, 0 ; New reg set 0? + je short AMRS_set0 ; yes, always set context + cmp bl, [CurRegSetn] ; Setting the same reg set? + je AMRS_exit ; yes, just return +AMRS_set0: ; Now set up new reg set + mov word ptr [CurRegSet], ax ; Set Current reg. set Offset + mov [CurRegSetn], bl + + or bl, bl ; Real register set? + jne _set_windows ; yes, go deal with it + ; no, deal with reg set 0 + mov ax, word ptr [bp.rES] ; Pick up user's pointer + mov [EMM_savES], ax ; and save for AMRS_get + mov dx, word ptr [bp.rDI] + mov [EMM_savDI], dx ; AX:DX <-- regs cntxt restore area + push ax + or ax, dx + pop ax + jz _set_windows ; AX:DX == 0:0 implies no save area + + ; construct GDT entry using EMM1_GSEL to access user's FRS buffer + ; + push es + Set_EMM_GDT EMM1_GSEL + pop es + + mov fs, bx ; FS:SI <-- FRS buffer + xor si, si + lods word ptr fs:[si] ; get saved count + movzx ecx, [_cntxt_pages] ; what it should be + cmp ax, cx ; Sensible count? + jne _set_windows ; no, restore last context + Get_FRS_window DI + shr ecx, 1 ; size in dwords + push ds ; xchg ds,fs + push fs + pop ds + pop fs ; use DS as default seg. reg. + rep movsd + push ds + push fs + pop ds + pop fs + jmp _set_windows ; set up mappings + + page +;*********************************************** +; +; AMRS_size - get the size of the register set 0 save area +; +; ENTRY: +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: return code set on stack +; DX = size of the save area +; +; USED: none +; +; DESCRIPTION: This function returns the size of the save area used +; for register set 0. +; +;----------------------------------------------- +AMRS_size: + movzx eax, [_cntxt_bytes] ; Previously calculated value + mov word ptr [bp.rDX], ax + ret + + page +;*********************************************** +; +; AMRS_allocate - allocate a fast register set +; +; ENTRY: +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: return code set on stack +; BL = register set number +; +; USED: EBX, ESI +; +; DESCRIPTION: This function allocates a free register set. +; +;----------------------------------------------- +AMRS_allocate: + cmp [FRS_free], 0 ; See if any are free + je short AMRS_noRS ; no, none available + ; Search for first free set + dec [FRS_free] ; We are going to take one + lea di, [FRS_array] ; Start of FRS structures + xor bl, bl ; FRS number +AMRS_search: + cmp [di.FRS_alloc], 0 ; This one free? + je short AMRS_foundRS ; yes, bl has the number + add di, size FRS_struc ; on to the next one + inc bl + cmp bl, FRS_COUNT ; Safety... should never fail + jb short AMRS_search + + mov byte ptr [bp.rAX+1], EMM_SW_MALFUNCTION ; Honesty... + ret + +AMRS_foundRS: + mov [di.FRS_alloc], 1 ; Allocate it + Get_FRS_Window SI + lea di, [di.FRS_Window] + movzx ecx, [_cntxt_pages] + shr ecx, 1 + rep movsd ; Initialise to current mapping + mov byte ptr [bp.rBX], bl ; Return the number + ret + +AMRS_noRS: ; None free; return error + mov byte ptr [bp.rAX+1], NO_MORE_FRSETS + ret + + page +;*********************************************** +; +; AMRS_deallocate - deallocate a fast register set +; +; ENTRY: BL = register set to deallocate +; SS:[EBP] -> regp stack frame +; DS = DGROUP +; +; EXIT: return code set on stack +; +; USED: EAX +; +; DESCRIPTION: This function deallocates a register set. +; +;----------------------------------------------- +AMRS_deallocate: + or bl, bl + jz AMRS_exit ; Deallocating 0 is ignored + cmp bl, [CurRegSetn] ; Can't deallocate current set + je short AMRS_undef_FRS + cmp bl, FRS_COUNT + jae short AMRS_undef_FRS ; Invalid Register set + movzx eax, bl + imul eax, size FRS_struc ; Offset into array + xchg ax, bx + cmp FRS_array[bx.FRS_alloc], 0 ; Paranoid... + xchg ax, bx + je short AMRS_undef_FRS ; Not allocated, complain + xchg ax, bx + mov FRS_array[bx.FRS_alloc], 0 ; Mark it free + xchg ax, bx + inc [FRS_free] ; one more set free + ret + +AMRS_Inv_FRS: +AMRS_undef_FRS: + mov byte ptr [bp.rAX+1], FRSET_UNDEFINED + ret + +_AlternateMapRegisterSet endp + + + page +;****************************************************************************** +; _Get_Key_Val - use the timer to get a random number for OSDisable Key +; +; ENTRY DS, ES = DGROUP selectors +; +; STACK +; +; EXIT EAX has randomish number +; +; USES Flags, EAX, EDX +; +;------------------------------------------------------------------------------ +_Get_Key_Val proc near + call Get_Counter_Value ; (Who cares about the junk in + mov dx, ax ; the high words...?) + call Get_Counter_Value ; Likely to be very close + mul edx ; Mess it all up! + ret + +_Get_Key_Val endp + +;****************************************************************************** +; +; NAME: +; Get_Counter_Value +; +; DESCRIPTION: +; Returns the current system timer counter value +; +; ENTRY: +; Assumes nothing +; +; EXIT: +; AX = Current counter value (High word of EAX NOT CHANGED) +; +; USES: +; Flags +; +;------------------------------------------------------------------------------ + +Get_Counter_Value PROC NEAR + +System_Clock_Port EQU 40h +Sys_Clock_Ctrl_Port EQU 43h + +Latch_Counter EQU 0 + + mov al, Latch_Counter + out Sys_Clock_Ctrl_Port, al ; Latch the timer counter + jmp $+2 + in al, System_Clock_Port ; Read the LSB + mov ah, al + jmp $+2 + in al, System_Clock_Port ; Read the MSB + xchg ah, al ; AX = Counter value + ret + +Get_Counter_Value ENDP + + +_TEXT ENDS +END + + + \ No newline at end of file diff --git a/v4.0/src/MEMM/EMM/EMMSUP.ASM b/v4.0/src/MEMM/EMM/EMMSUP.ASM new file mode 100644 index 0000000..4034e18 --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMSUP.ASM @@ -0,0 +1,652 @@ +page 58,132 +;****************************************************************************** + title EMMSUP - EMM support routines +;****************************************************************************** +; +; (C) Copyright MICROSOFT Corp. 1986 +; +; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver +; EMMLIB.LIB - Expanded Memory Manager Functions Library +; +; Module: EMMSUP - EMM support routines +; +; Version: 0.04 +; +; Date: May 13, 1986 +; +;****************************************************************************** +; +; Change log: +; +; DATE REVISION DESCRIPTION +; -------- -------- ------------------------------------------------------- +; 5/13/86 Original Initial _TEXT +; 6/14/86 Added _sotofar routine and removed stack define. +; And added protected mode check to Map_Page (SBP). +; 6/14/86 map_page now sets _current_map(SBP). +; 6/14/86 moved save_current_map and restore_map from C code (SBP) +; 6/14/86 brought SegOffTo24 and SetDescInfo in from LAST code +; segment as local routines(SBP). +; 6/21/86 0.02 cld in copyout (SBP). +; 6/21/86 0.02 MapHandlePage added. +; 6/23/86 0.02 make_addr, sotofar removed. source_addr and dest_addr +; added. +; 6/27/86 0.02 Fix for restore_map. +; 6/28/86 0.02 Name change from CEMM386 to CEMM (SBP). +; 7/06/86 0.04 Changed _emm_page,_emm_free, & _pft386 to ptrs (SBP). +; 7/06/86 0.04 Changed assumes from _DATA to DGROUP (SBP). +; 7/06/86 0.04 Changed internal save area structure (SBP). +; 7/06/86 0.04 moved SavePageMap and RestorePageMap to .ASM (SBP). +; 7/07/86 0.04 moved MapHandlePage,SavePageMap, and RestorePageMap to +; emmp.asm (SBP). +; 5/09/88 1.01 moved routines names_match and flush_tlb from win386 +; 9/01/88 rename SegOffTo24/SetDescInfo to +; SegOffTo24Resident/SetDescInfoResdient and made public +;****************************************************************************** +; +; Functional Description: +; Support routines for emm/386 +; C callable +; +; +;****************************************************************************** +.lfcond ; list false conditionals +.386p + +;****************************************************************************** +; P U B L I C S +;****************************************************************************** + public _source_addr + public _dest_addr + public _copyout + public _copyin + public _wcopy + public _wcopyb + public _valid_handle + public SetDescInfoResident + public SegOffTo24Resident +; +;****************************************************************************** +; D E F I N E S +;****************************************************************************** + + include vdmseg.inc + include vdmsel.inc + include desc.inc + include page.inc +; include instr386.inc + include emmdef.inc + +FALSE equ 0 +TRUE equ not FALSE +CR equ 0dh +LF equ 0ah + + page +;****************************************************************************** +; E X T E R N A L R E F E R E N C E S +;****************************************************************************** + +_DATA SEGMENT +; +; pointer to entry stack frame +; stored as offset, SS +extrn _regp:word + +; +; current state of mapping registers and # of mapping registers emulated +; +;extrn _current_map:byte +;extrn _map_size:byte + +; +; total # of EMM pages in system +; +extrn _total_pages:word + +; +; table of offsets into in to the first page table +; for user logical emm page map +; +extrn _page_frame_base:dword + +; +; ptr to table of emm page # for each handle's logical pages. +; +extrn _emm_page:word + +; +; ptr to table of page table entries for the EMM pages +; +extrn _pft386:word ; note: actually a dword array + +; +; handle data structure +; +extrn _handle_table:word +extrn _handle_table_size:word + +; +; save area for handles +; +extrn _save_map:byte + +_DATA ENDS + + + page +;****************************************************************************** +; L O C A L D A T A +;****************************************************************************** +_DATA SEGMENT +; +; kludge to prevent unresolved from C compiler +; +public __acrtused +__acrtused label dword + dd (0) +_DATA ENDS + + page +;****************************************************************************** +; C O D E +;****************************************************************************** +_TEXT SEGMENT +assume cs:_TEXT, ds:DGROUP, ss:DGROUP + +;*********************************************** +; +; _source_addr - return far pointer for source address (= int 67 entry DS:SI). +; +; SYNOPSIS: src = source_addr() +; char far *src; /* ptr to area at DS:SI */ +; +; DESCRIPTION: This function generates a far pointer equivalent to the client's +; DS:SI pointer. If this code was called in protected mode, the +; address is a (selector,offset) pair; otherwise, it is a segment +; offset pair. EMM1_GSEL is used if a selector is needed. +; +; 05/09/88 ISP No update needed for MEMM +;*********************************************** +_source_addr proc near +; + push bp +; + mov bp,[_regp] ; get entry stack frame pointer + test [bp.PFlag],PFLAG_VIRTUAL ;Q: real/virtual mode ? + jnz sa_pm ; N: go get selector/offset + mov ax,word ptr [bp.rSI] ; Y: get offset + mov dx,word ptr [bp.rDS] ; get segment + jmp sa_exit ; return DX:AX = seg:offset +; +; protected mode - set up selector to client's DS +sa_pm: + push bx + push cx + push es ; save ES + ; + ; load ES with GDT alias + ; + push GDTD_GSEL + pop es ; ES -> GDT + ; + ; compute physical address + ; + mov ax,word ptr [bp.rDS] ; ax <-- base addr + mov dx,word ptr [bp.rSI] ; dx <-- offset + call SegOffTo24Resident ; converts to physical addr + + ; + ; set up the appropriate table entry + ; + mov bx,EMM1_GSEL ; bx <-- selector + mov cx,0FFFFh ; cx <-- gets limit (64k) + mov ah,D_DATA0 ; ah <-- gets access rights + ; + ; at this point: + ; ah -- access rights + ; al -- bits 16-23 of linear address + ; dx -- low 16 bits of linear address + ; cx -- limit = 64k + ; bx -- selector + ; es -- selector to GDT Alias + call SetDescInfoResident ; set up descriptor + + ; + ; set up return pointer + ; + xor ax,ax ; ax <-- offset (0) + mov dx,bx ; dx <-- selector + ; + pop es ; restore ES + pop cx + pop bx +; +sa_exit: + pop bp + ret +; +_source_addr endp + +;*********************************************** +; +; _dest_addr - return far pointer for destination address (= int 67 entry ES:DI). +; +; SYNOPSIS: dest = dest_addr() +; char far *dest; /* ptr to area at ES:DI */ +; +; DESCRIPTION: This function generates a far pointer equivalent to the client's +; ES:DI pointer. If this code was called in protected mode, the +; address is a (selector,offset) pair; otherwise, it is a segment +; offset pair. EMM2_GSEL is used if a selector is needed. +; +; 05/09/88 ISP No update needed for MEMM +;*********************************************** +_dest_addr proc near +; + push bp +; + mov bp,[_regp] ; get entry stack frame pointer + test [bp.PFlag],PFLAG_VIRTUAL ;Q: real/virtual mode ? + jnz da_pm ; N: go get selector/offset + mov ax,word ptr [bp.rDI] ; Y: get offset + mov dx,word ptr [bp.rES] ; get segment + jmp da_exit ; return DX:AX = seg:offset +; +; protected mode - set up selector to client's DS +da_pm: + push bx + push cx + push es ; save ES + ; + ; load ES with GDT alias + ; + push GDTD_GSEL + pop es ; ES -> GDT + ; + ; compute physical address + ; + mov ax,word ptr [bp.rES] ; ax <-- base addr + mov dx,word ptr [bp.rDI] ; dx <-- offset + call SegOffTo24Resident ; converts to physical addr + + ; + ; set up the appropriate table entry + ; + mov bx,EMM2_GSEL ; bx <-- selector + mov cx,0FFFFh ; cx <-- gets limit (64k) + mov ah,D_DATA0 ; ah <-- gets access rights + ; + ; at this point: + ; ah -- access rights + ; al -- bits 16-23 of linear address + ; dx -- low 16 bits of linear address + ; cx -- limit = 64k + ; bx -- selector + ; es -- selector to GDT Alias + call SetDescInfoResident ; set up descriptor + + ; + ; set up return pointer + ; + xor ax,ax ; ax <-- offset (0) + mov dx,bx ; dx <-- selector + ; + pop es ; restore ES + pop cx + pop bx +; +da_exit: + pop bp + ret +; +_dest_addr endp + + page +;*********************************************** +; +; _copyout +; +; This routine takes a far pointer, a near pointer +; and a byte count and copies from the near address +; to the far address. +; +; Parameters: +; destptr -- sel:off 286 pointer to target area +; srcptr --- offset of source data in current D Seg +; count ---- byte count for copy +; +; uses: +; cx, ax, es +; +; 05/09/88 ISP No update needed for MEMM +;*********************************************** +destptr = 4 +srcptr = 8 +count = 10 +_copyout proc near + push bp ; entry prolog + mov bp,sp + push di ; reg var + push si ; reg var + + les di,[bp+destptr] ; es:di <-- destination address + mov si,[bp+srcptr] ; ds:si <-- source address + mov cx,[bp+count] ; cx <-- byte count + cld ; strings foward + rep movsb ; do it + + pop si ; restore reg var + pop di ; restore reg var + pop bp + ret +_copyout endp + page + +;*********************************************** +; +; _copyin +; +; This routine takes a near pointer, a far pointer +; and a byte count and copies from the far address +; to the near address. +; +; Parameters: +; destptr -- offset of dest in current D Seg +; srcptr --- sel:off 286 pointer to source data area +; count ---- byte count for copy +; +; uses: +; cx, ax, es +; +; 05/09/88 ISP Written for MEMM. +;*********************************************** +destptr = 4 +srcptr = 6 +count = 10 +_copyin proc near + push bp ; entry prolog + mov bp,sp + push di ; reg var + push si ; reg var + push ds + + push ds + pop es ; es to dgroup + + mov di,[bp+destptr] ; es:di <-- destination address + lds si,[bp+srcptr] ; ds:si <-- source address + mov cx,[bp+count] ; cx <-- byte count + cld ; strings foward + rep movsb ; do it + + pop ds + pop si ; restore reg var + pop di ; restore reg var + pop bp + ret +_copyin endp + page +;*********************************************** +; +; _wcopy +; +; This routine takes a two near pointers +; and a word count and copies from the +; first address to the second address. +; +; Parameters: +; srcptr --- offset of source data in current D Seg +; destptr -- offset of destination address in DS +; count ---- word count for copy +; +; uses: +; si, di, cx, ax +; (si, di are restored) +; +; 05/09/88 ISP No update needed for MEMM +;*********************************************** +srcptr = 4 +destptr = 6 +count = 8 +_wcopy proc near + push bp ; entry prolog + mov bp,sp + push di ; reg var + push si ; reg var + + cld ; clear dir flag (forward move) + mov ax,ds ; + mov es,ax ; mov es,ds + mov di,[bp+destptr] ; es:di <-- destination address + mov si,[bp+srcptr] ; ds:si <-- source address + mov cx,[bp+count] ; cx <-- word count + rep movsw ; do it + + pop si ; restore reg var + pop di ; restore reg var + pop bp + ret +_wcopy endp + page +;*********************************************** +; +; _wcopyb +; +; This routine takes a two near pointers +; and a word count and copies from the +; first address to the second address. +; The copy is done backwards to allow certain overlap of source and destination. +; +; Parameters: +; srcptr --- offset of source data in current D Seg +; destptr -- offset of destination address in DS +; count ---- word count for copy +; +; uses: +; si, di, cx, ax, es +; (si, di are restored) +; +; 05/20/88 ISP Shifted in from win386 and updated for 16 bit ptrs +;*********************************************** +srcptr = 4 +destptr = 6 +count = 8 +_wcopyb proc near + push bp ; entry prolog + mov bp,sp + push di ; reg var + push si ; reg var + + mov ax,ds ; + mov es,ax ; mov es,ds + mov di, word ptr [bp+destptr] ; destination address + mov si, word ptr [bp+srcptr] ; source address + mov cx, word ptr [bp+count] ; word count + dec cx + shl cx, 1 ; offset of 'last' word to move + add si, cx + add di, cx + mov cx, word ptr [bp+count] ; recover word count + + std ; set dir flag (backward move) + rep movsw ; do it + cld ; 'C' tends to expect this. + + pop si ; restore reg var + pop di ; restore reg var + pop bp + ret +_wcopyb endp + page +;*********************************************** +; +; _valid_handle - validate current handle +; +; SYNOPSIS: hp = _valid_handle() +; struct handle_ptr *hp; /* ptr to handle's structure */ +; /* OR NULL_HANDLE if invalid handle */ +; /* also sets AH = INVALID_HANDLE if it fails */ +; +; DESCRIPTION: This routine validates the current handle in regp->rDX and +; returns either an error or a ptr to the handle's index and +; page count structure. +; +; 05/09/88 ISP No update needed for MEMM +;*********************************************** +_valid_handle proc near +; + push bp + mov bp,[_regp] ; get entry args pointer + push bx +; + mov bx,word ptr [bp.rDX] ; BX = entry handle + cmp bx,[_handle_table_size] ;Q: handle in range ? + jae vh_fail ; N: return invalid handle error + shl bx,2 ; Y: BX = handle's table offset + add bx,offset DGROUP:_handle_table ; BX = offset to handle's data + cmp [bx.ht_index],NULL_PAGE ;Q: is this an active handle ? + je vh_fail ; N: return invalid handle error + mov ax,bx ; Y: return ptr to handle's data +; +vh_exit: + pop bx + pop bp + ret +vh_fail: + mov byte ptr [bp.rAX+1],INVALID_HANDLE ; set AH on stack + mov ax,NULL_HANDLE ; return NULL_HANDLE to caller + jmp short vh_exit + +; +_valid_handle endp + +;*********************************************** +; +; flush_tlb: +; +; no params, no return value, uses eax +; +; flush the Translation Look-Aside Buffer +; +; 05/09/88 ISP Shifted in from WIN386 +;*********************************************** +_flush_tlb proc near +public _flush_tlb + mov eax, cr3 + mov cr3, eax + ret +_flush_tlb endp + +;*********************************************** +; +; _Names_Match +; +; Returns a boolean value (0 = false, FFFF = True) if 2 handle names match +; +; uses: +; cx, ax +; +; 05/09/88 ISP Shifted in from WIN386 and modified for 16 bit ptrs +;*********************************************** +name1 = 4 +name2 = 6 + public _Names_Match +_Names_Match proc near + push bp ; entry prolog + mov bp,sp + push di ; reg var + push si ; reg var + + mov ax,ds ; initialise es segment to + mov es,ax ; DGROUP + + xor ax, ax ; Assume it did NOT work + + mov di, word ptr [bp+name1] ; First name + mov si, word ptr [bp+name2] ; Second name + cld + mov cx, 2 ; Compare 2 dwords + rep cmpsd ; do it + jne SHORT Names_Dont_Match + not ax ; They match! + +Names_Dont_Match: + pop si ; restore reg var + pop di ; restore reg var + pop bp + ret +_Names_Match endp + + page +;** SetDescInfoResident - set descriptor information +; +; The limit field of a specified descriptor is set. +; (limit = size - 1). +; The base address of the specified descriptor is set. +; The access field of the specified descriptor is set. +; +; ENTRY BX = selector +; ES:0 = descriptor table to use +; CX = limit +; AL, DX = 24 bit base address +; AH = access rights byte +; EXIT None +; USES Flags, other regs preserved +; +; WARNING This code only works on a 286. It can be called in +; either mode. + +SetDescInfoResident proc near + push bx ; save selector + and bl,SEL_LOW_MASK + +; fill in the limit field + + mov es:[bx],cx + +; fill in base address + + mov es:[bx + 2],dx + mov es:[bx + 4],al + +; fill in access rights byte + + mov es:[bx + 5],ah + pop bx + ret +SetDescInfoResident endp + + page +;** SegOffTo24Resident - convert seg:off to 24 bit physical address +; +; The specified real mode segment:offset is converted to +; a 24 bit physical address. +; +; ENTRY AX = segment +; DX = offset +; EXIT AL, DX = 24 bit physical address +; USES AH, Flags, other regs preserved. +; +; WARNING This code only works on a 286. It can be called in +; either mode. + +SegOffTo24Resident proc near + push cx + +; Convert AX:DX into 24 bit addr in AL, DX + + mov ch,ah + shl ax,4 + shr ch,4 ; CH = high byte + add dx,ax ; DX = low word + mov al,ch ; AL = high byte + adc al,0 ; propagate cy from low word + + pop cx + ret +SegOffTo24Resident endp + +_TEXT ENDS +END + \ No newline at end of file diff --git a/v4.0/src/MEMM/EMM/MAKEFILE b/v4.0/src/MEMM/EMM/MAKEFILE new file mode 100644 index 0000000..95f440a --- /dev/null +++ b/v4.0/src/MEMM/EMM/MAKEFILE @@ -0,0 +1,95 @@ +#****************************************************************************** +# title MAKEFILE - EMMLIB.LIB build file +#****************************************************************************** +# +# (C) Copyright MICROSOFT Corp. 1986 +# +# Title: MEMM - MICROSOFT Expanded Memory Manager 386 +# EMMLIB.LIB - EMM functions library +# +# Module: MAKEFILE for EMMLIB - EMM library +# +# Version: 0.02 +# +# Date: May 12, 1986 +# +#****************************************************************************** +# +# Change log: +# +# DATE REVISION DESCRIPTION +# -------- -------- ------------------------------------------------------- +# 06/12/86 Original +# 06/25/86 0.02 Added EMMDEF.INC (SBP). +# +#****************************************************************************** +# +# Functional Description: +# +# This file assembles and links EMMLIB.LIB +# +#****************************************************************************** +.SUFFIXES: +.SUFFIXES: .c .asm .obj .lst .def .lnk .lrf .exe .com + +# Definition for turning OFF high memory allocation +# HIFLAG = -DNOHIMEM => turns it off +# HIFLAG = => turns on high memory allocation +HIFLAG = /DNOHIMEM +#HIFLAG = + +# Definitions for assembler +# (using masm 4.00) +MASM = masm +#MASM = \bin\masm400 +#MASM = masm400 +AFLAGS = /Mx /t /DI386 /i..\memm $(HIFLAG) +AINC = ..\memm\vdmseg.inc ..\memm\vdmsel.inc emmdef.inc + +# Definitions for linker for old style .exe files +#LINK = \bin\link +LINK = link +LFLAGS = /NOI /M +LIBS = + +# Definitions for librarian +#LIB = \bin\lib +LIB = lib + +# Defines for C Compiler +C = cl +#C = \bin\msc +#C = msc +CFLAGS =/ASw /G2 /Oat /Gs /Ze /Zl /Fc /c + +# +# definition of objects +# +OBJS=emmfunct.obj emm40.obj emmp.obj emmsup.obj emmdisp.obj emmdata.obj emminc.obj +LOBJS=emmfunct.obj+emm40.obj+emmp.obj+emmsup.obj+emmdisp.obj+emmdata.obj + +emmlib.lib: $(OBJS) + del emmlib.lib + $(LIB) emmlib+$(LOBJS),; + +emmfunct.obj: emmfunct.c emm.h + $(C) $(CFLAGS) emmfunct.c + +emm40.obj: emm40.c emm.h + $(C) $(CFLAGS) emm40.c + +emmp.obj: emmp.asm $(AINC) + $(MASM) $(AFLAGS) emmp.asm,emmp.obj,emmp.lst; + +emmsup.obj: emmsup.asm $(AINC) + $(MASM) $(AFLAGS) emmsup.asm,emmsup.obj,emmsup.lst; + +emmdisp.obj: emmdisp.asm $(AINC) + $(MASM) $(AFLAGS) emmdisp.asm,emmdisp.obj,emmdisp.lst; + +emmdata.obj: emmdata.asm $(AINC) + $(MASM) $(AFLAGS) emmdata.asm,emmdata.obj,emmdata.lst; + +emminc.obj: emminc.asm $(AINC) + $(MASM) $(AFLAGS) emminc.asm,emminc.obj,emminc.lst; + -- cgit v1.2.3